diff --git a/Makefile b/Makefile
index 54652665b..ac3034c9b 100644
--- a/Makefile
+++ b/Makefile
@@ -108,7 +108,7 @@ clean:
#------------------------------------------------------------------------------
# make install is validated only for Linux, OSX, Hurd and some BSD targets
#------------------------------------------------------------------------------
-ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD DragonFly NetBSD))
+ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD DragonFly NetBSD MSYS_NT))
HOST_OS = POSIX
CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZLIB_SUPPORT:BOOL=ON -DZSTD_LZMA_SUPPORT:BOOL=ON
@@ -117,30 +117,36 @@ CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_B
list:
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
-.PHONY: install uninstall travis-install clangtest gpptest armtest usan asan uasan
+.PHONY: install clangtest gpptest armtest usan asan uasan
install:
@$(MAKE) -C $(ZSTDDIR) $@
@$(MAKE) -C $(PRGDIR) $@
+.PHONY: uninstall
uninstall:
@$(MAKE) -C $(ZSTDDIR) $@
@$(MAKE) -C $(PRGDIR) $@
+.PHONY: travis-install
travis-install:
$(MAKE) install PREFIX=~/install_test_dir
+.PHONY: gppbuild
gppbuild: clean
g++ -v
CC=g++ $(MAKE) -C programs all CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror"
+.PHONY: gcc5build
gcc5build: clean
gcc-5 -v
CC=gcc-5 $(MAKE) all MOREFLAGS="-Werror"
+.PHONY: gcc6build
gcc6build: clean
gcc-6 -v
CC=gcc-6 $(MAKE) all MOREFLAGS="-Werror"
+.PHONY: clangbuild
clangbuild: clean
clang -v
CXX=clang++ CC=clang $(MAKE) all MOREFLAGS="-Werror -Wconversion -Wno-sign-conversion -Wdocumentation"
@@ -224,10 +230,10 @@ asan-%: clean
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=address" $(MAKE) -C $(TESTDIR) $*
msan: clean
- $(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=memory -fno-omit-frame-pointer" # datagen.c fails this test for no obvious reason
+ $(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=memory -fno-omit-frame-pointer" HAVE_LZMA=0 # datagen.c fails this test for no obvious reason
msan-%: clean
- LDFLAGS=-fuse-ld=gold MOREFLAGS="-fno-sanitize-recover=all -fsanitize=memory -fno-omit-frame-pointer" $(MAKE) -C $(TESTDIR) $*
+ LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=memory -fno-omit-frame-pointer" FUZZER_FLAGS=--no-big-tests $(MAKE) -C $(TESTDIR) HAVE_LZMA=0 $*
asan32: clean
$(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address"
@@ -236,10 +242,11 @@ uasan: clean
$(MAKE) test CC=clang MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=address,undefined"
uasan-%: clean
- LDFLAGS=-fuse-ld=gold MOREFLAGS="-Og -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=address,undefined" $(MAKE) -C $(TESTDIR) $*
+ LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize-recover=signed-integer-overflow -fsanitize=address,undefined" $(MAKE) -C $(TESTDIR) $*
tsan-%: clean
- LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=thread" $(MAKE) -C $(TESTDIR) $*
+ LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=thread" $(MAKE) -C $(TESTDIR) $* FUZZER_FLAGS=--no-big-tests
+
apt-install:
sudo apt-get -yq --no-install-suggests --no-install-recommends --force-yes install $(APT_PACKAGES)
diff --git a/NEWS b/NEWS
index 7d9c9c94e..d23a58f02 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,18 @@
+v1.3.0
+cli : new : `--list` command, by Paul Cruz
+cli : changed : xz/lzma support enabled by default
+cli : changed : `-t *` continue processing list after a decompression error
+API : added : ZSTD_versionString()
+API : promoted to stable status : ZSTD_getFrameContentSize(), by Sean Purcell
+API exp : new advanced API : ZSTD_compress_generic(), ZSTD_CCtx_setParameter()
+API exp : new : API for static or external allocation : ZSTD_initStatic?Ctx()
+API exp : added : ZSTD_decompressBegin_usingDDict(), requested by Guy Riddle (#700)
+API exp : clarified memory estimation / measurement functions.
+API exp : changed : strongest strategy renamed ZSTD_btultra, fastest strategy ZSTD_fast set to 1
+tools : decodecorpus can generate random dictionary-compressed samples, by Paul Cruz
+new : contrib/seekable_format, demo and API, by Sean Purcell
+changed : contrib/linux-kernel, updated version and license, by Nick Terrell
+
v1.2.0
cli : changed : Multithreading enabled by default (use target zstd-nomt or HAVE_THREAD=0 to disable)
cli : new : command -T0 means "detect and use nb of cores", by Sean Purcell
diff --git a/README.md b/README.md
index 7caee5fd3..f37be4542 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,17 @@ and a command line utility producing and decoding `.zst` and `.gz` files.
For other programming languages,
you can consult a list of known ports on [Zstandard homepage](http://www.zstd.net/#other-languages).
-|Branch |Status |
-|------------|---------|
-|master | [](https://travis-ci.org/facebook/zstd) |
-|dev | [](https://travis-ci.org/facebook/zstd) |
+| dev branch status |
+|-------------------|
+| [![Build Status][travisDevBadge]][travisLink] [![Build status][AppveyorDevBadge]][AppveyorLink] [![Build status][CircleDevBadge]][CircleLink]
+
+[travisDevBadge]: https://travis-ci.org/facebook/zstd.svg?branch=dev "Continuous Integration test suite"
+[travisLink]: https://travis-ci.org/facebook/zstd
+[AppveyorDevBadge]: https://ci.appveyor.com/api/projects/status/xt38wbdxjk5mrbem/branch/dev?svg=true "Windows test suite"
+[AppveyorLink]: https://ci.appveyor.com/project/YannCollet/zstd-p0yf0
+[CircleDevBadge]: https://circleci.com/gh/facebook/zstd/tree/dev.svg?style=shield "Short test suite"
+[CircleLink]: https://circleci.com/gh/facebook/zstd
+
As a reference, several fast compression algorithms were tested and compared
on a server running Linux Debian (`Linux version 4.8.0-1-amd64`),
@@ -60,11 +67,11 @@ Previous charts provide results applicable to typical file and stream scenarios
The smaller the amount of data to compress, the more difficult it is to compress. This problem is common to all compression algorithms, and reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new data set, there is no "past" to build upon.
To solve this situation, Zstd offers a __training mode__, which can be used to tune the algorithm for a selected type of data.
-Training Zstandard is achieved by provide it with a few samples (one file per sample). The result of this training is stored in a file called "dictionary", which must be loaded before compression and decompression.
+Training Zstandard is achieved by providing it with a few samples (one file per sample). The result of this training is stored in a file called "dictionary", which must be loaded before compression and decompression.
Using this dictionary, the compression ratio achievable on small data improves dramatically.
The following example uses the `github-users` [sample set](https://github.com/facebook/zstd/releases/tag/v1.1.3), created from [github public API](https://developer.github.com/v3/users/#get-all-users).
-It consists of roughly 10K records weighting about 1KB each.
+It consists of roughly 10K records weighing about 1KB each.
Compression Ratio | Compression Speed | Decompression Speed
------------------|-------------------|--------------------
diff --git a/appveyor.yml b/appveyor.yml
index 67c4f72d7..1815563e7 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -30,12 +30,6 @@
SCRIPT: ""
TEST: "cmake"
- - COMPILER: "gcc"
- HOST: "mingw"
- PLATFORM: "x64"
- SCRIPT: ""
- TEST: "pzstd"
-
- COMPILER: "visual"
HOST: "visual"
PLATFORM: "x64"
@@ -88,12 +82,10 @@
( if [%COMPILER%]==[gcc] if [%ARTIFACT%]==[true]
lib\dll\example\build_package.bat &&
make -C programs DEBUGFLAGS= clean zstd &&
- cp programs\zstd.exe zstd_%PLATFORM%.exe &&
- appveyor PushArtifact zstd_%PLATFORM%.exe &&
- cp programs\zstd.exe bin\zstd.exe &&
- make -C programs DEBUGFLAGS= clean zstdmt &&
- cp programs\zstd.exe bin\zstdmt.exe &&
- cd bin\ && 7z a -tzip zstd-win-release-%PLATFORM%.zip * &&
+ cd programs\ && 7z a -tzip -mx9 zstd-win-binary-%PLATFORM%.zip zstd.exe &&
+ appveyor PushArtifact zstd-win-binary-%PLATFORM%.zip &&
+ cp zstd.exe ..\bin\zstd.exe &&
+ cd ..\bin\ && 7z a -tzip -mx9 zstd-win-release-%PLATFORM%.zip * &&
appveyor PushArtifact zstd-win-release-%PLATFORM%.zip
)
)
@@ -159,13 +151,6 @@
cd ..\..\.. &&
make clean
)
- - if [%TEST%]==[pzstd] (
- make -C contrib\pzstd googletest-mingw64 &&
- make -C contrib\pzstd pzstd.exe &&
- make -C contrib\pzstd tests &&
- make -C contrib\pzstd check &&
- make -C contrib\pzstd clean
- )
- SET "FUZZERTEST=-T30s"
- if [%HOST%]==[visual] if [%CONFIGURATION%]==[Release] (
CD tests &&
diff --git a/build/README.md b/build/README.md
index c4abe9efd..23f92cef1 100644
--- a/build/README.md
+++ b/build/README.md
@@ -5,7 +5,7 @@ Projects for various integrated development environments (IDE)
The following projects are included with the zstd distribution:
- `cmake` - CMake project contributed by Artyom Dymchenko
-- `VS2005` - Visual Studio 2005 project
+- `VS2005` - Visual Studio 2005 Project (this project has been moved to the contrib directory and will no longer be supported)
- `VS2008` - Visual Studio 2008 project
- `VS2010` - Visual Studio 2010 project (which also works well with Visual Studio 2012, 2013, 2015)
- `VS_scripts` - command line scripts prepared for Visual Studio compilation without IDE
diff --git a/build/VS2008/fullbench/fullbench.vcproj b/build/VS2008/fullbench/fullbench.vcproj
index 0734219b4..942934561 100644
--- a/build/VS2008/fullbench/fullbench.vcproj
+++ b/build/VS2008/fullbench/fullbench.vcproj
@@ -328,10 +328,6 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
-
-
@@ -340,10 +336,6 @@
RelativePath="..\..\..\lib\common\error_private.c"
>
-
-
@@ -352,36 +344,60 @@
RelativePath="..\..\..\lib\common\xxhash.c"
>
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -419,11 +435,11 @@
>
diff --git a/build/VS2010/fullbench/fullbench.vcxproj b/build/VS2010/fullbench/fullbench.vcxproj
index e16f5e1db..2bff4ca47 100644
--- a/build/VS2010/fullbench/fullbench.vcxproj
+++ b/build/VS2010/fullbench/fullbench.vcxproj
@@ -156,26 +156,32 @@
+
+
+
-
+
+
-
-
+
+
+
+
diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt
index 5c4eca61c..6e30c5325 100644
--- a/build/cmake/CMakeLists.txt
+++ b/build/cmake/CMakeLists.txt
@@ -18,6 +18,9 @@ LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
INCLUDE(AddZstdCompilationFlags)
ADD_ZSTD_COMPILATION_FLAGS()
+# Always hide XXHash symbols
+ADD_DEFINITIONS(-DXXH_NAMESPACE=ZSTD_)
+
#-----------------------------------------------------------------------------
# Options
#-----------------------------------------------------------------------------
@@ -30,6 +33,9 @@ ENDIF (UNIX)
OPTION(ZSTD_BUILD_PROGRAMS "BUILD PROGRAMS" ON)
OPTION(ZSTD_BUILD_CONTRIB "BUILD CONTRIB" OFF)
OPTION(ZSTD_BUILD_TESTS "BUILD TESTS" OFF)
+if (MSVC)
+ OPTION(ZSTD_USE_STATIC_RUNTIME "LINK TO STATIC RUN-TIME LIBRARIES" OFF)
+endif ()
IF (ZSTD_LEGACY_SUPPORT)
MESSAGE(STATUS "ZSTD_LEGACY_SUPPORT defined!")
@@ -45,6 +51,10 @@ ENDIF (ZSTD_LEGACY_SUPPORT)
ADD_SUBDIRECTORY(lib)
IF (ZSTD_BUILD_PROGRAMS)
+ IF (NOT ZSTD_BUILD_STATIC)
+ MESSAGE(SEND_ERROR "You need to build static library to build zstd CLI")
+ ENDIF (NOT ZSTD_BUILD_STATIC)
+
ADD_SUBDIRECTORY(programs)
ENDIF (ZSTD_BUILD_PROGRAMS)
diff --git a/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake b/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake
index e812418e3..a7dc08ea7 100644
--- a/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake
+++ b/build/cmake/CMakeModules/AddZstdCompilationFlags.cmake
@@ -34,27 +34,11 @@ MACRO(ADD_ZSTD_COMPILATION_FLAGS)
EnableCompilerFlag("-Wcast-qual" true true)
EnableCompilerFlag("-Wstrict-prototypes" true false)
elseif (MSVC) # Add specific compilation flags for Windows Visual
- EnableCompilerFlag("/Wall" true true)
-
- # Only for DEBUG version
- EnableCompilerFlag("/RTC1" true true)
- EnableCompilerFlag("/Zc:forScope" true true)
- EnableCompilerFlag("/Gd" true true)
- EnableCompilerFlag("/analyze:stacksize25000" true true)
-
- if (MSVC80 OR MSVC90 OR MSVC10 OR MSVC11)
- # To avoid compiler warning (level 4) C4571, compile with /EHa if you still want
- # your catch(...) blocks to catch structured exceptions.
- EnableCompilerFlag("/EHa" false true)
- endif (MSVC80 OR MSVC90 OR MSVC10 OR MSVC11)
set(ACTIVATE_MULTITHREADED_COMPILATION "ON" CACHE BOOL "activate multi-threaded compilation (/MP flag)")
- if (ACTIVATE_MULTITHREADED_COMPILATION)
+ if (CMAKE_GENERATOR MATCHES "Visual Studio" AND ACTIVATE_MULTITHREADED_COMPILATION)
EnableCompilerFlag("/MP" true true)
endif ()
-
- #For exceptions
- EnableCompilerFlag("/EHsc" true true)
# UNICODE SUPPORT
EnableCompilerFlag("/D_UNICODE" true true)
@@ -71,15 +55,12 @@ MACRO(ADD_ZSTD_COMPILATION_FLAGS)
string(REPLACE ";" " " ${flag_var} "${${flag_var}}")
ENDFOREACH (flag_var)
- if (MSVC)
- # Replace /MT to /MD flag
- # Replace /O2 to /O3 flag
+ if (MSVC AND ZSTD_USE_STATIC_RUNTIME)
FOREACH (flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
- STRING(REGEX REPLACE "/MT" "/MD" ${flag_var} "${${flag_var}}")
- STRING(REGEX REPLACE "/O2" "/Ox" ${flag_var} "${${flag_var}}")
+ STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
ENDFOREACH (flag_var)
endif ()
diff --git a/build/cmake/lib/CMakeLists.txt b/build/cmake/lib/CMakeLists.txt
index 429d49449..f763733bc 100644
--- a/build/cmake/lib/CMakeLists.txt
+++ b/build/cmake/lib/CMakeLists.txt
@@ -13,7 +13,12 @@
PROJECT(libzstd)
SET(CMAKE_INCLUDE_CURRENT_DIR TRUE)
-OPTION(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" OFF)
+OPTION(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" ON)
+OPTION(ZSTD_BUILD_SHARED "BUILD SHARED LIBRARIES" ON)
+
+IF(NOT ZSTD_BUILD_SHARED AND NOT ZSTD_BUILD_STATIC)
+ MESSAGE(SEND_ERROR "You need to build at least one flavor of libstd")
+ENDIF()
# Define library directory, where sources and header files are located
SET(LIBRARY_DIR ${ZSTD_SOURCE_DIR}/lib)
@@ -90,43 +95,44 @@ IF (MSVC)
ENDIF (MSVC)
# Split project to static and shared libraries build
-ADD_LIBRARY(libzstd_shared SHARED ${Sources} ${Headers} ${PlatformDependResources})
+IF (ZSTD_BUILD_SHARED)
+ ADD_LIBRARY(libzstd_shared SHARED ${Sources} ${Headers} ${PlatformDependResources})
+ENDIF (ZSTD_BUILD_SHARED)
IF (ZSTD_BUILD_STATIC)
ADD_LIBRARY(libzstd_static STATIC ${Sources} ${Headers})
ENDIF (ZSTD_BUILD_STATIC)
# Add specific compile definitions for MSVC project
IF (MSVC)
- SET_PROPERTY(TARGET libzstd_shared APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;_CONSOLE;_CRT_SECURE_NO_WARNINGS")
+ IF (ZSTD_BUILD_SHARED)
+ SET_PROPERTY(TARGET libzstd_shared APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_DLL_EXPORT=1;ZSTD_HEAPMODE=0;_CONSOLE;_CRT_SECURE_NO_WARNINGS")
+ ENDIF (ZSTD_BUILD_SHARED)
IF (ZSTD_BUILD_STATIC)
SET_PROPERTY(TARGET libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_HEAPMODE=0;_CRT_SECURE_NO_WARNINGS")
ENDIF (ZSTD_BUILD_STATIC)
ENDIF (MSVC)
-# Define library base name
+# With MSVC static library needs to be renamed to avoid conflict with import library
IF (MSVC)
-
- IF (CMAKE_SIZEOF_VOID_P MATCHES "8")
- SET(LIBRARY_BASE_NAME "zstdlib_x64")
- ELSE ()
- SET(LIBRARY_BASE_NAME "zstdlib_x86")
- ENDIF (CMAKE_SIZEOF_VOID_P MATCHES "8")
+ SET(STATIC_LIBRARY_BASE_NAME zstd_static)
ELSE ()
- SET(LIBRARY_BASE_NAME zstd)
+ SET(STATIC_LIBRARY_BASE_NAME zstd)
ENDIF (MSVC)
# Define static and shared library names
-SET_TARGET_PROPERTIES(
- libzstd_shared
- PROPERTIES
- OUTPUT_NAME ${LIBRARY_BASE_NAME}
- SOVERSION ${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE})
+IF (ZSTD_BUILD_SHARED)
+ SET_TARGET_PROPERTIES(
+ libzstd_shared
+ PROPERTIES
+ OUTPUT_NAME zstd
+ SOVERSION ${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE})
+ENDIF (ZSTD_BUILD_SHARED)
IF (ZSTD_BUILD_STATIC)
SET_TARGET_PROPERTIES(
libzstd_static
PROPERTIES
- OUTPUT_NAME ${LIBRARY_BASE_NAME})
+ OUTPUT_NAME ${STATIC_LIBRARY_BASE_NAME})
ENDIF (ZSTD_BUILD_STATIC)
IF (UNIX)
@@ -141,20 +147,29 @@ IF (UNIX)
-P "${CMAKE_CURRENT_SOURCE_DIR}/pkgconfig.cmake"
COMMENT "Creating pkg-config file")
- # install target
- INSTALL(FILES ${LIBRARY_DIR}/zstd.h ${LIBRARY_DIR}/deprecated/zbuff.h ${LIBRARY_DIR}/dictBuilder/zdict.h DESTINATION "include")
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/libzstd.pc" DESTINATION "share/pkgconfig")
- INSTALL(TARGETS libzstd_shared LIBRARY DESTINATION "lib")
- IF (ZSTD_BUILD_STATIC)
- INSTALL(TARGETS libzstd_static ARCHIVE DESTINATION "lib")
- ENDIF (ZSTD_BUILD_STATIC)
-
- # uninstall target
- CONFIGURE_FILE(
- "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
- IMMEDIATE @ONLY)
-
- ADD_CUSTOM_TARGET(uninstall
- COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
ENDIF (UNIX)
+
+# install target
+INSTALL(FILES
+ ${LIBRARY_DIR}/zstd.h
+ ${LIBRARY_DIR}/deprecated/zbuff.h
+ ${LIBRARY_DIR}/dictBuilder/zdict.h
+ ${LIBRARY_DIR}/common/zstd_errors.h
+ DESTINATION "include")
+
+IF (ZSTD_BUILD_SHARED)
+ INSTALL(TARGETS libzstd_shared RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib")
+ENDIF()
+IF (ZSTD_BUILD_STATIC)
+ INSTALL(TARGETS libzstd_static ARCHIVE DESTINATION "lib")
+ENDIF (ZSTD_BUILD_STATIC)
+
+# uninstall target
+CONFIGURE_FILE(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
+
+ADD_CUSTOM_TARGET(uninstall
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
diff --git a/build/cmake/programs/CMakeLists.txt b/build/cmake/programs/CMakeLists.txt
index cb6aa9218..98ca6cca0 100644
--- a/build/cmake/programs/CMakeLists.txt
+++ b/build/cmake/programs/CMakeLists.txt
@@ -30,14 +30,16 @@ IF (MSVC)
ENDIF (MSVC)
ADD_EXECUTABLE(zstd ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/bench.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/dibio.c ${PlatformDependResources})
-TARGET_LINK_LIBRARIES(zstd libzstd_shared)
-ADD_CUSTOM_TARGET(zstdcat ALL ${CMAKE_COMMAND} -E create_symlink zstd zstdcat DEPENDS zstd COMMENT "Creating zstdcat symlink")
-ADD_CUSTOM_TARGET(unzstd ALL ${CMAKE_COMMAND} -E create_symlink zstd unzstd DEPENDS zstd COMMENT "Creating unzstd symlink")
+TARGET_LINK_LIBRARIES(zstd libzstd_static)
INSTALL(TARGETS zstd RUNTIME DESTINATION "bin")
-INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstdcat DESTINATION "bin")
-INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/unzstd DESTINATION "bin")
IF (UNIX)
+ ADD_CUSTOM_TARGET(zstdcat ALL ${CMAKE_COMMAND} -E create_symlink zstd zstdcat DEPENDS zstd COMMENT "Creating zstdcat symlink")
+ ADD_CUSTOM_TARGET(unzstd ALL ${CMAKE_COMMAND} -E create_symlink zstd unzstd DEPENDS zstd COMMENT "Creating unzstd symlink")
+ INSTALL(TARGETS zstd RUNTIME DESTINATION "bin")
+ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/zstdcat DESTINATION "bin")
+ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/unzstd DESTINATION "bin")
+
ADD_CUSTOM_TARGET(zstd.1 ALL
${CMAKE_COMMAND} -E copy ${PROGRAMS_DIR}/zstd.1 .
COMMENT "Copying manpage zstd.1")
@@ -48,7 +50,7 @@ IF (UNIX)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/unzstd.1 DESTINATION "share/man/man1")
ADD_EXECUTABLE(zstd-frugal ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/fileio.c)
- TARGET_LINK_LIBRARIES(zstd-frugal libzstd_shared)
+ TARGET_LINK_LIBRARIES(zstd-frugal libzstd_static)
SET_PROPERTY(TARGET zstd-frugal APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_NOBENCH;ZSTD_NODICT")
ENDIF (UNIX)
diff --git a/contrib/VS2005/README.md b/contrib/VS2005/README.md
new file mode 100644
index 000000000..ec1ef68a0
--- /dev/null
+++ b/contrib/VS2005/README.md
@@ -0,0 +1,3 @@
+## Project Support Notice
+
+The VS2005 Project directory has been moved to the contrib directory in order to indicate that it will no longer be supported.
diff --git a/build/VS2005/fullbench/fullbench.vcproj b/contrib/VS2005/fullbench/fullbench.vcproj
similarity index 100%
rename from build/VS2005/fullbench/fullbench.vcproj
rename to contrib/VS2005/fullbench/fullbench.vcproj
diff --git a/build/VS2005/fuzzer/fuzzer.vcproj b/contrib/VS2005/fuzzer/fuzzer.vcproj
similarity index 100%
rename from build/VS2005/fuzzer/fuzzer.vcproj
rename to contrib/VS2005/fuzzer/fuzzer.vcproj
diff --git a/build/VS2005/zstd.sln b/contrib/VS2005/zstd.sln
similarity index 100%
rename from build/VS2005/zstd.sln
rename to contrib/VS2005/zstd.sln
diff --git a/build/VS2005/zstd/zstd.vcproj b/contrib/VS2005/zstd/zstd.vcproj
similarity index 100%
rename from build/VS2005/zstd/zstd.vcproj
rename to contrib/VS2005/zstd/zstd.vcproj
diff --git a/build/VS2005/zstdlib/zstdlib.vcproj b/contrib/VS2005/zstdlib/zstdlib.vcproj
similarity index 100%
rename from build/VS2005/zstdlib/zstdlib.vcproj
rename to contrib/VS2005/zstdlib/zstdlib.vcproj
diff --git a/contrib/linux-kernel/0000-cover-letter.patch b/contrib/linux-kernel/0000-cover-letter.patch
new file mode 100644
index 000000000..763b5a9cb
--- /dev/null
+++ b/contrib/linux-kernel/0000-cover-letter.patch
@@ -0,0 +1,96 @@
+From 8bc9a0ae5c86a6d02d9a5274b9965ddac0e8d330 Mon Sep 17 00:00:00 2001
+From: Nick Terrell
+Date: Wed, 28 Jun 2017 22:00:00 -0700
+Subject: [PATCH v2 0/4] Add xxhash and zstd modules
+
+Hi all,
+
+This patch set adds xxhash, zstd compression, and zstd decompression
+modules. It also adds zstd support to BtrFS and SquashFS.
+
+Each patch has relevant summaries, benchmarks, and tests.
+
+Best,
+Nick Terrell
+
+Changelog:
+
+v1 -> v2:
+- Make pointer in lib/xxhash.c:394 non-const (1/4)
+- Use div_u64() for division of u64s (2/4)
+- Reduce stack usage of ZSTD_compressSequences(), ZSTD_buildSeqTable(),
+ ZSTD_decompressSequencesLong(), FSE_buildDTable(), FSE_decompress_wksp(),
+ HUF_writeCTable(), HUF_readStats(), HUF_readCTable(),
+ HUF_compressWeights(), HUF_readDTableX2(), and HUF_readDTableX4() (2/4)
+- No zstd function uses more than 400 B of stack space (2/4)
+
+Nick Terrell (4):
+ lib: Add xxhash module
+ lib: Add zstd modules
+ btrfs: Add zstd support
+ squashfs: Add zstd support
+
+ fs/btrfs/Kconfig | 2 +
+ fs/btrfs/Makefile | 2 +-
+ fs/btrfs/compression.c | 1 +
+ fs/btrfs/compression.h | 6 +-
+ fs/btrfs/ctree.h | 1 +
+ fs/btrfs/disk-io.c | 2 +
+ fs/btrfs/ioctl.c | 6 +-
+ fs/btrfs/props.c | 6 +
+ fs/btrfs/super.c | 12 +-
+ fs/btrfs/sysfs.c | 2 +
+ fs/btrfs/zstd.c | 433 ++++++
+ fs/squashfs/Kconfig | 14 +
+ fs/squashfs/Makefile | 1 +
+ fs/squashfs/decompressor.c | 7 +
+ fs/squashfs/decompressor.h | 4 +
+ fs/squashfs/squashfs_fs.h | 1 +
+ fs/squashfs/zstd_wrapper.c | 150 ++
+ include/linux/xxhash.h | 236 +++
+ include/linux/zstd.h | 1157 +++++++++++++++
+ include/uapi/linux/btrfs.h | 8 +-
+ lib/Kconfig | 11 +
+ lib/Makefile | 3 +
+ lib/xxhash.c | 500 +++++++
+ lib/zstd/Makefile | 18 +
+ lib/zstd/bitstream.h | 374 +++++
+ lib/zstd/compress.c | 3479 ++++++++++++++++++++++++++++++++++++++++++++
+ lib/zstd/decompress.c | 2526 ++++++++++++++++++++++++++++++++
+ lib/zstd/entropy_common.c | 243 ++++
+ lib/zstd/error_private.h | 53 +
+ lib/zstd/fse.h | 575 ++++++++
+ lib/zstd/fse_compress.c | 795 ++++++++++
+ lib/zstd/fse_decompress.c | 332 +++++
+ lib/zstd/huf.h | 212 +++
+ lib/zstd/huf_compress.c | 771 ++++++++++
+ lib/zstd/huf_decompress.c | 960 ++++++++++++
+ lib/zstd/mem.h | 151 ++
+ lib/zstd/zstd_common.c | 75 +
+ lib/zstd/zstd_internal.h | 269 ++++
+ lib/zstd/zstd_opt.h | 1014 +++++++++++++
+ 39 files changed, 14400 insertions(+), 12 deletions(-)
+ create mode 100644 fs/btrfs/zstd.c
+ create mode 100644 fs/squashfs/zstd_wrapper.c
+ create mode 100644 include/linux/xxhash.h
+ create mode 100644 include/linux/zstd.h
+ create mode 100644 lib/xxhash.c
+ create mode 100644 lib/zstd/Makefile
+ create mode 100644 lib/zstd/bitstream.h
+ create mode 100644 lib/zstd/compress.c
+ create mode 100644 lib/zstd/decompress.c
+ create mode 100644 lib/zstd/entropy_common.c
+ create mode 100644 lib/zstd/error_private.h
+ create mode 100644 lib/zstd/fse.h
+ create mode 100644 lib/zstd/fse_compress.c
+ create mode 100644 lib/zstd/fse_decompress.c
+ create mode 100644 lib/zstd/huf.h
+ create mode 100644 lib/zstd/huf_compress.c
+ create mode 100644 lib/zstd/huf_decompress.c
+ create mode 100644 lib/zstd/mem.h
+ create mode 100644 lib/zstd/zstd_common.c
+ create mode 100644 lib/zstd/zstd_internal.h
+ create mode 100644 lib/zstd/zstd_opt.h
+
+--
+2.9.3
diff --git a/contrib/linux-kernel/0001-lib-Add-xxhash-module.patch b/contrib/linux-kernel/0001-lib-Add-xxhash-module.patch
new file mode 100644
index 000000000..84a2c53c6
--- /dev/null
+++ b/contrib/linux-kernel/0001-lib-Add-xxhash-module.patch
@@ -0,0 +1,862 @@
+From 5ac909c415ab4a18fd90794793c96e450795e8c6 Mon Sep 17 00:00:00 2001
+From: Nick Terrell
+Date: Wed, 21 Jun 2017 17:37:36 -0700
+Subject: [PATCH v2 1/4] lib: Add xxhash module
+
+Adds xxhash kernel module with xxh32 and xxh64 hashes. xxhash is an
+extremely fast non-cryptographic hash algorithm for checksumming.
+The zstd compression and decompression modules added in the next patch
+require xxhash. I extracted it out from zstd since it is useful on its
+own. I copied the code from the upstream XXHash source repository and
+translated it into kernel style. I ran benchmarks and tests in the kernel
+and tests in userland.
+
+I benchmarked xxhash as a special character device. I ran in four modes,
+no-op, xxh32, xxh64, and crc32. The no-op mode simply copies the data to
+kernel space and ignores it. The xxh32, xxh64, and crc32 modes compute
+hashes on the copied data. I also ran it with four different buffer sizes.
+The benchmark file is located in the upstream zstd source repository under
+`contrib/linux-kernel/xxhash_test.c` [1].
+
+I ran the benchmarks on a Ubuntu 14.04 VM with 2 cores and 4 GiB of RAM.
+The VM is running on a MacBook Pro with a 3.1 GHz Intel Core i7 processor,
+16 GB of RAM, and a SSD. I benchmarked using the file `filesystem.squashfs`
+from `ubuntu-16.10-desktop-amd64.iso`, which is 1,536,217,088 B large.
+Run the following commands for the benchmark:
+
+ modprobe xxhash_test
+ mknod xxhash_test c 245 0
+ time cp filesystem.squashfs xxhash_test
+
+The time is reported by the time of the userland `cp`.
+The GB/s is computed with
+
+ 1,536,217,008 B / time(buffer size, hash)
+
+which includes the time to copy from userland.
+The Normalized GB/s is computed with
+
+ 1,536,217,088 B / (time(buffer size, hash) - time(buffer size, none)).
+
+
+| Buffer Size (B) | Hash | Time (s) | GB/s | Adjusted GB/s |
+|-----------------|-------|----------|------|---------------|
+| 1024 | none | 0.408 | 3.77 | - |
+| 1024 | xxh32 | 0.649 | 2.37 | 6.37 |
+| 1024 | xxh64 | 0.542 | 2.83 | 11.46 |
+| 1024 | crc32 | 1.290 | 1.19 | 1.74 |
+| 4096 | none | 0.380 | 4.04 | - |
+| 4096 | xxh32 | 0.645 | 2.38 | 5.79 |
+| 4096 | xxh64 | 0.500 | 3.07 | 12.80 |
+| 4096 | crc32 | 1.168 | 1.32 | 1.95 |
+| 8192 | none | 0.351 | 4.38 | - |
+| 8192 | xxh32 | 0.614 | 2.50 | 5.84 |
+| 8192 | xxh64 | 0.464 | 3.31 | 13.60 |
+| 8192 | crc32 | 1.163 | 1.32 | 1.89 |
+| 16384 | none | 0.346 | 4.43 | - |
+| 16384 | xxh32 | 0.590 | 2.60 | 6.30 |
+| 16384 | xxh64 | 0.466 | 3.30 | 12.80 |
+| 16384 | crc32 | 1.183 | 1.30 | 1.84 |
+
+Tested in userland using the test-suite in the zstd repo under
+`contrib/linux-kernel/test/XXHashUserlandTest.cpp` [2] by mocking the
+kernel functions. A line in each branch of every function in `xxhash.c`
+was commented out to ensure that the test-suite fails. Additionally
+tested while testing zstd and with SMHasher [3].
+
+[1] https://phabricator.intern.facebook.com/P57526246
+[2] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/test/XXHashUserlandTest.cpp
+[3] https://github.com/aappleby/smhasher
+
+zstd source repository: https://github.com/facebook/zstd
+XXHash source repository: https://github.com/cyan4973/xxhash
+
+Signed-off-by: Nick Terrell
+---
+v1 -> v2:
+- Make pointer in lib/xxhash.c:394 non-const
+
+ include/linux/xxhash.h | 236 +++++++++++++++++++++++
+ lib/Kconfig | 3 +
+ lib/Makefile | 1 +
+ lib/xxhash.c | 500 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 740 insertions(+)
+ create mode 100644 include/linux/xxhash.h
+ create mode 100644 lib/xxhash.c
+
+diff --git a/include/linux/xxhash.h b/include/linux/xxhash.h
+new file mode 100644
+index 0000000..9e1f42c
+--- /dev/null
++++ b/include/linux/xxhash.h
+@@ -0,0 +1,236 @@
++/*
++ * xxHash - Extremely Fast Hash algorithm
++ * Copyright (C) 2012-2016, 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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at:
++ * - xxHash homepage: http://cyan4973.github.io/xxHash/
++ * - xxHash source repository: https://github.com/Cyan4973/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.
++ *
++ * A 64-bits version, named xxh64 offers much better speed,
++ * but for 64-bits applications only.
++ * Name Speed on 64 bits Speed on 32 bits
++ * xxh64 13.8 GB/s 1.9 GB/s
++ * xxh32 6.8 GB/s 6.0 GB/s
++ */
++
++#ifndef XXHASH_H
++#define XXHASH_H
++
++#include
++
++/*-****************************
++ * Simple Hash Functions
++ *****************************/
++
++/**
++ * xxh32() - calculate the 32-bit hash of the input with a given seed.
++ *
++ * @input: The data to hash.
++ * @length: The length of the data to hash.
++ * @seed: The seed can be used to alter the result predictably.
++ *
++ * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
++ *
++ * Return: The 32-bit hash of the data.
++ */
++uint32_t xxh32(const void *input, size_t length, uint32_t seed);
++
++/**
++ * xxh64() - calculate the 64-bit hash of the input with a given seed.
++ *
++ * @input: The data to hash.
++ * @length: The length of the data to hash.
++ * @seed: The seed can be used to alter the result predictably.
++ *
++ * This function runs 2x faster on 64-bit systems, but slower on 32-bit systems.
++ *
++ * Return: The 64-bit hash of the data.
++ */
++uint64_t xxh64(const void *input, size_t length, uint64_t seed);
++
++/*-****************************
++ * Streaming Hash Functions
++ *****************************/
++
++/*
++ * These definitions are only meant to allow allocation of XXH state
++ * statically, on stack, or in a struct for example.
++ * Do not use members directly.
++ */
++
++/**
++ * struct xxh32_state - private xxh32 state, do not use members directly
++ */
++struct xxh32_state {
++ uint32_t total_len_32;
++ uint32_t large_len;
++ uint32_t v1;
++ uint32_t v2;
++ uint32_t v3;
++ uint32_t v4;
++ uint32_t mem32[4];
++ uint32_t memsize;
++};
++
++/**
++ * struct xxh32_state - private xxh64 state, do not use members directly
++ */
++struct xxh64_state {
++ uint64_t total_len;
++ uint64_t v1;
++ uint64_t v2;
++ uint64_t v3;
++ uint64_t v4;
++ uint64_t mem64[4];
++ uint32_t memsize;
++};
++
++/**
++ * xxh32_reset() - reset the xxh32 state to start a new hashing operation
++ *
++ * @state: The xxh32 state to reset.
++ * @seed: Initialize the hash state with this seed.
++ *
++ * Call this function on any xxh32_state to prepare for a new hashing operation.
++ */
++void xxh32_reset(struct xxh32_state *state, uint32_t seed);
++
++/**
++ * xxh32_update() - hash the data given and update the xxh32 state
++ *
++ * @state: The xxh32 state to update.
++ * @input: The data to hash.
++ * @length: The length of the data to hash.
++ *
++ * After calling xxh32_reset() call xxh32_update() as many times as necessary.
++ *
++ * Return: Zero on success, otherwise an error code.
++ */
++int xxh32_update(struct xxh32_state *state, const void *input, size_t length);
++
++/**
++ * xxh32_digest() - produce the current xxh32 hash
++ *
++ * @state: Produce the current xxh32 hash of this state.
++ *
++ * A hash value can be produced at any time. It is still possible to continue
++ * inserting input into the hash state after a call to xxh32_digest(), and
++ * generate new hashes later on, by calling xxh32_digest() again.
++ *
++ * Return: The xxh32 hash stored in the state.
++ */
++uint32_t xxh32_digest(const struct xxh32_state *state);
++
++/**
++ * xxh64_reset() - reset the xxh64 state to start a new hashing operation
++ *
++ * @state: The xxh64 state to reset.
++ * @seed: Initialize the hash state with this seed.
++ */
++void xxh64_reset(struct xxh64_state *state, uint64_t seed);
++
++/**
++ * xxh64_update() - hash the data given and update the xxh64 state
++ * @state: The xxh64 state to update.
++ * @input: The data to hash.
++ * @length: The length of the data to hash.
++ *
++ * After calling xxh64_reset() call xxh64_update() as many times as necessary.
++ *
++ * Return: Zero on success, otherwise an error code.
++ */
++int xxh64_update(struct xxh64_state *state, const void *input, size_t length);
++
++/**
++ * xxh64_digest() - produce the current xxh64 hash
++ *
++ * @state: Produce the current xxh64 hash of this state.
++ *
++ * A hash value can be produced at any time. It is still possible to continue
++ * inserting input into the hash state after a call to xxh64_digest(), and
++ * generate new hashes later on, by calling xxh64_digest() again.
++ *
++ * Return: The xxh64 hash stored in the state.
++ */
++uint64_t xxh64_digest(const struct xxh64_state *state);
++
++/*-**************************
++ * Utils
++ ***************************/
++
++/**
++ * xxh32_copy_state() - copy the source state into the destination state
++ *
++ * @src: The source xxh32 state.
++ * @dst: The destination xxh32 state.
++ */
++void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src);
++
++/**
++ * xxh64_copy_state() - copy the source state into the destination state
++ *
++ * @src: The source xxh64 state.
++ * @dst: The destination xxh64 state.
++ */
++void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src);
++
++#endif /* XXHASH_H */
+diff --git a/lib/Kconfig b/lib/Kconfig
+index 0c8b78a..b6009d7 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -184,6 +184,9 @@ config CRC8
+ when they need to do cyclic redundancy check according CRC8
+ algorithm. Module will be called crc8.
+
++config XXHASH
++ tristate
++
+ config AUDIT_GENERIC
+ bool
+ depends on AUDIT && !AUDIT_ARCH
+diff --git a/lib/Makefile b/lib/Makefile
+index 0166fbc..1338226 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -102,6 +102,7 @@ obj-$(CONFIG_CRC32_SELFTEST) += crc32test.o
+ obj-$(CONFIG_CRC7) += crc7.o
+ obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
+ obj-$(CONFIG_CRC8) += crc8.o
++obj-$(CONFIG_XXHASH) += xxhash.o
+ obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
+
+ obj-$(CONFIG_842_COMPRESS) += 842/
+diff --git a/lib/xxhash.c b/lib/xxhash.c
+new file mode 100644
+index 0000000..aa61e2a
+--- /dev/null
++++ b/lib/xxhash.c
+@@ -0,0 +1,500 @@
++/*
++ * xxHash - Extremely Fast Hash algorithm
++ * Copyright (C) 2012-2016, 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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at:
++ * - xxHash homepage: http://cyan4973.github.io/xxHash/
++ * - xxHash source repository: https://github.com/Cyan4973/xxHash
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++/*-*************************************
++ * Macros
++ **************************************/
++#define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
++#define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
++
++#ifdef __LITTLE_ENDIAN
++# define XXH_CPU_LITTLE_ENDIAN 1
++#else
++# define XXH_CPU_LITTLE_ENDIAN 0
++#endif
++
++/*-*************************************
++ * Constants
++ **************************************/
++static const uint32_t PRIME32_1 = 2654435761U;
++static const uint32_t PRIME32_2 = 2246822519U;
++static const uint32_t PRIME32_3 = 3266489917U;
++static const uint32_t PRIME32_4 = 668265263U;
++static const uint32_t PRIME32_5 = 374761393U;
++
++static const uint64_t PRIME64_1 = 11400714785074694791ULL;
++static const uint64_t PRIME64_2 = 14029467366897019727ULL;
++static const uint64_t PRIME64_3 = 1609587929392839161ULL;
++static const uint64_t PRIME64_4 = 9650029242287828579ULL;
++static const uint64_t PRIME64_5 = 2870177450012600261ULL;
++
++/*-**************************
++ * Utils
++ ***************************/
++void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
++{
++ memcpy(dst, src, sizeof(*dst));
++}
++EXPORT_SYMBOL(xxh32_copy_state);
++
++void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
++{
++ memcpy(dst, src, sizeof(*dst));
++}
++EXPORT_SYMBOL(xxh64_copy_state);
++
++/*-***************************
++ * Simple Hash Functions
++ ****************************/
++static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
++{
++ seed += input * PRIME32_2;
++ seed = xxh_rotl32(seed, 13);
++ seed *= PRIME32_1;
++ return seed;
++}
++
++uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
++{
++ const uint8_t *p = (const uint8_t *)input;
++ const uint8_t *b_end = p + len;
++ uint32_t h32;
++
++ if (len >= 16) {
++ const uint8_t *const limit = b_end - 16;
++ uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
++ uint32_t v2 = seed + PRIME32_2;
++ uint32_t v3 = seed + 0;
++ uint32_t v4 = seed - PRIME32_1;
++
++ do {
++ v1 = xxh32_round(v1, get_unaligned_le32(p));
++ p += 4;
++ v2 = xxh32_round(v2, get_unaligned_le32(p));
++ p += 4;
++ v3 = xxh32_round(v3, get_unaligned_le32(p));
++ p += 4;
++ v4 = xxh32_round(v4, get_unaligned_le32(p));
++ 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 += (uint32_t)len;
++
++ while (p + 4 <= b_end) {
++ h32 += get_unaligned_le32(p) * PRIME32_3;
++ h32 = xxh_rotl32(h32, 17) * PRIME32_4;
++ p += 4;
++ }
++
++ while (p < b_end) {
++ 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;
++}
++EXPORT_SYMBOL(xxh32);
++
++static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
++{
++ acc += input * PRIME64_2;
++ acc = xxh_rotl64(acc, 31);
++ acc *= PRIME64_1;
++ return acc;
++}
++
++static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
++{
++ val = xxh64_round(0, val);
++ acc ^= val;
++ acc = acc * PRIME64_1 + PRIME64_4;
++ return acc;
++}
++
++uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
++{
++ const uint8_t *p = (const uint8_t *)input;
++ const uint8_t *const b_end = p + len;
++ uint64_t h64;
++
++ if (len >= 32) {
++ const uint8_t *const limit = b_end - 32;
++ uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
++ uint64_t v2 = seed + PRIME64_2;
++ uint64_t v3 = seed + 0;
++ uint64_t v4 = seed - PRIME64_1;
++
++ do {
++ v1 = xxh64_round(v1, get_unaligned_le64(p));
++ p += 8;
++ v2 = xxh64_round(v2, get_unaligned_le64(p));
++ p += 8;
++ v3 = xxh64_round(v3, get_unaligned_le64(p));
++ p += 8;
++ v4 = xxh64_round(v4, get_unaligned_le64(p));
++ p += 8;
++ } while (p <= limit);
++
++ h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
++ xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
++ h64 = xxh64_merge_round(h64, v1);
++ h64 = xxh64_merge_round(h64, v2);
++ h64 = xxh64_merge_round(h64, v3);
++ h64 = xxh64_merge_round(h64, v4);
++
++ } else {
++ h64 = seed + PRIME64_5;
++ }
++
++ h64 += (uint64_t)len;
++
++ while (p + 8 <= b_end) {
++ const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
++
++ h64 ^= k1;
++ h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
++ p += 8;
++ }
++
++ if (p + 4 <= b_end) {
++ h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
++ h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
++ p += 4;
++ }
++
++ while (p < b_end) {
++ 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;
++}
++EXPORT_SYMBOL(xxh64);
++
++/*-**************************************************
++ * Advanced Hash Functions
++ ***************************************************/
++void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
++{
++ /* use a local state for memcpy() to avoid strict-aliasing warnings */
++ struct xxh32_state state;
++
++ memset(&state, 0, sizeof(state));
++ state.v1 = seed + PRIME32_1 + PRIME32_2;
++ state.v2 = seed + PRIME32_2;
++ state.v3 = seed + 0;
++ state.v4 = seed - PRIME32_1;
++ memcpy(statePtr, &state, sizeof(state));
++}
++EXPORT_SYMBOL(xxh32_reset);
++
++void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
++{
++ /* use a local state for memcpy() to avoid strict-aliasing warnings */
++ struct xxh64_state state;
++
++ memset(&state, 0, sizeof(state));
++ state.v1 = seed + PRIME64_1 + PRIME64_2;
++ state.v2 = seed + PRIME64_2;
++ state.v3 = seed + 0;
++ state.v4 = seed - PRIME64_1;
++ memcpy(statePtr, &state, sizeof(state));
++}
++EXPORT_SYMBOL(xxh64_reset);
++
++int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
++{
++ const uint8_t *p = (const uint8_t *)input;
++ const uint8_t *const b_end = p + len;
++
++ if (input == NULL)
++ return -EINVAL;
++
++ state->total_len_32 += (uint32_t)len;
++ state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
++
++ if (state->memsize + len < 16) { /* fill in tmp buffer */
++ memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
++ state->memsize += (uint32_t)len;
++ return 0;
++ }
++
++ if (state->memsize) { /* some data left from previous update */
++ const uint32_t *p32 = state->mem32;
++
++ memcpy((uint8_t *)(state->mem32) + state->memsize, input,
++ 16 - state->memsize);
++
++ state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
++ p32++;
++ state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
++ p32++;
++ state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
++ p32++;
++ state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
++ p32++;
++
++ p += 16-state->memsize;
++ state->memsize = 0;
++ }
++
++ if (p <= b_end - 16) {
++ const uint8_t *const limit = b_end - 16;
++ uint32_t v1 = state->v1;
++ uint32_t v2 = state->v2;
++ uint32_t v3 = state->v3;
++ uint32_t v4 = state->v4;
++
++ do {
++ v1 = xxh32_round(v1, get_unaligned_le32(p));
++ p += 4;
++ v2 = xxh32_round(v2, get_unaligned_le32(p));
++ p += 4;
++ v3 = xxh32_round(v3, get_unaligned_le32(p));
++ p += 4;
++ v4 = xxh32_round(v4, get_unaligned_le32(p));
++ p += 4;
++ } while (p <= limit);
++
++ state->v1 = v1;
++ state->v2 = v2;
++ state->v3 = v3;
++ state->v4 = v4;
++ }
++
++ if (p < b_end) {
++ memcpy(state->mem32, p, (size_t)(b_end-p));
++ state->memsize = (uint32_t)(b_end-p);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(xxh32_update);
++
++uint32_t xxh32_digest(const struct xxh32_state *state)
++{
++ const uint8_t *p = (const uint8_t *)state->mem32;
++ const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
++ state->memsize;
++ uint32_t h32;
++
++ if (state->large_len) {
++ h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
++ xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
++ } else {
++ h32 = state->v3 /* == seed */ + PRIME32_5;
++ }
++
++ h32 += state->total_len_32;
++
++ while (p + 4 <= b_end) {
++ h32 += get_unaligned_le32(p) * PRIME32_3;
++ h32 = xxh_rotl32(h32, 17) * PRIME32_4;
++ p += 4;
++ }
++
++ while (p < b_end) {
++ 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;
++}
++EXPORT_SYMBOL(xxh32_digest);
++
++int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
++{
++ const uint8_t *p = (const uint8_t *)input;
++ const uint8_t *const b_end = p + len;
++
++ if (input == NULL)
++ return -EINVAL;
++
++ state->total_len += len;
++
++ if (state->memsize + len < 32) { /* fill in tmp buffer */
++ memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
++ state->memsize += (uint32_t)len;
++ return 0;
++ }
++
++ if (state->memsize) { /* tmp buffer is full */
++ uint64_t *p64 = state->mem64;
++
++ memcpy(((uint8_t *)p64) + state->memsize, input,
++ 32 - state->memsize);
++
++ state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
++ p64++;
++ state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
++ p64++;
++ state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
++ p64++;
++ state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
++
++ p += 32 - state->memsize;
++ state->memsize = 0;
++ }
++
++ if (p + 32 <= b_end) {
++ const uint8_t *const limit = b_end - 32;
++ uint64_t v1 = state->v1;
++ uint64_t v2 = state->v2;
++ uint64_t v3 = state->v3;
++ uint64_t v4 = state->v4;
++
++ do {
++ v1 = xxh64_round(v1, get_unaligned_le64(p));
++ p += 8;
++ v2 = xxh64_round(v2, get_unaligned_le64(p));
++ p += 8;
++ v3 = xxh64_round(v3, get_unaligned_le64(p));
++ p += 8;
++ v4 = xxh64_round(v4, get_unaligned_le64(p));
++ p += 8;
++ } while (p <= limit);
++
++ state->v1 = v1;
++ state->v2 = v2;
++ state->v3 = v3;
++ state->v4 = v4;
++ }
++
++ if (p < b_end) {
++ memcpy(state->mem64, p, (size_t)(b_end-p));
++ state->memsize = (uint32_t)(b_end - p);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(xxh64_update);
++
++uint64_t xxh64_digest(const struct xxh64_state *state)
++{
++ const uint8_t *p = (const uint8_t *)state->mem64;
++ const uint8_t *const b_end = (const uint8_t *)state->mem64 +
++ state->memsize;
++ uint64_t h64;
++
++ if (state->total_len >= 32) {
++ const uint64_t v1 = state->v1;
++ const uint64_t v2 = state->v2;
++ const uint64_t v3 = state->v3;
++ const uint64_t v4 = state->v4;
++
++ h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
++ xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
++ h64 = xxh64_merge_round(h64, v1);
++ h64 = xxh64_merge_round(h64, v2);
++ h64 = xxh64_merge_round(h64, v3);
++ h64 = xxh64_merge_round(h64, v4);
++ } else {
++ h64 = state->v3 + PRIME64_5;
++ }
++
++ h64 += (uint64_t)state->total_len;
++
++ while (p + 8 <= b_end) {
++ const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
++
++ h64 ^= k1;
++ h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
++ p += 8;
++ }
++
++ if (p + 4 <= b_end) {
++ h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
++ h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
++ p += 4;
++ }
++
++ while (p < b_end) {
++ 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;
++}
++EXPORT_SYMBOL(xxh64_digest);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("xxHash");
+--
+2.9.3
diff --git a/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch b/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch
new file mode 100644
index 000000000..971093996
--- /dev/null
+++ b/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch
@@ -0,0 +1,13290 @@
+From d2626127c6d6e60e940dd9a3ed58323bdcdc4930 Mon Sep 17 00:00:00 2001
+From: Nick Terrell
+Date: Tue, 16 May 2017 14:55:36 -0700
+Subject: [PATCH v2 2/4] lib: Add zstd modules
+
+Add zstd compression and decompression kernel modules.
+zstd offers a wide varity of compression speed and quality trade-offs.
+It can compress at speeds approaching lz4, and quality approaching lzma.
+zstd decompressions at speeds more than twice as fast as zlib, and
+decompression speed remains roughly the same across all compression levels.
+
+The code was ported from the upstream zstd source repository. The
+`linux/zstd.h` header was modified to match linux kernel style.
+The cross-platform and allocation code was stripped out. Instead zstd
+requires the caller to pass a preallocated workspace. The source files
+were clang-formatted [1] to match the Linux Kernel style as much as
+possible. Otherwise, the code was unmodified. We would like to avoid
+as much further manual modification to the source code as possible, so it
+will be easier to keep the kernel zstd up to date.
+
+I benchmarked zstd compression as a special character device. I ran zstd
+and zlib compression at several levels, as well as performing no
+compression, which measure the time spent copying the data to kernel space.
+Data is passed to the compresser 4096 B at a time. The benchmark file is
+located in the upstream zstd source repository under
+`contrib/linux-kernel/zstd_compress_test.c` [2].
+
+I ran the benchmarks on a Ubuntu 14.04 VM with 2 cores and 4 GiB of RAM.
+The VM is running on a MacBook Pro with a 3.1 GHz Intel Core i7 processor,
+16 GB of RAM, and a SSD. I benchmarked using `silesia.tar` [3], which is
+211,988,480 B large. Run the following commands for the benchmark:
+
+ sudo modprobe zstd_compress_test
+ sudo mknod zstd_compress_test c 245 0
+ sudo cp silesia.tar zstd_compress_test
+
+The time is reported by the time of the userland `cp`.
+The MB/s is computed with
+
+ 1,536,217,008 B / time(buffer size, hash)
+
+which includes the time to copy from userland.
+The Adjusted MB/s is computed with
+
+ 1,536,217,088 B / (time(buffer size, hash) - time(buffer size, none)).
+
+The memory reported is the amount of memory the compressor requests.
+
+| Method | Size (B) | Time (s) | Ratio | MB/s | Adj MB/s | Mem (MB) |
+|----------|----------|----------|-------|---------|----------|----------|
+| none | 11988480 | 0.100 | 1 | 2119.88 | - | - |
+| zstd -1 | 73645762 | 1.044 | 2.878 | 203.05 | 224.56 | 1.23 |
+| zstd -3 | 66988878 | 1.761 | 3.165 | 120.38 | 127.63 | 2.47 |
+| zstd -5 | 65001259 | 2.563 | 3.261 | 82.71 | 86.07 | 2.86 |
+| zstd -10 | 60165346 | 13.242 | 3.523 | 16.01 | 16.13 | 13.22 |
+| zstd -15 | 58009756 | 47.601 | 3.654 | 4.45 | 4.46 | 21.61 |
+| zstd -19 | 54014593 | 102.835 | 3.925 | 2.06 | 2.06 | 60.15 |
+| zlib -1 | 77260026 | 2.895 | 2.744 | 73.23 | 75.85 | 0.27 |
+| zlib -3 | 72972206 | 4.116 | 2.905 | 51.50 | 52.79 | 0.27 |
+| zlib -6 | 68190360 | 9.633 | 3.109 | 22.01 | 22.24 | 0.27 |
+| zlib -9 | 67613382 | 22.554 | 3.135 | 9.40 | 9.44 | 0.27 |
+
+I benchmarked zstd decompression using the same method on the same machine.
+The benchmark file is located in the upstream zstd repo under
+`contrib/linux-kernel/zstd_decompress_test.c` [4]. The memory reported is
+the amount of memory required to decompress data compressed with the given
+compression level. If you know the maximum size of your input, you can
+reduce the memory usage of decompression irrespective of the compression
+level.
+
+| Method | Time (s) | MB/s | Adjusted MB/s | Memory (MB) |
+|----------|----------|---------|---------------|-------------|
+| none | 0.025 | 8479.54 | - | - |
+| zstd -1 | 0.358 | 592.15 | 636.60 | 0.84 |
+| zstd -3 | 0.396 | 535.32 | 571.40 | 1.46 |
+| zstd -5 | 0.396 | 535.32 | 571.40 | 1.46 |
+| zstd -10 | 0.374 | 566.81 | 607.42 | 2.51 |
+| zstd -15 | 0.379 | 559.34 | 598.84 | 4.61 |
+| zstd -19 | 0.412 | 514.54 | 547.77 | 8.80 |
+| zlib -1 | 0.940 | 225.52 | 231.68 | 0.04 |
+| zlib -3 | 0.883 | 240.08 | 247.07 | 0.04 |
+| zlib -6 | 0.844 | 251.17 | 258.84 | 0.04 |
+| zlib -9 | 0.837 | 253.27 | 287.64 | 0.04 |
+
+Tested in userland using the test-suite in the zstd repo under
+`contrib/linux-kernel/test/UserlandTest.cpp` [5] by mocking the kernel
+functions. Fuzz tested using libfuzzer [6] with the fuzz harnesses under
+`contrib/linux-kernel/test/{RoundTripCrash.c,DecompressCrash.c}` [7] [8]
+with ASAN, UBSAN, and MSAN. Additionaly, it was tested while testing the
+BtrFS and SquashFS patches coming next.
+
+[1] https://clang.llvm.org/docs/ClangFormat.html
+[2] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/zstd_compress_test.c
+[3] http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
+[4] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/zstd_decompress_test.c
+[5] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/test/UserlandTest.cpp
+[6] http://llvm.org/docs/LibFuzzer.html
+[7] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/test/RoundTripCrash.c
+[8] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/test/DecompressCrash.c
+
+zstd source repository: https://github.com/facebook/zstd
+
+Signed-off-by: Nick Terrell
+---
+v1 -> v2:
+- Use div_u64() for division of u64s
+- Reduce stack usage of ZSTD_compressSequences(), ZSTD_buildSeqTable(),
+ ZSTD_decompressSequencesLong(), FSE_buildDTable(), FSE_decompress_wksp(),
+ HUF_writeCTable(), HUF_readStats(), HUF_readCTable(),
+ HUF_compressWeights(), HUF_readDTableX2(), and HUF_readDTableX4()
+- No function uses more than 400 B of stack space
+
+ include/linux/zstd.h | 1157 +++++++++++++++
+ lib/Kconfig | 8 +
+ lib/Makefile | 2 +
+ lib/zstd/Makefile | 18 +
+ lib/zstd/bitstream.h | 374 +++++
+ lib/zstd/compress.c | 3479 +++++++++++++++++++++++++++++++++++++++++++++
+ lib/zstd/decompress.c | 2526 ++++++++++++++++++++++++++++++++
+ lib/zstd/entropy_common.c | 243 ++++
+ lib/zstd/error_private.h | 53 +
+ lib/zstd/fse.h | 575 ++++++++
+ lib/zstd/fse_compress.c | 795 +++++++++++
+ lib/zstd/fse_decompress.c | 332 +++++
+ lib/zstd/huf.h | 212 +++
+ lib/zstd/huf_compress.c | 771 ++++++++++
+ lib/zstd/huf_decompress.c | 960 +++++++++++++
+ lib/zstd/mem.h | 151 ++
+ lib/zstd/zstd_common.c | 75 +
+ lib/zstd/zstd_internal.h | 269 ++++
+ lib/zstd/zstd_opt.h | 1014 +++++++++++++
+ 19 files changed, 13014 insertions(+)
+ create mode 100644 include/linux/zstd.h
+ create mode 100644 lib/zstd/Makefile
+ create mode 100644 lib/zstd/bitstream.h
+ create mode 100644 lib/zstd/compress.c
+ create mode 100644 lib/zstd/decompress.c
+ create mode 100644 lib/zstd/entropy_common.c
+ create mode 100644 lib/zstd/error_private.h
+ create mode 100644 lib/zstd/fse.h
+ create mode 100644 lib/zstd/fse_compress.c
+ create mode 100644 lib/zstd/fse_decompress.c
+ create mode 100644 lib/zstd/huf.h
+ create mode 100644 lib/zstd/huf_compress.c
+ create mode 100644 lib/zstd/huf_decompress.c
+ create mode 100644 lib/zstd/mem.h
+ create mode 100644 lib/zstd/zstd_common.c
+ create mode 100644 lib/zstd/zstd_internal.h
+ create mode 100644 lib/zstd/zstd_opt.h
+
+diff --git a/include/linux/zstd.h b/include/linux/zstd.h
+new file mode 100644
+index 0000000..249575e
+--- /dev/null
++++ b/include/linux/zstd.h
+@@ -0,0 +1,1157 @@
++/*
++ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This source code is licensed under the BSD-style license found in the
++ * LICENSE file in the root directory of https://github.com/facebook/zstd.
++ * An additional grant of patent rights can be found in the PATENTS file in the
++ * same directory.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ */
++
++#ifndef ZSTD_H
++#define ZSTD_H
++
++/* ====== Dependency ======*/
++#include /* size_t */
++
++
++/*-*****************************************************************************
++ * Introduction
++ *
++ * zstd, short for Zstandard, is a fast lossless compression algorithm,
++ * targeting real-time compression scenarios at zlib-level and better
++ * compression ratios. The zstd compression library provides in-memory
++ * compression and decompression functions. The library supports compression
++ * levels from 1 up to ZSTD_maxCLevel() which is 22. Levels >= 20, labeled
++ * ultra, should be used with caution, as they require more memory.
++ * Compression can be done in:
++ * - a single step, reusing a context (described as Explicit memory management)
++ * - unbounded multiple steps (described as Streaming compression)
++ * The compression ratio achievable on small data can be highly improved using
++ * compression with a dictionary in:
++ * - a single step (described as Simple dictionary API)
++ * - a single step, reusing a dictionary (described as Fast dictionary API)
++ ******************************************************************************/
++
++/*====== Helper functions ======*/
++
++/**
++ * enum ZSTD_ErrorCode - zstd error codes
++ *
++ * Functions that return size_t can be checked for errors using ZSTD_isError()
++ * and the ZSTD_ErrorCode can be extracted using ZSTD_getErrorCode().
++ */
++typedef enum {
++ ZSTD_error_no_error,
++ ZSTD_error_GENERIC,
++ ZSTD_error_prefix_unknown,
++ ZSTD_error_version_unsupported,
++ ZSTD_error_parameter_unknown,
++ ZSTD_error_frameParameter_unsupported,
++ ZSTD_error_frameParameter_unsupportedBy32bits,
++ ZSTD_error_frameParameter_windowTooLarge,
++ ZSTD_error_compressionParameter_unsupported,
++ ZSTD_error_init_missing,
++ ZSTD_error_memory_allocation,
++ ZSTD_error_stage_wrong,
++ ZSTD_error_dstSize_tooSmall,
++ ZSTD_error_srcSize_wrong,
++ ZSTD_error_corruption_detected,
++ ZSTD_error_checksum_wrong,
++ ZSTD_error_tableLog_tooLarge,
++ ZSTD_error_maxSymbolValue_tooLarge,
++ ZSTD_error_maxSymbolValue_tooSmall,
++ ZSTD_error_dictionary_corrupted,
++ ZSTD_error_dictionary_wrong,
++ ZSTD_error_dictionaryCreation_failed,
++ ZSTD_error_maxCode
++} ZSTD_ErrorCode;
++
++/**
++ * ZSTD_maxCLevel() - maximum compression level available
++ *
++ * Return: Maximum compression level available.
++ */
++int ZSTD_maxCLevel(void);
++/**
++ * ZSTD_compressBound() - maximum compressed size in worst case scenario
++ * @srcSize: The size of the data to compress.
++ *
++ * Return: The maximum compressed size in the worst case scenario.
++ */
++size_t ZSTD_compressBound(size_t srcSize);
++/**
++ * ZSTD_isError() - tells if a size_t function result is an error code
++ * @code: The function result to check for error.
++ *
++ * Return: Non-zero iff the code is an error.
++ */
++static __attribute__((unused)) unsigned int ZSTD_isError(size_t code)
++{
++ return code > (size_t)-ZSTD_error_maxCode;
++}
++/**
++ * ZSTD_getErrorCode() - translates an error function result to a ZSTD_ErrorCode
++ * @functionResult: The result of a function for which ZSTD_isError() is true.
++ *
++ * Return: The ZSTD_ErrorCode corresponding to the functionResult or 0
++ * if the functionResult isn't an error.
++ */
++static __attribute__((unused)) ZSTD_ErrorCode ZSTD_getErrorCode(
++ size_t functionResult)
++{
++ if (!ZSTD_isError(functionResult))
++ return (ZSTD_ErrorCode)0;
++ return (ZSTD_ErrorCode)(0 - functionResult);
++}
++
++/**
++ * enum ZSTD_strategy - zstd compression search strategy
++ *
++ * From faster to stronger.
++ */
++typedef enum {
++ ZSTD_fast,
++ ZSTD_dfast,
++ ZSTD_greedy,
++ ZSTD_lazy,
++ ZSTD_lazy2,
++ ZSTD_btlazy2,
++ ZSTD_btopt,
++ ZSTD_btopt2
++} ZSTD_strategy;
++
++/**
++ * struct ZSTD_compressionParameters - zstd compression parameters
++ * @windowLog: Log of the largest match distance. Larger means more
++ * compression, and more memory needed during decompression.
++ * @chainLog: Fully searched segment. Larger means more compression, slower,
++ * and more memory (useless for fast).
++ * @hashLog: Dispatch table. Larger means more compression,
++ * slower, and more memory.
++ * @searchLog: Number of searches. Larger means more compression and slower.
++ * @searchLength: Match length searched. Larger means faster decompression,
++ * sometimes less compression.
++ * @targetLength: Acceptable match size for optimal parser (only). Larger means
++ * more compression, and slower.
++ * @strategy: The zstd compression strategy.
++ */
++typedef struct {
++ unsigned int windowLog;
++ unsigned int chainLog;
++ unsigned int hashLog;
++ unsigned int searchLog;
++ unsigned int searchLength;
++ unsigned int targetLength;
++ ZSTD_strategy strategy;
++} ZSTD_compressionParameters;
++
++/**
++ * struct ZSTD_frameParameters - zstd frame parameters
++ * @contentSizeFlag: Controls whether content size will be present in the frame
++ * header (when known).
++ * @checksumFlag: Controls whether a 32-bit checksum is generated at the end
++ * of the frame for error detection.
++ * @noDictIDFlag: Controls whether dictID will be saved into the frame header
++ * when using dictionary compression.
++ *
++ * The default value is all fields set to 0.
++ */
++typedef struct {
++ unsigned int contentSizeFlag;
++ unsigned int checksumFlag;
++ unsigned int noDictIDFlag;
++} ZSTD_frameParameters;
++
++/**
++ * struct ZSTD_parameters - zstd parameters
++ * @cParams: The compression parameters.
++ * @fParams: The frame parameters.
++ */
++typedef struct {
++ ZSTD_compressionParameters cParams;
++ ZSTD_frameParameters fParams;
++} ZSTD_parameters;
++
++/**
++ * ZSTD_getCParams() - returns ZSTD_compressionParameters for selected level
++ * @compressionLevel: The compression level from 1 to ZSTD_maxCLevel().
++ * @estimatedSrcSize: The estimated source size to compress or 0 if unknown.
++ * @dictSize: The dictionary size or 0 if a dictionary isn't being used.
++ *
++ * Return: The selected ZSTD_compressionParameters.
++ */
++ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel,
++ unsigned long long estimatedSrcSize, size_t dictSize);
++
++/**
++ * ZSTD_getParams() - returns ZSTD_parameters for selected level
++ * @compressionLevel: The compression level from 1 to ZSTD_maxCLevel().
++ * @estimatedSrcSize: The estimated source size to compress or 0 if unknown.
++ * @dictSize: The dictionary size or 0 if a dictionary isn't being used.
++ *
++ * The same as ZSTD_getCParams() except also selects the default frame
++ * parameters (all zero).
++ *
++ * Return: The selected ZSTD_parameters.
++ */
++ZSTD_parameters ZSTD_getParams(int compressionLevel,
++ unsigned long long estimatedSrcSize, size_t dictSize);
++
++/*-*************************************
++ * Explicit memory management
++ **************************************/
++
++/**
++ * ZSTD_CCtxWorkspaceBound() - amount of memory needed to initialize a ZSTD_CCtx
++ * @cParams: The compression parameters to be used for compression.
++ *
++ * If multiple compression parameters might be used, the caller must call
++ * ZSTD_CCtxWorkspaceBound() for each set of parameters and use the maximum
++ * size.
++ *
++ * Return: A lower bound on the size of the workspace that is passed to
++ * ZSTD_initCCtx().
++ */
++size_t ZSTD_CCtxWorkspaceBound(ZSTD_compressionParameters cParams);
++
++/**
++ * struct ZSTD_CCtx - the zstd compression context
++ *
++ * When compressing many times it is recommended to allocate a context just once
++ * and reuse it for each successive compression operation.
++ */
++typedef struct ZSTD_CCtx_s ZSTD_CCtx;
++/**
++ * ZSTD_initCCtx() - initialize a zstd compression context
++ * @workspace: The workspace to emplace the context into. It must outlive
++ * the returned context.
++ * @workspaceSize: The size of workspace. Use ZSTD_CCtxWorkspaceBound() to
++ * determine how large the workspace must be.
++ *
++ * Return: A compression context emplaced into workspace.
++ */
++ZSTD_CCtx *ZSTD_initCCtx(void *workspace, size_t workspaceSize);
++
++/**
++ * ZSTD_compressCCtx() - compress src into dst
++ * @ctx: The context. Must have been initialized with a workspace at
++ * least as large as ZSTD_CCtxWorkspaceBound(params.cParams).
++ * @dst: The buffer to compress src into.
++ * @dstCapacity: The size of the destination buffer. May be any size, but
++ * ZSTD_compressBound(srcSize) is guaranteed to be large enough.
++ * @src: The data to compress.
++ * @srcSize: The size of the data to compress.
++ * @params: The parameters to use for compression. See ZSTD_getParams().
++ *
++ * Return: The compressed size or an error, which can be checked using
++ * ZSTD_isError().
++ */
++size_t ZSTD_compressCCtx(ZSTD_CCtx *ctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize, ZSTD_parameters params);
++
++/**
++ * ZSTD_DCtxWorkspaceBound() - amount of memory needed to initialize a ZSTD_DCtx
++ *
++ * Return: A lower bound on the size of the workspace that is passed to
++ * ZSTD_initDCtx().
++ */
++size_t ZSTD_DCtxWorkspaceBound(void);
++
++/**
++ * struct ZSTD_DCtx - the zstd decompression context
++ *
++ * When decompressing many times it is recommended to allocate a context just
++ * once and reuse it for each successive decompression operation.
++ */
++typedef struct ZSTD_DCtx_s ZSTD_DCtx;
++/**
++ * ZSTD_initDCtx() - initialize a zstd decompression context
++ * @workspace: The workspace to emplace the context into. It must outlive
++ * the returned context.
++ * @workspaceSize: The size of workspace. Use ZSTD_DCtxWorkspaceBound() to
++ * determine how large the workspace must be.
++ *
++ * Return: A decompression context emplaced into workspace.
++ */
++ZSTD_DCtx *ZSTD_initDCtx(void *workspace, size_t workspaceSize);
++
++/**
++ * ZSTD_decompressDCtx() - decompress zstd compressed src into dst
++ * @ctx: The decompression context.
++ * @dst: The buffer to decompress src into.
++ * @dstCapacity: The size of the destination buffer. Must be at least as large
++ * as the decompressed size. If the caller cannot upper bound the
++ * decompressed size, then it's better to use the streaming API.
++ * @src: The zstd compressed data to decompress. Multiple concatenated
++ * frames and skippable frames are allowed.
++ * @srcSize: The exact size of the data to decompress.
++ *
++ * Return: The decompressed size or an error, which can be checked using
++ * ZSTD_isError().
++ */
++size_t ZSTD_decompressDCtx(ZSTD_DCtx *ctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize);
++
++/*-************************
++ * Simple dictionary API
++ **************************/
++
++/**
++ * ZSTD_compress_usingDict() - compress src into dst using a dictionary
++ * @ctx: The context. Must have been initialized with a workspace at
++ * least as large as ZSTD_CCtxWorkspaceBound(params.cParams).
++ * @dst: The buffer to compress src into.
++ * @dstCapacity: The size of the destination buffer. May be any size, but
++ * ZSTD_compressBound(srcSize) is guaranteed to be large enough.
++ * @src: The data to compress.
++ * @srcSize: The size of the data to compress.
++ * @dict: The dictionary to use for compression.
++ * @dictSize: The size of the dictionary.
++ * @params: The parameters to use for compression. See ZSTD_getParams().
++ *
++ * Compression using a predefined dictionary. The same dictionary must be used
++ * during decompression.
++ *
++ * Return: The compressed size or an error, which can be checked using
++ * ZSTD_isError().
++ */
++size_t ZSTD_compress_usingDict(ZSTD_CCtx *ctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize, const void *dict, size_t dictSize,
++ ZSTD_parameters params);
++
++/**
++ * ZSTD_decompress_usingDict() - decompress src into dst using a dictionary
++ * @ctx: The decompression context.
++ * @dst: The buffer to decompress src into.
++ * @dstCapacity: The size of the destination buffer. Must be at least as large
++ * as the decompressed size. If the caller cannot upper bound the
++ * decompressed size, then it's better to use the streaming API.
++ * @src: The zstd compressed data to decompress. Multiple concatenated
++ * frames and skippable frames are allowed.
++ * @srcSize: The exact size of the data to decompress.
++ * @dict: The dictionary to use for decompression. The same dictionary
++ * must've been used to compress the data.
++ * @dictSize: The size of the dictionary.
++ *
++ * Return: The decompressed size or an error, which can be checked using
++ * ZSTD_isError().
++ */
++size_t ZSTD_decompress_usingDict(ZSTD_DCtx *ctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize, const void *dict, size_t dictSize);
++
++/*-**************************
++ * Fast dictionary API
++ ***************************/
++
++/**
++ * ZSTD_CDictWorkspaceBound() - memory needed to initialize a ZSTD_CDict
++ * @cParams: The compression parameters to be used for compression.
++ *
++ * Return: A lower bound on the size of the workspace that is passed to
++ * ZSTD_initCDict().
++ */
++size_t ZSTD_CDictWorkspaceBound(ZSTD_compressionParameters cParams);
++
++/**
++ * struct ZSTD_CDict - a digested dictionary to be used for compression
++ */
++typedef struct ZSTD_CDict_s ZSTD_CDict;
++
++/**
++ * ZSTD_initCDict() - initialize a digested dictionary for compression
++ * @dictBuffer: The dictionary to digest. The buffer is referenced by the
++ * ZSTD_CDict so it must outlive the returned ZSTD_CDict.
++ * @dictSize: The size of the dictionary.
++ * @params: The parameters to use for compression. See ZSTD_getParams().
++ * @workspace: The workspace. It must outlive the returned ZSTD_CDict.
++ * @workspaceSize: The workspace size. Must be at least
++ * ZSTD_CDictWorkspaceBound(params.cParams).
++ *
++ * When compressing multiple messages / blocks with the same dictionary it is
++ * recommended to load it just once. The ZSTD_CDict merely references the
++ * dictBuffer, so it must outlive the returned ZSTD_CDict.
++ *
++ * Return: The digested dictionary emplaced into workspace.
++ */
++ZSTD_CDict *ZSTD_initCDict(const void *dictBuffer, size_t dictSize,
++ ZSTD_parameters params, void *workspace, size_t workspaceSize);
++
++/**
++ * ZSTD_compress_usingCDict() - compress src into dst using a ZSTD_CDict
++ * @ctx: The context. Must have been initialized with a workspace at
++ * least as large as ZSTD_CCtxWorkspaceBound(cParams) where
++ * cParams are the compression parameters used to initialize the
++ * cdict.
++ * @dst: The buffer to compress src into.
++ * @dstCapacity: The size of the destination buffer. May be any size, but
++ * ZSTD_compressBound(srcSize) is guaranteed to be large enough.
++ * @src: The data to compress.
++ * @srcSize: The size of the data to compress.
++ * @cdict: The digested dictionary to use for compression.
++ * @params: The parameters to use for compression. See ZSTD_getParams().
++ *
++ * Compression using a digested dictionary. The same dictionary must be used
++ * during decompression.
++ *
++ * Return: The compressed size or an error, which can be checked using
++ * ZSTD_isError().
++ */
++size_t ZSTD_compress_usingCDict(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize, const ZSTD_CDict *cdict);
++
++
++/**
++ * ZSTD_DDictWorkspaceBound() - memory needed to initialize a ZSTD_DDict
++ *
++ * Return: A lower bound on the size of the workspace that is passed to
++ * ZSTD_initDDict().
++ */
++size_t ZSTD_DDictWorkspaceBound(void);
++
++/**
++ * struct ZSTD_DDict - a digested dictionary to be used for decompression
++ */
++typedef struct ZSTD_DDict_s ZSTD_DDict;
++
++/**
++ * ZSTD_initDDict() - initialize a digested dictionary for decompression
++ * @dictBuffer: The dictionary to digest. The buffer is referenced by the
++ * ZSTD_DDict so it must outlive the returned ZSTD_DDict.
++ * @dictSize: The size of the dictionary.
++ * @workspace: The workspace. It must outlive the returned ZSTD_DDict.
++ * @workspaceSize: The workspace size. Must be at least
++ * ZSTD_DDictWorkspaceBound().
++ *
++ * When decompressing multiple messages / blocks with the same dictionary it is
++ * recommended to load it just once. The ZSTD_DDict merely references the
++ * dictBuffer, so it must outlive the returned ZSTD_DDict.
++ *
++ * Return: The digested dictionary emplaced into workspace.
++ */
++ZSTD_DDict *ZSTD_initDDict(const void *dictBuffer, size_t dictSize,
++ void *workspace, size_t workspaceSize);
++
++/**
++ * ZSTD_decompress_usingDDict() - decompress src into dst using a ZSTD_DDict
++ * @ctx: The decompression context.
++ * @dst: The buffer to decompress src into.
++ * @dstCapacity: The size of the destination buffer. Must be at least as large
++ * as the decompressed size. If the caller cannot upper bound the
++ * decompressed size, then it's better to use the streaming API.
++ * @src: The zstd compressed data to decompress. Multiple concatenated
++ * frames and skippable frames are allowed.
++ * @srcSize: The exact size of the data to decompress.
++ * @ddict: The digested dictionary to use for decompression. The same
++ * dictionary must've been used to compress the data.
++ *
++ * Return: The decompressed size or an error, which can be checked using
++ * ZSTD_isError().
++ */
++size_t ZSTD_decompress_usingDDict(ZSTD_DCtx *dctx, void *dst,
++ size_t dstCapacity, const void *src, size_t srcSize,
++ const ZSTD_DDict *ddict);
++
++
++/*-**************************
++ * Streaming
++ ***************************/
++
++/**
++ * struct ZSTD_inBuffer - input buffer for streaming
++ * @src: Start of the input buffer.
++ * @size: Size of the input buffer.
++ * @pos: Position where reading stopped. Will be updated.
++ * Necessarily 0 <= pos <= size.
++ */
++typedef struct ZSTD_inBuffer_s {
++ const void *src;
++ size_t size;
++ size_t pos;
++} ZSTD_inBuffer;
++
++/**
++ * struct ZSTD_outBuffer - output buffer for streaming
++ * @dst: Start of the output buffer.
++ * @size: Size of the output buffer.
++ * @pos: Position where writing stopped. Will be updated.
++ * Necessarily 0 <= pos <= size.
++ */
++typedef struct ZSTD_outBuffer_s {
++ void *dst;
++ size_t size;
++ size_t pos;
++} ZSTD_outBuffer;
++
++
++
++/*-*****************************************************************************
++ * Streaming compression - HowTo
++ *
++ * A ZSTD_CStream object is required to track streaming operation.
++ * Use ZSTD_initCStream() to initialize a ZSTD_CStream object.
++ * ZSTD_CStream objects can be reused multiple times on consecutive compression
++ * operations. It is recommended to re-use ZSTD_CStream in situations where many
++ * streaming operations will be achieved consecutively. Use one separate
++ * ZSTD_CStream per thread for parallel execution.
++ *
++ * Use ZSTD_compressStream() repetitively to consume input stream.
++ * The function will automatically update both `pos` fields.
++ * Note that it may not consume the entire input, in which case `pos < size`,
++ * and it's up to the caller to present again remaining data.
++ * It returns a hint for the preferred number of bytes to use as an input for
++ * the next function call.
++ *
++ * At any moment, it's possible to flush whatever data remains within internal
++ * buffer, using ZSTD_flushStream(). `output->pos` will be updated. There might
++ * still be some content left within the internal buffer if `output->size` is
++ * too small. It returns the number of bytes left in the internal buffer and
++ * must be called until it returns 0.
++ *
++ * ZSTD_endStream() instructs to finish a frame. It will perform a flush and
++ * write frame epilogue. The epilogue is required for decoders to consider a
++ * frame completed. Similar to ZSTD_flushStream(), it may not be able to flush
++ * the full content if `output->size` is too small. In which case, call again
++ * ZSTD_endStream() to complete the flush. It returns the number of bytes left
++ * in the internal buffer and must be called until it returns 0.
++ ******************************************************************************/
++
++/**
++ * ZSTD_CStreamWorkspaceBound() - memory needed to initialize a ZSTD_CStream
++ * @cParams: The compression parameters to be used for compression.
++ *
++ * Return: A lower bound on the size of the workspace that is passed to
++ * ZSTD_initCStream() and ZSTD_initCStream_usingCDict().
++ */
++size_t ZSTD_CStreamWorkspaceBound(ZSTD_compressionParameters cParams);
++
++/**
++ * struct ZSTD_CStream - the zstd streaming compression context
++ */
++typedef struct ZSTD_CStream_s ZSTD_CStream;
++
++/*===== ZSTD_CStream management functions =====*/
++/**
++ * ZSTD_initCStream() - initialize a zstd streaming compression context
++ * @params: The zstd compression parameters.
++ * @pledgedSrcSize: If params.fParams.contentSizeFlag == 1 then the caller must
++ * pass the source size (zero means empty source). Otherwise,
++ * the caller may optionally pass the source size, or zero if
++ * unknown.
++ * @workspace: The workspace to emplace the context into. It must outlive
++ * the returned context.
++ * @workspaceSize: The size of workspace.
++ * Use ZSTD_CStreamWorkspaceBound(params.cParams) to determine
++ * how large the workspace must be.
++ *
++ * Return: The zstd streaming compression context.
++ */
++ZSTD_CStream *ZSTD_initCStream(ZSTD_parameters params,
++ unsigned long long pledgedSrcSize, void *workspace,
++ size_t workspaceSize);
++
++/**
++ * ZSTD_initCStream_usingCDict() - initialize a streaming compression context
++ * @cdict: The digested dictionary to use for compression.
++ * @pledgedSrcSize: Optionally the source size, or zero if unknown.
++ * @workspace: The workspace to emplace the context into. It must outlive
++ * the returned context.
++ * @workspaceSize: The size of workspace. Call ZSTD_CStreamWorkspaceBound()
++ * with the cParams used to initialize the cdict to determine
++ * how large the workspace must be.
++ *
++ * Return: The zstd streaming compression context.
++ */
++ZSTD_CStream *ZSTD_initCStream_usingCDict(const ZSTD_CDict *cdict,
++ unsigned long long pledgedSrcSize, void *workspace,
++ size_t workspaceSize);
++
++/*===== Streaming compression functions =====*/
++/**
++ * ZSTD_resetCStream() - reset the context using parameters from creation
++ * @zcs: The zstd streaming compression context to reset.
++ * @pledgedSrcSize: Optionally the source size, or zero if unknown.
++ *
++ * Resets the context using the parameters from creation. Skips dictionary
++ * loading, since it can be reused. If `pledgedSrcSize` is non-zero the frame
++ * content size is always written into the frame header.
++ *
++ * Return: Zero or an error, which can be checked using ZSTD_isError().
++ */
++size_t ZSTD_resetCStream(ZSTD_CStream *zcs, unsigned long long pledgedSrcSize);
++/**
++ * ZSTD_compressStream() - streaming compress some of input into output
++ * @zcs: The zstd streaming compression context.
++ * @output: Destination buffer. `output->pos` is updated to indicate how much
++ * compressed data was written.
++ * @input: Source buffer. `input->pos` is updated to indicate how much data was
++ * read. Note that it may not consume the entire input, in which case
++ * `input->pos < input->size`, and it's up to the caller to present
++ * remaining data again.
++ *
++ * The `input` and `output` buffers may be any size. Guaranteed to make some
++ * forward progress if `input` and `output` are not empty.
++ *
++ * Return: A hint for the number of bytes to use as the input for the next
++ * function call or an error, which can be checked using
++ * ZSTD_isError().
++ */
++size_t ZSTD_compressStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output,
++ ZSTD_inBuffer *input);
++/**
++ * ZSTD_flushStream() - flush internal buffers into output
++ * @zcs: The zstd streaming compression context.
++ * @output: Destination buffer. `output->pos` is updated to indicate how much
++ * compressed data was written.
++ *
++ * ZSTD_flushStream() must be called until it returns 0, meaning all the data
++ * has been flushed. Since ZSTD_flushStream() causes a block to be ended,
++ * calling it too often will degrade the compression ratio.
++ *
++ * Return: The number of bytes still present within internal buffers or an
++ * error, which can be checked using ZSTD_isError().
++ */
++size_t ZSTD_flushStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output);
++/**
++ * ZSTD_endStream() - flush internal buffers into output and end the frame
++ * @zcs: The zstd streaming compression context.
++ * @output: Destination buffer. `output->pos` is updated to indicate how much
++ * compressed data was written.
++ *
++ * ZSTD_endStream() must be called until it returns 0, meaning all the data has
++ * been flushed and the frame epilogue has been written.
++ *
++ * Return: The number of bytes still present within internal buffers or an
++ * error, which can be checked using ZSTD_isError().
++ */
++size_t ZSTD_endStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output);
++
++/**
++ * ZSTD_CStreamInSize() - recommended size for the input buffer
++ *
++ * Return: The recommended size for the input buffer.
++ */
++size_t ZSTD_CStreamInSize(void);
++/**
++ * ZSTD_CStreamOutSize() - recommended size for the output buffer
++ *
++ * When the output buffer is at least this large, it is guaranteed to be large
++ * enough to flush at least one complete compressed block.
++ *
++ * Return: The recommended size for the output buffer.
++ */
++size_t ZSTD_CStreamOutSize(void);
++
++
++
++/*-*****************************************************************************
++ * Streaming decompression - HowTo
++ *
++ * A ZSTD_DStream object is required to track streaming operations.
++ * Use ZSTD_initDStream() to initialize a ZSTD_DStream object.
++ * ZSTD_DStream objects can be re-used multiple times.
++ *
++ * Use ZSTD_decompressStream() repetitively to consume your input.
++ * The function will update both `pos` fields.
++ * If `input->pos < input->size`, some input has not been consumed.
++ * It's up to the caller to present again remaining data.
++ * If `output->pos < output->size`, decoder has flushed everything it could.
++ * Returns 0 iff a frame is completely decoded and fully flushed.
++ * Otherwise it returns a suggested next input size that will never load more
++ * than the current frame.
++ ******************************************************************************/
++
++/**
++ * ZSTD_DStreamWorkspaceBound() - memory needed to initialize a ZSTD_DStream
++ * @maxWindowSize: The maximum window size allowed for compressed frames.
++ *
++ * Return: A lower bound on the size of the workspace that is passed to
++ * ZSTD_initDStream() and ZSTD_initDStream_usingDDict().
++ */
++size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize);
++
++/**
++ * struct ZSTD_DStream - the zstd streaming decompression context
++ */
++typedef struct ZSTD_DStream_s ZSTD_DStream;
++/*===== ZSTD_DStream management functions =====*/
++/**
++ * ZSTD_initDStream() - initialize a zstd streaming decompression context
++ * @maxWindowSize: The maximum window size allowed for compressed frames.
++ * @workspace: The workspace to emplace the context into. It must outlive
++ * the returned context.
++ * @workspaceSize: The size of workspace.
++ * Use ZSTD_DStreamWorkspaceBound(maxWindowSize) to determine
++ * how large the workspace must be.
++ *
++ * Return: The zstd streaming decompression context.
++ */
++ZSTD_DStream *ZSTD_initDStream(size_t maxWindowSize, void *workspace,
++ size_t workspaceSize);
++/**
++ * ZSTD_initDStream_usingDDict() - initialize streaming decompression context
++ * @maxWindowSize: The maximum window size allowed for compressed frames.
++ * @ddict: The digested dictionary to use for decompression.
++ * @workspace: The workspace to emplace the context into. It must outlive
++ * the returned context.
++ * @workspaceSize: The size of workspace.
++ * Use ZSTD_DStreamWorkspaceBound(maxWindowSize) to determine
++ * how large the workspace must be.
++ *
++ * Return: The zstd streaming decompression context.
++ */
++ZSTD_DStream *ZSTD_initDStream_usingDDict(size_t maxWindowSize,
++ const ZSTD_DDict *ddict, void *workspace, size_t workspaceSize);
++
++/*===== Streaming decompression functions =====*/
++/**
++ * ZSTD_resetDStream() - reset the context using parameters from creation
++ * @zds: The zstd streaming decompression context to reset.
++ *
++ * Resets the context using the parameters from creation. Skips dictionary
++ * loading, since it can be reused.
++ *
++ * Return: Zero or an error, which can be checked using ZSTD_isError().
++ */
++size_t ZSTD_resetDStream(ZSTD_DStream *zds);
++/**
++ * ZSTD_decompressStream() - streaming decompress some of input into output
++ * @zds: The zstd streaming decompression context.
++ * @output: Destination buffer. `output.pos` is updated to indicate how much
++ * decompressed data was written.
++ * @input: Source buffer. `input.pos` is updated to indicate how much data was
++ * read. Note that it may not consume the entire input, in which case
++ * `input.pos < input.size`, and it's up to the caller to present
++ * remaining data again.
++ *
++ * The `input` and `output` buffers may be any size. Guaranteed to make some
++ * forward progress if `input` and `output` are not empty.
++ * ZSTD_decompressStream() will not consume the last byte of the frame until
++ * the entire frame is flushed.
++ *
++ * Return: Returns 0 iff a frame is completely decoded and fully flushed.
++ * Otherwise returns a hint for the number of bytes to use as the input
++ * for the next function call or an error, which can be checked using
++ * ZSTD_isError(). The size hint will never load more than the frame.
++ */
++size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output,
++ ZSTD_inBuffer *input);
++
++/**
++ * ZSTD_DStreamInSize() - recommended size for the input buffer
++ *
++ * Return: The recommended size for the input buffer.
++ */
++size_t ZSTD_DStreamInSize(void);
++/**
++ * ZSTD_DStreamOutSize() - recommended size for the output buffer
++ *
++ * When the output buffer is at least this large, it is guaranteed to be large
++ * enough to flush at least one complete decompressed block.
++ *
++ * Return: The recommended size for the output buffer.
++ */
++size_t ZSTD_DStreamOutSize(void);
++
++
++/* --- Constants ---*/
++#define ZSTD_MAGICNUMBER 0xFD2FB528 /* >= v0.8.0 */
++#define ZSTD_MAGIC_SKIPPABLE_START 0x184D2A50U
++
++#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1)
++#define ZSTD_CONTENTSIZE_ERROR (0ULL - 2)
++
++#define ZSTD_WINDOWLOG_MAX_32 27
++#define ZSTD_WINDOWLOG_MAX_64 27
++#define ZSTD_WINDOWLOG_MAX \
++ ((unsigned int)(sizeof(size_t) == 4 \
++ ? ZSTD_WINDOWLOG_MAX_32 \
++ : ZSTD_WINDOWLOG_MAX_64))
++#define ZSTD_WINDOWLOG_MIN 10
++#define ZSTD_HASHLOG_MAX ZSTD_WINDOWLOG_MAX
++#define ZSTD_HASHLOG_MIN 6
++#define ZSTD_CHAINLOG_MAX (ZSTD_WINDOWLOG_MAX+1)
++#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN
++#define ZSTD_HASHLOG3_MAX 17
++#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1)
++#define ZSTD_SEARCHLOG_MIN 1
++/* only for ZSTD_fast, other strategies are limited to 6 */
++#define ZSTD_SEARCHLENGTH_MAX 7
++/* only for ZSTD_btopt, other strategies are limited to 4 */
++#define ZSTD_SEARCHLENGTH_MIN 3
++#define ZSTD_TARGETLENGTH_MIN 4
++#define ZSTD_TARGETLENGTH_MAX 999
++
++/* for static allocation */
++#define ZSTD_FRAMEHEADERSIZE_MAX 18
++#define ZSTD_FRAMEHEADERSIZE_MIN 6
++static const size_t ZSTD_frameHeaderSize_prefix = 5;
++static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN;
++static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX;
++/* magic number + skippable frame length */
++static const size_t ZSTD_skippableHeaderSize = 8;
++
++
++/*-*************************************
++ * Compressed size functions
++ **************************************/
++
++/**
++ * ZSTD_findFrameCompressedSize() - returns the size of a compressed frame
++ * @src: Source buffer. It should point to the start of a zstd encoded frame
++ * or a skippable frame.
++ * @srcSize: The size of the source buffer. It must be at least as large as the
++ * size of the frame.
++ *
++ * Return: The compressed size of the frame pointed to by `src` or an error,
++ * which can be check with ZSTD_isError().
++ * Suitable to pass to ZSTD_decompress() or similar functions.
++ */
++size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize);
++
++/*-*************************************
++ * Decompressed size functions
++ **************************************/
++/**
++ * ZSTD_getFrameContentSize() - returns the content size in a zstd frame header
++ * @src: It should point to the start of a zstd encoded frame.
++ * @srcSize: The size of the source buffer. It must be at least as large as the
++ * frame header. `ZSTD_frameHeaderSize_max` is always large enough.
++ *
++ * Return: The frame content size stored in the frame header if known.
++ * `ZSTD_CONTENTSIZE_UNKNOWN` if the content size isn't stored in the
++ * frame header. `ZSTD_CONTENTSIZE_ERROR` on invalid input.
++ */
++unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
++
++/**
++ * ZSTD_findDecompressedSize() - returns decompressed size of a series of frames
++ * @src: It should point to the start of a series of zstd encoded and/or
++ * skippable frames.
++ * @srcSize: The exact size of the series of frames.
++ *
++ * If any zstd encoded frame in the series doesn't have the frame content size
++ * set, `ZSTD_CONTENTSIZE_UNKNOWN` is returned. But frame content size is always
++ * set when using ZSTD_compress(). The decompressed size can be very large.
++ * If the source is untrusted, the decompressed size could be wrong or
++ * intentionally modified. Always ensure the result fits within the
++ * application's authorized limits. ZSTD_findDecompressedSize() handles multiple
++ * frames, and so it must traverse the input to read each frame header. This is
++ * efficient as most of the data is skipped, however it does mean that all frame
++ * data must be present and valid.
++ *
++ * Return: Decompressed size of all the data contained in the frames if known.
++ * `ZSTD_CONTENTSIZE_UNKNOWN` if the decompressed size is unknown.
++ * `ZSTD_CONTENTSIZE_ERROR` if an error occurred.
++ */
++unsigned long long ZSTD_findDecompressedSize(const void *src, size_t srcSize);
++
++/*-*************************************
++ * Advanced compression functions
++ **************************************/
++/**
++ * ZSTD_checkCParams() - ensure parameter values remain within authorized range
++ * @cParams: The zstd compression parameters.
++ *
++ * Return: Zero or an error, which can be checked using ZSTD_isError().
++ */
++size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams);
++
++/**
++ * ZSTD_adjustCParams() - optimize parameters for a given srcSize and dictSize
++ * @srcSize: Optionally the estimated source size, or zero if unknown.
++ * @dictSize: Optionally the estimated dictionary size, or zero if unknown.
++ *
++ * Return: The optimized parameters.
++ */
++ZSTD_compressionParameters ZSTD_adjustCParams(
++ ZSTD_compressionParameters cParams, unsigned long long srcSize,
++ size_t dictSize);
++
++/*--- Advanced decompression functions ---*/
++
++/**
++ * ZSTD_isFrame() - returns true iff the buffer starts with a valid frame
++ * @buffer: The source buffer to check.
++ * @size: The size of the source buffer, must be at least 4 bytes.
++ *
++ * Return: True iff the buffer starts with a zstd or skippable frame identifier.
++ */
++unsigned int ZSTD_isFrame(const void *buffer, size_t size);
++
++/**
++ * ZSTD_getDictID_fromDict() - returns the dictionary id stored in a dictionary
++ * @dict: The dictionary buffer.
++ * @dictSize: The size of the dictionary buffer.
++ *
++ * Return: The dictionary id stored within the dictionary or 0 if the
++ * dictionary is not a zstd dictionary. If it returns 0 the
++ * dictionary can still be loaded as a content-only dictionary.
++ */
++unsigned int ZSTD_getDictID_fromDict(const void *dict, size_t dictSize);
++
++/**
++ * ZSTD_getDictID_fromDDict() - returns the dictionary id stored in a ZSTD_DDict
++ * @ddict: The ddict to find the id of.
++ *
++ * Return: The dictionary id stored within `ddict` or 0 if the dictionary is not
++ * a zstd dictionary. If it returns 0 `ddict` will be loaded as a
++ * content-only dictionary.
++ */
++unsigned int ZSTD_getDictID_fromDDict(const ZSTD_DDict *ddict);
++
++/**
++ * ZSTD_getDictID_fromFrame() - returns the dictionary id stored in a zstd frame
++ * @src: Source buffer. It must be a zstd encoded frame.
++ * @srcSize: The size of the source buffer. It must be at least as large as the
++ * frame header. `ZSTD_frameHeaderSize_max` is always large enough.
++ *
++ * Return: The dictionary id required to decompress the frame stored within
++ * `src` or 0 if the dictionary id could not be decoded. It can return
++ * 0 if the frame does not require a dictionary, the dictionary id
++ * wasn't stored in the frame, `src` is not a zstd frame, or `srcSize`
++ * is too small.
++ */
++unsigned int ZSTD_getDictID_fromFrame(const void *src, size_t srcSize);
++
++/**
++ * struct ZSTD_frameParams - zstd frame parameters stored in the frame header
++ * @frameContentSize: The frame content size, or 0 if not present.
++ * @windowSize: The window size, or 0 if the frame is a skippable frame.
++ * @dictID: The dictionary id, or 0 if not present.
++ * @checksumFlag: Whether a checksum was used.
++ */
++typedef struct {
++ unsigned long long frameContentSize;
++ unsigned int windowSize;
++ unsigned int dictID;
++ unsigned int checksumFlag;
++} ZSTD_frameParams;
++
++/**
++ * ZSTD_getFrameParams() - extracts parameters from a zstd or skippable frame
++ * @fparamsPtr: On success the frame parameters are written here.
++ * @src: The source buffer. It must point to a zstd or skippable frame.
++ * @srcSize: The size of the source buffer. `ZSTD_frameHeaderSize_max` is
++ * always large enough to succeed.
++ *
++ * Return: 0 on success. If more data is required it returns how many bytes
++ * must be provided to make forward progress. Otherwise it returns
++ * an error, which can be checked using ZSTD_isError().
++ */
++size_t ZSTD_getFrameParams(ZSTD_frameParams *fparamsPtr, const void *src,
++ size_t srcSize);
++
++/*-*****************************************************************************
++ * Buffer-less and synchronous inner streaming functions
++ *
++ * This is an advanced API, giving full control over buffer management, for
++ * users which need direct control over memory.
++ * But it's also a complex one, with many restrictions (documented below).
++ * Prefer using normal streaming API for an easier experience
++ ******************************************************************************/
++
++/*-*****************************************************************************
++ * Buffer-less streaming compression (synchronous mode)
++ *
++ * A ZSTD_CCtx object is required to track streaming operations.
++ * Use ZSTD_initCCtx() to initialize a context.
++ * ZSTD_CCtx object can be re-used multiple times within successive compression
++ * operations.
++ *
++ * Start by initializing a context.
++ * Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary
++ * compression,
++ * or ZSTD_compressBegin_advanced(), for finer parameter control.
++ * It's also possible to duplicate a reference context which has already been
++ * initialized, using ZSTD_copyCCtx()
++ *
++ * Then, consume your input using ZSTD_compressContinue().
++ * There are some important considerations to keep in mind when using this
++ * advanced function :
++ * - ZSTD_compressContinue() has no internal buffer. It uses externally provided
++ * buffer only.
++ * - Interface is synchronous : input is consumed entirely and produce 1+
++ * (or more) compressed blocks.
++ * - Caller must ensure there is enough space in `dst` to store compressed data
++ * under worst case scenario. Worst case evaluation is provided by
++ * ZSTD_compressBound().
++ * ZSTD_compressContinue() doesn't guarantee recover after a failed
++ * compression.
++ * - ZSTD_compressContinue() presumes prior input ***is still accessible and
++ * unmodified*** (up to maximum distance size, see WindowLog).
++ * It remembers all previous contiguous blocks, plus one separated memory
++ * segment (which can itself consists of multiple contiguous blocks)
++ * - ZSTD_compressContinue() detects that prior input has been overwritten when
++ * `src` buffer overlaps. In which case, it will "discard" the relevant memory
++ * section from its history.
++ *
++ * Finish a frame with ZSTD_compressEnd(), which will write the last block(s)
++ * and optional checksum. It's possible to use srcSize==0, in which case, it
++ * will write a final empty block to end the frame. Without last block mark,
++ * frames will be considered unfinished (corrupted) by decoders.
++ *
++ * `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some new
++ * frame.
++ ******************************************************************************/
++
++/*===== Buffer-less streaming compression functions =====*/
++size_t ZSTD_compressBegin(ZSTD_CCtx *cctx, int compressionLevel);
++size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx *cctx, const void *dict,
++ size_t dictSize, int compressionLevel);
++size_t ZSTD_compressBegin_advanced(ZSTD_CCtx *cctx, const void *dict,
++ size_t dictSize, ZSTD_parameters params,
++ unsigned long long pledgedSrcSize);
++size_t ZSTD_copyCCtx(ZSTD_CCtx *cctx, const ZSTD_CCtx *preparedCCtx,
++ unsigned long long pledgedSrcSize);
++size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx *cctx, const ZSTD_CDict *cdict,
++ unsigned long long pledgedSrcSize);
++size_t ZSTD_compressContinue(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize);
++size_t ZSTD_compressEnd(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize);
++
++
++
++/*-*****************************************************************************
++ * Buffer-less streaming decompression (synchronous mode)
++ *
++ * A ZSTD_DCtx object is required to track streaming operations.
++ * Use ZSTD_initDCtx() to initialize a context.
++ * A ZSTD_DCtx object can be re-used multiple times.
++ *
++ * First typical operation is to retrieve frame parameters, using
++ * ZSTD_getFrameParams(). It fills a ZSTD_frameParams structure which provide
++ * important information to correctly decode the frame, such as the minimum
++ * rolling buffer size to allocate to decompress data (`windowSize`), and the
++ * dictionary ID used.
++ * Note: content size is optional, it may not be present. 0 means unknown.
++ * Note that these values could be wrong, either because of data malformation,
++ * or because an attacker is spoofing deliberate false information. As a
++ * consequence, check that values remain within valid application range,
++ * especially `windowSize`, before allocation. Each application can set its own
++ * limit, depending on local restrictions. For extended interoperability, it is
++ * recommended to support at least 8 MB.
++ * Frame parameters are extracted from the beginning of the compressed frame.
++ * Data fragment must be large enough to ensure successful decoding, typically
++ * `ZSTD_frameHeaderSize_max` bytes.
++ * Result: 0: successful decoding, the `ZSTD_frameParams` structure is filled.
++ * >0: `srcSize` is too small, provide at least this many bytes.
++ * errorCode, which can be tested using ZSTD_isError().
++ *
++ * Start decompression, with ZSTD_decompressBegin() or
++ * ZSTD_decompressBegin_usingDict(). Alternatively, you can copy a prepared
++ * context, using ZSTD_copyDCtx().
++ *
++ * Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue()
++ * alternatively.
++ * ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize'
++ * to ZSTD_decompressContinue().
++ * ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will
++ * fail.
++ *
++ * The result of ZSTD_decompressContinue() is the number of bytes regenerated
++ * within 'dst' (necessarily <= dstCapacity). It can be zero, which is not an
++ * error; it just means ZSTD_decompressContinue() has decoded some metadata
++ * item. It can also be an error code, which can be tested with ZSTD_isError().
++ *
++ * ZSTD_decompressContinue() needs previous data blocks during decompression, up
++ * to `windowSize`. They should preferably be located contiguously, prior to
++ * current block. Alternatively, a round buffer of sufficient size is also
++ * possible. Sufficient size is determined by frame parameters.
++ * ZSTD_decompressContinue() is very sensitive to contiguity, if 2 blocks don't
++ * follow each other, make sure that either the compressor breaks contiguity at
++ * the same place, or that previous contiguous segment is large enough to
++ * properly handle maximum back-reference.
++ *
++ * A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
++ * Context can then be reset to start a new decompression.
++ *
++ * Note: it's possible to know if next input to present is a header or a block,
++ * using ZSTD_nextInputType(). This information is not required to properly
++ * decode a frame.
++ *
++ * == Special case: skippable frames ==
++ *
++ * Skippable frames allow integration of user-defined data into a flow of
++ * concatenated frames. Skippable frames will be ignored (skipped) by a
++ * decompressor. The format of skippable frames is as follows:
++ * a) Skippable frame ID - 4 Bytes, Little endian format, any value from
++ * 0x184D2A50 to 0x184D2A5F
++ * b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
++ * c) Frame Content - any content (User Data) of length equal to Frame Size
++ * For skippable frames ZSTD_decompressContinue() always returns 0.
++ * For skippable frames ZSTD_getFrameParams() returns fparamsPtr->windowLog==0
++ * what means that a frame is skippable.
++ * Note: If fparamsPtr->frameContentSize==0, it is ambiguous: the frame might
++ * actually be a zstd encoded frame with no content. For purposes of
++ * decompression, it is valid in both cases to skip the frame using
++ * ZSTD_findFrameCompressedSize() to find its size in bytes.
++ * It also returns frame size as fparamsPtr->frameContentSize.
++ ******************************************************************************/
++
++/*===== Buffer-less streaming decompression functions =====*/
++size_t ZSTD_decompressBegin(ZSTD_DCtx *dctx);
++size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx *dctx, const void *dict,
++ size_t dictSize);
++void ZSTD_copyDCtx(ZSTD_DCtx *dctx, const ZSTD_DCtx *preparedDCtx);
++size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx *dctx);
++size_t ZSTD_decompressContinue(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize);
++typedef enum {
++ ZSTDnit_frameHeader,
++ ZSTDnit_blockHeader,
++ ZSTDnit_block,
++ ZSTDnit_lastBlock,
++ ZSTDnit_checksum,
++ ZSTDnit_skippableFrame
++} ZSTD_nextInputType_e;
++ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx *dctx);
++
++/*-*****************************************************************************
++ * Block functions
++ *
++ * Block functions produce and decode raw zstd blocks, without frame metadata.
++ * Frame metadata cost is typically ~18 bytes, which can be non-negligible for
++ * very small blocks (< 100 bytes). User will have to take in charge required
++ * information to regenerate data, such as compressed and content sizes.
++ *
++ * A few rules to respect:
++ * - Compressing and decompressing require a context structure
++ * + Use ZSTD_initCCtx() and ZSTD_initDCtx()
++ * - It is necessary to init context before starting
++ * + compression : ZSTD_compressBegin()
++ * + decompression : ZSTD_decompressBegin()
++ * + variants _usingDict() are also allowed
++ * + copyCCtx() and copyDCtx() work too
++ * - Block size is limited, it must be <= ZSTD_getBlockSizeMax()
++ * + If you need to compress more, cut data into multiple blocks
++ * + Consider using the regular ZSTD_compress() instead, as frame metadata
++ * costs become negligible when source size is large.
++ * - When a block is considered not compressible enough, ZSTD_compressBlock()
++ * result will be zero. In which case, nothing is produced into `dst`.
++ * + User must test for such outcome and deal directly with uncompressed data
++ * + ZSTD_decompressBlock() doesn't accept uncompressed data as input!!!
++ * + In case of multiple successive blocks, decoder must be informed of
++ * uncompressed block existence to follow proper history. Use
++ * ZSTD_insertBlock() in such a case.
++ ******************************************************************************/
++
++/* Define for static allocation */
++#define ZSTD_BLOCKSIZE_ABSOLUTEMAX (128 * 1024)
++/*===== Raw zstd block functions =====*/
++size_t ZSTD_getBlockSizeMax(ZSTD_CCtx *cctx);
++size_t ZSTD_compressBlock(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize);
++size_t ZSTD_decompressBlock(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity,
++ const void *src, size_t srcSize);
++size_t ZSTD_insertBlock(ZSTD_DCtx *dctx, const void *blockStart,
++ size_t blockSize);
++
++#endif /* ZSTD_H */
+diff --git a/lib/Kconfig b/lib/Kconfig
+index b6009d7..f00ddab 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -241,6 +241,14 @@ config LZ4HC_COMPRESS
+ config LZ4_DECOMPRESS
+ tristate
+
++config ZSTD_COMPRESS
++ select XXHASH
++ tristate
++
++config ZSTD_DECOMPRESS
++ select XXHASH
++ tristate
++
+ source "lib/xz/Kconfig"
+
+ #
+diff --git a/lib/Makefile b/lib/Makefile
+index 1338226..4fcef16 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -116,6 +116,8 @@ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
+ obj-$(CONFIG_LZ4_COMPRESS) += lz4/
+ obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/
+ obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
++obj-$(CONFIG_ZSTD_COMPRESS) += zstd/
++obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/
+ obj-$(CONFIG_XZ_DEC) += xz/
+ obj-$(CONFIG_RAID6_PQ) += raid6/
+
+diff --git a/lib/zstd/Makefile b/lib/zstd/Makefile
+new file mode 100644
+index 0000000..dd0a359
+--- /dev/null
++++ b/lib/zstd/Makefile
+@@ -0,0 +1,18 @@
++obj-$(CONFIG_ZSTD_COMPRESS) += zstd_compress.o
++obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd_decompress.o
++
++ccflags-y += -O3
++
++# Object files unique to zstd_compress and zstd_decompress
++zstd_compress-y := fse_compress.o huf_compress.o compress.o
++zstd_decompress-y := huf_decompress.o decompress.o
++
++# These object files are shared between the modules.
++# Always add them to zstd_compress.
++# Unless both zstd_compress and zstd_decompress are built in
++# then also add them to zstd_decompress.
++zstd_compress-y += entropy_common.o fse_decompress.o zstd_common.o
++
++ifneq ($(CONFIG_ZSTD_COMPRESS)$(CONFIG_ZSTD_DECOMPRESS),yy)
++ zstd_decompress-y += entropy_common.o fse_decompress.o zstd_common.o
++endif
+diff --git a/lib/zstd/bitstream.h b/lib/zstd/bitstream.h
+new file mode 100644
+index 0000000..a826b99
+--- /dev/null
++++ b/lib/zstd/bitstream.h
+@@ -0,0 +1,374 @@
++/*
++ * bitstream
++ * Part of FSE library
++ * header file (to include)
++ * Copyright (C) 2013-2016, 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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at :
++ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
++ */
++#ifndef BITSTREAM_H_MODULE
++#define BITSTREAM_H_MODULE
++
++/*
++* This API consists of small unitary functions, which must be inlined for best performance.
++* Since link-time-optimization is not available for all compilers,
++* these functions are defined into a .h to be included.
++*/
++
++/*-****************************************
++* Dependencies
++******************************************/
++#include "error_private.h" /* error codes and messages */
++#include "mem.h" /* unaligned access routines */
++
++/*=========================================
++* Target specific
++=========================================*/
++#define STREAM_ACCUMULATOR_MIN_32 25
++#define STREAM_ACCUMULATOR_MIN_64 57
++#define STREAM_ACCUMULATOR_MIN ((U32)(ZSTD_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
++
++/*-******************************************
++* bitStream encoding API (write forward)
++********************************************/
++/* bitStream can mix input from multiple sources.
++* A critical property of these streams is that they encode and decode in **reverse** direction.
++* So the first bit sequence you add will be the last to be read, like a LIFO stack.
++*/
++typedef struct {
++ size_t bitContainer;
++ int bitPos;
++ char *startPtr;
++ char *ptr;
++ char *endPtr;
++} BIT_CStream_t;
++
++ZSTD_STATIC size_t BIT_initCStream(BIT_CStream_t *bitC, void *dstBuffer, size_t dstCapacity);
++ZSTD_STATIC void BIT_addBits(BIT_CStream_t *bitC, size_t value, unsigned nbBits);
++ZSTD_STATIC void BIT_flushBits(BIT_CStream_t *bitC);
++ZSTD_STATIC size_t BIT_closeCStream(BIT_CStream_t *bitC);
++
++/* Start with initCStream, providing the size of buffer to write into.
++* bitStream will never write outside of this buffer.
++* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
++*
++* bits are first added to a local register.
++* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
++* Writing data into memory is an explicit operation, performed by the flushBits function.
++* Hence keep track how many bits are potentially stored into local register to avoid register overflow.
++* After a flushBits, a maximum of 7 bits might still be stored into local register.
++*
++* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
++*
++* Last operation is to close the bitStream.
++* The function returns the final size of CStream in bytes.
++* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
++*/
++
++/*-********************************************
++* bitStream decoding API (read backward)
++**********************************************/
++typedef struct {
++ size_t bitContainer;
++ unsigned bitsConsumed;
++ const char *ptr;
++ const char *start;
++} BIT_DStream_t;
++
++typedef enum {
++ BIT_DStream_unfinished = 0,
++ BIT_DStream_endOfBuffer = 1,
++ BIT_DStream_completed = 2,
++ BIT_DStream_overflow = 3
++} BIT_DStream_status; /* result of BIT_reloadDStream() */
++/* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
++
++ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void *srcBuffer, size_t srcSize);
++ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, unsigned nbBits);
++ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD);
++ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *bitD);
++
++/* Start by invoking BIT_initDStream().
++* A chunk of the bitStream is then stored into a local register.
++* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
++* You can then retrieve bitFields stored into the local register, **in reverse order**.
++* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
++* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
++* Otherwise, it can be less than that, so proceed accordingly.
++* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
++*/
++
++/*-****************************************
++* unsafe API
++******************************************/
++ZSTD_STATIC void BIT_addBitsFast(BIT_CStream_t *bitC, size_t value, unsigned nbBits);
++/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
++
++ZSTD_STATIC void BIT_flushBitsFast(BIT_CStream_t *bitC);
++/* unsafe version; does not check buffer overflow */
++
++ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, unsigned nbBits);
++/* faster, but works only if nbBits >= 1 */
++
++/*-**************************************************************
++* Internal functions
++****************************************************************/
++ZSTD_STATIC unsigned BIT_highbit32(register U32 val) { return 31 - __builtin_clz(val); }
++
++/*===== Local Constants =====*/
++static const unsigned BIT_mask[] = {0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF,
++ 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF,
++ 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF}; /* up to 26 bits */
++
++/*-**************************************************************
++* bitStream encoding
++****************************************************************/
++/*! BIT_initCStream() :
++ * `dstCapacity` must be > sizeof(void*)
++ * @return : 0 if success,
++ otherwise an error code (can be tested using ERR_isError() ) */
++ZSTD_STATIC size_t BIT_initCStream(BIT_CStream_t *bitC, void *startPtr, size_t dstCapacity)
++{
++ bitC->bitContainer = 0;
++ bitC->bitPos = 0;
++ bitC->startPtr = (char *)startPtr;
++ bitC->ptr = bitC->startPtr;
++ bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->ptr);
++ if (dstCapacity <= sizeof(bitC->ptr))
++ return ERROR(dstSize_tooSmall);
++ return 0;
++}
++
++/*! BIT_addBits() :
++ can add up to 26 bits into `bitC`.
++ Does not check for register overflow ! */
++ZSTD_STATIC void BIT_addBits(BIT_CStream_t *bitC, size_t value, unsigned nbBits)
++{
++ bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
++ bitC->bitPos += nbBits;
++}
++
++/*! BIT_addBitsFast() :
++ * works only if `value` is _clean_, meaning all high bits above nbBits are 0 */
++ZSTD_STATIC void BIT_addBitsFast(BIT_CStream_t *bitC, size_t value, unsigned nbBits)
++{
++ bitC->bitContainer |= value << bitC->bitPos;
++ bitC->bitPos += nbBits;
++}
++
++/*! BIT_flushBitsFast() :
++ * unsafe version; does not check buffer overflow */
++ZSTD_STATIC void BIT_flushBitsFast(BIT_CStream_t *bitC)
++{
++ size_t const nbBytes = bitC->bitPos >> 3;
++ ZSTD_writeLEST(bitC->ptr, bitC->bitContainer);
++ bitC->ptr += nbBytes;
++ bitC->bitPos &= 7;
++ bitC->bitContainer >>= nbBytes * 8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
++}
++
++/*! BIT_flushBits() :
++ * safe version; check for buffer overflow, and prevents it.
++ * note : does not signal buffer overflow. This will be revealed later on using BIT_closeCStream() */
++ZSTD_STATIC void BIT_flushBits(BIT_CStream_t *bitC)
++{
++ size_t const nbBytes = bitC->bitPos >> 3;
++ ZSTD_writeLEST(bitC->ptr, bitC->bitContainer);
++ bitC->ptr += nbBytes;
++ if (bitC->ptr > bitC->endPtr)
++ bitC->ptr = bitC->endPtr;
++ bitC->bitPos &= 7;
++ bitC->bitContainer >>= nbBytes * 8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
++}
++
++/*! BIT_closeCStream() :
++ * @return : size of CStream, in bytes,
++ or 0 if it could not fit into dstBuffer */
++ZSTD_STATIC size_t BIT_closeCStream(BIT_CStream_t *bitC)
++{
++ BIT_addBitsFast(bitC, 1, 1); /* endMark */
++ BIT_flushBits(bitC);
++
++ if (bitC->ptr >= bitC->endPtr)
++ return 0; /* doesn't fit within authorized budget : cancel */
++
++ return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
++}
++
++/*-********************************************************
++* bitStream decoding
++**********************************************************/
++/*! BIT_initDStream() :
++* Initialize a BIT_DStream_t.
++* `bitD` : a pointer to an already allocated BIT_DStream_t structure.
++* `srcSize` must be the *exact* size of the bitStream, in bytes.
++* @return : size of stream (== srcSize) or an errorCode if a problem is detected
++*/
++ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void *srcBuffer, size_t srcSize)
++{
++ if (srcSize < 1) {
++ memset(bitD, 0, sizeof(*bitD));
++ return ERROR(srcSize_wrong);
++ }
++
++ if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
++ bitD->start = (const char *)srcBuffer;
++ bitD->ptr = (const char *)srcBuffer + srcSize - sizeof(bitD->bitContainer);
++ bitD->bitContainer = ZSTD_readLEST(bitD->ptr);
++ {
++ BYTE const lastByte = ((const BYTE *)srcBuffer)[srcSize - 1];
++ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
++ if (lastByte == 0)
++ return ERROR(GENERIC); /* endMark not present */
++ }
++ } else {
++ bitD->start = (const char *)srcBuffer;
++ bitD->ptr = bitD->start;
++ bitD->bitContainer = *(const BYTE *)(bitD->start);
++ switch (srcSize) {
++ case 7: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[6]) << (sizeof(bitD->bitContainer) * 8 - 16);
++ case 6: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[5]) << (sizeof(bitD->bitContainer) * 8 - 24);
++ case 5: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[4]) << (sizeof(bitD->bitContainer) * 8 - 32);
++ case 4: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[3]) << 24;
++ case 3: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[2]) << 16;
++ case 2: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[1]) << 8;
++ default:;
++ }
++ {
++ BYTE const lastByte = ((const BYTE *)srcBuffer)[srcSize - 1];
++ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
++ if (lastByte == 0)
++ return ERROR(GENERIC); /* endMark not present */
++ }
++ bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize) * 8;
++ }
++
++ return srcSize;
++}
++
++ZSTD_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) { return bitContainer >> start; }
++
++ZSTD_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) { return (bitContainer >> start) & BIT_mask[nbBits]; }
++
++ZSTD_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) { return bitContainer & BIT_mask[nbBits]; }
++
++/*! BIT_lookBits() :
++ * Provides next n bits from local register.
++ * local register is not modified.
++ * On 32-bits, maxNbBits==24.
++ * On 64-bits, maxNbBits==56.
++ * @return : value extracted
++ */
++ZSTD_STATIC size_t BIT_lookBits(const BIT_DStream_t *bitD, U32 nbBits)
++{
++ U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1;
++ return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask - nbBits) & bitMask);
++}
++
++/*! BIT_lookBitsFast() :
++* unsafe version; only works only if nbBits >= 1 */
++ZSTD_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t *bitD, U32 nbBits)
++{
++ U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1;
++ return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask + 1) - nbBits) & bitMask);
++}
++
++ZSTD_STATIC void BIT_skipBits(BIT_DStream_t *bitD, U32 nbBits) { bitD->bitsConsumed += nbBits; }
++
++/*! BIT_readBits() :
++ * Read (consume) next n bits from local register and update.
++ * Pay attention to not read more than nbBits contained into local register.
++ * @return : extracted value.
++ */
++ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, U32 nbBits)
++{
++ size_t const value = BIT_lookBits(bitD, nbBits);
++ BIT_skipBits(bitD, nbBits);
++ return value;
++}
++
++/*! BIT_readBitsFast() :
++* unsafe version; only works only if nbBits >= 1 */
++ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, U32 nbBits)
++{
++ size_t const value = BIT_lookBitsFast(bitD, nbBits);
++ BIT_skipBits(bitD, nbBits);
++ return value;
++}
++
++/*! BIT_reloadDStream() :
++* Refill `bitD` from buffer previously set in BIT_initDStream() .
++* This function is safe, it guarantees it will not read beyond src buffer.
++* @return : status of `BIT_DStream_t` internal register.
++ if status == BIT_DStream_unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
++ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD)
++{
++ if (bitD->bitsConsumed > (sizeof(bitD->bitContainer) * 8)) /* should not happen => corruption detected */
++ return BIT_DStream_overflow;
++
++ if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
++ bitD->ptr -= bitD->bitsConsumed >> 3;
++ bitD->bitsConsumed &= 7;
++ bitD->bitContainer = ZSTD_readLEST(bitD->ptr);
++ return BIT_DStream_unfinished;
++ }
++ if (bitD->ptr == bitD->start) {
++ if (bitD->bitsConsumed < sizeof(bitD->bitContainer) * 8)
++ return BIT_DStream_endOfBuffer;
++ return BIT_DStream_completed;
++ }
++ {
++ U32 nbBytes = bitD->bitsConsumed >> 3;
++ BIT_DStream_status result = BIT_DStream_unfinished;
++ if (bitD->ptr - nbBytes < bitD->start) {
++ nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
++ result = BIT_DStream_endOfBuffer;
++ }
++ bitD->ptr -= nbBytes;
++ bitD->bitsConsumed -= nbBytes * 8;
++ bitD->bitContainer = ZSTD_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */
++ return result;
++ }
++}
++
++/*! BIT_endOfDStream() :
++* @return Tells if DStream has exactly reached its end (all bits consumed).
++*/
++ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *DStream)
++{
++ return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer) * 8));
++}
++
++#endif /* BITSTREAM_H_MODULE */
+diff --git a/lib/zstd/compress.c b/lib/zstd/compress.c
+new file mode 100644
+index 0000000..d60ab7d
+--- /dev/null
++++ b/lib/zstd/compress.c
+@@ -0,0 +1,3479 @@
++/**
++ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This source code is licensed under the BSD-style license found in the
++ * LICENSE file in the root directory of https://github.com/facebook/zstd.
++ * An additional grant of patent rights can be found in the PATENTS file in the
++ * same directory.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ */
++
++/*-*************************************
++* Dependencies
++***************************************/
++#include "fse.h"
++#include "huf.h"
++#include "mem.h"
++#include "zstd_internal.h" /* includes zstd.h */
++#include
++#include
++#include /* memset */
++
++/*-*************************************
++* Constants
++***************************************/
++static const U32 g_searchStrength = 8; /* control skip over incompressible data */
++#define HASH_READ_SIZE 8
++typedef enum { ZSTDcs_created = 0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
++
++/*-*************************************
++* Helper functions
++***************************************/
++size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
++
++/*-*************************************
++* Sequence storage
++***************************************/
++static void ZSTD_resetSeqStore(seqStore_t *ssPtr)
++{
++ ssPtr->lit = ssPtr->litStart;
++ ssPtr->sequences = ssPtr->sequencesStart;
++ ssPtr->longLengthID = 0;
++}
++
++/*-*************************************
++* Context memory management
++***************************************/
++struct ZSTD_CCtx_s {
++ const BYTE *nextSrc; /* next block here to continue on curr prefix */
++ const BYTE *base; /* All regular indexes relative to this position */
++ const BYTE *dictBase; /* extDict indexes relative to this position */
++ U32 dictLimit; /* below that point, need extDict */
++ U32 lowLimit; /* below that point, no more data */
++ U32 nextToUpdate; /* index from which to continue dictionary update */
++ U32 nextToUpdate3; /* index from which to continue dictionary update */
++ U32 hashLog3; /* dispatch table : larger == faster, more memory */
++ U32 loadedDictEnd; /* index of end of dictionary */
++ U32 forceWindow; /* force back-references to respect limit of 1< 3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
++ size_t const h3Size = ((size_t)1) << hashLog3;
++ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
++ size_t const optSpace =
++ ((MaxML + 1) + (MaxLL + 1) + (MaxOff + 1) + (1 << Litbits)) * sizeof(U32) + (ZSTD_OPT_NUM + 1) * (sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
++ size_t const workspaceSize = tableSpace + (256 * sizeof(U32)) /* huffTable */ + tokenSpace +
++ (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
++
++ return ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_CCtx)) + ZSTD_ALIGN(workspaceSize);
++}
++
++static ZSTD_CCtx *ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
++{
++ ZSTD_CCtx *cctx;
++ if (!customMem.customAlloc || !customMem.customFree)
++ return NULL;
++ cctx = (ZSTD_CCtx *)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
++ if (!cctx)
++ return NULL;
++ memset(cctx, 0, sizeof(ZSTD_CCtx));
++ cctx->customMem = customMem;
++ return cctx;
++}
++
++ZSTD_CCtx *ZSTD_initCCtx(void *workspace, size_t workspaceSize)
++{
++ ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
++ ZSTD_CCtx *cctx = ZSTD_createCCtx_advanced(stackMem);
++ if (cctx) {
++ cctx->workSpace = ZSTD_stackAllocAll(cctx->customMem.opaque, &cctx->workSpaceSize);
++ }
++ return cctx;
++}
++
++size_t ZSTD_freeCCtx(ZSTD_CCtx *cctx)
++{
++ if (cctx == NULL)
++ return 0; /* support free on NULL */
++ ZSTD_free(cctx->workSpace, cctx->customMem);
++ ZSTD_free(cctx, cctx->customMem);
++ return 0; /* reserved as a potential error code in the future */
++}
++
++const seqStore_t *ZSTD_getSeqStore(const ZSTD_CCtx *ctx) /* hidden interface */ { return &(ctx->seqStore); }
++
++static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx *cctx) { return cctx->params; }
++
++/** ZSTD_checkParams() :
++ ensure param values remain within authorized range.
++ @return : 0, or an error code if one value is beyond authorized range */
++size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
++{
++#define CLAMPCHECK(val, min, max) \
++ { \
++ if ((val < min) | (val > max)) \
++ return ERROR(compressionParameter_unsupported); \
++ }
++ CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
++ CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
++ CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
++ CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
++ CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
++ CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
++ if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2)
++ return ERROR(compressionParameter_unsupported);
++ return 0;
++}
++
++/** ZSTD_cycleLog() :
++ * condition for correct operation : hashLog > 1 */
++static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
++{
++ U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
++ return hashLog - btScale;
++}
++
++/** ZSTD_adjustCParams() :
++ optimize `cPar` for a given input (`srcSize` and `dictSize`).
++ mostly downsizing to reduce memory consumption and initialization.
++ Both `srcSize` and `dictSize` are optional (use 0 if unknown),
++ but if both are 0, no optimization can be done.
++ Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
++ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
++{
++ if (srcSize + dictSize == 0)
++ return cPar; /* no size information available : no adjustment */
++
++ /* resize params, to use less memory when necessary */
++ {
++ U32 const minSrcSize = (srcSize == 0) ? 500 : 0;
++ U64 const rSize = srcSize + dictSize + minSrcSize;
++ if (rSize < ((U64)1 << ZSTD_WINDOWLOG_MAX)) {
++ U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
++ if (cPar.windowLog > srcLog)
++ cPar.windowLog = srcLog;
++ }
++ }
++ if (cPar.hashLog > cPar.windowLog)
++ cPar.hashLog = cPar.windowLog;
++ {
++ U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
++ if (cycleLog > cPar.windowLog)
++ cPar.chainLog -= (cycleLog - cPar.windowLog);
++ }
++
++ if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
++ cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
++
++ return cPar;
++}
++
++static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
++{
++ return (param1.cParams.hashLog == param2.cParams.hashLog) & (param1.cParams.chainLog == param2.cParams.chainLog) &
++ (param1.cParams.strategy == param2.cParams.strategy) & ((param1.cParams.searchLength == 3) == (param2.cParams.searchLength == 3));
++}
++
++/*! ZSTD_continueCCtx() :
++ reuse CCtx without reset (note : requires no dictionary) */
++static size_t ZSTD_continueCCtx(ZSTD_CCtx *cctx, ZSTD_parameters params, U64 frameContentSize)
++{
++ U32 const end = (U32)(cctx->nextSrc - cctx->base);
++ cctx->params = params;
++ cctx->frameContentSize = frameContentSize;
++ cctx->lowLimit = end;
++ cctx->dictLimit = end;
++ cctx->nextToUpdate = end + 1;
++ cctx->stage = ZSTDcs_init;
++ cctx->dictID = 0;
++ cctx->loadedDictEnd = 0;
++ {
++ int i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ cctx->rep[i] = repStartValue[i];
++ }
++ cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
++ xxh64_reset(&cctx->xxhState, 0);
++ return 0;
++}
++
++typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
++
++/*! ZSTD_resetCCtx_advanced() :
++ note : `params` must be validated */
++static size_t ZSTD_resetCCtx_advanced(ZSTD_CCtx *zc, ZSTD_parameters params, U64 frameContentSize, ZSTD_compResetPolicy_e const crp)
++{
++ if (crp == ZSTDcrp_continue)
++ if (ZSTD_equivalentParams(params, zc->params)) {
++ zc->flagStaticTables = 0;
++ zc->flagStaticHufTable = HUF_repeat_none;
++ return ZSTD_continueCCtx(zc, params, frameContentSize);
++ }
++
++ {
++ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
++ U32 const divider = (params.cParams.searchLength == 3) ? 3 : 4;
++ size_t const maxNbSeq = blockSize / divider;
++ size_t const tokenSpace = blockSize + 11 * maxNbSeq;
++ size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
++ size_t const hSize = ((size_t)1) << params.cParams.hashLog;
++ U32 const hashLog3 = (params.cParams.searchLength > 3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
++ size_t const h3Size = ((size_t)1) << hashLog3;
++ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
++ void *ptr;
++
++ /* Check if workSpace is large enough, alloc a new one if needed */
++ {
++ size_t const optSpace = ((MaxML + 1) + (MaxLL + 1) + (MaxOff + 1) + (1 << Litbits)) * sizeof(U32) +
++ (ZSTD_OPT_NUM + 1) * (sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
++ size_t const neededSpace = tableSpace + (256 * sizeof(U32)) /* huffTable */ + tokenSpace +
++ (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
++ if (zc->workSpaceSize < neededSpace) {
++ ZSTD_free(zc->workSpace, zc->customMem);
++ zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
++ if (zc->workSpace == NULL)
++ return ERROR(memory_allocation);
++ zc->workSpaceSize = neededSpace;
++ }
++ }
++
++ if (crp != ZSTDcrp_noMemset)
++ memset(zc->workSpace, 0, tableSpace); /* reset tables only */
++ xxh64_reset(&zc->xxhState, 0);
++ zc->hashLog3 = hashLog3;
++ zc->hashTable = (U32 *)(zc->workSpace);
++ zc->chainTable = zc->hashTable + hSize;
++ zc->hashTable3 = zc->chainTable + chainSize;
++ ptr = zc->hashTable3 + h3Size;
++ zc->hufTable = (HUF_CElt *)ptr;
++ zc->flagStaticTables = 0;
++ zc->flagStaticHufTable = HUF_repeat_none;
++ ptr = ((U32 *)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
++
++ zc->nextToUpdate = 1;
++ zc->nextSrc = NULL;
++ zc->base = NULL;
++ zc->dictBase = NULL;
++ zc->dictLimit = 0;
++ zc->lowLimit = 0;
++ zc->params = params;
++ zc->blockSize = blockSize;
++ zc->frameContentSize = frameContentSize;
++ {
++ int i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ zc->rep[i] = repStartValue[i];
++ }
++
++ if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
++ zc->seqStore.litFreq = (U32 *)ptr;
++ zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1 << Litbits);
++ zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL + 1);
++ zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML + 1);
++ ptr = zc->seqStore.offCodeFreq + (MaxOff + 1);
++ zc->seqStore.matchTable = (ZSTD_match_t *)ptr;
++ ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM + 1;
++ zc->seqStore.priceTable = (ZSTD_optimal_t *)ptr;
++ ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM + 1;
++ zc->seqStore.litLengthSum = 0;
++ }
++ zc->seqStore.sequencesStart = (seqDef *)ptr;
++ ptr = zc->seqStore.sequencesStart + maxNbSeq;
++ zc->seqStore.llCode = (BYTE *)ptr;
++ zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
++ zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
++ zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
++
++ zc->stage = ZSTDcs_init;
++ zc->dictID = 0;
++ zc->loadedDictEnd = 0;
++
++ return 0;
++ }
++}
++
++/* ZSTD_invalidateRepCodes() :
++ * ensures next compression will not use repcodes from previous block.
++ * Note : only works with regular variant;
++ * do not use with extDict variant ! */
++void ZSTD_invalidateRepCodes(ZSTD_CCtx *cctx)
++{
++ int i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ cctx->rep[i] = 0;
++}
++
++/*! ZSTD_copyCCtx() :
++* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
++* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
++* @return : 0, or an error code */
++size_t ZSTD_copyCCtx(ZSTD_CCtx *dstCCtx, const ZSTD_CCtx *srcCCtx, unsigned long long pledgedSrcSize)
++{
++ if (srcCCtx->stage != ZSTDcs_init)
++ return ERROR(stage_wrong);
++
++ memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
++ {
++ ZSTD_parameters params = srcCCtx->params;
++ params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
++ ZSTD_resetCCtx_advanced(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
++ }
++
++ /* copy tables */
++ {
++ size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
++ size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
++ size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
++ size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
++ memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
++ }
++
++ /* copy dictionary offsets */
++ dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
++ dstCCtx->nextToUpdate3 = srcCCtx->nextToUpdate3;
++ dstCCtx->nextSrc = srcCCtx->nextSrc;
++ dstCCtx->base = srcCCtx->base;
++ dstCCtx->dictBase = srcCCtx->dictBase;
++ dstCCtx->dictLimit = srcCCtx->dictLimit;
++ dstCCtx->lowLimit = srcCCtx->lowLimit;
++ dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd;
++ dstCCtx->dictID = srcCCtx->dictID;
++
++ /* copy entropy tables */
++ dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
++ dstCCtx->flagStaticHufTable = srcCCtx->flagStaticHufTable;
++ if (srcCCtx->flagStaticTables) {
++ memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
++ memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
++ memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
++ }
++ if (srcCCtx->flagStaticHufTable) {
++ memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256 * 4);
++ }
++
++ return 0;
++}
++
++/*! ZSTD_reduceTable() :
++* reduce table indexes by `reducerValue` */
++static void ZSTD_reduceTable(U32 *const table, U32 const size, U32 const reducerValue)
++{
++ U32 u;
++ for (u = 0; u < size; u++) {
++ if (table[u] < reducerValue)
++ table[u] = 0;
++ else
++ table[u] -= reducerValue;
++ }
++}
++
++/*! ZSTD_reduceIndex() :
++* rescale all indexes to avoid future overflow (indexes are U32) */
++static void ZSTD_reduceIndex(ZSTD_CCtx *zc, const U32 reducerValue)
++{
++ {
++ U32 const hSize = 1 << zc->params.cParams.hashLog;
++ ZSTD_reduceTable(zc->hashTable, hSize, reducerValue);
++ }
++
++ {
++ U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
++ ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
++ }
++
++ {
++ U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
++ ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue);
++ }
++}
++
++/*-*******************************************************
++* Block entropic compression
++*********************************************************/
++
++/* See doc/zstd_compression_format.md for detailed format description */
++
++size_t ZSTD_noCompressBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ if (srcSize + ZSTD_blockHeaderSize > dstCapacity)
++ return ERROR(dstSize_tooSmall);
++ memcpy((BYTE *)dst + ZSTD_blockHeaderSize, src, srcSize);
++ ZSTD_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
++ return ZSTD_blockHeaderSize + srcSize;
++}
++
++static size_t ZSTD_noCompressLiterals(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ BYTE *const ostart = (BYTE * const)dst;
++ U32 const flSize = 1 + (srcSize > 31) + (srcSize > 4095);
++
++ if (srcSize + flSize > dstCapacity)
++ return ERROR(dstSize_tooSmall);
++
++ switch (flSize) {
++ case 1: /* 2 - 1 - 5 */ ostart[0] = (BYTE)((U32)set_basic + (srcSize << 3)); break;
++ case 2: /* 2 - 2 - 12 */ ZSTD_writeLE16(ostart, (U16)((U32)set_basic + (1 << 2) + (srcSize << 4))); break;
++ default: /*note : should not be necessary : flSize is within {1,2,3} */
++ case 3: /* 2 - 2 - 20 */ ZSTD_writeLE32(ostart, (U32)((U32)set_basic + (3 << 2) + (srcSize << 4))); break;
++ }
++
++ memcpy(ostart + flSize, src, srcSize);
++ return srcSize + flSize;
++}
++
++static size_t ZSTD_compressRleLiteralsBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ BYTE *const ostart = (BYTE * const)dst;
++ U32 const flSize = 1 + (srcSize > 31) + (srcSize > 4095);
++
++ (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
++
++ switch (flSize) {
++ case 1: /* 2 - 1 - 5 */ ostart[0] = (BYTE)((U32)set_rle + (srcSize << 3)); break;
++ case 2: /* 2 - 2 - 12 */ ZSTD_writeLE16(ostart, (U16)((U32)set_rle + (1 << 2) + (srcSize << 4))); break;
++ default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
++ case 3: /* 2 - 2 - 20 */ ZSTD_writeLE32(ostart, (U32)((U32)set_rle + (3 << 2) + (srcSize << 4))); break;
++ }
++
++ ostart[flSize] = *(const BYTE *)src;
++ return flSize + 1;
++}
++
++static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
++
++static size_t ZSTD_compressLiterals(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ size_t const minGain = ZSTD_minGain(srcSize);
++ size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
++ BYTE *const ostart = (BYTE *)dst;
++ U32 singleStream = srcSize < 256;
++ symbolEncodingType_e hType = set_compressed;
++ size_t cLitSize;
++
++/* small ? don't even attempt compression (speed opt) */
++#define LITERAL_NOENTROPY 63
++ {
++ size_t const minLitSize = zc->flagStaticHufTable == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
++ if (srcSize <= minLitSize)
++ return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
++ }
++
++ if (dstCapacity < lhSize + 1)
++ return ERROR(dstSize_tooSmall); /* not enough space for compression */
++ {
++ HUF_repeat repeat = zc->flagStaticHufTable;
++ int const preferRepeat = zc->params.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
++ if (repeat == HUF_repeat_valid && lhSize == 3)
++ singleStream = 1;
++ cLitSize = singleStream ? HUF_compress1X_repeat(ostart + lhSize, dstCapacity - lhSize, src, srcSize, 255, 11, zc->tmpCounters,
++ sizeof(zc->tmpCounters), zc->hufTable, &repeat, preferRepeat)
++ : HUF_compress4X_repeat(ostart + lhSize, dstCapacity - lhSize, src, srcSize, 255, 11, zc->tmpCounters,
++ sizeof(zc->tmpCounters), zc->hufTable, &repeat, preferRepeat);
++ if (repeat != HUF_repeat_none) {
++ hType = set_repeat;
++ } /* reused the existing table */
++ else {
++ zc->flagStaticHufTable = HUF_repeat_check;
++ } /* now have a table to reuse */
++ }
++
++ if ((cLitSize == 0) | (cLitSize >= srcSize - minGain)) {
++ zc->flagStaticHufTable = HUF_repeat_none;
++ return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
++ }
++ if (cLitSize == 1) {
++ zc->flagStaticHufTable = HUF_repeat_none;
++ return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
++ }
++
++ /* Build header */
++ switch (lhSize) {
++ case 3: /* 2 - 2 - 10 - 10 */
++ {
++ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize << 4) + ((U32)cLitSize << 14);
++ ZSTD_writeLE24(ostart, lhc);
++ break;
++ }
++ case 4: /* 2 - 2 - 14 - 14 */
++ {
++ U32 const lhc = hType + (2 << 2) + ((U32)srcSize << 4) + ((U32)cLitSize << 18);
++ ZSTD_writeLE32(ostart, lhc);
++ break;
++ }
++ default: /* should not be necessary, lhSize is only {3,4,5} */
++ case 5: /* 2 - 2 - 18 - 18 */
++ {
++ U32 const lhc = hType + (3 << 2) + ((U32)srcSize << 4) + ((U32)cLitSize << 22);
++ ZSTD_writeLE32(ostart, lhc);
++ ostart[4] = (BYTE)(cLitSize >> 10);
++ break;
++ }
++ }
++ return lhSize + cLitSize;
++}
++
++static const BYTE LL_Code[64] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18, 18,
++ 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23,
++ 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24};
++
++static const BYTE ML_Code[128] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
++ 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38,
++ 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42,
++ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42};
++
++void ZSTD_seqToCodes(const seqStore_t *seqStorePtr)
++{
++ BYTE const LL_deltaCode = 19;
++ BYTE const ML_deltaCode = 36;
++ const seqDef *const sequences = seqStorePtr->sequencesStart;
++ BYTE *const llCodeTable = seqStorePtr->llCode;
++ BYTE *const ofCodeTable = seqStorePtr->ofCode;
++ BYTE *const mlCodeTable = seqStorePtr->mlCode;
++ U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
++ U32 u;
++ for (u = 0; u < nbSeq; u++) {
++ U32 const llv = sequences[u].litLength;
++ U32 const mlv = sequences[u].matchLength;
++ llCodeTable[u] = (llv > 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
++ ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
++ mlCodeTable[u] = (mlv > 127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
++ }
++ if (seqStorePtr->longLengthID == 1)
++ llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
++ if (seqStorePtr->longLengthID == 2)
++ mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
++}
++
++ZSTD_STATIC size_t ZSTD_compressSequences(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, size_t srcSize)
++{
++ const int longOffsets = zc->params.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
++ const seqStore_t *seqStorePtr = &(zc->seqStore);
++ FSE_CTable *CTable_LitLength = zc->litlengthCTable;
++ FSE_CTable *CTable_OffsetBits = zc->offcodeCTable;
++ FSE_CTable *CTable_MatchLength = zc->matchlengthCTable;
++ U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
++ const seqDef *const sequences = seqStorePtr->sequencesStart;
++ const BYTE *const ofCodeTable = seqStorePtr->ofCode;
++ const BYTE *const llCodeTable = seqStorePtr->llCode;
++ const BYTE *const mlCodeTable = seqStorePtr->mlCode;
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *const oend = ostart + dstCapacity;
++ BYTE *op = ostart;
++ size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
++ BYTE *seqHead;
++
++ U32 *count;
++ S16 *norm;
++ U32 *workspace;
++ size_t workspaceSize = sizeof(zc->tmpCounters);
++ {
++ size_t spaceUsed32 = 0;
++ count = (U32 *)zc->tmpCounters + spaceUsed32;
++ spaceUsed32 += MaxSeq + 1;
++ norm = (S16 *)((U32 *)zc->tmpCounters + spaceUsed32);
++ spaceUsed32 += ALIGN(sizeof(S16) * (MaxSeq + 1), sizeof(U32)) >> 2;
++
++ workspace = (U32 *)zc->tmpCounters + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++ }
++
++ /* Compress literals */
++ {
++ const BYTE *const literals = seqStorePtr->litStart;
++ size_t const litSize = seqStorePtr->lit - literals;
++ size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
++ if (ZSTD_isError(cSize))
++ return cSize;
++ op += cSize;
++ }
++
++ /* Sequences Header */
++ if ((oend - op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */)
++ return ERROR(dstSize_tooSmall);
++ if (nbSeq < 0x7F)
++ *op++ = (BYTE)nbSeq;
++ else if (nbSeq < LONGNBSEQ)
++ op[0] = (BYTE)((nbSeq >> 8) + 0x80), op[1] = (BYTE)nbSeq, op += 2;
++ else
++ op[0] = 0xFF, ZSTD_writeLE16(op + 1, (U16)(nbSeq - LONGNBSEQ)), op += 3;
++ if (nbSeq == 0)
++ goto _check_compressibility;
++
++ /* seqHead : flags for FSE encoding type */
++ seqHead = op++;
++
++#define MIN_SEQ_FOR_DYNAMIC_FSE 64
++#define MAX_SEQ_FOR_STATIC_FSE 1000
++
++ /* convert length/distances into codes */
++ ZSTD_seqToCodes(seqStorePtr);
++
++ /* CTable for Literal Lengths */
++ {
++ U32 max = MaxLL;
++ size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace);
++ if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
++ *op++ = llCodeTable[0];
++ FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
++ LLtype = set_rle;
++ } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
++ LLtype = set_repeat;
++ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog - 1)))) {
++ FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, workspace, workspaceSize);
++ LLtype = set_basic;
++ } else {
++ size_t nbSeq_1 = nbSeq;
++ const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
++ if (count[llCodeTable[nbSeq - 1]] > 1) {
++ count[llCodeTable[nbSeq - 1]]--;
++ nbSeq_1--;
++ }
++ FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
++ {
++ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
++ if (FSE_isError(NCountSize))
++ return NCountSize;
++ op += NCountSize;
++ }
++ FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, workspace, workspaceSize);
++ LLtype = set_compressed;
++ }
++ }
++
++ /* CTable for Offsets */
++ {
++ U32 max = MaxOff;
++ size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace);
++ if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
++ *op++ = ofCodeTable[0];
++ FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
++ Offtype = set_rle;
++ } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
++ Offtype = set_repeat;
++ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog - 1)))) {
++ FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, workspace, workspaceSize);
++ Offtype = set_basic;
++ } else {
++ size_t nbSeq_1 = nbSeq;
++ const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
++ if (count[ofCodeTable[nbSeq - 1]] > 1) {
++ count[ofCodeTable[nbSeq - 1]]--;
++ nbSeq_1--;
++ }
++ FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
++ {
++ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
++ if (FSE_isError(NCountSize))
++ return NCountSize;
++ op += NCountSize;
++ }
++ FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, workspace, workspaceSize);
++ Offtype = set_compressed;
++ }
++ }
++
++ /* CTable for MatchLengths */
++ {
++ U32 max = MaxML;
++ size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace);
++ if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
++ *op++ = *mlCodeTable;
++ FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
++ MLtype = set_rle;
++ } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
++ MLtype = set_repeat;
++ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog - 1)))) {
++ FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, workspace, workspaceSize);
++ MLtype = set_basic;
++ } else {
++ size_t nbSeq_1 = nbSeq;
++ const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
++ if (count[mlCodeTable[nbSeq - 1]] > 1) {
++ count[mlCodeTable[nbSeq - 1]]--;
++ nbSeq_1--;
++ }
++ FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
++ {
++ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
++ if (FSE_isError(NCountSize))
++ return NCountSize;
++ op += NCountSize;
++ }
++ FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, workspace, workspaceSize);
++ MLtype = set_compressed;
++ }
++ }
++
++ *seqHead = (BYTE)((LLtype << 6) + (Offtype << 4) + (MLtype << 2));
++ zc->flagStaticTables = 0;
++
++ /* Encoding Sequences */
++ {
++ BIT_CStream_t blockStream;
++ FSE_CState_t stateMatchLength;
++ FSE_CState_t stateOffsetBits;
++ FSE_CState_t stateLitLength;
++
++ CHECK_E(BIT_initCStream(&blockStream, op, oend - op), dstSize_tooSmall); /* not enough space remaining */
++
++ /* first symbols */
++ FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq - 1]);
++ FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq - 1]);
++ FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq - 1]);
++ BIT_addBits(&blockStream, sequences[nbSeq - 1].litLength, LL_bits[llCodeTable[nbSeq - 1]]);
++ if (ZSTD_32bits())
++ BIT_flushBits(&blockStream);
++ BIT_addBits(&blockStream, sequences[nbSeq - 1].matchLength, ML_bits[mlCodeTable[nbSeq - 1]]);
++ if (ZSTD_32bits())
++ BIT_flushBits(&blockStream);
++ if (longOffsets) {
++ U32 const ofBits = ofCodeTable[nbSeq - 1];
++ int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN - 1);
++ if (extraBits) {
++ BIT_addBits(&blockStream, sequences[nbSeq - 1].offset, extraBits);
++ BIT_flushBits(&blockStream);
++ }
++ BIT_addBits(&blockStream, sequences[nbSeq - 1].offset >> extraBits, ofBits - extraBits);
++ } else {
++ BIT_addBits(&blockStream, sequences[nbSeq - 1].offset, ofCodeTable[nbSeq - 1]);
++ }
++ BIT_flushBits(&blockStream);
++
++ {
++ size_t n;
++ for (n = nbSeq - 2; n < nbSeq; n--) { /* intentional underflow */
++ BYTE const llCode = llCodeTable[n];
++ BYTE const ofCode = ofCodeTable[n];
++ BYTE const mlCode = mlCodeTable[n];
++ U32 const llBits = LL_bits[llCode];
++ U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
++ U32 const mlBits = ML_bits[mlCode];
++ /* (7)*/ /* (7)*/
++ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
++ FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
++ if (ZSTD_32bits())
++ BIT_flushBits(&blockStream); /* (7)*/
++ FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
++ if (ZSTD_32bits() || (ofBits + mlBits + llBits >= 64 - 7 - (LLFSELog + MLFSELog + OffFSELog)))
++ BIT_flushBits(&blockStream); /* (7)*/
++ BIT_addBits(&blockStream, sequences[n].litLength, llBits);
++ if (ZSTD_32bits() && ((llBits + mlBits) > 24))
++ BIT_flushBits(&blockStream);
++ BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
++ if (ZSTD_32bits())
++ BIT_flushBits(&blockStream); /* (7)*/
++ if (longOffsets) {
++ int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN - 1);
++ if (extraBits) {
++ BIT_addBits(&blockStream, sequences[n].offset, extraBits);
++ BIT_flushBits(&blockStream); /* (7)*/
++ }
++ BIT_addBits(&blockStream, sequences[n].offset >> extraBits, ofBits - extraBits); /* 31 */
++ } else {
++ BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
++ }
++ BIT_flushBits(&blockStream); /* (7)*/
++ }
++ }
++
++ FSE_flushCState(&blockStream, &stateMatchLength);
++ FSE_flushCState(&blockStream, &stateOffsetBits);
++ FSE_flushCState(&blockStream, &stateLitLength);
++
++ {
++ size_t const streamSize = BIT_closeCStream(&blockStream);
++ if (streamSize == 0)
++ return ERROR(dstSize_tooSmall); /* not enough space */
++ op += streamSize;
++ }
++ }
++
++/* check compressibility */
++_check_compressibility:
++ {
++ size_t const minGain = ZSTD_minGain(srcSize);
++ size_t const maxCSize = srcSize - minGain;
++ if ((size_t)(op - ostart) >= maxCSize) {
++ zc->flagStaticHufTable = HUF_repeat_none;
++ return 0;
++ }
++ }
++
++ /* confirm repcodes */
++ {
++ int i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ zc->rep[i] = zc->repToConfirm[i];
++ }
++
++ return op - ostart;
++}
++
++/*! ZSTD_storeSeq() :
++ Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
++ `offsetCode` : distance to match, or 0 == repCode.
++ `matchCode` : matchLength - MINMATCH
++*/
++ZSTD_STATIC void ZSTD_storeSeq(seqStore_t *seqStorePtr, size_t litLength, const void *literals, U32 offsetCode, size_t matchCode)
++{
++ /* copy Literals */
++ ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
++ seqStorePtr->lit += litLength;
++
++ /* literal Length */
++ if (litLength > 0xFFFF) {
++ seqStorePtr->longLengthID = 1;
++ seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
++ }
++ seqStorePtr->sequences[0].litLength = (U16)litLength;
++
++ /* match offset */
++ seqStorePtr->sequences[0].offset = offsetCode + 1;
++
++ /* match Length */
++ if (matchCode > 0xFFFF) {
++ seqStorePtr->longLengthID = 2;
++ seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
++ }
++ seqStorePtr->sequences[0].matchLength = (U16)matchCode;
++
++ seqStorePtr->sequences++;
++}
++
++/*-*************************************
++* Match length counter
++***************************************/
++static unsigned ZSTD_NbCommonBytes(register size_t val)
++{
++ if (ZSTD_isLittleEndian()) {
++ if (ZSTD_64bits()) {
++ return (__builtin_ctzll((U64)val) >> 3);
++ } else { /* 32 bits */
++ return (__builtin_ctz((U32)val) >> 3);
++ }
++ } else { /* Big Endian CPU */
++ if (ZSTD_64bits()) {
++ return (__builtin_clzll(val) >> 3);
++ } else { /* 32 bits */
++ return (__builtin_clz((U32)val) >> 3);
++ }
++ }
++}
++
++static size_t ZSTD_count(const BYTE *pIn, const BYTE *pMatch, const BYTE *const pInLimit)
++{
++ const BYTE *const pStart = pIn;
++ const BYTE *const pInLoopLimit = pInLimit - (sizeof(size_t) - 1);
++
++ while (pIn < pInLoopLimit) {
++ size_t const diff = ZSTD_readST(pMatch) ^ ZSTD_readST(pIn);
++ if (!diff) {
++ pIn += sizeof(size_t);
++ pMatch += sizeof(size_t);
++ continue;
++ }
++ pIn += ZSTD_NbCommonBytes(diff);
++ return (size_t)(pIn - pStart);
++ }
++ if (ZSTD_64bits())
++ if ((pIn < (pInLimit - 3)) && (ZSTD_read32(pMatch) == ZSTD_read32(pIn))) {
++ pIn += 4;
++ pMatch += 4;
++ }
++ if ((pIn < (pInLimit - 1)) && (ZSTD_read16(pMatch) == ZSTD_read16(pIn))) {
++ pIn += 2;
++ pMatch += 2;
++ }
++ if ((pIn < pInLimit) && (*pMatch == *pIn))
++ pIn++;
++ return (size_t)(pIn - pStart);
++}
++
++/** ZSTD_count_2segments() :
++* can count match length with `ip` & `match` in 2 different segments.
++* convention : on reaching mEnd, match count continue starting from iStart
++*/
++static size_t ZSTD_count_2segments(const BYTE *ip, const BYTE *match, const BYTE *iEnd, const BYTE *mEnd, const BYTE *iStart)
++{
++ const BYTE *const vEnd = MIN(ip + (mEnd - match), iEnd);
++ size_t const matchLength = ZSTD_count(ip, match, vEnd);
++ if (match + matchLength != mEnd)
++ return matchLength;
++ return matchLength + ZSTD_count(ip + matchLength, iStart, iEnd);
++}
++
++/*-*************************************
++* Hashes
++***************************************/
++static const U32 prime3bytes = 506832829U;
++static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32 - 24)) * prime3bytes) >> (32 - h); }
++ZSTD_STATIC size_t ZSTD_hash3Ptr(const void *ptr, U32 h) { return ZSTD_hash3(ZSTD_readLE32(ptr), h); } /* only in zstd_opt.h */
++
++static const U32 prime4bytes = 2654435761U;
++static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32 - h); }
++static size_t ZSTD_hash4Ptr(const void *ptr, U32 h) { return ZSTD_hash4(ZSTD_read32(ptr), h); }
++
++static const U64 prime5bytes = 889523592379ULL;
++static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64 - 40)) * prime5bytes) >> (64 - h)); }
++static size_t ZSTD_hash5Ptr(const void *p, U32 h) { return ZSTD_hash5(ZSTD_readLE64(p), h); }
++
++static const U64 prime6bytes = 227718039650203ULL;
++static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64 - 48)) * prime6bytes) >> (64 - h)); }
++static size_t ZSTD_hash6Ptr(const void *p, U32 h) { return ZSTD_hash6(ZSTD_readLE64(p), h); }
++
++static const U64 prime7bytes = 58295818150454627ULL;
++static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64 - 56)) * prime7bytes) >> (64 - h)); }
++static size_t ZSTD_hash7Ptr(const void *p, U32 h) { return ZSTD_hash7(ZSTD_readLE64(p), h); }
++
++static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
++static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u)*prime8bytes) >> (64 - h)); }
++static size_t ZSTD_hash8Ptr(const void *p, U32 h) { return ZSTD_hash8(ZSTD_readLE64(p), h); }
++
++static size_t ZSTD_hashPtr(const void *p, U32 hBits, U32 mls)
++{
++ switch (mls) {
++ // case 3: return ZSTD_hash3Ptr(p, hBits);
++ default:
++ case 4: return ZSTD_hash4Ptr(p, hBits);
++ case 5: return ZSTD_hash5Ptr(p, hBits);
++ case 6: return ZSTD_hash6Ptr(p, hBits);
++ case 7: return ZSTD_hash7Ptr(p, hBits);
++ case 8: return ZSTD_hash8Ptr(p, hBits);
++ }
++}
++
++/*-*************************************
++* Fast Scan
++***************************************/
++static void ZSTD_fillHashTable(ZSTD_CCtx *zc, const void *end, const U32 mls)
++{
++ U32 *const hashTable = zc->hashTable;
++ U32 const hBits = zc->params.cParams.hashLog;
++ const BYTE *const base = zc->base;
++ const BYTE *ip = base + zc->nextToUpdate;
++ const BYTE *const iend = ((const BYTE *)end) - HASH_READ_SIZE;
++ const size_t fastHashFillStep = 3;
++
++ while (ip <= iend) {
++ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
++ ip += fastHashFillStep;
++ }
++}
++
++FORCE_INLINE
++void ZSTD_compressBlock_fast_generic(ZSTD_CCtx *cctx, const void *src, size_t srcSize, const U32 mls)
++{
++ U32 *const hashTable = cctx->hashTable;
++ U32 const hBits = cctx->params.cParams.hashLog;
++ seqStore_t *seqStorePtr = &(cctx->seqStore);
++ const BYTE *const base = cctx->base;
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *ip = istart;
++ const BYTE *anchor = istart;
++ const U32 lowestIndex = cctx->dictLimit;
++ const BYTE *const lowest = base + lowestIndex;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *const ilimit = iend - HASH_READ_SIZE;
++ U32 offset_1 = cctx->rep[0], offset_2 = cctx->rep[1];
++ U32 offsetSaved = 0;
++
++ /* init */
++ ip += (ip == lowest);
++ {
++ U32 const maxRep = (U32)(ip - lowest);
++ if (offset_2 > maxRep)
++ offsetSaved = offset_2, offset_2 = 0;
++ if (offset_1 > maxRep)
++ offsetSaved = offset_1, offset_1 = 0;
++ }
++
++ /* Main Search Loop */
++ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
++ size_t mLength;
++ size_t const h = ZSTD_hashPtr(ip, hBits, mls);
++ U32 const curr = (U32)(ip - base);
++ U32 const matchIndex = hashTable[h];
++ const BYTE *match = base + matchIndex;
++ hashTable[h] = curr; /* update hash table */
++
++ if ((offset_1 > 0) & (ZSTD_read32(ip + 1 - offset_1) == ZSTD_read32(ip + 1))) {
++ mLength = ZSTD_count(ip + 1 + 4, ip + 1 + 4 - offset_1, iend) + 4;
++ ip++;
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, 0, mLength - MINMATCH);
++ } else {
++ U32 offset;
++ if ((matchIndex <= lowestIndex) || (ZSTD_read32(match) != ZSTD_read32(ip))) {
++ ip += ((ip - anchor) >> g_searchStrength) + 1;
++ continue;
++ }
++ mLength = ZSTD_count(ip + 4, match + 4, iend) + 4;
++ offset = (U32)(ip - match);
++ while (((ip > anchor) & (match > lowest)) && (ip[-1] == match[-1])) {
++ ip--;
++ match--;
++ mLength++;
++ } /* catch up */
++ offset_2 = offset_1;
++ offset_1 = offset;
++
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
++ }
++
++ /* match found */
++ ip += mLength;
++ anchor = ip;
++
++ if (ip <= ilimit) {
++ /* Fill Table */
++ hashTable[ZSTD_hashPtr(base + curr + 2, hBits, mls)] = curr + 2; /* here because curr+2 could be > iend-8 */
++ hashTable[ZSTD_hashPtr(ip - 2, hBits, mls)] = (U32)(ip - 2 - base);
++ /* check immediate repcode */
++ while ((ip <= ilimit) && ((offset_2 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_2)))) {
++ /* store sequence */
++ size_t const rLength = ZSTD_count(ip + 4, ip + 4 - offset_2, iend) + 4;
++ {
++ U32 const tmpOff = offset_2;
++ offset_2 = offset_1;
++ offset_1 = tmpOff;
++ } /* swap offset_2 <=> offset_1 */
++ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
++ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength - MINMATCH);
++ ip += rLength;
++ anchor = ip;
++ continue; /* faster when present ... (?) */
++ }
++ }
++ }
++
++ /* save reps for next block */
++ cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
++ cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
++
++ /* Last Literals */
++ {
++ size_t const lastLLSize = iend - anchor;
++ memcpy(seqStorePtr->lit, anchor, lastLLSize);
++ seqStorePtr->lit += lastLLSize;
++ }
++}
++
++static void ZSTD_compressBlock_fast(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++ const U32 mls = ctx->params.cParams.searchLength;
++ switch (mls) {
++ default: /* includes case 3 */
++ case 4: ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
++ case 5: ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
++ case 6: ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
++ case 7: ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
++ }
++}
++
++static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const U32 mls)
++{
++ U32 *hashTable = ctx->hashTable;
++ const U32 hBits = ctx->params.cParams.hashLog;
++ seqStore_t *seqStorePtr = &(ctx->seqStore);
++ const BYTE *const base = ctx->base;
++ const BYTE *const dictBase = ctx->dictBase;
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *ip = istart;
++ const BYTE *anchor = istart;
++ const U32 lowestIndex = ctx->lowLimit;
++ const BYTE *const dictStart = dictBase + lowestIndex;
++ const U32 dictLimit = ctx->dictLimit;
++ const BYTE *const lowPrefixPtr = base + dictLimit;
++ const BYTE *const dictEnd = dictBase + dictLimit;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *const ilimit = iend - 8;
++ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
++
++ /* Search Loop */
++ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
++ const size_t h = ZSTD_hashPtr(ip, hBits, mls);
++ const U32 matchIndex = hashTable[h];
++ const BYTE *matchBase = matchIndex < dictLimit ? dictBase : base;
++ const BYTE *match = matchBase + matchIndex;
++ const U32 curr = (U32)(ip - base);
++ const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */
++ const BYTE *repBase = repIndex < dictLimit ? dictBase : base;
++ const BYTE *repMatch = repBase + repIndex;
++ size_t mLength;
++ hashTable[h] = curr; /* update hash table */
++
++ if ((((U32)((dictLimit - 1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex)) &&
++ (ZSTD_read32(repMatch) == ZSTD_read32(ip + 1))) {
++ const BYTE *repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
++ mLength = ZSTD_count_2segments(ip + 1 + EQUAL_READ32, repMatch + EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
++ ip++;
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, 0, mLength - MINMATCH);
++ } else {
++ if ((matchIndex < lowestIndex) || (ZSTD_read32(match) != ZSTD_read32(ip))) {
++ ip += ((ip - anchor) >> g_searchStrength) + 1;
++ continue;
++ }
++ {
++ const BYTE *matchEnd = matchIndex < dictLimit ? dictEnd : iend;
++ const BYTE *lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
++ U32 offset;
++ mLength = ZSTD_count_2segments(ip + EQUAL_READ32, match + EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
++ while (((ip > anchor) & (match > lowMatchPtr)) && (ip[-1] == match[-1])) {
++ ip--;
++ match--;
++ mLength++;
++ } /* catch up */
++ offset = curr - matchIndex;
++ offset_2 = offset_1;
++ offset_1 = offset;
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
++ }
++ }
++
++ /* found a match : store it */
++ ip += mLength;
++ anchor = ip;
++
++ if (ip <= ilimit) {
++ /* Fill Table */
++ hashTable[ZSTD_hashPtr(base + curr + 2, hBits, mls)] = curr + 2;
++ hashTable[ZSTD_hashPtr(ip - 2, hBits, mls)] = (U32)(ip - 2 - base);
++ /* check immediate repcode */
++ while (ip <= ilimit) {
++ U32 const curr2 = (U32)(ip - base);
++ U32 const repIndex2 = curr2 - offset_2;
++ const BYTE *repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
++ if ((((U32)((dictLimit - 1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
++ && (ZSTD_read32(repMatch2) == ZSTD_read32(ip))) {
++ const BYTE *const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
++ size_t repLength2 =
++ ZSTD_count_2segments(ip + EQUAL_READ32, repMatch2 + EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
++ U32 tmpOffset = offset_2;
++ offset_2 = offset_1;
++ offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
++ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2 - MINMATCH);
++ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = curr2;
++ ip += repLength2;
++ anchor = ip;
++ continue;
++ }
++ break;
++ }
++ }
++ }
++
++ /* save reps for next block */
++ ctx->repToConfirm[0] = offset_1;
++ ctx->repToConfirm[1] = offset_2;
++
++ /* Last Literals */
++ {
++ size_t const lastLLSize = iend - anchor;
++ memcpy(seqStorePtr->lit, anchor, lastLLSize);
++ seqStorePtr->lit += lastLLSize;
++ }
++}
++
++static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++ U32 const mls = ctx->params.cParams.searchLength;
++ switch (mls) {
++ default: /* includes case 3 */
++ case 4: ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
++ case 5: ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
++ case 6: ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
++ case 7: ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
++ }
++}
++
++/*-*************************************
++* Double Fast
++***************************************/
++static void ZSTD_fillDoubleHashTable(ZSTD_CCtx *cctx, const void *end, const U32 mls)
++{
++ U32 *const hashLarge = cctx->hashTable;
++ U32 const hBitsL = cctx->params.cParams.hashLog;
++ U32 *const hashSmall = cctx->chainTable;
++ U32 const hBitsS = cctx->params.cParams.chainLog;
++ const BYTE *const base = cctx->base;
++ const BYTE *ip = base + cctx->nextToUpdate;
++ const BYTE *const iend = ((const BYTE *)end) - HASH_READ_SIZE;
++ const size_t fastHashFillStep = 3;
++
++ while (ip <= iend) {
++ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
++ hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
++ ip += fastHashFillStep;
++ }
++}
++
++FORCE_INLINE
++void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx *cctx, const void *src, size_t srcSize, const U32 mls)
++{
++ U32 *const hashLong = cctx->hashTable;
++ const U32 hBitsL = cctx->params.cParams.hashLog;
++ U32 *const hashSmall = cctx->chainTable;
++ const U32 hBitsS = cctx->params.cParams.chainLog;
++ seqStore_t *seqStorePtr = &(cctx->seqStore);
++ const BYTE *const base = cctx->base;
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *ip = istart;
++ const BYTE *anchor = istart;
++ const U32 lowestIndex = cctx->dictLimit;
++ const BYTE *const lowest = base + lowestIndex;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *const ilimit = iend - HASH_READ_SIZE;
++ U32 offset_1 = cctx->rep[0], offset_2 = cctx->rep[1];
++ U32 offsetSaved = 0;
++
++ /* init */
++ ip += (ip == lowest);
++ {
++ U32 const maxRep = (U32)(ip - lowest);
++ if (offset_2 > maxRep)
++ offsetSaved = offset_2, offset_2 = 0;
++ if (offset_1 > maxRep)
++ offsetSaved = offset_1, offset_1 = 0;
++ }
++
++ /* Main Search Loop */
++ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
++ size_t mLength;
++ size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
++ size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
++ U32 const curr = (U32)(ip - base);
++ U32 const matchIndexL = hashLong[h2];
++ U32 const matchIndexS = hashSmall[h];
++ const BYTE *matchLong = base + matchIndexL;
++ const BYTE *match = base + matchIndexS;
++ hashLong[h2] = hashSmall[h] = curr; /* update hash tables */
++
++ if ((offset_1 > 0) & (ZSTD_read32(ip + 1 - offset_1) == ZSTD_read32(ip + 1))) { /* note : by construction, offset_1 <= curr */
++ mLength = ZSTD_count(ip + 1 + 4, ip + 1 + 4 - offset_1, iend) + 4;
++ ip++;
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, 0, mLength - MINMATCH);
++ } else {
++ U32 offset;
++ if ((matchIndexL > lowestIndex) && (ZSTD_read64(matchLong) == ZSTD_read64(ip))) {
++ mLength = ZSTD_count(ip + 8, matchLong + 8, iend) + 8;
++ offset = (U32)(ip - matchLong);
++ while (((ip > anchor) & (matchLong > lowest)) && (ip[-1] == matchLong[-1])) {
++ ip--;
++ matchLong--;
++ mLength++;
++ } /* catch up */
++ } else if ((matchIndexS > lowestIndex) && (ZSTD_read32(match) == ZSTD_read32(ip))) {
++ size_t const h3 = ZSTD_hashPtr(ip + 1, hBitsL, 8);
++ U32 const matchIndex3 = hashLong[h3];
++ const BYTE *match3 = base + matchIndex3;
++ hashLong[h3] = curr + 1;
++ if ((matchIndex3 > lowestIndex) && (ZSTD_read64(match3) == ZSTD_read64(ip + 1))) {
++ mLength = ZSTD_count(ip + 9, match3 + 8, iend) + 8;
++ ip++;
++ offset = (U32)(ip - match3);
++ while (((ip > anchor) & (match3 > lowest)) && (ip[-1] == match3[-1])) {
++ ip--;
++ match3--;
++ mLength++;
++ } /* catch up */
++ } else {
++ mLength = ZSTD_count(ip + 4, match + 4, iend) + 4;
++ offset = (U32)(ip - match);
++ while (((ip > anchor) & (match > lowest)) && (ip[-1] == match[-1])) {
++ ip--;
++ match--;
++ mLength++;
++ } /* catch up */
++ }
++ } else {
++ ip += ((ip - anchor) >> g_searchStrength) + 1;
++ continue;
++ }
++
++ offset_2 = offset_1;
++ offset_1 = offset;
++
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
++ }
++
++ /* match found */
++ ip += mLength;
++ anchor = ip;
++
++ if (ip <= ilimit) {
++ /* Fill Table */
++ hashLong[ZSTD_hashPtr(base + curr + 2, hBitsL, 8)] = hashSmall[ZSTD_hashPtr(base + curr + 2, hBitsS, mls)] =
++ curr + 2; /* here because curr+2 could be > iend-8 */
++ hashLong[ZSTD_hashPtr(ip - 2, hBitsL, 8)] = hashSmall[ZSTD_hashPtr(ip - 2, hBitsS, mls)] = (U32)(ip - 2 - base);
++
++ /* check immediate repcode */
++ while ((ip <= ilimit) && ((offset_2 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_2)))) {
++ /* store sequence */
++ size_t const rLength = ZSTD_count(ip + 4, ip + 4 - offset_2, iend) + 4;
++ {
++ U32 const tmpOff = offset_2;
++ offset_2 = offset_1;
++ offset_1 = tmpOff;
++ } /* swap offset_2 <=> offset_1 */
++ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
++ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
++ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength - MINMATCH);
++ ip += rLength;
++ anchor = ip;
++ continue; /* faster when present ... (?) */
++ }
++ }
++ }
++
++ /* save reps for next block */
++ cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
++ cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
++
++ /* Last Literals */
++ {
++ size_t const lastLLSize = iend - anchor;
++ memcpy(seqStorePtr->lit, anchor, lastLLSize);
++ seqStorePtr->lit += lastLLSize;
++ }
++}
++
++static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++ const U32 mls = ctx->params.cParams.searchLength;
++ switch (mls) {
++ default: /* includes case 3 */
++ case 4: ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
++ case 5: ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
++ case 6: ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
++ case 7: ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
++ }
++}
++
++static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const U32 mls)
++{
++ U32 *const hashLong = ctx->hashTable;
++ U32 const hBitsL = ctx->params.cParams.hashLog;
++ U32 *const hashSmall = ctx->chainTable;
++ U32 const hBitsS = ctx->params.cParams.chainLog;
++ seqStore_t *seqStorePtr = &(ctx->seqStore);
++ const BYTE *const base = ctx->base;
++ const BYTE *const dictBase = ctx->dictBase;
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *ip = istart;
++ const BYTE *anchor = istart;
++ const U32 lowestIndex = ctx->lowLimit;
++ const BYTE *const dictStart = dictBase + lowestIndex;
++ const U32 dictLimit = ctx->dictLimit;
++ const BYTE *const lowPrefixPtr = base + dictLimit;
++ const BYTE *const dictEnd = dictBase + dictLimit;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *const ilimit = iend - 8;
++ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
++
++ /* Search Loop */
++ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
++ const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
++ const U32 matchIndex = hashSmall[hSmall];
++ const BYTE *matchBase = matchIndex < dictLimit ? dictBase : base;
++ const BYTE *match = matchBase + matchIndex;
++
++ const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
++ const U32 matchLongIndex = hashLong[hLong];
++ const BYTE *matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
++ const BYTE *matchLong = matchLongBase + matchLongIndex;
++
++ const U32 curr = (U32)(ip - base);
++ const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */
++ const BYTE *repBase = repIndex < dictLimit ? dictBase : base;
++ const BYTE *repMatch = repBase + repIndex;
++ size_t mLength;
++ hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */
++
++ if ((((U32)((dictLimit - 1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex)) &&
++ (ZSTD_read32(repMatch) == ZSTD_read32(ip + 1))) {
++ const BYTE *repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
++ mLength = ZSTD_count_2segments(ip + 1 + 4, repMatch + 4, iend, repMatchEnd, lowPrefixPtr) + 4;
++ ip++;
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, 0, mLength - MINMATCH);
++ } else {
++ if ((matchLongIndex > lowestIndex) && (ZSTD_read64(matchLong) == ZSTD_read64(ip))) {
++ const BYTE *matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
++ const BYTE *lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
++ U32 offset;
++ mLength = ZSTD_count_2segments(ip + 8, matchLong + 8, iend, matchEnd, lowPrefixPtr) + 8;
++ offset = curr - matchLongIndex;
++ while (((ip > anchor) & (matchLong > lowMatchPtr)) && (ip[-1] == matchLong[-1])) {
++ ip--;
++ matchLong--;
++ mLength++;
++ } /* catch up */
++ offset_2 = offset_1;
++ offset_1 = offset;
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
++
++ } else if ((matchIndex > lowestIndex) && (ZSTD_read32(match) == ZSTD_read32(ip))) {
++ size_t const h3 = ZSTD_hashPtr(ip + 1, hBitsL, 8);
++ U32 const matchIndex3 = hashLong[h3];
++ const BYTE *const match3Base = matchIndex3 < dictLimit ? dictBase : base;
++ const BYTE *match3 = match3Base + matchIndex3;
++ U32 offset;
++ hashLong[h3] = curr + 1;
++ if ((matchIndex3 > lowestIndex) && (ZSTD_read64(match3) == ZSTD_read64(ip + 1))) {
++ const BYTE *matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
++ const BYTE *lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
++ mLength = ZSTD_count_2segments(ip + 9, match3 + 8, iend, matchEnd, lowPrefixPtr) + 8;
++ ip++;
++ offset = curr + 1 - matchIndex3;
++ while (((ip > anchor) & (match3 > lowMatchPtr)) && (ip[-1] == match3[-1])) {
++ ip--;
++ match3--;
++ mLength++;
++ } /* catch up */
++ } else {
++ const BYTE *matchEnd = matchIndex < dictLimit ? dictEnd : iend;
++ const BYTE *lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
++ mLength = ZSTD_count_2segments(ip + 4, match + 4, iend, matchEnd, lowPrefixPtr) + 4;
++ offset = curr - matchIndex;
++ while (((ip > anchor) & (match > lowMatchPtr)) && (ip[-1] == match[-1])) {
++ ip--;
++ match--;
++ mLength++;
++ } /* catch up */
++ }
++ offset_2 = offset_1;
++ offset_1 = offset;
++ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
++
++ } else {
++ ip += ((ip - anchor) >> g_searchStrength) + 1;
++ continue;
++ }
++ }
++
++ /* found a match : store it */
++ ip += mLength;
++ anchor = ip;
++
++ if (ip <= ilimit) {
++ /* Fill Table */
++ hashSmall[ZSTD_hashPtr(base + curr + 2, hBitsS, mls)] = curr + 2;
++ hashLong[ZSTD_hashPtr(base + curr + 2, hBitsL, 8)] = curr + 2;
++ hashSmall[ZSTD_hashPtr(ip - 2, hBitsS, mls)] = (U32)(ip - 2 - base);
++ hashLong[ZSTD_hashPtr(ip - 2, hBitsL, 8)] = (U32)(ip - 2 - base);
++ /* check immediate repcode */
++ while (ip <= ilimit) {
++ U32 const curr2 = (U32)(ip - base);
++ U32 const repIndex2 = curr2 - offset_2;
++ const BYTE *repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
++ if ((((U32)((dictLimit - 1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
++ && (ZSTD_read32(repMatch2) == ZSTD_read32(ip))) {
++ const BYTE *const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
++ size_t const repLength2 =
++ ZSTD_count_2segments(ip + EQUAL_READ32, repMatch2 + EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
++ U32 tmpOffset = offset_2;
++ offset_2 = offset_1;
++ offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
++ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2 - MINMATCH);
++ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = curr2;
++ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = curr2;
++ ip += repLength2;
++ anchor = ip;
++ continue;
++ }
++ break;
++ }
++ }
++ }
++
++ /* save reps for next block */
++ ctx->repToConfirm[0] = offset_1;
++ ctx->repToConfirm[1] = offset_2;
++
++ /* Last Literals */
++ {
++ size_t const lastLLSize = iend - anchor;
++ memcpy(seqStorePtr->lit, anchor, lastLLSize);
++ seqStorePtr->lit += lastLLSize;
++ }
++}
++
++static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++ U32 const mls = ctx->params.cParams.searchLength;
++ switch (mls) {
++ default: /* includes case 3 */
++ case 4: ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
++ case 5: ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
++ case 6: ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
++ case 7: ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
++ }
++}
++
++/*-*************************************
++* Binary Tree search
++***************************************/
++/** ZSTD_insertBt1() : add one or multiple positions to tree.
++* ip : assumed <= iend-8 .
++* @return : nb of positions added */
++static U32 ZSTD_insertBt1(ZSTD_CCtx *zc, const BYTE *const ip, const U32 mls, const BYTE *const iend, U32 nbCompares, U32 extDict)
++{
++ U32 *const hashTable = zc->hashTable;
++ U32 const hashLog = zc->params.cParams.hashLog;
++ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
++ U32 *const bt = zc->chainTable;
++ U32 const btLog = zc->params.cParams.chainLog - 1;
++ U32 const btMask = (1 << btLog) - 1;
++ U32 matchIndex = hashTable[h];
++ size_t commonLengthSmaller = 0, commonLengthLarger = 0;
++ const BYTE *const base = zc->base;
++ const BYTE *const dictBase = zc->dictBase;
++ const U32 dictLimit = zc->dictLimit;
++ const BYTE *const dictEnd = dictBase + dictLimit;
++ const BYTE *const prefixStart = base + dictLimit;
++ const BYTE *match;
++ const U32 curr = (U32)(ip - base);
++ const U32 btLow = btMask >= curr ? 0 : curr - btMask;
++ U32 *smallerPtr = bt + 2 * (curr & btMask);
++ U32 *largerPtr = smallerPtr + 1;
++ U32 dummy32; /* to be nullified at the end */
++ U32 const windowLow = zc->lowLimit;
++ U32 matchEndIdx = curr + 8;
++ size_t bestLength = 8;
++
++ hashTable[h] = curr; /* Update Hash Table */
++
++ while (nbCompares-- && (matchIndex > windowLow)) {
++ U32 *const nextPtr = bt + 2 * (matchIndex & btMask);
++ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
++
++ if ((!extDict) || (matchIndex + matchLength >= dictLimit)) {
++ match = base + matchIndex;
++ if (match[matchLength] == ip[matchLength])
++ matchLength += ZSTD_count(ip + matchLength + 1, match + matchLength + 1, iend) + 1;
++ } else {
++ match = dictBase + matchIndex;
++ matchLength += ZSTD_count_2segments(ip + matchLength, match + matchLength, iend, dictEnd, prefixStart);
++ if (matchIndex + matchLength >= dictLimit)
++ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
++ }
++
++ if (matchLength > bestLength) {
++ bestLength = matchLength;
++ if (matchLength > matchEndIdx - matchIndex)
++ matchEndIdx = matchIndex + (U32)matchLength;
++ }
++
++ if (ip + matchLength == iend) /* equal : no way to know if inf or sup */
++ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
++
++ if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
++ /* match is smaller than curr */
++ *smallerPtr = matchIndex; /* update smaller idx */
++ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
++ if (matchIndex <= btLow) {
++ smallerPtr = &dummy32;
++ break;
++ } /* beyond tree size, stop the search */
++ smallerPtr = nextPtr + 1; /* new "smaller" => larger of match */
++ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to curr) */
++ } else {
++ /* match is larger than curr */
++ *largerPtr = matchIndex;
++ commonLengthLarger = matchLength;
++ if (matchIndex <= btLow) {
++ largerPtr = &dummy32;
++ break;
++ } /* beyond tree size, stop the search */
++ largerPtr = nextPtr;
++ matchIndex = nextPtr[0];
++ }
++ }
++
++ *smallerPtr = *largerPtr = 0;
++ if (bestLength > 384)
++ return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
++ if (matchEndIdx > curr + 8)
++ return matchEndIdx - curr - 8;
++ return 1;
++}
++
++static size_t ZSTD_insertBtAndFindBestMatch(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iend, size_t *offsetPtr, U32 nbCompares, const U32 mls,
++ U32 extDict)
++{
++ U32 *const hashTable = zc->hashTable;
++ U32 const hashLog = zc->params.cParams.hashLog;
++ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
++ U32 *const bt = zc->chainTable;
++ U32 const btLog = zc->params.cParams.chainLog - 1;
++ U32 const btMask = (1 << btLog) - 1;
++ U32 matchIndex = hashTable[h];
++ size_t commonLengthSmaller = 0, commonLengthLarger = 0;
++ const BYTE *const base = zc->base;
++ const BYTE *const dictBase = zc->dictBase;
++ const U32 dictLimit = zc->dictLimit;
++ const BYTE *const dictEnd = dictBase + dictLimit;
++ const BYTE *const prefixStart = base + dictLimit;
++ const U32 curr = (U32)(ip - base);
++ const U32 btLow = btMask >= curr ? 0 : curr - btMask;
++ const U32 windowLow = zc->lowLimit;
++ U32 *smallerPtr = bt + 2 * (curr & btMask);
++ U32 *largerPtr = bt + 2 * (curr & btMask) + 1;
++ U32 matchEndIdx = curr + 8;
++ U32 dummy32; /* to be nullified at the end */
++ size_t bestLength = 0;
++
++ hashTable[h] = curr; /* Update Hash Table */
++
++ while (nbCompares-- && (matchIndex > windowLow)) {
++ U32 *const nextPtr = bt + 2 * (matchIndex & btMask);
++ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
++ const BYTE *match;
++
++ if ((!extDict) || (matchIndex + matchLength >= dictLimit)) {
++ match = base + matchIndex;
++ if (match[matchLength] == ip[matchLength])
++ matchLength += ZSTD_count(ip + matchLength + 1, match + matchLength + 1, iend) + 1;
++ } else {
++ match = dictBase + matchIndex;
++ matchLength += ZSTD_count_2segments(ip + matchLength, match + matchLength, iend, dictEnd, prefixStart);
++ if (matchIndex + matchLength >= dictLimit)
++ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
++ }
++
++ if (matchLength > bestLength) {
++ if (matchLength > matchEndIdx - matchIndex)
++ matchEndIdx = matchIndex + (U32)matchLength;
++ if ((4 * (int)(matchLength - bestLength)) > (int)(ZSTD_highbit32(curr - matchIndex + 1) - ZSTD_highbit32((U32)offsetPtr[0] + 1)))
++ bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + curr - matchIndex;
++ if (ip + matchLength == iend) /* equal : no way to know if inf or sup */
++ break; /* drop, to guarantee consistency (miss a little bit of compression) */
++ }
++
++ if (match[matchLength] < ip[matchLength]) {
++ /* match is smaller than curr */
++ *smallerPtr = matchIndex; /* update smaller idx */
++ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
++ if (matchIndex <= btLow) {
++ smallerPtr = &dummy32;
++ break;
++ } /* beyond tree size, stop the search */
++ smallerPtr = nextPtr + 1; /* new "smaller" => larger of match */
++ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to curr) */
++ } else {
++ /* match is larger than curr */
++ *largerPtr = matchIndex;
++ commonLengthLarger = matchLength;
++ if (matchIndex <= btLow) {
++ largerPtr = &dummy32;
++ break;
++ } /* beyond tree size, stop the search */
++ largerPtr = nextPtr;
++ matchIndex = nextPtr[0];
++ }
++ }
++
++ *smallerPtr = *largerPtr = 0;
++
++ zc->nextToUpdate = (matchEndIdx > curr + 8) ? matchEndIdx - 8 : curr + 1;
++ return bestLength;
++}
++
++static void ZSTD_updateTree(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iend, const U32 nbCompares, const U32 mls)
++{
++ const BYTE *const base = zc->base;
++ const U32 target = (U32)(ip - base);
++ U32 idx = zc->nextToUpdate;
++
++ while (idx < target)
++ idx += ZSTD_insertBt1(zc, base + idx, mls, iend, nbCompares, 0);
++}
++
++/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
++static size_t ZSTD_BtFindBestMatch(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts, const U32 mls)
++{
++ if (ip < zc->base + zc->nextToUpdate)
++ return 0; /* skipped area */
++ ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
++ return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
++}
++
++static size_t ZSTD_BtFindBestMatch_selectMLS(ZSTD_CCtx *zc, /* Index table will be updated */
++ const BYTE *ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts, const U32 matchLengthSearch)
++{
++ switch (matchLengthSearch) {
++ default: /* includes case 3 */
++ case 4: return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
++ case 5: return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
++ case 7:
++ case 6: return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
++ }
++}
++
++static void ZSTD_updateTree_extDict(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iend, const U32 nbCompares, const U32 mls)
++{
++ const BYTE *const base = zc->base;
++ const U32 target = (U32)(ip - base);
++ U32 idx = zc->nextToUpdate;
++
++ while (idx < target)
++ idx += ZSTD_insertBt1(zc, base + idx, mls, iend, nbCompares, 1);
++}
++
++/** Tree updater, providing best match */
++static size_t ZSTD_BtFindBestMatch_extDict(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts,
++ const U32 mls)
++{
++ if (ip < zc->base + zc->nextToUpdate)
++ return 0; /* skipped area */
++ ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
++ return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
++}
++
++static size_t ZSTD_BtFindBestMatch_selectMLS_extDict(ZSTD_CCtx *zc, /* Index table will be updated */
++ const BYTE *ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts,
++ const U32 matchLengthSearch)
++{
++ switch (matchLengthSearch) {
++ default: /* includes case 3 */
++ case 4: return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
++ case 5: return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
++ case 7:
++ case 6: return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
++ }
++}
++
++/* *********************************
++* Hash Chain
++***********************************/
++#define NEXT_IN_CHAIN(d, mask) chainTable[(d)&mask]
++
++/* Update chains up to ip (excluded)
++ Assumption : always within prefix (i.e. not within extDict) */
++FORCE_INLINE
++U32 ZSTD_insertAndFindFirstIndex(ZSTD_CCtx *zc, const BYTE *ip, U32 mls)
++{
++ U32 *const hashTable = zc->hashTable;
++ const U32 hashLog = zc->params.cParams.hashLog;
++ U32 *const chainTable = zc->chainTable;
++ const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
++ const BYTE *const base = zc->base;
++ const U32 target = (U32)(ip - base);
++ U32 idx = zc->nextToUpdate;
++
++ while (idx < target) { /* catch up */
++ size_t const h = ZSTD_hashPtr(base + idx, hashLog, mls);
++ NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
++ hashTable[h] = idx;
++ idx++;
++ }
++
++ zc->nextToUpdate = target;
++ return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
++}
++
++/* inlining is important to hardwire a hot branch (template emulation) */
++FORCE_INLINE
++size_t ZSTD_HcFindBestMatch_generic(ZSTD_CCtx *zc, /* Index table will be updated */
++ const BYTE *const ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts, const U32 mls,
++ const U32 extDict)
++{
++ U32 *const chainTable = zc->chainTable;
++ const U32 chainSize = (1 << zc->params.cParams.chainLog);
++ const U32 chainMask = chainSize - 1;
++ const BYTE *const base = zc->base;
++ const BYTE *const dictBase = zc->dictBase;
++ const U32 dictLimit = zc->dictLimit;
++ const BYTE *const prefixStart = base + dictLimit;
++ const BYTE *const dictEnd = dictBase + dictLimit;
++ const U32 lowLimit = zc->lowLimit;
++ const U32 curr = (U32)(ip - base);
++ const U32 minChain = curr > chainSize ? curr - chainSize : 0;
++ int nbAttempts = maxNbAttempts;
++ size_t ml = EQUAL_READ32 - 1;
++
++ /* HC4 match finder */
++ U32 matchIndex = ZSTD_insertAndFindFirstIndex(zc, ip, mls);
++
++ for (; (matchIndex > lowLimit) & (nbAttempts > 0); nbAttempts--) {
++ const BYTE *match;
++ size_t currMl = 0;
++ if ((!extDict) || matchIndex >= dictLimit) {
++ match = base + matchIndex;
++ if (match[ml] == ip[ml]) /* potentially better */
++ currMl = ZSTD_count(ip, match, iLimit);
++ } else {
++ match = dictBase + matchIndex;
++ if (ZSTD_read32(match) == ZSTD_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
++ currMl = ZSTD_count_2segments(ip + EQUAL_READ32, match + EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
++ }
++
++ /* save best solution */
++ if (currMl > ml) {
++ ml = currMl;
++ *offsetPtr = curr - matchIndex + ZSTD_REP_MOVE;
++ if (ip + currMl == iLimit)
++ break; /* best possible, and avoid read overflow*/
++ }
++
++ if (matchIndex <= minChain)
++ break;
++ matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
++ }
++
++ return ml;
++}
++
++FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS(ZSTD_CCtx *zc, const BYTE *ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts,
++ const U32 matchLengthSearch)
++{
++ switch (matchLengthSearch) {
++ default: /* includes case 3 */
++ case 4: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
++ case 5: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
++ case 7:
++ case 6: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
++ }
++}
++
++FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS(ZSTD_CCtx *zc, const BYTE *ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts,
++ const U32 matchLengthSearch)
++{
++ switch (matchLengthSearch) {
++ default: /* includes case 3 */
++ case 4: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
++ case 5: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
++ case 7:
++ case 6: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
++ }
++}
++
++/* *******************************
++* Common parser - lazy strategy
++*********************************/
++FORCE_INLINE
++void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const U32 searchMethod, const U32 depth)
++{
++ seqStore_t *seqStorePtr = &(ctx->seqStore);
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *ip = istart;
++ const BYTE *anchor = istart;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *const ilimit = iend - 8;
++ const BYTE *const base = ctx->base + ctx->dictLimit;
++
++ U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
++ U32 const mls = ctx->params.cParams.searchLength;
++
++ typedef size_t (*searchMax_f)(ZSTD_CCtx * zc, const BYTE *ip, const BYTE *iLimit, size_t *offsetPtr, U32 maxNbAttempts, U32 matchLengthSearch);
++ searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
++ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset = 0;
++
++ /* init */
++ ip += (ip == base);
++ ctx->nextToUpdate3 = ctx->nextToUpdate;
++ {
++ U32 const maxRep = (U32)(ip - base);
++ if (offset_2 > maxRep)
++ savedOffset = offset_2, offset_2 = 0;
++ if (offset_1 > maxRep)
++ savedOffset = offset_1, offset_1 = 0;
++ }
++
++ /* Match Loop */
++ while (ip < ilimit) {
++ size_t matchLength = 0;
++ size_t offset = 0;
++ const BYTE *start = ip + 1;
++
++ /* check repCode */
++ if ((offset_1 > 0) & (ZSTD_read32(ip + 1) == ZSTD_read32(ip + 1 - offset_1))) {
++ /* repcode : we take it */
++ matchLength = ZSTD_count(ip + 1 + EQUAL_READ32, ip + 1 + EQUAL_READ32 - offset_1, iend) + EQUAL_READ32;
++ if (depth == 0)
++ goto _storeSequence;
++ }
++
++ /* first search (depth 0) */
++ {
++ size_t offsetFound = 99999999;
++ size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
++ if (ml2 > matchLength)
++ matchLength = ml2, start = ip, offset = offsetFound;
++ }
++
++ if (matchLength < EQUAL_READ32) {
++ ip += ((ip - anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
++ continue;
++ }
++
++ /* let's try to find a better solution */
++ if (depth >= 1)
++ while (ip < ilimit) {
++ ip++;
++ if ((offset) && ((offset_1 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_1)))) {
++ size_t const mlRep = ZSTD_count(ip + EQUAL_READ32, ip + EQUAL_READ32 - offset_1, iend) + EQUAL_READ32;
++ int const gain2 = (int)(mlRep * 3);
++ int const gain1 = (int)(matchLength * 3 - ZSTD_highbit32((U32)offset + 1) + 1);
++ if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
++ matchLength = mlRep, offset = 0, start = ip;
++ }
++ {
++ size_t offset2 = 99999999;
++ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
++ int const gain2 = (int)(ml2 * 4 - ZSTD_highbit32((U32)offset2 + 1)); /* raw approx */
++ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 4);
++ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
++ matchLength = ml2, offset = offset2, start = ip;
++ continue; /* search a better one */
++ }
++ }
++
++ /* let's find an even better one */
++ if ((depth == 2) && (ip < ilimit)) {
++ ip++;
++ if ((offset) && ((offset_1 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_1)))) {
++ size_t const ml2 = ZSTD_count(ip + EQUAL_READ32, ip + EQUAL_READ32 - offset_1, iend) + EQUAL_READ32;
++ int const gain2 = (int)(ml2 * 4);
++ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 1);
++ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
++ matchLength = ml2, offset = 0, start = ip;
++ }
++ {
++ size_t offset2 = 99999999;
++ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
++ int const gain2 = (int)(ml2 * 4 - ZSTD_highbit32((U32)offset2 + 1)); /* raw approx */
++ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 7);
++ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
++ matchLength = ml2, offset = offset2, start = ip;
++ continue;
++ }
++ }
++ }
++ break; /* nothing found : store previous solution */
++ }
++
++ /* NOTE:
++ * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
++ * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
++ * overflows the pointer, which is undefined behavior.
++ */
++ /* catch up */
++ if (offset) {
++ while ((start > anchor) && (start > base + offset - ZSTD_REP_MOVE) &&
++ (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1])) /* only search for offset within prefix */
++ {
++ start--;
++ matchLength++;
++ }
++ offset_2 = offset_1;
++ offset_1 = (U32)(offset - ZSTD_REP_MOVE);
++ }
++
++ /* store sequence */
++_storeSequence:
++ {
++ size_t const litLength = start - anchor;
++ ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength - MINMATCH);
++ anchor = ip = start + matchLength;
++ }
++
++ /* check immediate repcode */
++ while ((ip <= ilimit) && ((offset_2 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_2)))) {
++ /* store sequence */
++ matchLength = ZSTD_count(ip + EQUAL_READ32, ip + EQUAL_READ32 - offset_2, iend) + EQUAL_READ32;
++ offset = offset_2;
++ offset_2 = offset_1;
++ offset_1 = (U32)offset; /* swap repcodes */
++ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength - MINMATCH);
++ ip += matchLength;
++ anchor = ip;
++ continue; /* faster when present ... (?) */
++ }
++ }
++
++ /* Save reps for next block */
++ ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
++ ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
++
++ /* Last Literals */
++ {
++ size_t const lastLLSize = iend - anchor;
++ memcpy(seqStorePtr->lit, anchor, lastLLSize);
++ seqStorePtr->lit += lastLLSize;
++ }
++}
++
++static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); }
++
++static void ZSTD_compressBlock_lazy2(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2); }
++
++static void ZSTD_compressBlock_lazy(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1); }
++
++static void ZSTD_compressBlock_greedy(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0); }
++
++FORCE_INLINE
++void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const U32 searchMethod, const U32 depth)
++{
++ seqStore_t *seqStorePtr = &(ctx->seqStore);
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *ip = istart;
++ const BYTE *anchor = istart;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *const ilimit = iend - 8;
++ const BYTE *const base = ctx->base;
++ const U32 dictLimit = ctx->dictLimit;
++ const U32 lowestIndex = ctx->lowLimit;
++ const BYTE *const prefixStart = base + dictLimit;
++ const BYTE *const dictBase = ctx->dictBase;
++ const BYTE *const dictEnd = dictBase + dictLimit;
++ const BYTE *const dictStart = dictBase + ctx->lowLimit;
++
++ const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
++ const U32 mls = ctx->params.cParams.searchLength;
++
++ typedef size_t (*searchMax_f)(ZSTD_CCtx * zc, const BYTE *ip, const BYTE *iLimit, size_t *offsetPtr, U32 maxNbAttempts, U32 matchLengthSearch);
++ searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
++
++ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
++
++ /* init */
++ ctx->nextToUpdate3 = ctx->nextToUpdate;
++ ip += (ip == prefixStart);
++
++ /* Match Loop */
++ while (ip < ilimit) {
++ size_t matchLength = 0;
++ size_t offset = 0;
++ const BYTE *start = ip + 1;
++ U32 curr = (U32)(ip - base);
++
++ /* check repCode */
++ {
++ const U32 repIndex = (U32)(curr + 1 - offset_1);
++ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
++ const BYTE *const repMatch = repBase + repIndex;
++ if (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
++ if (ZSTD_read32(ip + 1) == ZSTD_read32(repMatch)) {
++ /* repcode detected we should take it */
++ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
++ matchLength =
++ ZSTD_count_2segments(ip + 1 + EQUAL_READ32, repMatch + EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
++ if (depth == 0)
++ goto _storeSequence;
++ }
++ }
++
++ /* first search (depth 0) */
++ {
++ size_t offsetFound = 99999999;
++ size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
++ if (ml2 > matchLength)
++ matchLength = ml2, start = ip, offset = offsetFound;
++ }
++
++ if (matchLength < EQUAL_READ32) {
++ ip += ((ip - anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
++ continue;
++ }
++
++ /* let's try to find a better solution */
++ if (depth >= 1)
++ while (ip < ilimit) {
++ ip++;
++ curr++;
++ /* check repCode */
++ if (offset) {
++ const U32 repIndex = (U32)(curr - offset_1);
++ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
++ const BYTE *const repMatch = repBase + repIndex;
++ if (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
++ if (ZSTD_read32(ip) == ZSTD_read32(repMatch)) {
++ /* repcode detected */
++ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
++ size_t const repLength =
++ ZSTD_count_2segments(ip + EQUAL_READ32, repMatch + EQUAL_READ32, iend, repEnd, prefixStart) +
++ EQUAL_READ32;
++ int const gain2 = (int)(repLength * 3);
++ int const gain1 = (int)(matchLength * 3 - ZSTD_highbit32((U32)offset + 1) + 1);
++ if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
++ matchLength = repLength, offset = 0, start = ip;
++ }
++ }
++
++ /* search match, depth 1 */
++ {
++ size_t offset2 = 99999999;
++ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
++ int const gain2 = (int)(ml2 * 4 - ZSTD_highbit32((U32)offset2 + 1)); /* raw approx */
++ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 4);
++ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
++ matchLength = ml2, offset = offset2, start = ip;
++ continue; /* search a better one */
++ }
++ }
++
++ /* let's find an even better one */
++ if ((depth == 2) && (ip < ilimit)) {
++ ip++;
++ curr++;
++ /* check repCode */
++ if (offset) {
++ const U32 repIndex = (U32)(curr - offset_1);
++ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
++ const BYTE *const repMatch = repBase + repIndex;
++ if (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
++ if (ZSTD_read32(ip) == ZSTD_read32(repMatch)) {
++ /* repcode detected */
++ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
++ size_t repLength = ZSTD_count_2segments(ip + EQUAL_READ32, repMatch + EQUAL_READ32, iend,
++ repEnd, prefixStart) +
++ EQUAL_READ32;
++ int gain2 = (int)(repLength * 4);
++ int gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 1);
++ if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
++ matchLength = repLength, offset = 0, start = ip;
++ }
++ }
++
++ /* search match, depth 2 */
++ {
++ size_t offset2 = 99999999;
++ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
++ int const gain2 = (int)(ml2 * 4 - ZSTD_highbit32((U32)offset2 + 1)); /* raw approx */
++ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 7);
++ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
++ matchLength = ml2, offset = offset2, start = ip;
++ continue;
++ }
++ }
++ }
++ break; /* nothing found : store previous solution */
++ }
++
++ /* catch up */
++ if (offset) {
++ U32 const matchIndex = (U32)((start - base) - (offset - ZSTD_REP_MOVE));
++ const BYTE *match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
++ const BYTE *const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
++ while ((start > anchor) && (match > mStart) && (start[-1] == match[-1])) {
++ start--;
++ match--;
++ matchLength++;
++ } /* catch up */
++ offset_2 = offset_1;
++ offset_1 = (U32)(offset - ZSTD_REP_MOVE);
++ }
++
++ /* store sequence */
++ _storeSequence : {
++ size_t const litLength = start - anchor;
++ ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength - MINMATCH);
++ anchor = ip = start + matchLength;
++ }
++
++ /* check immediate repcode */
++ while (ip <= ilimit) {
++ const U32 repIndex = (U32)((ip - base) - offset_2);
++ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
++ const BYTE *const repMatch = repBase + repIndex;
++ if (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
++ if (ZSTD_read32(ip) == ZSTD_read32(repMatch)) {
++ /* repcode detected we should take it */
++ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
++ matchLength =
++ ZSTD_count_2segments(ip + EQUAL_READ32, repMatch + EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
++ offset = offset_2;
++ offset_2 = offset_1;
++ offset_1 = (U32)offset; /* swap offset history */
++ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength - MINMATCH);
++ ip += matchLength;
++ anchor = ip;
++ continue; /* faster when present ... (?) */
++ }
++ break;
++ }
++ }
++
++ /* Save reps for next block */
++ ctx->repToConfirm[0] = offset_1;
++ ctx->repToConfirm[1] = offset_2;
++
++ /* Last Literals */
++ {
++ size_t const lastLLSize = iend - anchor;
++ memcpy(seqStorePtr->lit, anchor, lastLLSize);
++ seqStorePtr->lit += lastLLSize;
++ }
++}
++
++void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0); }
++
++static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++ ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
++}
++
++static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++ ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
++}
++
++static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++ ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
++}
++
++/* The optimal parser */
++#include "zstd_opt.h"
++
++static void ZSTD_compressBlock_btopt(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++#ifdef ZSTD_OPT_H_91842398743
++ ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
++#else
++ (void)ctx;
++ (void)src;
++ (void)srcSize;
++ return;
++#endif
++}
++
++static void ZSTD_compressBlock_btopt2(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++#ifdef ZSTD_OPT_H_91842398743
++ ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
++#else
++ (void)ctx;
++ (void)src;
++ (void)srcSize;
++ return;
++#endif
++}
++
++static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++#ifdef ZSTD_OPT_H_91842398743
++ ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
++#else
++ (void)ctx;
++ (void)src;
++ (void)srcSize;
++ return;
++#endif
++}
++
++static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
++{
++#ifdef ZSTD_OPT_H_91842398743
++ ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
++#else
++ (void)ctx;
++ (void)src;
++ (void)srcSize;
++ return;
++#endif
++}
++
++typedef void (*ZSTD_blockCompressor)(ZSTD_CCtx *ctx, const void *src, size_t srcSize);
++
++static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
++{
++ static const ZSTD_blockCompressor blockCompressor[2][8] = {
++ {ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2,
++ ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2},
++ {ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,
++ ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btopt2_extDict}};
++
++ return blockCompressor[extDict][(U32)strat];
++}
++
++static size_t ZSTD_compressBlock_internal(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
++ const BYTE *const base = zc->base;
++ const BYTE *const istart = (const BYTE *)src;
++ const U32 curr = (U32)(istart - base);
++ if (srcSize < MIN_CBLOCK_SIZE + ZSTD_blockHeaderSize + 1)
++ return 0; /* don't even attempt compression below a certain srcSize */
++ ZSTD_resetSeqStore(&(zc->seqStore));
++ if (curr > zc->nextToUpdate + 384)
++ zc->nextToUpdate = curr - MIN(192, (U32)(curr - zc->nextToUpdate - 384)); /* update tree not updated after finding very long rep matches */
++ blockCompressor(zc, src, srcSize);
++ return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
++}
++
++/*! ZSTD_compress_generic() :
++* Compress a chunk of data into one or multiple blocks.
++* All blocks will be terminated, all input will be consumed.
++* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
++* Frame is supposed already started (header already produced)
++* @return : compressed size, or an error code
++*/
++static size_t ZSTD_compress_generic(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, U32 lastFrameChunk)
++{
++ size_t blockSize = cctx->blockSize;
++ size_t remaining = srcSize;
++ const BYTE *ip = (const BYTE *)src;
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *op = ostart;
++ U32 const maxDist = 1 << cctx->params.cParams.windowLog;
++
++ if (cctx->params.fParams.checksumFlag && srcSize)
++ xxh64_update(&cctx->xxhState, src, srcSize);
++
++ while (remaining) {
++ U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
++ size_t cSize;
++
++ if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
++ return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
++ if (remaining < blockSize)
++ blockSize = remaining;
++
++ /* preemptive overflow correction */
++ if (cctx->lowLimit > (3U << 29)) {
++ U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
++ U32 const curr = (U32)(ip - cctx->base);
++ U32 const newCurr = (curr & cycleMask) + (1 << cctx->params.cParams.windowLog);
++ U32 const correction = curr - newCurr;
++ ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
++ ZSTD_reduceIndex(cctx, correction);
++ cctx->base += correction;
++ cctx->dictBase += correction;
++ cctx->lowLimit -= correction;
++ cctx->dictLimit -= correction;
++ if (cctx->nextToUpdate < correction)
++ cctx->nextToUpdate = 0;
++ else
++ cctx->nextToUpdate -= correction;
++ }
++
++ if ((U32)(ip + blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
++ /* enforce maxDist */
++ U32 const newLowLimit = (U32)(ip + blockSize - cctx->base) - maxDist;
++ if (cctx->lowLimit < newLowLimit)
++ cctx->lowLimit = newLowLimit;
++ if (cctx->dictLimit < cctx->lowLimit)
++ cctx->dictLimit = cctx->lowLimit;
++ }
++
++ cSize = ZSTD_compressBlock_internal(cctx, op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize, ip, blockSize);
++ if (ZSTD_isError(cSize))
++ return cSize;
++
++ if (cSize == 0) { /* block is not compressible */
++ U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw) << 1) + (U32)(blockSize << 3);
++ if (blockSize + ZSTD_blockHeaderSize > dstCapacity)
++ return ERROR(dstSize_tooSmall);
++ ZSTD_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
++ memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
++ cSize = ZSTD_blockHeaderSize + blockSize;
++ } else {
++ U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed) << 1) + (U32)(cSize << 3);
++ ZSTD_writeLE24(op, cBlockHeader24);
++ cSize += ZSTD_blockHeaderSize;
++ }
++
++ remaining -= blockSize;
++ dstCapacity -= cSize;
++ ip += blockSize;
++ op += cSize;
++ }
++
++ if (lastFrameChunk && (op > ostart))
++ cctx->stage = ZSTDcs_ending;
++ return op - ostart;
++}
++
++static size_t ZSTD_writeFrameHeader(void *dst, size_t dstCapacity, ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
++{
++ BYTE *const op = (BYTE *)dst;
++ U32 const dictIDSizeCode = (dictID > 0) + (dictID >= 256) + (dictID >= 65536); /* 0-3 */
++ U32 const checksumFlag = params.fParams.checksumFlag > 0;
++ U32 const windowSize = 1U << params.cParams.windowLog;
++ U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
++ BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
++ U32 const fcsCode =
++ params.fParams.contentSizeFlag ? (pledgedSrcSize >= 256) + (pledgedSrcSize >= 65536 + 256) + (pledgedSrcSize >= 0xFFFFFFFFU) : 0; /* 0-3 */
++ BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag << 2) + (singleSegment << 5) + (fcsCode << 6));
++ size_t pos;
++
++ if (dstCapacity < ZSTD_frameHeaderSize_max)
++ return ERROR(dstSize_tooSmall);
++
++ ZSTD_writeLE32(dst, ZSTD_MAGICNUMBER);
++ op[4] = frameHeaderDecriptionByte;
++ pos = 5;
++ if (!singleSegment)
++ op[pos++] = windowLogByte;
++ switch (dictIDSizeCode) {
++ default: /* impossible */
++ case 0: break;
++ case 1:
++ op[pos] = (BYTE)(dictID);
++ pos++;
++ break;
++ case 2:
++ ZSTD_writeLE16(op + pos, (U16)dictID);
++ pos += 2;
++ break;
++ case 3:
++ ZSTD_writeLE32(op + pos, dictID);
++ pos += 4;
++ break;
++ }
++ switch (fcsCode) {
++ default: /* impossible */
++ case 0:
++ if (singleSegment)
++ op[pos++] = (BYTE)(pledgedSrcSize);
++ break;
++ case 1:
++ ZSTD_writeLE16(op + pos, (U16)(pledgedSrcSize - 256));
++ pos += 2;
++ break;
++ case 2:
++ ZSTD_writeLE32(op + pos, (U32)(pledgedSrcSize));
++ pos += 4;
++ break;
++ case 3:
++ ZSTD_writeLE64(op + pos, (U64)(pledgedSrcSize));
++ pos += 8;
++ break;
++ }
++ return pos;
++}
++
++static size_t ZSTD_compressContinue_internal(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, U32 frame, U32 lastFrameChunk)
++{
++ const BYTE *const ip = (const BYTE *)src;
++ size_t fhSize = 0;
++
++ if (cctx->stage == ZSTDcs_created)
++ return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
++
++ if (frame && (cctx->stage == ZSTDcs_init)) {
++ fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
++ if (ZSTD_isError(fhSize))
++ return fhSize;
++ dstCapacity -= fhSize;
++ dst = (char *)dst + fhSize;
++ cctx->stage = ZSTDcs_ongoing;
++ }
++
++ /* Check if blocks follow each other */
++ if (src != cctx->nextSrc) {
++ /* not contiguous */
++ ptrdiff_t const delta = cctx->nextSrc - ip;
++ cctx->lowLimit = cctx->dictLimit;
++ cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
++ cctx->dictBase = cctx->base;
++ cctx->base -= delta;
++ cctx->nextToUpdate = cctx->dictLimit;
++ if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE)
++ cctx->lowLimit = cctx->dictLimit; /* too small extDict */
++ }
++
++ /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
++ if ((ip + srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
++ ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
++ U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
++ cctx->lowLimit = lowLimitMax;
++ }
++
++ cctx->nextSrc = ip + srcSize;
++
++ if (srcSize) {
++ size_t const cSize = frame ? ZSTD_compress_generic(cctx, dst, dstCapacity, src, srcSize, lastFrameChunk)
++ : ZSTD_compressBlock_internal(cctx, dst, dstCapacity, src, srcSize);
++ if (ZSTD_isError(cSize))
++ return cSize;
++ return cSize + fhSize;
++ } else
++ return fhSize;
++}
++
++size_t ZSTD_compressContinue(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
++}
++
++size_t ZSTD_getBlockSizeMax(ZSTD_CCtx *cctx) { return MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog); }
++
++size_t ZSTD_compressBlock(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
++ if (srcSize > blockSizeMax)
++ return ERROR(srcSize_wrong);
++ return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
++}
++
++/*! ZSTD_loadDictionaryContent() :
++ * @return : 0, or an error code
++ */
++static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx *zc, const void *src, size_t srcSize)
++{
++ const BYTE *const ip = (const BYTE *)src;
++ const BYTE *const iend = ip + srcSize;
++
++ /* input becomes curr prefix */
++ zc->lowLimit = zc->dictLimit;
++ zc->dictLimit = (U32)(zc->nextSrc - zc->base);
++ zc->dictBase = zc->base;
++ zc->base += ip - zc->nextSrc;
++ zc->nextToUpdate = zc->dictLimit;
++ zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
++
++ zc->nextSrc = iend;
++ if (srcSize <= HASH_READ_SIZE)
++ return 0;
++
++ switch (zc->params.cParams.strategy) {
++ case ZSTD_fast: ZSTD_fillHashTable(zc, iend, zc->params.cParams.searchLength); break;
++
++ case ZSTD_dfast: ZSTD_fillDoubleHashTable(zc, iend, zc->params.cParams.searchLength); break;
++
++ case ZSTD_greedy:
++ case ZSTD_lazy:
++ case ZSTD_lazy2:
++ if (srcSize >= HASH_READ_SIZE)
++ ZSTD_insertAndFindFirstIndex(zc, iend - HASH_READ_SIZE, zc->params.cParams.searchLength);
++ break;
++
++ case ZSTD_btlazy2:
++ case ZSTD_btopt:
++ case ZSTD_btopt2:
++ if (srcSize >= HASH_READ_SIZE)
++ ZSTD_updateTree(zc, iend - HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
++ break;
++
++ default:
++ return ERROR(GENERIC); /* strategy doesn't exist; impossible */
++ }
++
++ zc->nextToUpdate = (U32)(iend - zc->base);
++ return 0;
++}
++
++/* Dictionaries that assign zero probability to symbols that show up causes problems
++ when FSE encoding. Refuse dictionaries that assign zero probability to symbols
++ that we may encounter during compression.
++ NOTE: This behavior is not standard and could be improved in the future. */
++static size_t ZSTD_checkDictNCount(short *normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue)
++{
++ U32 s;
++ if (dictMaxSymbolValue < maxSymbolValue)
++ return ERROR(dictionary_corrupted);
++ for (s = 0; s <= maxSymbolValue; ++s) {
++ if (normalizedCounter[s] == 0)
++ return ERROR(dictionary_corrupted);
++ }
++ return 0;
++}
++
++/* Dictionary format :
++ * See :
++ * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
++ */
++/*! ZSTD_loadZstdDictionary() :
++ * @return : 0, or an error code
++ * assumptions : magic number supposed already checked
++ * dictSize supposed > 8
++ */
++static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx *cctx, const void *dict, size_t dictSize)
++{
++ const BYTE *dictPtr = (const BYTE *)dict;
++ const BYTE *const dictEnd = dictPtr + dictSize;
++ short offcodeNCount[MaxOff + 1];
++ unsigned offcodeMaxValue = MaxOff;
++
++ dictPtr += 4; /* skip magic number */
++ cctx->dictID = cctx->params.fParams.noDictIDFlag ? 0 : ZSTD_readLE32(dictPtr);
++ dictPtr += 4;
++
++ {
++ size_t const hufHeaderSize = HUF_readCTable_wksp(cctx->hufTable, 255, dictPtr, dictEnd - dictPtr, cctx->tmpCounters, sizeof(cctx->tmpCounters));
++ if (HUF_isError(hufHeaderSize))
++ return ERROR(dictionary_corrupted);
++ dictPtr += hufHeaderSize;
++ }
++
++ {
++ unsigned offcodeLog;
++ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd - dictPtr);
++ if (FSE_isError(offcodeHeaderSize))
++ return ERROR(dictionary_corrupted);
++ if (offcodeLog > OffFSELog)
++ return ERROR(dictionary_corrupted);
++ /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
++ CHECK_E(FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, cctx->tmpCounters, sizeof(cctx->tmpCounters)),
++ dictionary_corrupted);
++ dictPtr += offcodeHeaderSize;
++ }
++
++ {
++ short matchlengthNCount[MaxML + 1];
++ unsigned matchlengthMaxValue = MaxML, matchlengthLog;
++ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd - dictPtr);
++ if (FSE_isError(matchlengthHeaderSize))
++ return ERROR(dictionary_corrupted);
++ if (matchlengthLog > MLFSELog)
++ return ERROR(dictionary_corrupted);
++ /* Every match length code must have non-zero probability */
++ CHECK_F(ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
++ CHECK_E(
++ FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, cctx->tmpCounters, sizeof(cctx->tmpCounters)),
++ dictionary_corrupted);
++ dictPtr += matchlengthHeaderSize;
++ }
++
++ {
++ short litlengthNCount[MaxLL + 1];
++ unsigned litlengthMaxValue = MaxLL, litlengthLog;
++ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd - dictPtr);
++ if (FSE_isError(litlengthHeaderSize))
++ return ERROR(dictionary_corrupted);
++ if (litlengthLog > LLFSELog)
++ return ERROR(dictionary_corrupted);
++ /* Every literal length code must have non-zero probability */
++ CHECK_F(ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
++ CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, cctx->tmpCounters, sizeof(cctx->tmpCounters)),
++ dictionary_corrupted);
++ dictPtr += litlengthHeaderSize;
++ }
++
++ if (dictPtr + 12 > dictEnd)
++ return ERROR(dictionary_corrupted);
++ cctx->rep[0] = ZSTD_readLE32(dictPtr + 0);
++ cctx->rep[1] = ZSTD_readLE32(dictPtr + 4);
++ cctx->rep[2] = ZSTD_readLE32(dictPtr + 8);
++ dictPtr += 12;
++
++ {
++ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
++ U32 offcodeMax = MaxOff;
++ if (dictContentSize <= ((U32)-1) - 128 KB) {
++ U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
++ offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
++ }
++ /* All offset values <= dictContentSize + 128 KB must be representable */
++ CHECK_F(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
++ /* All repCodes must be <= dictContentSize and != 0*/
++ {
++ U32 u;
++ for (u = 0; u < 3; u++) {
++ if (cctx->rep[u] == 0)
++ return ERROR(dictionary_corrupted);
++ if (cctx->rep[u] > dictContentSize)
++ return ERROR(dictionary_corrupted);
++ }
++ }
++
++ cctx->flagStaticTables = 1;
++ cctx->flagStaticHufTable = HUF_repeat_valid;
++ return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
++ }
++}
++
++/** ZSTD_compress_insertDictionary() :
++* @return : 0, or an error code */
++static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx *cctx, const void *dict, size_t dictSize)
++{
++ if ((dict == NULL) || (dictSize <= 8))
++ return 0;
++
++ /* dict as pure content */
++ if ((ZSTD_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
++ return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
++
++ /* dict as zstd dictionary */
++ return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
++}
++
++/*! ZSTD_compressBegin_internal() :
++* @return : 0, or an error code */
++static size_t ZSTD_compressBegin_internal(ZSTD_CCtx *cctx, const void *dict, size_t dictSize, ZSTD_parameters params, U64 pledgedSrcSize)
++{
++ ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
++ CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
++ return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
++}
++
++/*! ZSTD_compressBegin_advanced() :
++* @return : 0, or an error code */
++size_t ZSTD_compressBegin_advanced(ZSTD_CCtx *cctx, const void *dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize)
++{
++ /* compression parameters verification and optimization */
++ CHECK_F(ZSTD_checkCParams(params.cParams));
++ return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
++}
++
++size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx *cctx, const void *dict, size_t dictSize, int compressionLevel)
++{
++ ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
++ return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
++}
++
++size_t ZSTD_compressBegin(ZSTD_CCtx *cctx, int compressionLevel) { return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); }
++
++/*! ZSTD_writeEpilogue() :
++* Ends a frame.
++* @return : nb of bytes written into dst (or an error code) */
++static size_t ZSTD_writeEpilogue(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity)
++{
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *op = ostart;
++ size_t fhSize = 0;
++
++ if (cctx->stage == ZSTDcs_created)
++ return ERROR(stage_wrong); /* init missing */
++
++ /* special case : empty frame */
++ if (cctx->stage == ZSTDcs_init) {
++ fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
++ if (ZSTD_isError(fhSize))
++ return fhSize;
++ dstCapacity -= fhSize;
++ op += fhSize;
++ cctx->stage = ZSTDcs_ongoing;
++ }
++
++ if (cctx->stage != ZSTDcs_ending) {
++ /* write one last empty block, make it the "last" block */
++ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw) << 1) + 0;
++ if (dstCapacity < 4)
++ return ERROR(dstSize_tooSmall);
++ ZSTD_writeLE32(op, cBlockHeader24);
++ op += ZSTD_blockHeaderSize;
++ dstCapacity -= ZSTD_blockHeaderSize;
++ }
++
++ if (cctx->params.fParams.checksumFlag) {
++ U32 const checksum = (U32)xxh64_digest(&cctx->xxhState);
++ if (dstCapacity < 4)
++ return ERROR(dstSize_tooSmall);
++ ZSTD_writeLE32(op, checksum);
++ op += 4;
++ }
++
++ cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
++ return op - ostart;
++}
++
++size_t ZSTD_compressEnd(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ size_t endResult;
++ size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
++ if (ZSTD_isError(cSize))
++ return cSize;
++ endResult = ZSTD_writeEpilogue(cctx, (char *)dst + cSize, dstCapacity - cSize);
++ if (ZSTD_isError(endResult))
++ return endResult;
++ return cSize + endResult;
++}
++
++static size_t ZSTD_compress_internal(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize,
++ ZSTD_parameters params)
++{
++ CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
++ return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
++}
++
++size_t ZSTD_compress_usingDict(ZSTD_CCtx *ctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize,
++ ZSTD_parameters params)
++{
++ return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
++}
++
++size_t ZSTD_compressCCtx(ZSTD_CCtx *ctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, ZSTD_parameters params)
++{
++ return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, NULL, 0, params);
++}
++
++/* ===== Dictionary API ===== */
++
++struct ZSTD_CDict_s {
++ void *dictBuffer;
++ const void *dictContent;
++ size_t dictContentSize;
++ ZSTD_CCtx *refContext;
++}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
++
++size_t ZSTD_CDictWorkspaceBound(ZSTD_compressionParameters cParams) { return ZSTD_CCtxWorkspaceBound(cParams) + ZSTD_ALIGN(sizeof(ZSTD_CDict)); }
++
++static ZSTD_CDict *ZSTD_createCDict_advanced(const void *dictBuffer, size_t dictSize, unsigned byReference, ZSTD_parameters params, ZSTD_customMem customMem)
++{
++ if (!customMem.customAlloc || !customMem.customFree)
++ return NULL;
++
++ {
++ ZSTD_CDict *const cdict = (ZSTD_CDict *)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
++ ZSTD_CCtx *const cctx = ZSTD_createCCtx_advanced(customMem);
++
++ if (!cdict || !cctx) {
++ ZSTD_free(cdict, customMem);
++ ZSTD_freeCCtx(cctx);
++ return NULL;
++ }
++
++ if ((byReference) || (!dictBuffer) || (!dictSize)) {
++ cdict->dictBuffer = NULL;
++ cdict->dictContent = dictBuffer;
++ } else {
++ void *const internalBuffer = ZSTD_malloc(dictSize, customMem);
++ if (!internalBuffer) {
++ ZSTD_free(cctx, customMem);
++ ZSTD_free(cdict, customMem);
++ return NULL;
++ }
++ memcpy(internalBuffer, dictBuffer, dictSize);
++ cdict->dictBuffer = internalBuffer;
++ cdict->dictContent = internalBuffer;
++ }
++
++ {
++ size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
++ if (ZSTD_isError(errorCode)) {
++ ZSTD_free(cdict->dictBuffer, customMem);
++ ZSTD_free(cdict, customMem);
++ ZSTD_freeCCtx(cctx);
++ return NULL;
++ }
++ }
++
++ cdict->refContext = cctx;
++ cdict->dictContentSize = dictSize;
++ return cdict;
++ }
++}
++
++ZSTD_CDict *ZSTD_initCDict(const void *dict, size_t dictSize, ZSTD_parameters params, void *workspace, size_t workspaceSize)
++{
++ ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
++ return ZSTD_createCDict_advanced(dict, dictSize, 1, params, stackMem);
++}
++
++size_t ZSTD_freeCDict(ZSTD_CDict *cdict)
++{
++ if (cdict == NULL)
++ return 0; /* support free on NULL */
++ {
++ ZSTD_customMem const cMem = cdict->refContext->customMem;
++ ZSTD_freeCCtx(cdict->refContext);
++ ZSTD_free(cdict->dictBuffer, cMem);
++ ZSTD_free(cdict, cMem);
++ return 0;
++ }
++}
++
++static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict *cdict) { return ZSTD_getParamsFromCCtx(cdict->refContext); }
++
++size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx *cctx, const ZSTD_CDict *cdict, unsigned long long pledgedSrcSize)
++{
++ if (cdict->dictContentSize)
++ CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
++ else {
++ ZSTD_parameters params = cdict->refContext->params;
++ params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
++ CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, params, pledgedSrcSize));
++ }
++ return 0;
++}
++
++/*! ZSTD_compress_usingCDict() :
++* Compression using a digested Dictionary.
++* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
++* Note that compression level is decided during dictionary creation */
++size_t ZSTD_compress_usingCDict(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const ZSTD_CDict *cdict)
++{
++ CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
++
++ if (cdict->refContext->params.fParams.contentSizeFlag == 1) {
++ cctx->params.fParams.contentSizeFlag = 1;
++ cctx->frameContentSize = srcSize;
++ } else {
++ cctx->params.fParams.contentSizeFlag = 0;
++ }
++
++ return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
++}
++
++/* ******************************************************************
++* Streaming
++********************************************************************/
++
++typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
++
++struct ZSTD_CStream_s {
++ ZSTD_CCtx *cctx;
++ ZSTD_CDict *cdictLocal;
++ const ZSTD_CDict *cdict;
++ char *inBuff;
++ size_t inBuffSize;
++ size_t inToCompress;
++ size_t inBuffPos;
++ size_t inBuffTarget;
++ size_t blockSize;
++ char *outBuff;
++ size_t outBuffSize;
++ size_t outBuffContentSize;
++ size_t outBuffFlushedSize;
++ ZSTD_cStreamStage stage;
++ U32 checksum;
++ U32 frameEnded;
++ U64 pledgedSrcSize;
++ U64 inputProcessed;
++ ZSTD_parameters params;
++ ZSTD_customMem customMem;
++}; /* typedef'd to ZSTD_CStream within "zstd.h" */
++
++size_t ZSTD_CStreamWorkspaceBound(ZSTD_compressionParameters cParams)
++{
++ size_t const inBuffSize = (size_t)1 << cParams.windowLog;
++ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, inBuffSize);
++ size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
++
++ return ZSTD_CCtxWorkspaceBound(cParams) + ZSTD_ALIGN(sizeof(ZSTD_CStream)) + ZSTD_ALIGN(inBuffSize) + ZSTD_ALIGN(outBuffSize);
++}
++
++ZSTD_CStream *ZSTD_createCStream_advanced(ZSTD_customMem customMem)
++{
++ ZSTD_CStream *zcs;
++
++ if (!customMem.customAlloc || !customMem.customFree)
++ return NULL;
++
++ zcs = (ZSTD_CStream *)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
++ if (zcs == NULL)
++ return NULL;
++ memset(zcs, 0, sizeof(ZSTD_CStream));
++ memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
++ zcs->cctx = ZSTD_createCCtx_advanced(customMem);
++ if (zcs->cctx == NULL) {
++ ZSTD_freeCStream(zcs);
++ return NULL;
++ }
++ return zcs;
++}
++
++size_t ZSTD_freeCStream(ZSTD_CStream *zcs)
++{
++ if (zcs == NULL)
++ return 0; /* support free on NULL */
++ {
++ ZSTD_customMem const cMem = zcs->customMem;
++ ZSTD_freeCCtx(zcs->cctx);
++ zcs->cctx = NULL;
++ ZSTD_freeCDict(zcs->cdictLocal);
++ zcs->cdictLocal = NULL;
++ ZSTD_free(zcs->inBuff, cMem);
++ zcs->inBuff = NULL;
++ ZSTD_free(zcs->outBuff, cMem);
++ zcs->outBuff = NULL;
++ ZSTD_free(zcs, cMem);
++ return 0;
++ }
++}
++
++/*====== Initialization ======*/
++
++size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
++size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */; }
++
++static size_t ZSTD_resetCStream_internal(ZSTD_CStream *zcs, unsigned long long pledgedSrcSize)
++{
++ if (zcs->inBuffSize == 0)
++ return ERROR(stage_wrong); /* zcs has not been init at least once => can't reset */
++
++ if (zcs->cdict)
++ CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
++ else
++ CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
++
++ zcs->inToCompress = 0;
++ zcs->inBuffPos = 0;
++ zcs->inBuffTarget = zcs->blockSize;
++ zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
++ zcs->stage = zcss_load;
++ zcs->frameEnded = 0;
++ zcs->pledgedSrcSize = pledgedSrcSize;
++ zcs->inputProcessed = 0;
++ return 0; /* ready to go */
++}
++
++size_t ZSTD_resetCStream(ZSTD_CStream *zcs, unsigned long long pledgedSrcSize)
++{
++
++ zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
++
++ return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
++}
++
++static size_t ZSTD_initCStream_advanced(ZSTD_CStream *zcs, const void *dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize)
++{
++ /* allocate buffers */
++ {
++ size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
++ if (zcs->inBuffSize < neededInBuffSize) {
++ zcs->inBuffSize = neededInBuffSize;
++ ZSTD_free(zcs->inBuff, zcs->customMem);
++ zcs->inBuff = (char *)ZSTD_malloc(neededInBuffSize, zcs->customMem);
++ if (zcs->inBuff == NULL)
++ return ERROR(memory_allocation);
++ }
++ zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
++ }
++ if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize) + 1) {
++ zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize) + 1;
++ ZSTD_free(zcs->outBuff, zcs->customMem);
++ zcs->outBuff = (char *)ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
++ if (zcs->outBuff == NULL)
++ return ERROR(memory_allocation);
++ }
++
++ if (dict && dictSize >= 8) {
++ ZSTD_freeCDict(zcs->cdictLocal);
++ zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
++ if (zcs->cdictLocal == NULL)
++ return ERROR(memory_allocation);
++ zcs->cdict = zcs->cdictLocal;
++ } else
++ zcs->cdict = NULL;
++
++ zcs->checksum = params.fParams.checksumFlag > 0;
++ zcs->params = params;
++
++ return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
++}
++
++ZSTD_CStream *ZSTD_initCStream(ZSTD_parameters params, unsigned long long pledgedSrcSize, void *workspace, size_t workspaceSize)
++{
++ ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
++ ZSTD_CStream *const zcs = ZSTD_createCStream_advanced(stackMem);
++ if (zcs) {
++ size_t const code = ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
++ if (ZSTD_isError(code)) {
++ return NULL;
++ }
++ }
++ return zcs;
++}
++
++ZSTD_CStream *ZSTD_initCStream_usingCDict(const ZSTD_CDict *cdict, unsigned long long pledgedSrcSize, void *workspace, size_t workspaceSize)
++{
++ ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
++ ZSTD_CStream *const zcs = ZSTD_initCStream(params, pledgedSrcSize, workspace, workspaceSize);
++ if (zcs) {
++ zcs->cdict = cdict;
++ if (ZSTD_isError(ZSTD_resetCStream_internal(zcs, pledgedSrcSize))) {
++ return NULL;
++ }
++ }
++ return zcs;
++}
++
++/*====== Compression ======*/
++
++typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
++
++ZSTD_STATIC size_t ZSTD_limitCopy(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ size_t const length = MIN(dstCapacity, srcSize);
++ memcpy(dst, src, length);
++ return length;
++}
++
++static size_t ZSTD_compressStream_generic(ZSTD_CStream *zcs, void *dst, size_t *dstCapacityPtr, const void *src, size_t *srcSizePtr, ZSTD_flush_e const flush)
++{
++ U32 someMoreWork = 1;
++ const char *const istart = (const char *)src;
++ const char *const iend = istart + *srcSizePtr;
++ const char *ip = istart;
++ char *const ostart = (char *)dst;
++ char *const oend = ostart + *dstCapacityPtr;
++ char *op = ostart;
++
++ while (someMoreWork) {
++ switch (zcs->stage) {
++ case zcss_init:
++ return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
++
++ case zcss_load:
++ /* complete inBuffer */
++ {
++ size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
++ size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend - ip);
++ zcs->inBuffPos += loaded;
++ ip += loaded;
++ if ((zcs->inBuffPos == zcs->inToCompress) || (!flush && (toLoad != loaded))) {
++ someMoreWork = 0;
++ break; /* not enough input to get a full block : stop there, wait for more */
++ }
++ }
++ /* compress curr block (note : this stage cannot be stopped in the middle) */
++ {
++ void *cDst;
++ size_t cSize;
++ size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
++ size_t oSize = oend - op;
++ if (oSize >= ZSTD_compressBound(iSize))
++ cDst = op; /* compress directly into output buffer (avoid flush stage) */
++ else
++ cDst = zcs->outBuff, oSize = zcs->outBuffSize;
++ cSize = (flush == zsf_end) ? ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize)
++ : ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
++ if (ZSTD_isError(cSize))
++ return cSize;
++ if (flush == zsf_end)
++ zcs->frameEnded = 1;
++ /* prepare next block */
++ zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
++ if (zcs->inBuffTarget > zcs->inBuffSize)
++ zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
++ zcs->inToCompress = zcs->inBuffPos;
++ if (cDst == op) {
++ op += cSize;
++ break;
++ } /* no need to flush */
++ zcs->outBuffContentSize = cSize;
++ zcs->outBuffFlushedSize = 0;
++ zcs->stage = zcss_flush; /* pass-through to flush stage */
++ }
++
++ case zcss_flush: {
++ size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
++ size_t const flushed = ZSTD_limitCopy(op, oend - op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
++ op += flushed;
++ zcs->outBuffFlushedSize += flushed;
++ if (toFlush != flushed) {
++ someMoreWork = 0;
++ break;
++ } /* dst too small to store flushed data : stop there */
++ zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
++ zcs->stage = zcss_load;
++ break;
++ }
++
++ case zcss_final:
++ someMoreWork = 0; /* do nothing */
++ break;
++
++ default:
++ return ERROR(GENERIC); /* impossible */
++ }
++ }
++
++ *srcSizePtr = ip - istart;
++ *dstCapacityPtr = op - ostart;
++ zcs->inputProcessed += *srcSizePtr;
++ if (zcs->frameEnded)
++ return 0;
++ {
++ size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
++ if (hintInSize == 0)
++ hintInSize = zcs->blockSize;
++ return hintInSize;
++ }
++}
++
++size_t ZSTD_compressStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output, ZSTD_inBuffer *input)
++{
++ size_t sizeRead = input->size - input->pos;
++ size_t sizeWritten = output->size - output->pos;
++ size_t const result =
++ ZSTD_compressStream_generic(zcs, (char *)(output->dst) + output->pos, &sizeWritten, (const char *)(input->src) + input->pos, &sizeRead, zsf_gather);
++ input->pos += sizeRead;
++ output->pos += sizeWritten;
++ return result;
++}
++
++/*====== Finalize ======*/
++
++/*! ZSTD_flushStream() :
++* @return : amount of data remaining to flush */
++size_t ZSTD_flushStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output)
++{
++ size_t srcSize = 0;
++ size_t sizeWritten = output->size - output->pos;
++ size_t const result = ZSTD_compressStream_generic(zcs, (char *)(output->dst) + output->pos, &sizeWritten, &srcSize,
++ &srcSize, /* use a valid src address instead of NULL */
++ zsf_flush);
++ output->pos += sizeWritten;
++ if (ZSTD_isError(result))
++ return result;
++ return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
++}
++
++size_t ZSTD_endStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output)
++{
++ BYTE *const ostart = (BYTE *)(output->dst) + output->pos;
++ BYTE *const oend = (BYTE *)(output->dst) + output->size;
++ BYTE *op = ostart;
++
++ if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
++ return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
++
++ if (zcs->stage != zcss_final) {
++ /* flush whatever remains */
++ size_t srcSize = 0;
++ size_t sizeWritten = output->size - output->pos;
++ size_t const notEnded =
++ ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
++ size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
++ op += sizeWritten;
++ if (remainingToFlush) {
++ output->pos += sizeWritten;
++ return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
++ }
++ /* create epilogue */
++ zcs->stage = zcss_final;
++ zcs->outBuffContentSize = !notEnded ? 0 : ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL,
++ 0); /* write epilogue, including final empty block, into outBuff */
++ }
++
++ /* flush epilogue */
++ {
++ size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
++ size_t const flushed = ZSTD_limitCopy(op, oend - op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
++ op += flushed;
++ zcs->outBuffFlushedSize += flushed;
++ output->pos += op - ostart;
++ if (toFlush == flushed)
++ zcs->stage = zcss_init; /* end reached */
++ return toFlush - flushed;
++ }
++}
++
++/*-===== Pre-defined compression levels =====-*/
++
++#define ZSTD_DEFAULT_CLEVEL 1
++#define ZSTD_MAX_CLEVEL 22
++int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
++
++static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL + 1] = {
++ {
++ /* "default" */
++ /* W, C, H, S, L, TL, strat */
++ {18, 12, 12, 1, 7, 16, ZSTD_fast}, /* level 0 - never used */
++ {19, 13, 14, 1, 7, 16, ZSTD_fast}, /* level 1 */
++ {19, 15, 16, 1, 6, 16, ZSTD_fast}, /* level 2 */
++ {20, 16, 17, 1, 5, 16, ZSTD_dfast}, /* level 3.*/
++ {20, 18, 18, 1, 5, 16, ZSTD_dfast}, /* level 4.*/
++ {20, 15, 18, 3, 5, 16, ZSTD_greedy}, /* level 5 */
++ {21, 16, 19, 2, 5, 16, ZSTD_lazy}, /* level 6 */
++ {21, 17, 20, 3, 5, 16, ZSTD_lazy}, /* level 7 */
++ {21, 18, 20, 3, 5, 16, ZSTD_lazy2}, /* level 8 */
++ {21, 20, 20, 3, 5, 16, ZSTD_lazy2}, /* level 9 */
++ {21, 19, 21, 4, 5, 16, ZSTD_lazy2}, /* level 10 */
++ {22, 20, 22, 4, 5, 16, ZSTD_lazy2}, /* level 11 */
++ {22, 20, 22, 5, 5, 16, ZSTD_lazy2}, /* level 12 */
++ {22, 21, 22, 5, 5, 16, ZSTD_lazy2}, /* level 13 */
++ {22, 21, 22, 6, 5, 16, ZSTD_lazy2}, /* level 14 */
++ {22, 21, 21, 5, 5, 16, ZSTD_btlazy2}, /* level 15 */
++ {23, 22, 22, 5, 5, 16, ZSTD_btlazy2}, /* level 16 */
++ {23, 21, 22, 4, 5, 24, ZSTD_btopt}, /* level 17 */
++ {23, 23, 22, 6, 5, 32, ZSTD_btopt}, /* level 18 */
++ {23, 23, 22, 6, 3, 48, ZSTD_btopt}, /* level 19 */
++ {25, 25, 23, 7, 3, 64, ZSTD_btopt2}, /* level 20 */
++ {26, 26, 23, 7, 3, 256, ZSTD_btopt2}, /* level 21 */
++ {27, 27, 25, 9, 3, 512, ZSTD_btopt2}, /* level 22 */
++ },
++ {
++ /* for srcSize <= 256 KB */
++ /* W, C, H, S, L, T, strat */
++ {0, 0, 0, 0, 0, 0, ZSTD_fast}, /* level 0 - not used */
++ {18, 13, 14, 1, 6, 8, ZSTD_fast}, /* level 1 */
++ {18, 14, 13, 1, 5, 8, ZSTD_dfast}, /* level 2 */
++ {18, 16, 15, 1, 5, 8, ZSTD_dfast}, /* level 3 */
++ {18, 15, 17, 1, 5, 8, ZSTD_greedy}, /* level 4.*/
++ {18, 16, 17, 4, 5, 8, ZSTD_greedy}, /* level 5.*/
++ {18, 16, 17, 3, 5, 8, ZSTD_lazy}, /* level 6.*/
++ {18, 17, 17, 4, 4, 8, ZSTD_lazy}, /* level 7 */
++ {18, 17, 17, 4, 4, 8, ZSTD_lazy2}, /* level 8 */
++ {18, 17, 17, 5, 4, 8, ZSTD_lazy2}, /* level 9 */
++ {18, 17, 17, 6, 4, 8, ZSTD_lazy2}, /* level 10 */
++ {18, 18, 17, 6, 4, 8, ZSTD_lazy2}, /* level 11.*/
++ {18, 18, 17, 7, 4, 8, ZSTD_lazy2}, /* level 12.*/
++ {18, 19, 17, 6, 4, 8, ZSTD_btlazy2}, /* level 13 */
++ {18, 18, 18, 4, 4, 16, ZSTD_btopt}, /* level 14.*/
++ {18, 18, 18, 4, 3, 16, ZSTD_btopt}, /* level 15.*/
++ {18, 19, 18, 6, 3, 32, ZSTD_btopt}, /* level 16.*/
++ {18, 19, 18, 8, 3, 64, ZSTD_btopt}, /* level 17.*/
++ {18, 19, 18, 9, 3, 128, ZSTD_btopt}, /* level 18.*/
++ {18, 19, 18, 10, 3, 256, ZSTD_btopt}, /* level 19.*/
++ {18, 19, 18, 11, 3, 512, ZSTD_btopt2}, /* level 20.*/
++ {18, 19, 18, 12, 3, 512, ZSTD_btopt2}, /* level 21.*/
++ {18, 19, 18, 13, 3, 512, ZSTD_btopt2}, /* level 22.*/
++ },
++ {
++ /* for srcSize <= 128 KB */
++ /* W, C, H, S, L, T, strat */
++ {17, 12, 12, 1, 7, 8, ZSTD_fast}, /* level 0 - not used */
++ {17, 12, 13, 1, 6, 8, ZSTD_fast}, /* level 1 */
++ {17, 13, 16, 1, 5, 8, ZSTD_fast}, /* level 2 */
++ {17, 16, 16, 2, 5, 8, ZSTD_dfast}, /* level 3 */
++ {17, 13, 15, 3, 4, 8, ZSTD_greedy}, /* level 4 */
++ {17, 15, 17, 4, 4, 8, ZSTD_greedy}, /* level 5 */
++ {17, 16, 17, 3, 4, 8, ZSTD_lazy}, /* level 6 */
++ {17, 15, 17, 4, 4, 8, ZSTD_lazy2}, /* level 7 */
++ {17, 17, 17, 4, 4, 8, ZSTD_lazy2}, /* level 8 */
++ {17, 17, 17, 5, 4, 8, ZSTD_lazy2}, /* level 9 */
++ {17, 17, 17, 6, 4, 8, ZSTD_lazy2}, /* level 10 */
++ {17, 17, 17, 7, 4, 8, ZSTD_lazy2}, /* level 11 */
++ {17, 17, 17, 8, 4, 8, ZSTD_lazy2}, /* level 12 */
++ {17, 18, 17, 6, 4, 8, ZSTD_btlazy2}, /* level 13.*/
++ {17, 17, 17, 7, 3, 8, ZSTD_btopt}, /* level 14.*/
++ {17, 17, 17, 7, 3, 16, ZSTD_btopt}, /* level 15.*/
++ {17, 18, 17, 7, 3, 32, ZSTD_btopt}, /* level 16.*/
++ {17, 18, 17, 7, 3, 64, ZSTD_btopt}, /* level 17.*/
++ {17, 18, 17, 7, 3, 256, ZSTD_btopt}, /* level 18.*/
++ {17, 18, 17, 8, 3, 256, ZSTD_btopt}, /* level 19.*/
++ {17, 18, 17, 9, 3, 256, ZSTD_btopt2}, /* level 20.*/
++ {17, 18, 17, 10, 3, 256, ZSTD_btopt2}, /* level 21.*/
++ {17, 18, 17, 11, 3, 512, ZSTD_btopt2}, /* level 22.*/
++ },
++ {
++ /* for srcSize <= 16 KB */
++ /* W, C, H, S, L, T, strat */
++ {14, 12, 12, 1, 7, 6, ZSTD_fast}, /* level 0 - not used */
++ {14, 14, 14, 1, 6, 6, ZSTD_fast}, /* level 1 */
++ {14, 14, 14, 1, 4, 6, ZSTD_fast}, /* level 2 */
++ {14, 14, 14, 1, 4, 6, ZSTD_dfast}, /* level 3.*/
++ {14, 14, 14, 4, 4, 6, ZSTD_greedy}, /* level 4.*/
++ {14, 14, 14, 3, 4, 6, ZSTD_lazy}, /* level 5.*/
++ {14, 14, 14, 4, 4, 6, ZSTD_lazy2}, /* level 6 */
++ {14, 14, 14, 5, 4, 6, ZSTD_lazy2}, /* level 7 */
++ {14, 14, 14, 6, 4, 6, ZSTD_lazy2}, /* level 8.*/
++ {14, 15, 14, 6, 4, 6, ZSTD_btlazy2}, /* level 9.*/
++ {14, 15, 14, 3, 3, 6, ZSTD_btopt}, /* level 10.*/
++ {14, 15, 14, 6, 3, 8, ZSTD_btopt}, /* level 11.*/
++ {14, 15, 14, 6, 3, 16, ZSTD_btopt}, /* level 12.*/
++ {14, 15, 14, 6, 3, 24, ZSTD_btopt}, /* level 13.*/
++ {14, 15, 15, 6, 3, 48, ZSTD_btopt}, /* level 14.*/
++ {14, 15, 15, 6, 3, 64, ZSTD_btopt}, /* level 15.*/
++ {14, 15, 15, 6, 3, 96, ZSTD_btopt}, /* level 16.*/
++ {14, 15, 15, 6, 3, 128, ZSTD_btopt}, /* level 17.*/
++ {14, 15, 15, 6, 3, 256, ZSTD_btopt}, /* level 18.*/
++ {14, 15, 15, 7, 3, 256, ZSTD_btopt}, /* level 19.*/
++ {14, 15, 15, 8, 3, 256, ZSTD_btopt2}, /* level 20.*/
++ {14, 15, 15, 9, 3, 256, ZSTD_btopt2}, /* level 21.*/
++ {14, 15, 15, 10, 3, 256, ZSTD_btopt2}, /* level 22.*/
++ },
++};
++
++/*! ZSTD_getCParams() :
++* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
++* Size values are optional, provide 0 if not known or unused */
++ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
++{
++ ZSTD_compressionParameters cp;
++ size_t const addedSize = srcSize ? 0 : 500;
++ U64 const rSize = srcSize + dictSize ? srcSize + dictSize + addedSize : (U64)-1;
++ U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
++ if (compressionLevel <= 0)
++ compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
++ if (compressionLevel > ZSTD_MAX_CLEVEL)
++ compressionLevel = ZSTD_MAX_CLEVEL;
++ cp = ZSTD_defaultCParameters[tableID][compressionLevel];
++ if (ZSTD_32bits()) { /* auto-correction, for 32-bits mode */
++ if (cp.windowLog > ZSTD_WINDOWLOG_MAX)
++ cp.windowLog = ZSTD_WINDOWLOG_MAX;
++ if (cp.chainLog > ZSTD_CHAINLOG_MAX)
++ cp.chainLog = ZSTD_CHAINLOG_MAX;
++ if (cp.hashLog > ZSTD_HASHLOG_MAX)
++ cp.hashLog = ZSTD_HASHLOG_MAX;
++ }
++ cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
++ return cp;
++}
++
++/*! ZSTD_getParams() :
++* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
++* All fields of `ZSTD_frameParameters` are set to default (0) */
++ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
++{
++ ZSTD_parameters params;
++ ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
++ memset(¶ms, 0, sizeof(params));
++ params.cParams = cParams;
++ return params;
++}
++
++EXPORT_SYMBOL(ZSTD_maxCLevel);
++EXPORT_SYMBOL(ZSTD_compressBound);
++
++EXPORT_SYMBOL(ZSTD_CCtxWorkspaceBound);
++EXPORT_SYMBOL(ZSTD_initCCtx);
++EXPORT_SYMBOL(ZSTD_compressCCtx);
++EXPORT_SYMBOL(ZSTD_compress_usingDict);
++
++EXPORT_SYMBOL(ZSTD_CDictWorkspaceBound);
++EXPORT_SYMBOL(ZSTD_initCDict);
++EXPORT_SYMBOL(ZSTD_compress_usingCDict);
++
++EXPORT_SYMBOL(ZSTD_CStreamWorkspaceBound);
++EXPORT_SYMBOL(ZSTD_initCStream);
++EXPORT_SYMBOL(ZSTD_initCStream_usingCDict);
++EXPORT_SYMBOL(ZSTD_resetCStream);
++EXPORT_SYMBOL(ZSTD_compressStream);
++EXPORT_SYMBOL(ZSTD_flushStream);
++EXPORT_SYMBOL(ZSTD_endStream);
++EXPORT_SYMBOL(ZSTD_CStreamInSize);
++EXPORT_SYMBOL(ZSTD_CStreamOutSize);
++
++EXPORT_SYMBOL(ZSTD_getCParams);
++EXPORT_SYMBOL(ZSTD_getParams);
++EXPORT_SYMBOL(ZSTD_checkCParams);
++EXPORT_SYMBOL(ZSTD_adjustCParams);
++
++EXPORT_SYMBOL(ZSTD_compressBegin);
++EXPORT_SYMBOL(ZSTD_compressBegin_usingDict);
++EXPORT_SYMBOL(ZSTD_compressBegin_advanced);
++EXPORT_SYMBOL(ZSTD_copyCCtx);
++EXPORT_SYMBOL(ZSTD_compressBegin_usingCDict);
++EXPORT_SYMBOL(ZSTD_compressContinue);
++EXPORT_SYMBOL(ZSTD_compressEnd);
++
++EXPORT_SYMBOL(ZSTD_getBlockSizeMax);
++EXPORT_SYMBOL(ZSTD_compressBlock);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("Zstd Compressor");
+diff --git a/lib/zstd/decompress.c b/lib/zstd/decompress.c
+new file mode 100644
+index 0000000..62449ae
+--- /dev/null
++++ b/lib/zstd/decompress.c
+@@ -0,0 +1,2526 @@
++/**
++ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This source code is licensed under the BSD-style license found in the
++ * LICENSE file in the root directory of https://github.com/facebook/zstd.
++ * An additional grant of patent rights can be found in the PATENTS file in the
++ * same directory.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ */
++
++/* ***************************************************************
++* Tuning parameters
++*****************************************************************/
++/*!
++* MAXWINDOWSIZE_DEFAULT :
++* maximum window size accepted by DStream, by default.
++* Frames requiring more memory will be rejected.
++*/
++#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
++#define ZSTD_MAXWINDOWSIZE_DEFAULT ((1 << ZSTD_WINDOWLOG_MAX) + 1) /* defined within zstd.h */
++#endif
++
++/*-*******************************************************
++* Dependencies
++*********************************************************/
++#include "fse.h"
++#include "huf.h"
++#include "mem.h" /* low level memory routines */
++#include "zstd_internal.h"
++#include
++#include
++#include /* memcpy, memmove, memset */
++
++#define ZSTD_PREFETCH(ptr) __builtin_prefetch(ptr, 0, 0)
++
++/*-*************************************
++* Macros
++***************************************/
++#define ZSTD_isError ERR_isError /* for inlining */
++#define FSE_isError ERR_isError
++#define HUF_isError ERR_isError
++
++/*_*******************************************************
++* Memory operations
++**********************************************************/
++static void ZSTD_copy4(void *dst, const void *src) { memcpy(dst, src, 4); }
++
++/*-*************************************************************
++* Context management
++***************************************************************/
++typedef enum {
++ ZSTDds_getFrameHeaderSize,
++ ZSTDds_decodeFrameHeader,
++ ZSTDds_decodeBlockHeader,
++ ZSTDds_decompressBlock,
++ ZSTDds_decompressLastBlock,
++ ZSTDds_checkChecksum,
++ ZSTDds_decodeSkippableHeader,
++ ZSTDds_skipFrame
++} ZSTD_dStage;
++
++typedef struct {
++ FSE_DTable LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)];
++ FSE_DTable OFTable[FSE_DTABLE_SIZE_U32(OffFSELog)];
++ FSE_DTable MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)];
++ HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
++ U64 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32 / 2];
++ U32 rep[ZSTD_REP_NUM];
++} ZSTD_entropyTables_t;
++
++struct ZSTD_DCtx_s {
++ const FSE_DTable *LLTptr;
++ const FSE_DTable *MLTptr;
++ const FSE_DTable *OFTptr;
++ const HUF_DTable *HUFptr;
++ ZSTD_entropyTables_t entropy;
++ const void *previousDstEnd; /* detect continuity */
++ const void *base; /* start of curr segment */
++ const void *vBase; /* virtual start of previous segment if it was just before curr one */
++ const void *dictEnd; /* end of previous segment */
++ size_t expected;
++ ZSTD_frameParams fParams;
++ blockType_e bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */
++ ZSTD_dStage stage;
++ U32 litEntropy;
++ U32 fseEntropy;
++ struct xxh64_state xxhState;
++ size_t headerSize;
++ U32 dictID;
++ const BYTE *litPtr;
++ ZSTD_customMem customMem;
++ size_t litSize;
++ size_t rleSize;
++ BYTE litBuffer[ZSTD_BLOCKSIZE_ABSOLUTEMAX + WILDCOPY_OVERLENGTH];
++ BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
++}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
++
++size_t ZSTD_DCtxWorkspaceBound(void) { return ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_DCtx)); }
++
++size_t ZSTD_decompressBegin(ZSTD_DCtx *dctx)
++{
++ dctx->expected = ZSTD_frameHeaderSize_prefix;
++ dctx->stage = ZSTDds_getFrameHeaderSize;
++ dctx->previousDstEnd = NULL;
++ dctx->base = NULL;
++ dctx->vBase = NULL;
++ dctx->dictEnd = NULL;
++ dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
++ dctx->litEntropy = dctx->fseEntropy = 0;
++ dctx->dictID = 0;
++ ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
++ memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
++ dctx->LLTptr = dctx->entropy.LLTable;
++ dctx->MLTptr = dctx->entropy.MLTable;
++ dctx->OFTptr = dctx->entropy.OFTable;
++ dctx->HUFptr = dctx->entropy.hufTable;
++ return 0;
++}
++
++ZSTD_DCtx *ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
++{
++ ZSTD_DCtx *dctx;
++
++ if (!customMem.customAlloc || !customMem.customFree)
++ return NULL;
++
++ dctx = (ZSTD_DCtx *)ZSTD_malloc(sizeof(ZSTD_DCtx), customMem);
++ if (!dctx)
++ return NULL;
++ memcpy(&dctx->customMem, &customMem, sizeof(customMem));
++ ZSTD_decompressBegin(dctx);
++ return dctx;
++}
++
++ZSTD_DCtx *ZSTD_initDCtx(void *workspace, size_t workspaceSize)
++{
++ ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
++ return ZSTD_createDCtx_advanced(stackMem);
++}
++
++size_t ZSTD_freeDCtx(ZSTD_DCtx *dctx)
++{
++ if (dctx == NULL)
++ return 0; /* support free on NULL */
++ ZSTD_free(dctx, dctx->customMem);
++ return 0; /* reserved as a potential error code in the future */
++}
++
++void ZSTD_copyDCtx(ZSTD_DCtx *dstDCtx, const ZSTD_DCtx *srcDCtx)
++{
++ size_t const workSpaceSize = (ZSTD_BLOCKSIZE_ABSOLUTEMAX + WILDCOPY_OVERLENGTH) + ZSTD_frameHeaderSize_max;
++ memcpy(dstDCtx, srcDCtx, sizeof(ZSTD_DCtx) - workSpaceSize); /* no need to copy workspace */
++}
++
++static void ZSTD_refDDict(ZSTD_DCtx *dstDCtx, const ZSTD_DDict *ddict);
++
++/*-*************************************************************
++* Decompression section
++***************************************************************/
++
++/*! ZSTD_isFrame() :
++ * Tells if the content of `buffer` starts with a valid Frame Identifier.
++ * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
++ * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
++ * Note 3 : Skippable Frame Identifiers are considered valid. */
++unsigned ZSTD_isFrame(const void *buffer, size_t size)
++{
++ if (size < 4)
++ return 0;
++ {
++ U32 const magic = ZSTD_readLE32(buffer);
++ if (magic == ZSTD_MAGICNUMBER)
++ return 1;
++ if ((magic & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START)
++ return 1;
++ }
++ return 0;
++}
++
++/** ZSTD_frameHeaderSize() :
++* srcSize must be >= ZSTD_frameHeaderSize_prefix.
++* @return : size of the Frame Header */
++static size_t ZSTD_frameHeaderSize(const void *src, size_t srcSize)
++{
++ if (srcSize < ZSTD_frameHeaderSize_prefix)
++ return ERROR(srcSize_wrong);
++ {
++ BYTE const fhd = ((const BYTE *)src)[4];
++ U32 const dictID = fhd & 3;
++ U32 const singleSegment = (fhd >> 5) & 1;
++ U32 const fcsId = fhd >> 6;
++ return ZSTD_frameHeaderSize_prefix + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + (singleSegment && !fcsId);
++ }
++}
++
++/** ZSTD_getFrameParams() :
++* decode Frame Header, or require larger `srcSize`.
++* @return : 0, `fparamsPtr` is correctly filled,
++* >0, `srcSize` is too small, result is expected `srcSize`,
++* or an error code, which can be tested using ZSTD_isError() */
++size_t ZSTD_getFrameParams(ZSTD_frameParams *fparamsPtr, const void *src, size_t srcSize)
++{
++ const BYTE *ip = (const BYTE *)src;
++
++ if (srcSize < ZSTD_frameHeaderSize_prefix)
++ return ZSTD_frameHeaderSize_prefix;
++ if (ZSTD_readLE32(src) != ZSTD_MAGICNUMBER) {
++ if ((ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
++ if (srcSize < ZSTD_skippableHeaderSize)
++ return ZSTD_skippableHeaderSize; /* magic number + skippable frame length */
++ memset(fparamsPtr, 0, sizeof(*fparamsPtr));
++ fparamsPtr->frameContentSize = ZSTD_readLE32((const char *)src + 4);
++ fparamsPtr->windowSize = 0; /* windowSize==0 means a frame is skippable */
++ return 0;
++ }
++ return ERROR(prefix_unknown);
++ }
++
++ /* ensure there is enough `srcSize` to fully read/decode frame header */
++ {
++ size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize);
++ if (srcSize < fhsize)
++ return fhsize;
++ }
++
++ {
++ BYTE const fhdByte = ip[4];
++ size_t pos = 5;
++ U32 const dictIDSizeCode = fhdByte & 3;
++ U32 const checksumFlag = (fhdByte >> 2) & 1;
++ U32 const singleSegment = (fhdByte >> 5) & 1;
++ U32 const fcsID = fhdByte >> 6;
++ U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX;
++ U32 windowSize = 0;
++ U32 dictID = 0;
++ U64 frameContentSize = 0;
++ if ((fhdByte & 0x08) != 0)
++ return ERROR(frameParameter_unsupported); /* reserved bits, which must be zero */
++ if (!singleSegment) {
++ BYTE const wlByte = ip[pos++];
++ U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
++ if (windowLog > ZSTD_WINDOWLOG_MAX)
++ return ERROR(frameParameter_windowTooLarge); /* avoids issue with 1 << windowLog */
++ windowSize = (1U << windowLog);
++ windowSize += (windowSize >> 3) * (wlByte & 7);
++ }
++
++ switch (dictIDSizeCode) {
++ default: /* impossible */
++ case 0: break;
++ case 1:
++ dictID = ip[pos];
++ pos++;
++ break;
++ case 2:
++ dictID = ZSTD_readLE16(ip + pos);
++ pos += 2;
++ break;
++ case 3:
++ dictID = ZSTD_readLE32(ip + pos);
++ pos += 4;
++ break;
++ }
++ switch (fcsID) {
++ default: /* impossible */
++ case 0:
++ if (singleSegment)
++ frameContentSize = ip[pos];
++ break;
++ case 1: frameContentSize = ZSTD_readLE16(ip + pos) + 256; break;
++ case 2: frameContentSize = ZSTD_readLE32(ip + pos); break;
++ case 3: frameContentSize = ZSTD_readLE64(ip + pos); break;
++ }
++ if (!windowSize)
++ windowSize = (U32)frameContentSize;
++ if (windowSize > windowSizeMax)
++ return ERROR(frameParameter_windowTooLarge);
++ fparamsPtr->frameContentSize = frameContentSize;
++ fparamsPtr->windowSize = windowSize;
++ fparamsPtr->dictID = dictID;
++ fparamsPtr->checksumFlag = checksumFlag;
++ }
++ return 0;
++}
++
++/** ZSTD_getFrameContentSize() :
++* compatible with legacy mode
++* @return : decompressed size of the single frame pointed to be `src` if known, otherwise
++* - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
++* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
++unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
++{
++ {
++ ZSTD_frameParams fParams;
++ if (ZSTD_getFrameParams(&fParams, src, srcSize) != 0)
++ return ZSTD_CONTENTSIZE_ERROR;
++ if (fParams.windowSize == 0) {
++ /* Either skippable or empty frame, size == 0 either way */
++ return 0;
++ } else if (fParams.frameContentSize != 0) {
++ return fParams.frameContentSize;
++ } else {
++ return ZSTD_CONTENTSIZE_UNKNOWN;
++ }
++ }
++}
++
++/** ZSTD_findDecompressedSize() :
++ * compatible with legacy mode
++ * `srcSize` must be the exact length of some number of ZSTD compressed and/or
++ * skippable frames
++ * @return : decompressed size of the frames contained */
++unsigned long long ZSTD_findDecompressedSize(const void *src, size_t srcSize)
++{
++ {
++ unsigned long long totalDstSize = 0;
++ while (srcSize >= ZSTD_frameHeaderSize_prefix) {
++ const U32 magicNumber = ZSTD_readLE32(src);
++
++ if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
++ size_t skippableSize;
++ if (srcSize < ZSTD_skippableHeaderSize)
++ return ERROR(srcSize_wrong);
++ skippableSize = ZSTD_readLE32((const BYTE *)src + 4) + ZSTD_skippableHeaderSize;
++ if (srcSize < skippableSize) {
++ return ZSTD_CONTENTSIZE_ERROR;
++ }
++
++ src = (const BYTE *)src + skippableSize;
++ srcSize -= skippableSize;
++ continue;
++ }
++
++ {
++ unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
++ if (ret >= ZSTD_CONTENTSIZE_ERROR)
++ return ret;
++
++ /* check for overflow */
++ if (totalDstSize + ret < totalDstSize)
++ return ZSTD_CONTENTSIZE_ERROR;
++ totalDstSize += ret;
++ }
++ {
++ size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
++ if (ZSTD_isError(frameSrcSize)) {
++ return ZSTD_CONTENTSIZE_ERROR;
++ }
++
++ src = (const BYTE *)src + frameSrcSize;
++ srcSize -= frameSrcSize;
++ }
++ }
++
++ if (srcSize) {
++ return ZSTD_CONTENTSIZE_ERROR;
++ }
++
++ return totalDstSize;
++ }
++}
++
++/** ZSTD_decodeFrameHeader() :
++* `headerSize` must be the size provided by ZSTD_frameHeaderSize().
++* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
++static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx *dctx, const void *src, size_t headerSize)
++{
++ size_t const result = ZSTD_getFrameParams(&(dctx->fParams), src, headerSize);
++ if (ZSTD_isError(result))
++ return result; /* invalid header */
++ if (result > 0)
++ return ERROR(srcSize_wrong); /* headerSize too small */
++ if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
++ return ERROR(dictionary_wrong);
++ if (dctx->fParams.checksumFlag)
++ xxh64_reset(&dctx->xxhState, 0);
++ return 0;
++}
++
++typedef struct {
++ blockType_e blockType;
++ U32 lastBlock;
++ U32 origSize;
++} blockProperties_t;
++
++/*! ZSTD_getcBlockSize() :
++* Provides the size of compressed block from block header `src` */
++size_t ZSTD_getcBlockSize(const void *src, size_t srcSize, blockProperties_t *bpPtr)
++{
++ if (srcSize < ZSTD_blockHeaderSize)
++ return ERROR(srcSize_wrong);
++ {
++ U32 const cBlockHeader = ZSTD_readLE24(src);
++ U32 const cSize = cBlockHeader >> 3;
++ bpPtr->lastBlock = cBlockHeader & 1;
++ bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3);
++ bpPtr->origSize = cSize; /* only useful for RLE */
++ if (bpPtr->blockType == bt_rle)
++ return 1;
++ if (bpPtr->blockType == bt_reserved)
++ return ERROR(corruption_detected);
++ return cSize;
++ }
++}
++
++static size_t ZSTD_copyRawBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ if (srcSize > dstCapacity)
++ return ERROR(dstSize_tooSmall);
++ memcpy(dst, src, srcSize);
++ return srcSize;
++}
++
++static size_t ZSTD_setRleBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize, size_t regenSize)
++{
++ if (srcSize != 1)
++ return ERROR(srcSize_wrong);
++ if (regenSize > dstCapacity)
++ return ERROR(dstSize_tooSmall);
++ memset(dst, *(const BYTE *)src, regenSize);
++ return regenSize;
++}
++
++/*! ZSTD_decodeLiteralsBlock() :
++ @return : nb of bytes read from src (< srcSize ) */
++size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx *dctx, const void *src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
++{
++ if (srcSize < MIN_CBLOCK_SIZE)
++ return ERROR(corruption_detected);
++
++ {
++ const BYTE *const istart = (const BYTE *)src;
++ symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3);
++
++ switch (litEncType) {
++ case set_repeat:
++ if (dctx->litEntropy == 0)
++ return ERROR(dictionary_corrupted);
++ /* fall-through */
++ case set_compressed:
++ if (srcSize < 5)
++ return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
++ {
++ size_t lhSize, litSize, litCSize;
++ U32 singleStream = 0;
++ U32 const lhlCode = (istart[0] >> 2) & 3;
++ U32 const lhc = ZSTD_readLE32(istart);
++ switch (lhlCode) {
++ case 0:
++ case 1:
++ default: /* note : default is impossible, since lhlCode into [0..3] */
++ /* 2 - 2 - 10 - 10 */
++ singleStream = !lhlCode;
++ lhSize = 3;
++ litSize = (lhc >> 4) & 0x3FF;
++ litCSize = (lhc >> 14) & 0x3FF;
++ break;
++ case 2:
++ /* 2 - 2 - 14 - 14 */
++ lhSize = 4;
++ litSize = (lhc >> 4) & 0x3FFF;
++ litCSize = lhc >> 18;
++ break;
++ case 3:
++ /* 2 - 2 - 18 - 18 */
++ lhSize = 5;
++ litSize = (lhc >> 4) & 0x3FFFF;
++ litCSize = (lhc >> 22) + (istart[4] << 10);
++ break;
++ }
++ if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX)
++ return ERROR(corruption_detected);
++ if (litCSize + lhSize > srcSize)
++ return ERROR(corruption_detected);
++
++ if (HUF_isError(
++ (litEncType == set_repeat)
++ ? (singleStream ? HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart + lhSize, litCSize, dctx->HUFptr)
++ : HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart + lhSize, litCSize, dctx->HUFptr))
++ : (singleStream
++ ? HUF_decompress1X2_DCtx_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart + lhSize, litCSize,
++ dctx->entropy.workspace, sizeof(dctx->entropy.workspace))
++ : HUF_decompress4X_hufOnly_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart + lhSize, litCSize,
++ dctx->entropy.workspace, sizeof(dctx->entropy.workspace)))))
++ return ERROR(corruption_detected);
++
++ dctx->litPtr = dctx->litBuffer;
++ dctx->litSize = litSize;
++ dctx->litEntropy = 1;
++ if (litEncType == set_compressed)
++ dctx->HUFptr = dctx->entropy.hufTable;
++ memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
++ return litCSize + lhSize;
++ }
++
++ case set_basic: {
++ size_t litSize, lhSize;
++ U32 const lhlCode = ((istart[0]) >> 2) & 3;
++ switch (lhlCode) {
++ case 0:
++ case 2:
++ default: /* note : default is impossible, since lhlCode into [0..3] */
++ lhSize = 1;
++ litSize = istart[0] >> 3;
++ break;
++ case 1:
++ lhSize = 2;
++ litSize = ZSTD_readLE16(istart) >> 4;
++ break;
++ case 3:
++ lhSize = 3;
++ litSize = ZSTD_readLE24(istart) >> 4;
++ break;
++ }
++
++ if (lhSize + litSize + WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */
++ if (litSize + lhSize > srcSize)
++ return ERROR(corruption_detected);
++ memcpy(dctx->litBuffer, istart + lhSize, litSize);
++ dctx->litPtr = dctx->litBuffer;
++ dctx->litSize = litSize;
++ memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
++ return lhSize + litSize;
++ }
++ /* direct reference into compressed stream */
++ dctx->litPtr = istart + lhSize;
++ dctx->litSize = litSize;
++ return lhSize + litSize;
++ }
++
++ case set_rle: {
++ U32 const lhlCode = ((istart[0]) >> 2) & 3;
++ size_t litSize, lhSize;
++ switch (lhlCode) {
++ case 0:
++ case 2:
++ default: /* note : default is impossible, since lhlCode into [0..3] */
++ lhSize = 1;
++ litSize = istart[0] >> 3;
++ break;
++ case 1:
++ lhSize = 2;
++ litSize = ZSTD_readLE16(istart) >> 4;
++ break;
++ case 3:
++ lhSize = 3;
++ litSize = ZSTD_readLE24(istart) >> 4;
++ if (srcSize < 4)
++ return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */
++ break;
++ }
++ if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX)
++ return ERROR(corruption_detected);
++ memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
++ dctx->litPtr = dctx->litBuffer;
++ dctx->litSize = litSize;
++ return lhSize + 1;
++ }
++ default:
++ return ERROR(corruption_detected); /* impossible */
++ }
++ }
++}
++
++typedef union {
++ FSE_decode_t realData;
++ U32 alignedBy4;
++} FSE_decode_t4;
++
++static const FSE_decode_t4 LL_defaultDTable[(1 << LL_DEFAULTNORMLOG) + 1] = {
++ {{LL_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */
++ {{0, 0, 4}}, /* 0 : base, symbol, bits */
++ {{16, 0, 4}},
++ {{32, 1, 5}},
++ {{0, 3, 5}},
++ {{0, 4, 5}},
++ {{0, 6, 5}},
++ {{0, 7, 5}},
++ {{0, 9, 5}},
++ {{0, 10, 5}},
++ {{0, 12, 5}},
++ {{0, 14, 6}},
++ {{0, 16, 5}},
++ {{0, 18, 5}},
++ {{0, 19, 5}},
++ {{0, 21, 5}},
++ {{0, 22, 5}},
++ {{0, 24, 5}},
++ {{32, 25, 5}},
++ {{0, 26, 5}},
++ {{0, 27, 6}},
++ {{0, 29, 6}},
++ {{0, 31, 6}},
++ {{32, 0, 4}},
++ {{0, 1, 4}},
++ {{0, 2, 5}},
++ {{32, 4, 5}},
++ {{0, 5, 5}},
++ {{32, 7, 5}},
++ {{0, 8, 5}},
++ {{32, 10, 5}},
++ {{0, 11, 5}},
++ {{0, 13, 6}},
++ {{32, 16, 5}},
++ {{0, 17, 5}},
++ {{32, 19, 5}},
++ {{0, 20, 5}},
++ {{32, 22, 5}},
++ {{0, 23, 5}},
++ {{0, 25, 4}},
++ {{16, 25, 4}},
++ {{32, 26, 5}},
++ {{0, 28, 6}},
++ {{0, 30, 6}},
++ {{48, 0, 4}},
++ {{16, 1, 4}},
++ {{32, 2, 5}},
++ {{32, 3, 5}},
++ {{32, 5, 5}},
++ {{32, 6, 5}},
++ {{32, 8, 5}},
++ {{32, 9, 5}},
++ {{32, 11, 5}},
++ {{32, 12, 5}},
++ {{0, 15, 6}},
++ {{32, 17, 5}},
++ {{32, 18, 5}},
++ {{32, 20, 5}},
++ {{32, 21, 5}},
++ {{32, 23, 5}},
++ {{32, 24, 5}},
++ {{0, 35, 6}},
++ {{0, 34, 6}},
++ {{0, 33, 6}},
++ {{0, 32, 6}},
++}; /* LL_defaultDTable */
++
++static const FSE_decode_t4 ML_defaultDTable[(1 << ML_DEFAULTNORMLOG) + 1] = {
++ {{ML_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */
++ {{0, 0, 6}}, /* 0 : base, symbol, bits */
++ {{0, 1, 4}},
++ {{32, 2, 5}},
++ {{0, 3, 5}},
++ {{0, 5, 5}},
++ {{0, 6, 5}},
++ {{0, 8, 5}},
++ {{0, 10, 6}},
++ {{0, 13, 6}},
++ {{0, 16, 6}},
++ {{0, 19, 6}},
++ {{0, 22, 6}},
++ {{0, 25, 6}},
++ {{0, 28, 6}},
++ {{0, 31, 6}},
++ {{0, 33, 6}},
++ {{0, 35, 6}},
++ {{0, 37, 6}},
++ {{0, 39, 6}},
++ {{0, 41, 6}},
++ {{0, 43, 6}},
++ {{0, 45, 6}},
++ {{16, 1, 4}},
++ {{0, 2, 4}},
++ {{32, 3, 5}},
++ {{0, 4, 5}},
++ {{32, 6, 5}},
++ {{0, 7, 5}},
++ {{0, 9, 6}},
++ {{0, 12, 6}},
++ {{0, 15, 6}},
++ {{0, 18, 6}},
++ {{0, 21, 6}},
++ {{0, 24, 6}},
++ {{0, 27, 6}},
++ {{0, 30, 6}},
++ {{0, 32, 6}},
++ {{0, 34, 6}},
++ {{0, 36, 6}},
++ {{0, 38, 6}},
++ {{0, 40, 6}},
++ {{0, 42, 6}},
++ {{0, 44, 6}},
++ {{32, 1, 4}},
++ {{48, 1, 4}},
++ {{16, 2, 4}},
++ {{32, 4, 5}},
++ {{32, 5, 5}},
++ {{32, 7, 5}},
++ {{32, 8, 5}},
++ {{0, 11, 6}},
++ {{0, 14, 6}},
++ {{0, 17, 6}},
++ {{0, 20, 6}},
++ {{0, 23, 6}},
++ {{0, 26, 6}},
++ {{0, 29, 6}},
++ {{0, 52, 6}},
++ {{0, 51, 6}},
++ {{0, 50, 6}},
++ {{0, 49, 6}},
++ {{0, 48, 6}},
++ {{0, 47, 6}},
++ {{0, 46, 6}},
++}; /* ML_defaultDTable */
++
++static const FSE_decode_t4 OF_defaultDTable[(1 << OF_DEFAULTNORMLOG) + 1] = {
++ {{OF_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */
++ {{0, 0, 5}}, /* 0 : base, symbol, bits */
++ {{0, 6, 4}},
++ {{0, 9, 5}},
++ {{0, 15, 5}},
++ {{0, 21, 5}},
++ {{0, 3, 5}},
++ {{0, 7, 4}},
++ {{0, 12, 5}},
++ {{0, 18, 5}},
++ {{0, 23, 5}},
++ {{0, 5, 5}},
++ {{0, 8, 4}},
++ {{0, 14, 5}},
++ {{0, 20, 5}},
++ {{0, 2, 5}},
++ {{16, 7, 4}},
++ {{0, 11, 5}},
++ {{0, 17, 5}},
++ {{0, 22, 5}},
++ {{0, 4, 5}},
++ {{16, 8, 4}},
++ {{0, 13, 5}},
++ {{0, 19, 5}},
++ {{0, 1, 5}},
++ {{16, 6, 4}},
++ {{0, 10, 5}},
++ {{0, 16, 5}},
++ {{0, 28, 5}},
++ {{0, 27, 5}},
++ {{0, 26, 5}},
++ {{0, 25, 5}},
++ {{0, 24, 5}},
++}; /* OF_defaultDTable */
++
++/*! ZSTD_buildSeqTable() :
++ @return : nb bytes read from src,
++ or an error code if it fails, testable with ZSTD_isError()
++*/
++static size_t ZSTD_buildSeqTable(FSE_DTable *DTableSpace, const FSE_DTable **DTablePtr, symbolEncodingType_e type, U32 max, U32 maxLog, const void *src,
++ size_t srcSize, const FSE_decode_t4 *defaultTable, U32 flagRepeatTable, void *workspace, size_t workspaceSize)
++{
++ const void *const tmpPtr = defaultTable; /* bypass strict aliasing */
++ switch (type) {
++ case set_rle:
++ if (!srcSize)
++ return ERROR(srcSize_wrong);
++ if ((*(const BYTE *)src) > max)
++ return ERROR(corruption_detected);
++ FSE_buildDTable_rle(DTableSpace, *(const BYTE *)src);
++ *DTablePtr = DTableSpace;
++ return 1;
++ case set_basic: *DTablePtr = (const FSE_DTable *)tmpPtr; return 0;
++ case set_repeat:
++ if (!flagRepeatTable)
++ return ERROR(corruption_detected);
++ return 0;
++ default: /* impossible */
++ case set_compressed: {
++ U32 tableLog;
++ S16 *norm = (S16 *)workspace;
++ size_t const spaceUsed32 = ALIGN(sizeof(S16) * (MaxSeq + 1), sizeof(U32)) >> 2;
++
++ if ((spaceUsed32 << 2) > workspaceSize)
++ return ERROR(GENERIC);
++ workspace = (U32 *)workspace + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++ {
++ size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
++ if (FSE_isError(headerSize))
++ return ERROR(corruption_detected);
++ if (tableLog > maxLog)
++ return ERROR(corruption_detected);
++ FSE_buildDTable_wksp(DTableSpace, norm, max, tableLog, workspace, workspaceSize);
++ *DTablePtr = DTableSpace;
++ return headerSize;
++ }
++ }
++ }
++}
++
++size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx *dctx, int *nbSeqPtr, const void *src, size_t srcSize)
++{
++ const BYTE *const istart = (const BYTE *const)src;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *ip = istart;
++
++ /* check */
++ if (srcSize < MIN_SEQUENCES_SIZE)
++ return ERROR(srcSize_wrong);
++
++ /* SeqHead */
++ {
++ int nbSeq = *ip++;
++ if (!nbSeq) {
++ *nbSeqPtr = 0;
++ return 1;
++ }
++ if (nbSeq > 0x7F) {
++ if (nbSeq == 0xFF) {
++ if (ip + 2 > iend)
++ return ERROR(srcSize_wrong);
++ nbSeq = ZSTD_readLE16(ip) + LONGNBSEQ, ip += 2;
++ } else {
++ if (ip >= iend)
++ return ERROR(srcSize_wrong);
++ nbSeq = ((nbSeq - 0x80) << 8) + *ip++;
++ }
++ }
++ *nbSeqPtr = nbSeq;
++ }
++
++ /* FSE table descriptors */
++ if (ip + 4 > iend)
++ return ERROR(srcSize_wrong); /* minimum possible size */
++ {
++ symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6);
++ symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3);
++ symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3);
++ ip++;
++
++ /* Build DTables */
++ {
++ size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, LLtype, MaxLL, LLFSELog, ip, iend - ip,
++ LL_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace));
++ if (ZSTD_isError(llhSize))
++ return ERROR(corruption_detected);
++ ip += llhSize;
++ }
++ {
++ size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, OFtype, MaxOff, OffFSELog, ip, iend - ip,
++ OF_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace));
++ if (ZSTD_isError(ofhSize))
++ return ERROR(corruption_detected);
++ ip += ofhSize;
++ }
++ {
++ size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, MLtype, MaxML, MLFSELog, ip, iend - ip,
++ ML_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace));
++ if (ZSTD_isError(mlhSize))
++ return ERROR(corruption_detected);
++ ip += mlhSize;
++ }
++ }
++
++ return ip - istart;
++}
++
++typedef struct {
++ size_t litLength;
++ size_t matchLength;
++ size_t offset;
++ const BYTE *match;
++} seq_t;
++
++typedef struct {
++ BIT_DStream_t DStream;
++ FSE_DState_t stateLL;
++ FSE_DState_t stateOffb;
++ FSE_DState_t stateML;
++ size_t prevOffset[ZSTD_REP_NUM];
++ const BYTE *base;
++ size_t pos;
++ uPtrDiff gotoDict;
++} seqState_t;
++
++FORCE_NOINLINE
++size_t ZSTD_execSequenceLast7(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
++ const BYTE *const vBase, const BYTE *const dictEnd)
++{
++ BYTE *const oLitEnd = op + sequence.litLength;
++ size_t const sequenceLength = sequence.litLength + sequence.matchLength;
++ BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
++ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
++ const BYTE *const iLitEnd = *litPtr + sequence.litLength;
++ const BYTE *match = oLitEnd - sequence.offset;
++
++ /* check */
++ if (oMatchEnd > oend)
++ return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
++ if (iLitEnd > litLimit)
++ return ERROR(corruption_detected); /* over-read beyond lit buffer */
++ if (oLitEnd <= oend_w)
++ return ERROR(GENERIC); /* Precondition */
++
++ /* copy literals */
++ if (op < oend_w) {
++ ZSTD_wildcopy(op, *litPtr, oend_w - op);
++ *litPtr += oend_w - op;
++ op = oend_w;
++ }
++ while (op < oLitEnd)
++ *op++ = *(*litPtr)++;
++
++ /* copy Match */
++ if (sequence.offset > (size_t)(oLitEnd - base)) {
++ /* offset beyond prefix */
++ if (sequence.offset > (size_t)(oLitEnd - vBase))
++ return ERROR(corruption_detected);
++ match = dictEnd - (base - match);
++ if (match + sequence.matchLength <= dictEnd) {
++ memmove(oLitEnd, match, sequence.matchLength);
++ return sequenceLength;
++ }
++ /* span extDict & currPrefixSegment */
++ {
++ size_t const length1 = dictEnd - match;
++ memmove(oLitEnd, match, length1);
++ op = oLitEnd + length1;
++ sequence.matchLength -= length1;
++ match = base;
++ }
++ }
++ while (op < oMatchEnd)
++ *op++ = *match++;
++ return sequenceLength;
++}
++
++static seq_t ZSTD_decodeSequence(seqState_t *seqState)
++{
++ seq_t seq;
++
++ U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
++ U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
++ U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */
++
++ U32 const llBits = LL_bits[llCode];
++ U32 const mlBits = ML_bits[mlCode];
++ U32 const ofBits = ofCode;
++ U32 const totalBits = llBits + mlBits + ofBits;
++
++ static const U32 LL_base[MaxLL + 1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18,
++ 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000};
++
++ static const U32 ML_base[MaxML + 1] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
++ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41,
++ 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003};
++
++ static const U32 OF_base[MaxOff + 1] = {0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD,
++ 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD,
++ 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD};
++
++ /* sequence */
++ {
++ size_t offset;
++ if (!ofCode)
++ offset = 0;
++ else {
++ offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
++ if (ZSTD_32bits())
++ BIT_reloadDStream(&seqState->DStream);
++ }
++
++ if (ofCode <= 1) {
++ offset += (llCode == 0);
++ if (offset) {
++ size_t temp = (offset == 3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
++ temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
++ if (offset != 1)
++ seqState->prevOffset[2] = seqState->prevOffset[1];
++ seqState->prevOffset[1] = seqState->prevOffset[0];
++ seqState->prevOffset[0] = offset = temp;
++ } else {
++ offset = seqState->prevOffset[0];
++ }
++ } else {
++ seqState->prevOffset[2] = seqState->prevOffset[1];
++ seqState->prevOffset[1] = seqState->prevOffset[0];
++ seqState->prevOffset[0] = offset;
++ }
++ seq.offset = offset;
++ }
++
++ seq.matchLength = ML_base[mlCode] + ((mlCode > 31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
++ if (ZSTD_32bits() && (mlBits + llBits > 24))
++ BIT_reloadDStream(&seqState->DStream);
++
++ seq.litLength = LL_base[llCode] + ((llCode > 15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
++ if (ZSTD_32bits() || (totalBits > 64 - 7 - (LLFSELog + MLFSELog + OffFSELog)))
++ BIT_reloadDStream(&seqState->DStream);
++
++ /* ANS state update */
++ FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
++ FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
++ if (ZSTD_32bits())
++ BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
++ FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
++
++ return seq;
++}
++
++FORCE_INLINE
++size_t ZSTD_execSequence(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
++ const BYTE *const vBase, const BYTE *const dictEnd)
++{
++ BYTE *const oLitEnd = op + sequence.litLength;
++ size_t const sequenceLength = sequence.litLength + sequence.matchLength;
++ BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
++ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
++ const BYTE *const iLitEnd = *litPtr + sequence.litLength;
++ const BYTE *match = oLitEnd - sequence.offset;
++
++ /* check */
++ if (oMatchEnd > oend)
++ return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
++ if (iLitEnd > litLimit)
++ return ERROR(corruption_detected); /* over-read beyond lit buffer */
++ if (oLitEnd > oend_w)
++ return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
++
++ /* copy Literals */
++ ZSTD_copy8(op, *litPtr);
++ if (sequence.litLength > 8)
++ ZSTD_wildcopy(op + 8, (*litPtr) + 8,
++ sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
++ op = oLitEnd;
++ *litPtr = iLitEnd; /* update for next sequence */
++
++ /* copy Match */
++ if (sequence.offset > (size_t)(oLitEnd - base)) {
++ /* offset beyond prefix */
++ if (sequence.offset > (size_t)(oLitEnd - vBase))
++ return ERROR(corruption_detected);
++ match = dictEnd + (match - base);
++ if (match + sequence.matchLength <= dictEnd) {
++ memmove(oLitEnd, match, sequence.matchLength);
++ return sequenceLength;
++ }
++ /* span extDict & currPrefixSegment */
++ {
++ size_t const length1 = dictEnd - match;
++ memmove(oLitEnd, match, length1);
++ op = oLitEnd + length1;
++ sequence.matchLength -= length1;
++ match = base;
++ if (op > oend_w || sequence.matchLength < MINMATCH) {
++ U32 i;
++ for (i = 0; i < sequence.matchLength; ++i)
++ op[i] = match[i];
++ return sequenceLength;
++ }
++ }
++ }
++ /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
++
++ /* match within prefix */
++ if (sequence.offset < 8) {
++ /* close range match, overlap */
++ static const U32 dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; /* added */
++ static const int dec64table[] = {8, 8, 8, 7, 8, 9, 10, 11}; /* subtracted */
++ int const sub2 = dec64table[sequence.offset];
++ op[0] = match[0];
++ op[1] = match[1];
++ op[2] = match[2];
++ op[3] = match[3];
++ match += dec32table[sequence.offset];
++ ZSTD_copy4(op + 4, match);
++ match -= sub2;
++ } else {
++ ZSTD_copy8(op, match);
++ }
++ op += 8;
++ match += 8;
++
++ if (oMatchEnd > oend - (16 - MINMATCH)) {
++ if (op < oend_w) {
++ ZSTD_wildcopy(op, match, oend_w - op);
++ match += oend_w - op;
++ op = oend_w;
++ }
++ while (op < oMatchEnd)
++ *op++ = *match++;
++ } else {
++ ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8); /* works even if matchLength < 8 */
++ }
++ return sequenceLength;
++}
++
++static size_t ZSTD_decompressSequences(ZSTD_DCtx *dctx, void *dst, size_t maxDstSize, const void *seqStart, size_t seqSize)
++{
++ const BYTE *ip = (const BYTE *)seqStart;
++ const BYTE *const iend = ip + seqSize;
++ BYTE *const ostart = (BYTE * const)dst;
++ BYTE *const oend = ostart + maxDstSize;
++ BYTE *op = ostart;
++ const BYTE *litPtr = dctx->litPtr;
++ const BYTE *const litEnd = litPtr + dctx->litSize;
++ const BYTE *const base = (const BYTE *)(dctx->base);
++ const BYTE *const vBase = (const BYTE *)(dctx->vBase);
++ const BYTE *const dictEnd = (const BYTE *)(dctx->dictEnd);
++ int nbSeq;
++
++ /* Build Decoding Tables */
++ {
++ size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
++ if (ZSTD_isError(seqHSize))
++ return seqHSize;
++ ip += seqHSize;
++ }
++
++ /* Regen sequences */
++ if (nbSeq) {
++ seqState_t seqState;
++ dctx->fseEntropy = 1;
++ {
++ U32 i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ seqState.prevOffset[i] = dctx->entropy.rep[i];
++ }
++ CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend - ip), corruption_detected);
++ FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
++ FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
++ FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
++
++ for (; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq;) {
++ nbSeq--;
++ {
++ seq_t const sequence = ZSTD_decodeSequence(&seqState);
++ size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
++ if (ZSTD_isError(oneSeqSize))
++ return oneSeqSize;
++ op += oneSeqSize;
++ }
++ }
++
++ /* check if reached exact end */
++ if (nbSeq)
++ return ERROR(corruption_detected);
++ /* save reps for next block */
++ {
++ U32 i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]);
++ }
++ }
++
++ /* last literal segment */
++ {
++ size_t const lastLLSize = litEnd - litPtr;
++ if (lastLLSize > (size_t)(oend - op))
++ return ERROR(dstSize_tooSmall);
++ memcpy(op, litPtr, lastLLSize);
++ op += lastLLSize;
++ }
++
++ return op - ostart;
++}
++
++FORCE_INLINE seq_t ZSTD_decodeSequenceLong_generic(seqState_t *seqState, int const longOffsets)
++{
++ seq_t seq;
++
++ U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
++ U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
++ U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */
++
++ U32 const llBits = LL_bits[llCode];
++ U32 const mlBits = ML_bits[mlCode];
++ U32 const ofBits = ofCode;
++ U32 const totalBits = llBits + mlBits + ofBits;
++
++ static const U32 LL_base[MaxLL + 1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18,
++ 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000};
++
++ static const U32 ML_base[MaxML + 1] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
++ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41,
++ 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003};
++
++ static const U32 OF_base[MaxOff + 1] = {0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD,
++ 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD,
++ 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD};
++
++ /* sequence */
++ {
++ size_t offset;
++ if (!ofCode)
++ offset = 0;
++ else {
++ if (longOffsets) {
++ int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN);
++ offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
++ if (ZSTD_32bits() || extraBits)
++ BIT_reloadDStream(&seqState->DStream);
++ if (extraBits)
++ offset += BIT_readBitsFast(&seqState->DStream, extraBits);
++ } else {
++ offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
++ if (ZSTD_32bits())
++ BIT_reloadDStream(&seqState->DStream);
++ }
++ }
++
++ if (ofCode <= 1) {
++ offset += (llCode == 0);
++ if (offset) {
++ size_t temp = (offset == 3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
++ temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
++ if (offset != 1)
++ seqState->prevOffset[2] = seqState->prevOffset[1];
++ seqState->prevOffset[1] = seqState->prevOffset[0];
++ seqState->prevOffset[0] = offset = temp;
++ } else {
++ offset = seqState->prevOffset[0];
++ }
++ } else {
++ seqState->prevOffset[2] = seqState->prevOffset[1];
++ seqState->prevOffset[1] = seqState->prevOffset[0];
++ seqState->prevOffset[0] = offset;
++ }
++ seq.offset = offset;
++ }
++
++ seq.matchLength = ML_base[mlCode] + ((mlCode > 31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
++ if (ZSTD_32bits() && (mlBits + llBits > 24))
++ BIT_reloadDStream(&seqState->DStream);
++
++ seq.litLength = LL_base[llCode] + ((llCode > 15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
++ if (ZSTD_32bits() || (totalBits > 64 - 7 - (LLFSELog + MLFSELog + OffFSELog)))
++ BIT_reloadDStream(&seqState->DStream);
++
++ {
++ size_t const pos = seqState->pos + seq.litLength;
++ seq.match = seqState->base + pos - seq.offset; /* single memory segment */
++ if (seq.offset > pos)
++ seq.match += seqState->gotoDict; /* separate memory segment */
++ seqState->pos = pos + seq.matchLength;
++ }
++
++ /* ANS state update */
++ FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
++ FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
++ if (ZSTD_32bits())
++ BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
++ FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
++
++ return seq;
++}
++
++static seq_t ZSTD_decodeSequenceLong(seqState_t *seqState, unsigned const windowSize)
++{
++ if (ZSTD_highbit32(windowSize) > STREAM_ACCUMULATOR_MIN) {
++ return ZSTD_decodeSequenceLong_generic(seqState, 1);
++ } else {
++ return ZSTD_decodeSequenceLong_generic(seqState, 0);
++ }
++}
++
++FORCE_INLINE
++size_t ZSTD_execSequenceLong(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
++ const BYTE *const vBase, const BYTE *const dictEnd)
++{
++ BYTE *const oLitEnd = op + sequence.litLength;
++ size_t const sequenceLength = sequence.litLength + sequence.matchLength;
++ BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
++ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
++ const BYTE *const iLitEnd = *litPtr + sequence.litLength;
++ const BYTE *match = sequence.match;
++
++ /* check */
++ if (oMatchEnd > oend)
++ return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
++ if (iLitEnd > litLimit)
++ return ERROR(corruption_detected); /* over-read beyond lit buffer */
++ if (oLitEnd > oend_w)
++ return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
++
++ /* copy Literals */
++ ZSTD_copy8(op, *litPtr);
++ if (sequence.litLength > 8)
++ ZSTD_wildcopy(op + 8, (*litPtr) + 8,
++ sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
++ op = oLitEnd;
++ *litPtr = iLitEnd; /* update for next sequence */
++
++ /* copy Match */
++ if (sequence.offset > (size_t)(oLitEnd - base)) {
++ /* offset beyond prefix */
++ if (sequence.offset > (size_t)(oLitEnd - vBase))
++ return ERROR(corruption_detected);
++ if (match + sequence.matchLength <= dictEnd) {
++ memmove(oLitEnd, match, sequence.matchLength);
++ return sequenceLength;
++ }
++ /* span extDict & currPrefixSegment */
++ {
++ size_t const length1 = dictEnd - match;
++ memmove(oLitEnd, match, length1);
++ op = oLitEnd + length1;
++ sequence.matchLength -= length1;
++ match = base;
++ if (op > oend_w || sequence.matchLength < MINMATCH) {
++ U32 i;
++ for (i = 0; i < sequence.matchLength; ++i)
++ op[i] = match[i];
++ return sequenceLength;
++ }
++ }
++ }
++ /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
++
++ /* match within prefix */
++ if (sequence.offset < 8) {
++ /* close range match, overlap */
++ static const U32 dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; /* added */
++ static const int dec64table[] = {8, 8, 8, 7, 8, 9, 10, 11}; /* subtracted */
++ int const sub2 = dec64table[sequence.offset];
++ op[0] = match[0];
++ op[1] = match[1];
++ op[2] = match[2];
++ op[3] = match[3];
++ match += dec32table[sequence.offset];
++ ZSTD_copy4(op + 4, match);
++ match -= sub2;
++ } else {
++ ZSTD_copy8(op, match);
++ }
++ op += 8;
++ match += 8;
++
++ if (oMatchEnd > oend - (16 - MINMATCH)) {
++ if (op < oend_w) {
++ ZSTD_wildcopy(op, match, oend_w - op);
++ match += oend_w - op;
++ op = oend_w;
++ }
++ while (op < oMatchEnd)
++ *op++ = *match++;
++ } else {
++ ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8); /* works even if matchLength < 8 */
++ }
++ return sequenceLength;
++}
++
++static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx *dctx, void *dst, size_t maxDstSize, const void *seqStart, size_t seqSize)
++{
++ const BYTE *ip = (const BYTE *)seqStart;
++ const BYTE *const iend = ip + seqSize;
++ BYTE *const ostart = (BYTE * const)dst;
++ BYTE *const oend = ostart + maxDstSize;
++ BYTE *op = ostart;
++ const BYTE *litPtr = dctx->litPtr;
++ const BYTE *const litEnd = litPtr + dctx->litSize;
++ const BYTE *const base = (const BYTE *)(dctx->base);
++ const BYTE *const vBase = (const BYTE *)(dctx->vBase);
++ const BYTE *const dictEnd = (const BYTE *)(dctx->dictEnd);
++ unsigned const windowSize = dctx->fParams.windowSize;
++ int nbSeq;
++
++ /* Build Decoding Tables */
++ {
++ size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
++ if (ZSTD_isError(seqHSize))
++ return seqHSize;
++ ip += seqHSize;
++ }
++
++ /* Regen sequences */
++ if (nbSeq) {
++#define STORED_SEQS 4
++#define STOSEQ_MASK (STORED_SEQS - 1)
++#define ADVANCED_SEQS 4
++ seq_t *sequences = (seq_t *)dctx->entropy.workspace;
++ int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
++ seqState_t seqState;
++ int seqNb;
++ ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.workspace) >= sizeof(seq_t) * STORED_SEQS);
++ dctx->fseEntropy = 1;
++ {
++ U32 i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ seqState.prevOffset[i] = dctx->entropy.rep[i];
++ }
++ seqState.base = base;
++ seqState.pos = (size_t)(op - base);
++ seqState.gotoDict = (uPtrDiff)dictEnd - (uPtrDiff)base; /* cast to avoid undefined behaviour */
++ CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend - ip), corruption_detected);
++ FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
++ FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
++ FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
++
++ /* prepare in advance */
++ for (seqNb = 0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && seqNb < seqAdvance; seqNb++) {
++ sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, windowSize);
++ }
++ if (seqNb < seqAdvance)
++ return ERROR(corruption_detected);
++
++ /* decode and decompress */
++ for (; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && seqNb < nbSeq; seqNb++) {
++ seq_t const sequence = ZSTD_decodeSequenceLong(&seqState, windowSize);
++ size_t const oneSeqSize =
++ ZSTD_execSequenceLong(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd);
++ if (ZSTD_isError(oneSeqSize))
++ return oneSeqSize;
++ ZSTD_PREFETCH(sequence.match);
++ sequences[seqNb & STOSEQ_MASK] = sequence;
++ op += oneSeqSize;
++ }
++ if (seqNb < nbSeq)
++ return ERROR(corruption_detected);
++
++ /* finish queue */
++ seqNb -= seqAdvance;
++ for (; seqNb < nbSeq; seqNb++) {
++ size_t const oneSeqSize = ZSTD_execSequenceLong(op, oend, sequences[seqNb & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd);
++ if (ZSTD_isError(oneSeqSize))
++ return oneSeqSize;
++ op += oneSeqSize;
++ }
++
++ /* save reps for next block */
++ {
++ U32 i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]);
++ }
++ }
++
++ /* last literal segment */
++ {
++ size_t const lastLLSize = litEnd - litPtr;
++ if (lastLLSize > (size_t)(oend - op))
++ return ERROR(dstSize_tooSmall);
++ memcpy(op, litPtr, lastLLSize);
++ op += lastLLSize;
++ }
++
++ return op - ostart;
++}
++
++static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{ /* blockType == blockCompressed */
++ const BYTE *ip = (const BYTE *)src;
++
++ if (srcSize >= ZSTD_BLOCKSIZE_ABSOLUTEMAX)
++ return ERROR(srcSize_wrong);
++
++ /* Decode literals section */
++ {
++ size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
++ if (ZSTD_isError(litCSize))
++ return litCSize;
++ ip += litCSize;
++ srcSize -= litCSize;
++ }
++ if (sizeof(size_t) > 4) /* do not enable prefetching on 32-bits x86, as it's performance detrimental */
++ /* likely because of register pressure */
++ /* if that's the correct cause, then 32-bits ARM should be affected differently */
++ /* it would be good to test this on ARM real hardware, to see if prefetch version improves speed */
++ if (dctx->fParams.windowSize > (1 << 23))
++ return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize);
++ return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize);
++}
++
++static void ZSTD_checkContinuity(ZSTD_DCtx *dctx, const void *dst)
++{
++ if (dst != dctx->previousDstEnd) { /* not contiguous */
++ dctx->dictEnd = dctx->previousDstEnd;
++ dctx->vBase = (const char *)dst - ((const char *)(dctx->previousDstEnd) - (const char *)(dctx->base));
++ dctx->base = dst;
++ dctx->previousDstEnd = dst;
++ }
++}
++
++size_t ZSTD_decompressBlock(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ size_t dSize;
++ ZSTD_checkContinuity(dctx, dst);
++ dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize);
++ dctx->previousDstEnd = (char *)dst + dSize;
++ return dSize;
++}
++
++/** ZSTD_insertBlock() :
++ insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
++size_t ZSTD_insertBlock(ZSTD_DCtx *dctx, const void *blockStart, size_t blockSize)
++{
++ ZSTD_checkContinuity(dctx, blockStart);
++ dctx->previousDstEnd = (const char *)blockStart + blockSize;
++ return blockSize;
++}
++
++size_t ZSTD_generateNxBytes(void *dst, size_t dstCapacity, BYTE byte, size_t length)
++{
++ if (length > dstCapacity)
++ return ERROR(dstSize_tooSmall);
++ memset(dst, byte, length);
++ return length;
++}
++
++/** ZSTD_findFrameCompressedSize() :
++ * compatible with legacy mode
++ * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
++ * `srcSize` must be at least as large as the frame contained
++ * @return : the compressed size of the frame starting at `src` */
++size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
++{
++ if (srcSize >= ZSTD_skippableHeaderSize && (ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
++ return ZSTD_skippableHeaderSize + ZSTD_readLE32((const BYTE *)src + 4);
++ } else {
++ const BYTE *ip = (const BYTE *)src;
++ const BYTE *const ipstart = ip;
++ size_t remainingSize = srcSize;
++ ZSTD_frameParams fParams;
++
++ size_t const headerSize = ZSTD_frameHeaderSize(ip, remainingSize);
++ if (ZSTD_isError(headerSize))
++ return headerSize;
++
++ /* Frame Header */
++ {
++ size_t const ret = ZSTD_getFrameParams(&fParams, ip, remainingSize);
++ if (ZSTD_isError(ret))
++ return ret;
++ if (ret > 0)
++ return ERROR(srcSize_wrong);
++ }
++
++ ip += headerSize;
++ remainingSize -= headerSize;
++
++ /* Loop on each block */
++ while (1) {
++ blockProperties_t blockProperties;
++ size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
++ if (ZSTD_isError(cBlockSize))
++ return cBlockSize;
++
++ if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
++ return ERROR(srcSize_wrong);
++
++ ip += ZSTD_blockHeaderSize + cBlockSize;
++ remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
++
++ if (blockProperties.lastBlock)
++ break;
++ }
++
++ if (fParams.checksumFlag) { /* Frame content checksum */
++ if (remainingSize < 4)
++ return ERROR(srcSize_wrong);
++ ip += 4;
++ remainingSize -= 4;
++ }
++
++ return ip - ipstart;
++ }
++}
++
++/*! ZSTD_decompressFrame() :
++* @dctx must be properly initialized */
++static size_t ZSTD_decompressFrame(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void **srcPtr, size_t *srcSizePtr)
++{
++ const BYTE *ip = (const BYTE *)(*srcPtr);
++ BYTE *const ostart = (BYTE * const)dst;
++ BYTE *const oend = ostart + dstCapacity;
++ BYTE *op = ostart;
++ size_t remainingSize = *srcSizePtr;
++
++ /* check */
++ if (remainingSize < ZSTD_frameHeaderSize_min + ZSTD_blockHeaderSize)
++ return ERROR(srcSize_wrong);
++
++ /* Frame Header */
++ {
++ size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_frameHeaderSize_prefix);
++ if (ZSTD_isError(frameHeaderSize))
++ return frameHeaderSize;
++ if (remainingSize < frameHeaderSize + ZSTD_blockHeaderSize)
++ return ERROR(srcSize_wrong);
++ CHECK_F(ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize));
++ ip += frameHeaderSize;
++ remainingSize -= frameHeaderSize;
++ }
++
++ /* Loop on each block */
++ while (1) {
++ size_t decodedSize;
++ blockProperties_t blockProperties;
++ size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
++ if (ZSTD_isError(cBlockSize))
++ return cBlockSize;
++
++ ip += ZSTD_blockHeaderSize;
++ remainingSize -= ZSTD_blockHeaderSize;
++ if (cBlockSize > remainingSize)
++ return ERROR(srcSize_wrong);
++
++ switch (blockProperties.blockType) {
++ case bt_compressed: decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend - op, ip, cBlockSize); break;
++ case bt_raw: decodedSize = ZSTD_copyRawBlock(op, oend - op, ip, cBlockSize); break;
++ case bt_rle: decodedSize = ZSTD_generateNxBytes(op, oend - op, *ip, blockProperties.origSize); break;
++ case bt_reserved:
++ default: return ERROR(corruption_detected);
++ }
++
++ if (ZSTD_isError(decodedSize))
++ return decodedSize;
++ if (dctx->fParams.checksumFlag)
++ xxh64_update(&dctx->xxhState, op, decodedSize);
++ op += decodedSize;
++ ip += cBlockSize;
++ remainingSize -= cBlockSize;
++ if (blockProperties.lastBlock)
++ break;
++ }
++
++ if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
++ U32 const checkCalc = (U32)xxh64_digest(&dctx->xxhState);
++ U32 checkRead;
++ if (remainingSize < 4)
++ return ERROR(checksum_wrong);
++ checkRead = ZSTD_readLE32(ip);
++ if (checkRead != checkCalc)
++ return ERROR(checksum_wrong);
++ ip += 4;
++ remainingSize -= 4;
++ }
++
++ /* Allow caller to get size read */
++ *srcPtr = ip;
++ *srcSizePtr = remainingSize;
++ return op - ostart;
++}
++
++static const void *ZSTD_DDictDictContent(const ZSTD_DDict *ddict);
++static size_t ZSTD_DDictDictSize(const ZSTD_DDict *ddict);
++
++static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize,
++ const ZSTD_DDict *ddict)
++{
++ void *const dststart = dst;
++
++ if (ddict) {
++ if (dict) {
++ /* programmer error, these two cases should be mutually exclusive */
++ return ERROR(GENERIC);
++ }
++
++ dict = ZSTD_DDictDictContent(ddict);
++ dictSize = ZSTD_DDictDictSize(ddict);
++ }
++
++ while (srcSize >= ZSTD_frameHeaderSize_prefix) {
++ U32 magicNumber;
++
++ magicNumber = ZSTD_readLE32(src);
++ if (magicNumber != ZSTD_MAGICNUMBER) {
++ if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
++ size_t skippableSize;
++ if (srcSize < ZSTD_skippableHeaderSize)
++ return ERROR(srcSize_wrong);
++ skippableSize = ZSTD_readLE32((const BYTE *)src + 4) + ZSTD_skippableHeaderSize;
++ if (srcSize < skippableSize) {
++ return ERROR(srcSize_wrong);
++ }
++
++ src = (const BYTE *)src + skippableSize;
++ srcSize -= skippableSize;
++ continue;
++ } else {
++ return ERROR(prefix_unknown);
++ }
++ }
++
++ if (ddict) {
++ /* we were called from ZSTD_decompress_usingDDict */
++ ZSTD_refDDict(dctx, ddict);
++ } else {
++ /* this will initialize correctly with no dict if dict == NULL, so
++ * use this in all cases but ddict */
++ CHECK_F(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize));
++ }
++ ZSTD_checkContinuity(dctx, dst);
++
++ {
++ const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, &src, &srcSize);
++ if (ZSTD_isError(res))
++ return res;
++ /* don't need to bounds check this, ZSTD_decompressFrame will have
++ * already */
++ dst = (BYTE *)dst + res;
++ dstCapacity -= res;
++ }
++ }
++
++ if (srcSize)
++ return ERROR(srcSize_wrong); /* input not entirely consumed */
++
++ return (BYTE *)dst - (BYTE *)dststart;
++}
++
++size_t ZSTD_decompress_usingDict(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize)
++{
++ return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);
++}
++
++size_t ZSTD_decompressDCtx(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ return ZSTD_decompress_usingDict(dctx, dst, dstCapacity, src, srcSize, NULL, 0);
++}
++
++/*-**************************************
++* Advanced Streaming Decompression API
++* Bufferless and synchronous
++****************************************/
++size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx *dctx) { return dctx->expected; }
++
++ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx *dctx)
++{
++ switch (dctx->stage) {
++ default: /* should not happen */
++ case ZSTDds_getFrameHeaderSize:
++ case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader;
++ case ZSTDds_decodeBlockHeader: return ZSTDnit_blockHeader;
++ case ZSTDds_decompressBlock: return ZSTDnit_block;
++ case ZSTDds_decompressLastBlock: return ZSTDnit_lastBlock;
++ case ZSTDds_checkChecksum: return ZSTDnit_checksum;
++ case ZSTDds_decodeSkippableHeader:
++ case ZSTDds_skipFrame: return ZSTDnit_skippableFrame;
++ }
++}
++
++int ZSTD_isSkipFrame(ZSTD_DCtx *dctx) { return dctx->stage == ZSTDds_skipFrame; } /* for zbuff */
++
++/** ZSTD_decompressContinue() :
++* @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
++* or an error code, which can be tested using ZSTD_isError() */
++size_t ZSTD_decompressContinue(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ /* Sanity check */
++ if (srcSize != dctx->expected)
++ return ERROR(srcSize_wrong);
++ if (dstCapacity)
++ ZSTD_checkContinuity(dctx, dst);
++
++ switch (dctx->stage) {
++ case ZSTDds_getFrameHeaderSize:
++ if (srcSize != ZSTD_frameHeaderSize_prefix)
++ return ERROR(srcSize_wrong); /* impossible */
++ if ((ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
++ memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
++ dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix; /* magic number + skippable frame length */
++ dctx->stage = ZSTDds_decodeSkippableHeader;
++ return 0;
++ }
++ dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix);
++ if (ZSTD_isError(dctx->headerSize))
++ return dctx->headerSize;
++ memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
++ if (dctx->headerSize > ZSTD_frameHeaderSize_prefix) {
++ dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_prefix;
++ dctx->stage = ZSTDds_decodeFrameHeader;
++ return 0;
++ }
++ dctx->expected = 0; /* not necessary to copy more */
++
++ case ZSTDds_decodeFrameHeader:
++ memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
++ CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize));
++ dctx->expected = ZSTD_blockHeaderSize;
++ dctx->stage = ZSTDds_decodeBlockHeader;
++ return 0;
++
++ case ZSTDds_decodeBlockHeader: {
++ blockProperties_t bp;
++ size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
++ if (ZSTD_isError(cBlockSize))
++ return cBlockSize;
++ dctx->expected = cBlockSize;
++ dctx->bType = bp.blockType;
++ dctx->rleSize = bp.origSize;
++ if (cBlockSize) {
++ dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
++ return 0;
++ }
++ /* empty block */
++ if (bp.lastBlock) {
++ if (dctx->fParams.checksumFlag) {
++ dctx->expected = 4;
++ dctx->stage = ZSTDds_checkChecksum;
++ } else {
++ dctx->expected = 0; /* end of frame */
++ dctx->stage = ZSTDds_getFrameHeaderSize;
++ }
++ } else {
++ dctx->expected = 3; /* go directly to next header */
++ dctx->stage = ZSTDds_decodeBlockHeader;
++ }
++ return 0;
++ }
++ case ZSTDds_decompressLastBlock:
++ case ZSTDds_decompressBlock: {
++ size_t rSize;
++ switch (dctx->bType) {
++ case bt_compressed: rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); break;
++ case bt_raw: rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); break;
++ case bt_rle: rSize = ZSTD_setRleBlock(dst, dstCapacity, src, srcSize, dctx->rleSize); break;
++ case bt_reserved: /* should never happen */
++ default: return ERROR(corruption_detected);
++ }
++ if (ZSTD_isError(rSize))
++ return rSize;
++ if (dctx->fParams.checksumFlag)
++ xxh64_update(&dctx->xxhState, dst, rSize);
++
++ if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
++ if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
++ dctx->expected = 4;
++ dctx->stage = ZSTDds_checkChecksum;
++ } else {
++ dctx->expected = 0; /* ends here */
++ dctx->stage = ZSTDds_getFrameHeaderSize;
++ }
++ } else {
++ dctx->stage = ZSTDds_decodeBlockHeader;
++ dctx->expected = ZSTD_blockHeaderSize;
++ dctx->previousDstEnd = (char *)dst + rSize;
++ }
++ return rSize;
++ }
++ case ZSTDds_checkChecksum: {
++ U32 const h32 = (U32)xxh64_digest(&dctx->xxhState);
++ U32 const check32 = ZSTD_readLE32(src); /* srcSize == 4, guaranteed by dctx->expected */
++ if (check32 != h32)
++ return ERROR(checksum_wrong);
++ dctx->expected = 0;
++ dctx->stage = ZSTDds_getFrameHeaderSize;
++ return 0;
++ }
++ case ZSTDds_decodeSkippableHeader: {
++ memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
++ dctx->expected = ZSTD_readLE32(dctx->headerBuffer + 4);
++ dctx->stage = ZSTDds_skipFrame;
++ return 0;
++ }
++ case ZSTDds_skipFrame: {
++ dctx->expected = 0;
++ dctx->stage = ZSTDds_getFrameHeaderSize;
++ return 0;
++ }
++ default:
++ return ERROR(GENERIC); /* impossible */
++ }
++}
++
++static size_t ZSTD_refDictContent(ZSTD_DCtx *dctx, const void *dict, size_t dictSize)
++{
++ dctx->dictEnd = dctx->previousDstEnd;
++ dctx->vBase = (const char *)dict - ((const char *)(dctx->previousDstEnd) - (const char *)(dctx->base));
++ dctx->base = dict;
++ dctx->previousDstEnd = (const char *)dict + dictSize;
++ return 0;
++}
++
++/* ZSTD_loadEntropy() :
++ * dict : must point at beginning of a valid zstd dictionary
++ * @return : size of entropy tables read */
++static size_t ZSTD_loadEntropy(ZSTD_entropyTables_t *entropy, const void *const dict, size_t const dictSize)
++{
++ const BYTE *dictPtr = (const BYTE *)dict;
++ const BYTE *const dictEnd = dictPtr + dictSize;
++
++ if (dictSize <= 8)
++ return ERROR(dictionary_corrupted);
++ dictPtr += 8; /* skip header = magic + dictID */
++
++ {
++ size_t const hSize = HUF_readDTableX4_wksp(entropy->hufTable, dictPtr, dictEnd - dictPtr, entropy->workspace, sizeof(entropy->workspace));
++ if (HUF_isError(hSize))
++ return ERROR(dictionary_corrupted);
++ dictPtr += hSize;
++ }
++
++ {
++ short offcodeNCount[MaxOff + 1];
++ U32 offcodeMaxValue = MaxOff, offcodeLog;
++ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd - dictPtr);
++ if (FSE_isError(offcodeHeaderSize))
++ return ERROR(dictionary_corrupted);
++ if (offcodeLog > OffFSELog)
++ return ERROR(dictionary_corrupted);
++ CHECK_E(FSE_buildDTable_wksp(entropy->OFTable, offcodeNCount, offcodeMaxValue, offcodeLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted);
++ dictPtr += offcodeHeaderSize;
++ }
++
++ {
++ short matchlengthNCount[MaxML + 1];
++ unsigned matchlengthMaxValue = MaxML, matchlengthLog;
++ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd - dictPtr);
++ if (FSE_isError(matchlengthHeaderSize))
++ return ERROR(dictionary_corrupted);
++ if (matchlengthLog > MLFSELog)
++ return ERROR(dictionary_corrupted);
++ CHECK_E(FSE_buildDTable_wksp(entropy->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted);
++ dictPtr += matchlengthHeaderSize;
++ }
++
++ {
++ short litlengthNCount[MaxLL + 1];
++ unsigned litlengthMaxValue = MaxLL, litlengthLog;
++ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd - dictPtr);
++ if (FSE_isError(litlengthHeaderSize))
++ return ERROR(dictionary_corrupted);
++ if (litlengthLog > LLFSELog)
++ return ERROR(dictionary_corrupted);
++ CHECK_E(FSE_buildDTable_wksp(entropy->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted);
++ dictPtr += litlengthHeaderSize;
++ }
++
++ if (dictPtr + 12 > dictEnd)
++ return ERROR(dictionary_corrupted);
++ {
++ int i;
++ size_t const dictContentSize = (size_t)(dictEnd - (dictPtr + 12));
++ for (i = 0; i < 3; i++) {
++ U32 const rep = ZSTD_readLE32(dictPtr);
++ dictPtr += 4;
++ if (rep == 0 || rep >= dictContentSize)
++ return ERROR(dictionary_corrupted);
++ entropy->rep[i] = rep;
++ }
++ }
++
++ return dictPtr - (const BYTE *)dict;
++}
++
++static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx *dctx, const void *dict, size_t dictSize)
++{
++ if (dictSize < 8)
++ return ZSTD_refDictContent(dctx, dict, dictSize);
++ {
++ U32 const magic = ZSTD_readLE32(dict);
++ if (magic != ZSTD_DICT_MAGIC) {
++ return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */
++ }
++ }
++ dctx->dictID = ZSTD_readLE32((const char *)dict + 4);
++
++ /* load entropy tables */
++ {
++ size_t const eSize = ZSTD_loadEntropy(&dctx->entropy, dict, dictSize);
++ if (ZSTD_isError(eSize))
++ return ERROR(dictionary_corrupted);
++ dict = (const char *)dict + eSize;
++ dictSize -= eSize;
++ }
++ dctx->litEntropy = dctx->fseEntropy = 1;
++
++ /* reference dictionary content */
++ return ZSTD_refDictContent(dctx, dict, dictSize);
++}
++
++size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx *dctx, const void *dict, size_t dictSize)
++{
++ CHECK_F(ZSTD_decompressBegin(dctx));
++ if (dict && dictSize)
++ CHECK_E(ZSTD_decompress_insertDictionary(dctx, dict, dictSize), dictionary_corrupted);
++ return 0;
++}
++
++/* ====== ZSTD_DDict ====== */
++
++struct ZSTD_DDict_s {
++ void *dictBuffer;
++ const void *dictContent;
++ size_t dictSize;
++ ZSTD_entropyTables_t entropy;
++ U32 dictID;
++ U32 entropyPresent;
++ ZSTD_customMem cMem;
++}; /* typedef'd to ZSTD_DDict within "zstd.h" */
++
++size_t ZSTD_DDictWorkspaceBound(void) { return ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_DDict)); }
++
++static const void *ZSTD_DDictDictContent(const ZSTD_DDict *ddict) { return ddict->dictContent; }
++
++static size_t ZSTD_DDictDictSize(const ZSTD_DDict *ddict) { return ddict->dictSize; }
++
++static void ZSTD_refDDict(ZSTD_DCtx *dstDCtx, const ZSTD_DDict *ddict)
++{
++ ZSTD_decompressBegin(dstDCtx); /* init */
++ if (ddict) { /* support refDDict on NULL */
++ dstDCtx->dictID = ddict->dictID;
++ dstDCtx->base = ddict->dictContent;
++ dstDCtx->vBase = ddict->dictContent;
++ dstDCtx->dictEnd = (const BYTE *)ddict->dictContent + ddict->dictSize;
++ dstDCtx->previousDstEnd = dstDCtx->dictEnd;
++ if (ddict->entropyPresent) {
++ dstDCtx->litEntropy = 1;
++ dstDCtx->fseEntropy = 1;
++ dstDCtx->LLTptr = ddict->entropy.LLTable;
++ dstDCtx->MLTptr = ddict->entropy.MLTable;
++ dstDCtx->OFTptr = ddict->entropy.OFTable;
++ dstDCtx->HUFptr = ddict->entropy.hufTable;
++ dstDCtx->entropy.rep[0] = ddict->entropy.rep[0];
++ dstDCtx->entropy.rep[1] = ddict->entropy.rep[1];
++ dstDCtx->entropy.rep[2] = ddict->entropy.rep[2];
++ } else {
++ dstDCtx->litEntropy = 0;
++ dstDCtx->fseEntropy = 0;
++ }
++ }
++}
++
++static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict *ddict)
++{
++ ddict->dictID = 0;
++ ddict->entropyPresent = 0;
++ if (ddict->dictSize < 8)
++ return 0;
++ {
++ U32 const magic = ZSTD_readLE32(ddict->dictContent);
++ if (magic != ZSTD_DICT_MAGIC)
++ return 0; /* pure content mode */
++ }
++ ddict->dictID = ZSTD_readLE32((const char *)ddict->dictContent + 4);
++
++ /* load entropy tables */
++ CHECK_E(ZSTD_loadEntropy(&ddict->entropy, ddict->dictContent, ddict->dictSize), dictionary_corrupted);
++ ddict->entropyPresent = 1;
++ return 0;
++}
++
++static ZSTD_DDict *ZSTD_createDDict_advanced(const void *dict, size_t dictSize, unsigned byReference, ZSTD_customMem customMem)
++{
++ if (!customMem.customAlloc || !customMem.customFree)
++ return NULL;
++
++ {
++ ZSTD_DDict *const ddict = (ZSTD_DDict *)ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
++ if (!ddict)
++ return NULL;
++ ddict->cMem = customMem;
++
++ if ((byReference) || (!dict) || (!dictSize)) {
++ ddict->dictBuffer = NULL;
++ ddict->dictContent = dict;
++ } else {
++ void *const internalBuffer = ZSTD_malloc(dictSize, customMem);
++ if (!internalBuffer) {
++ ZSTD_freeDDict(ddict);
++ return NULL;
++ }
++ memcpy(internalBuffer, dict, dictSize);
++ ddict->dictBuffer = internalBuffer;
++ ddict->dictContent = internalBuffer;
++ }
++ ddict->dictSize = dictSize;
++ ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
++ /* parse dictionary content */
++ {
++ size_t const errorCode = ZSTD_loadEntropy_inDDict(ddict);
++ if (ZSTD_isError(errorCode)) {
++ ZSTD_freeDDict(ddict);
++ return NULL;
++ }
++ }
++
++ return ddict;
++ }
++}
++
++/*! ZSTD_initDDict() :
++* Create a digested dictionary, to start decompression without startup delay.
++* `dict` content is copied inside DDict.
++* Consequently, `dict` can be released after `ZSTD_DDict` creation */
++ZSTD_DDict *ZSTD_initDDict(const void *dict, size_t dictSize, void *workspace, size_t workspaceSize)
++{
++ ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
++ return ZSTD_createDDict_advanced(dict, dictSize, 1, stackMem);
++}
++
++size_t ZSTD_freeDDict(ZSTD_DDict *ddict)
++{
++ if (ddict == NULL)
++ return 0; /* support free on NULL */
++ {
++ ZSTD_customMem const cMem = ddict->cMem;
++ ZSTD_free(ddict->dictBuffer, cMem);
++ ZSTD_free(ddict, cMem);
++ return 0;
++ }
++}
++
++/*! ZSTD_getDictID_fromDict() :
++ * Provides the dictID stored within dictionary.
++ * if @return == 0, the dictionary is not conformant with Zstandard specification.
++ * It can still be loaded, but as a content-only dictionary. */
++unsigned ZSTD_getDictID_fromDict(const void *dict, size_t dictSize)
++{
++ if (dictSize < 8)
++ return 0;
++ if (ZSTD_readLE32(dict) != ZSTD_DICT_MAGIC)
++ return 0;
++ return ZSTD_readLE32((const char *)dict + 4);
++}
++
++/*! ZSTD_getDictID_fromDDict() :
++ * Provides the dictID of the dictionary loaded into `ddict`.
++ * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
++ * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
++unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict *ddict)
++{
++ if (ddict == NULL)
++ return 0;
++ return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
++}
++
++/*! ZSTD_getDictID_fromFrame() :
++ * Provides the dictID required to decompressed the frame stored within `src`.
++ * If @return == 0, the dictID could not be decoded.
++ * This could for one of the following reasons :
++ * - The frame does not require a dictionary to be decoded (most common case).
++ * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information.
++ * Note : this use case also happens when using a non-conformant dictionary.
++ * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`).
++ * - This is not a Zstandard frame.
++ * When identifying the exact failure cause, it's possible to used ZSTD_getFrameParams(), which will provide a more precise error code. */
++unsigned ZSTD_getDictID_fromFrame(const void *src, size_t srcSize)
++{
++ ZSTD_frameParams zfp = {0, 0, 0, 0};
++ size_t const hError = ZSTD_getFrameParams(&zfp, src, srcSize);
++ if (ZSTD_isError(hError))
++ return 0;
++ return zfp.dictID;
++}
++
++/*! ZSTD_decompress_usingDDict() :
++* Decompression using a pre-digested Dictionary
++* Use dictionary without significant overhead. */
++size_t ZSTD_decompress_usingDDict(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const ZSTD_DDict *ddict)
++{
++ /* pass content and size in case legacy frames are encountered */
++ return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, NULL, 0, ddict);
++}
++
++/*=====================================
++* Streaming decompression
++*====================================*/
++
++typedef enum { zdss_init, zdss_loadHeader, zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
++
++/* *** Resource management *** */
++struct ZSTD_DStream_s {
++ ZSTD_DCtx *dctx;
++ ZSTD_DDict *ddictLocal;
++ const ZSTD_DDict *ddict;
++ ZSTD_frameParams fParams;
++ ZSTD_dStreamStage stage;
++ char *inBuff;
++ size_t inBuffSize;
++ size_t inPos;
++ size_t maxWindowSize;
++ char *outBuff;
++ size_t outBuffSize;
++ size_t outStart;
++ size_t outEnd;
++ size_t blockSize;
++ BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store frame header */
++ size_t lhSize;
++ ZSTD_customMem customMem;
++ void *legacyContext;
++ U32 previousLegacyVersion;
++ U32 legacyVersion;
++ U32 hostageByte;
++}; /* typedef'd to ZSTD_DStream within "zstd.h" */
++
++size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize)
++{
++ size_t const blockSize = MIN(maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
++ size_t const inBuffSize = blockSize;
++ size_t const outBuffSize = maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
++ return ZSTD_DCtxWorkspaceBound() + ZSTD_ALIGN(sizeof(ZSTD_DStream)) + ZSTD_ALIGN(inBuffSize) + ZSTD_ALIGN(outBuffSize);
++}
++
++static ZSTD_DStream *ZSTD_createDStream_advanced(ZSTD_customMem customMem)
++{
++ ZSTD_DStream *zds;
++
++ if (!customMem.customAlloc || !customMem.customFree)
++ return NULL;
++
++ zds = (ZSTD_DStream *)ZSTD_malloc(sizeof(ZSTD_DStream), customMem);
++ if (zds == NULL)
++ return NULL;
++ memset(zds, 0, sizeof(ZSTD_DStream));
++ memcpy(&zds->customMem, &customMem, sizeof(ZSTD_customMem));
++ zds->dctx = ZSTD_createDCtx_advanced(customMem);
++ if (zds->dctx == NULL) {
++ ZSTD_freeDStream(zds);
++ return NULL;
++ }
++ zds->stage = zdss_init;
++ zds->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
++ return zds;
++}
++
++ZSTD_DStream *ZSTD_initDStream(size_t maxWindowSize, void *workspace, size_t workspaceSize)
++{
++ ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
++ ZSTD_DStream *zds = ZSTD_createDStream_advanced(stackMem);
++ if (!zds) {
++ return NULL;
++ }
++
++ zds->maxWindowSize = maxWindowSize;
++ zds->stage = zdss_loadHeader;
++ zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
++ ZSTD_freeDDict(zds->ddictLocal);
++ zds->ddictLocal = NULL;
++ zds->ddict = zds->ddictLocal;
++ zds->legacyVersion = 0;
++ zds->hostageByte = 0;
++
++ {
++ size_t const blockSize = MIN(zds->maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
++ size_t const neededOutSize = zds->maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
++
++ zds->inBuff = (char *)ZSTD_malloc(blockSize, zds->customMem);
++ zds->inBuffSize = blockSize;
++ zds->outBuff = (char *)ZSTD_malloc(neededOutSize, zds->customMem);
++ zds->outBuffSize = neededOutSize;
++ if (zds->inBuff == NULL || zds->outBuff == NULL) {
++ ZSTD_freeDStream(zds);
++ return NULL;
++ }
++ }
++ return zds;
++}
++
++ZSTD_DStream *ZSTD_initDStream_usingDDict(size_t maxWindowSize, const ZSTD_DDict *ddict, void *workspace, size_t workspaceSize)
++{
++ ZSTD_DStream *zds = ZSTD_initDStream(maxWindowSize, workspace, workspaceSize);
++ if (zds) {
++ zds->ddict = ddict;
++ }
++ return zds;
++}
++
++size_t ZSTD_freeDStream(ZSTD_DStream *zds)
++{
++ if (zds == NULL)
++ return 0; /* support free on null */
++ {
++ ZSTD_customMem const cMem = zds->customMem;
++ ZSTD_freeDCtx(zds->dctx);
++ zds->dctx = NULL;
++ ZSTD_freeDDict(zds->ddictLocal);
++ zds->ddictLocal = NULL;
++ ZSTD_free(zds->inBuff, cMem);
++ zds->inBuff = NULL;
++ ZSTD_free(zds->outBuff, cMem);
++ zds->outBuff = NULL;
++ ZSTD_free(zds, cMem);
++ return 0;
++ }
++}
++
++/* *** Initialization *** */
++
++size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX + ZSTD_blockHeaderSize; }
++size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
++
++size_t ZSTD_resetDStream(ZSTD_DStream *zds)
++{
++ zds->stage = zdss_loadHeader;
++ zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
++ zds->legacyVersion = 0;
++ zds->hostageByte = 0;
++ return ZSTD_frameHeaderSize_prefix;
++}
++
++/* ***** Decompression ***** */
++
++ZSTD_STATIC size_t ZSTD_limitCopy(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
++{
++ size_t const length = MIN(dstCapacity, srcSize);
++ memcpy(dst, src, length);
++ return length;
++}
++
++size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inBuffer *input)
++{
++ const char *const istart = (const char *)(input->src) + input->pos;
++ const char *const iend = (const char *)(input->src) + input->size;
++ const char *ip = istart;
++ char *const ostart = (char *)(output->dst) + output->pos;
++ char *const oend = (char *)(output->dst) + output->size;
++ char *op = ostart;
++ U32 someMoreWork = 1;
++
++ while (someMoreWork) {
++ switch (zds->stage) {
++ case zdss_init:
++ ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */
++ /* fall-through */
++
++ case zdss_loadHeader: {
++ size_t const hSize = ZSTD_getFrameParams(&zds->fParams, zds->headerBuffer, zds->lhSize);
++ if (ZSTD_isError(hSize))
++ return hSize;
++ if (hSize != 0) { /* need more input */
++ size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */
++ if (toLoad > (size_t)(iend - ip)) { /* not enough input to load full header */
++ memcpy(zds->headerBuffer + zds->lhSize, ip, iend - ip);
++ zds->lhSize += iend - ip;
++ input->pos = input->size;
++ return (MAX(ZSTD_frameHeaderSize_min, hSize) - zds->lhSize) +
++ ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
++ }
++ memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad);
++ zds->lhSize = hSize;
++ ip += toLoad;
++ break;
++ }
++
++ /* check for single-pass mode opportunity */
++ if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */
++ && (U64)(size_t)(oend - op) >= zds->fParams.frameContentSize) {
++ size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend - istart);
++ if (cSize <= (size_t)(iend - istart)) {
++ size_t const decompressedSize = ZSTD_decompress_usingDDict(zds->dctx, op, oend - op, istart, cSize, zds->ddict);
++ if (ZSTD_isError(decompressedSize))
++ return decompressedSize;
++ ip = istart + cSize;
++ op += decompressedSize;
++ zds->dctx->expected = 0;
++ zds->stage = zdss_init;
++ someMoreWork = 0;
++ break;
++ }
++ }
++
++ /* Consume header */
++ ZSTD_refDDict(zds->dctx, zds->ddict);
++ {
++ size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */
++ CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer, h1Size));
++ {
++ size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx);
++ CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer + h1Size, h2Size));
++ }
++ }
++
++ zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
++ if (zds->fParams.windowSize > zds->maxWindowSize)
++ return ERROR(frameParameter_windowTooLarge);
++
++ /* Buffers are preallocated, but double check */
++ {
++ size_t const blockSize = MIN(zds->maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
++ size_t const neededOutSize = zds->maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
++ if (zds->inBuffSize < blockSize) {
++ return ERROR(GENERIC);
++ }
++ if (zds->outBuffSize < neededOutSize) {
++ return ERROR(GENERIC);
++ }
++ zds->blockSize = blockSize;
++ }
++ zds->stage = zdss_read;
++ }
++ /* pass-through */
++
++ case zdss_read: {
++ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
++ if (neededInSize == 0) { /* end of frame */
++ zds->stage = zdss_init;
++ someMoreWork = 0;
++ break;
++ }
++ if ((size_t)(iend - ip) >= neededInSize) { /* decode directly from src */
++ const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);
++ size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart,
++ (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), ip, neededInSize);
++ if (ZSTD_isError(decodedSize))
++ return decodedSize;
++ ip += neededInSize;
++ if (!decodedSize && !isSkipFrame)
++ break; /* this was just a header */
++ zds->outEnd = zds->outStart + decodedSize;
++ zds->stage = zdss_flush;
++ break;
++ }
++ if (ip == iend) {
++ someMoreWork = 0;
++ break;
++ } /* no more input */
++ zds->stage = zdss_load;
++ /* pass-through */
++ }
++
++ case zdss_load: {
++ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
++ size_t const toLoad = neededInSize - zds->inPos; /* should always be <= remaining space within inBuff */
++ size_t loadedSize;
++ if (toLoad > zds->inBuffSize - zds->inPos)
++ return ERROR(corruption_detected); /* should never happen */
++ loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend - ip);
++ ip += loadedSize;
++ zds->inPos += loadedSize;
++ if (loadedSize < toLoad) {
++ someMoreWork = 0;
++ break;
++ } /* not enough input, wait for more */
++
++ /* decode loaded input */
++ {
++ const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);
++ size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
++ zds->inBuff, neededInSize);
++ if (ZSTD_isError(decodedSize))
++ return decodedSize;
++ zds->inPos = 0; /* input is consumed */
++ if (!decodedSize && !isSkipFrame) {
++ zds->stage = zdss_read;
++ break;
++ } /* this was just a header */
++ zds->outEnd = zds->outStart + decodedSize;
++ zds->stage = zdss_flush;
++ /* pass-through */
++ }
++ }
++
++ case zdss_flush: {
++ size_t const toFlushSize = zds->outEnd - zds->outStart;
++ size_t const flushedSize = ZSTD_limitCopy(op, oend - op, zds->outBuff + zds->outStart, toFlushSize);
++ op += flushedSize;
++ zds->outStart += flushedSize;
++ if (flushedSize == toFlushSize) { /* flush completed */
++ zds->stage = zdss_read;
++ if (zds->outStart + zds->blockSize > zds->outBuffSize)
++ zds->outStart = zds->outEnd = 0;
++ break;
++ }
++ /* cannot complete flush */
++ someMoreWork = 0;
++ break;
++ }
++ default:
++ return ERROR(GENERIC); /* impossible */
++ }
++ }
++
++ /* result */
++ input->pos += (size_t)(ip - istart);
++ output->pos += (size_t)(op - ostart);
++ {
++ size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->dctx);
++ if (!nextSrcSizeHint) { /* frame fully decoded */
++ if (zds->outEnd == zds->outStart) { /* output fully flushed */
++ if (zds->hostageByte) {
++ if (input->pos >= input->size) {
++ zds->stage = zdss_read;
++ return 1;
++ } /* can't release hostage (not present) */
++ input->pos++; /* release hostage */
++ }
++ return 0;
++ }
++ if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
++ input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */
++ zds->hostageByte = 1;
++ }
++ return 1;
++ }
++ nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->dctx) == ZSTDnit_block); /* preload header of next block */
++ if (zds->inPos > nextSrcSizeHint)
++ return ERROR(GENERIC); /* should never happen */
++ nextSrcSizeHint -= zds->inPos; /* already loaded*/
++ return nextSrcSizeHint;
++ }
++}
++
++EXPORT_SYMBOL(ZSTD_DCtxWorkspaceBound);
++EXPORT_SYMBOL(ZSTD_initDCtx);
++EXPORT_SYMBOL(ZSTD_decompressDCtx);
++EXPORT_SYMBOL(ZSTD_decompress_usingDict);
++
++EXPORT_SYMBOL(ZSTD_DDictWorkspaceBound);
++EXPORT_SYMBOL(ZSTD_initDDict);
++EXPORT_SYMBOL(ZSTD_decompress_usingDDict);
++
++EXPORT_SYMBOL(ZSTD_DStreamWorkspaceBound);
++EXPORT_SYMBOL(ZSTD_initDStream);
++EXPORT_SYMBOL(ZSTD_initDStream_usingDDict);
++EXPORT_SYMBOL(ZSTD_resetDStream);
++EXPORT_SYMBOL(ZSTD_decompressStream);
++EXPORT_SYMBOL(ZSTD_DStreamInSize);
++EXPORT_SYMBOL(ZSTD_DStreamOutSize);
++
++EXPORT_SYMBOL(ZSTD_findFrameCompressedSize);
++EXPORT_SYMBOL(ZSTD_getFrameContentSize);
++EXPORT_SYMBOL(ZSTD_findDecompressedSize);
++
++EXPORT_SYMBOL(ZSTD_isFrame);
++EXPORT_SYMBOL(ZSTD_getDictID_fromDict);
++EXPORT_SYMBOL(ZSTD_getDictID_fromDDict);
++EXPORT_SYMBOL(ZSTD_getDictID_fromFrame);
++
++EXPORT_SYMBOL(ZSTD_getFrameParams);
++EXPORT_SYMBOL(ZSTD_decompressBegin);
++EXPORT_SYMBOL(ZSTD_decompressBegin_usingDict);
++EXPORT_SYMBOL(ZSTD_copyDCtx);
++EXPORT_SYMBOL(ZSTD_nextSrcSizeToDecompress);
++EXPORT_SYMBOL(ZSTD_decompressContinue);
++EXPORT_SYMBOL(ZSTD_nextInputType);
++
++EXPORT_SYMBOL(ZSTD_decompressBlock);
++EXPORT_SYMBOL(ZSTD_insertBlock);
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("Zstd Decompressor");
+diff --git a/lib/zstd/entropy_common.c b/lib/zstd/entropy_common.c
+new file mode 100644
+index 0000000..2b0a643
+--- /dev/null
++++ b/lib/zstd/entropy_common.c
+@@ -0,0 +1,243 @@
++/*
++ * Common functions of New Generation Entropy library
++ * Copyright (C) 2016, 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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at :
++ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
++ */
++
++/* *************************************
++* Dependencies
++***************************************/
++#include "error_private.h" /* ERR_*, ERROR */
++#include "fse.h"
++#include "huf.h"
++#include "mem.h"
++
++/*=== Version ===*/
++unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
++
++/*=== Error Management ===*/
++unsigned FSE_isError(size_t code) { return ERR_isError(code); }
++
++unsigned HUF_isError(size_t code) { return ERR_isError(code); }
++
++/*-**************************************************************
++* FSE NCount encoding-decoding
++****************************************************************/
++size_t FSE_readNCount(short *normalizedCounter, unsigned *maxSVPtr, unsigned *tableLogPtr, const void *headerBuffer, size_t hbSize)
++{
++ const BYTE *const istart = (const BYTE *)headerBuffer;
++ const BYTE *const iend = istart + hbSize;
++ const BYTE *ip = istart;
++ int nbBits;
++ int remaining;
++ int threshold;
++ U32 bitStream;
++ int bitCount;
++ unsigned charnum = 0;
++ int previous0 = 0;
++
++ if (hbSize < 4)
++ return ERROR(srcSize_wrong);
++ bitStream = ZSTD_readLE32(ip);
++ nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
++ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX)
++ return ERROR(tableLog_tooLarge);
++ bitStream >>= 4;
++ bitCount = 4;
++ *tableLogPtr = nbBits;
++ remaining = (1 << nbBits) + 1;
++ threshold = 1 << nbBits;
++ nbBits++;
++
++ while ((remaining > 1) & (charnum <= *maxSVPtr)) {
++ if (previous0) {
++ unsigned n0 = charnum;
++ while ((bitStream & 0xFFFF) == 0xFFFF) {
++ n0 += 24;
++ if (ip < iend - 5) {
++ ip += 2;
++ bitStream = ZSTD_readLE32(ip) >> bitCount;
++ } else {
++ bitStream >>= 16;
++ bitCount += 16;
++ }
++ }
++ while ((bitStream & 3) == 3) {
++ n0 += 3;
++ bitStream >>= 2;
++ bitCount += 2;
++ }
++ n0 += bitStream & 3;
++ bitCount += 2;
++ if (n0 > *maxSVPtr)
++ return ERROR(maxSymbolValue_tooSmall);
++ while (charnum < n0)
++ normalizedCounter[charnum++] = 0;
++ if ((ip <= iend - 7) || (ip + (bitCount >> 3) <= iend - 4)) {
++ ip += bitCount >> 3;
++ bitCount &= 7;
++ bitStream = ZSTD_readLE32(ip) >> bitCount;
++ } else {
++ bitStream >>= 2;
++ }
++ }
++ {
++ int const max = (2 * threshold - 1) - remaining;
++ int count;
++
++ if ((bitStream & (threshold - 1)) < (U32)max) {
++ count = bitStream & (threshold - 1);
++ bitCount += nbBits - 1;
++ } else {
++ count = bitStream & (2 * threshold - 1);
++ if (count >= threshold)
++ count -= max;
++ bitCount += nbBits;
++ }
++
++ count--; /* extra accuracy */
++ remaining -= count < 0 ? -count : count; /* -1 means +1 */
++ normalizedCounter[charnum++] = (short)count;
++ previous0 = !count;
++ while (remaining < threshold) {
++ nbBits--;
++ threshold >>= 1;
++ }
++
++ if ((ip <= iend - 7) || (ip + (bitCount >> 3) <= iend - 4)) {
++ ip += bitCount >> 3;
++ bitCount &= 7;
++ } else {
++ bitCount -= (int)(8 * (iend - 4 - ip));
++ ip = iend - 4;
++ }
++ bitStream = ZSTD_readLE32(ip) >> (bitCount & 31);
++ }
++ } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
++ if (remaining != 1)
++ return ERROR(corruption_detected);
++ if (bitCount > 32)
++ return ERROR(corruption_detected);
++ *maxSVPtr = charnum - 1;
++
++ ip += (bitCount + 7) >> 3;
++ return ip - istart;
++}
++
++/*! HUF_readStats() :
++ Read compact Huffman tree, saved by HUF_writeCTable().
++ `huffWeight` is destination buffer.
++ `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
++ @return : size read from `src` , or an error Code .
++ Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
++*/
++size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
++{
++ U32 weightTotal;
++ const BYTE *ip = (const BYTE *)src;
++ size_t iSize;
++ size_t oSize;
++
++ if (!srcSize)
++ return ERROR(srcSize_wrong);
++ iSize = ip[0];
++ /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */
++
++ if (iSize >= 128) { /* special header */
++ oSize = iSize - 127;
++ iSize = ((oSize + 1) / 2);
++ if (iSize + 1 > srcSize)
++ return ERROR(srcSize_wrong);
++ if (oSize >= hwSize)
++ return ERROR(corruption_detected);
++ ip += 1;
++ {
++ U32 n;
++ for (n = 0; n < oSize; n += 2) {
++ huffWeight[n] = ip[n / 2] >> 4;
++ huffWeight[n + 1] = ip[n / 2] & 15;
++ }
++ }
++ } else { /* header compressed with FSE (normal case) */
++ if (iSize + 1 > srcSize)
++ return ERROR(srcSize_wrong);
++ oSize = FSE_decompress_wksp(huffWeight, hwSize - 1, ip + 1, iSize, 6, workspace, workspaceSize); /* max (hwSize-1) values decoded, as last one is implied */
++ if (FSE_isError(oSize))
++ return oSize;
++ }
++
++ /* collect weight stats */
++ memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
++ weightTotal = 0;
++ {
++ U32 n;
++ for (n = 0; n < oSize; n++) {
++ if (huffWeight[n] >= HUF_TABLELOG_MAX)
++ return ERROR(corruption_detected);
++ rankStats[huffWeight[n]]++;
++ weightTotal += (1 << huffWeight[n]) >> 1;
++ }
++ }
++ if (weightTotal == 0)
++ return ERROR(corruption_detected);
++
++ /* get last non-null symbol weight (implied, total must be 2^n) */
++ {
++ U32 const tableLog = BIT_highbit32(weightTotal) + 1;
++ if (tableLog > HUF_TABLELOG_MAX)
++ return ERROR(corruption_detected);
++ *tableLogPtr = tableLog;
++ /* determine last weight */
++ {
++ U32 const total = 1 << tableLog;
++ U32 const rest = total - weightTotal;
++ U32 const verif = 1 << BIT_highbit32(rest);
++ U32 const lastWeight = BIT_highbit32(rest) + 1;
++ if (verif != rest)
++ return ERROR(corruption_detected); /* last value must be a clean power of 2 */
++ huffWeight[oSize] = (BYTE)lastWeight;
++ rankStats[lastWeight]++;
++ }
++ }
++
++ /* check tree construction validity */
++ if ((rankStats[1] < 2) || (rankStats[1] & 1))
++ return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
++
++ /* results */
++ *nbSymbolsPtr = (U32)(oSize + 1);
++ return iSize + 1;
++}
+diff --git a/lib/zstd/error_private.h b/lib/zstd/error_private.h
+new file mode 100644
+index 0000000..1a60b31
+--- /dev/null
++++ b/lib/zstd/error_private.h
+@@ -0,0 +1,53 @@
++/**
++ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This source code is licensed under the BSD-style license found in the
++ * LICENSE file in the root directory of https://github.com/facebook/zstd.
++ * An additional grant of patent rights can be found in the PATENTS file in the
++ * same directory.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ */
++
++/* Note : this module is expected to remain private, do not expose it */
++
++#ifndef ERROR_H_MODULE
++#define ERROR_H_MODULE
++
++/* ****************************************
++* Dependencies
++******************************************/
++#include /* size_t */
++#include /* enum list */
++
++/* ****************************************
++* Compiler-specific
++******************************************/
++#define ERR_STATIC static __attribute__((unused))
++
++/*-****************************************
++* Customization (error_public.h)
++******************************************/
++typedef ZSTD_ErrorCode ERR_enum;
++#define PREFIX(name) ZSTD_error_##name
++
++/*-****************************************
++* Error codes handling
++******************************************/
++#define ERROR(name) ((size_t)-PREFIX(name))
++
++ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
++
++ERR_STATIC ERR_enum ERR_getErrorCode(size_t code)
++{
++ if (!ERR_isError(code))
++ return (ERR_enum)0;
++ return (ERR_enum)(0 - code);
++}
++
++#endif /* ERROR_H_MODULE */
+diff --git a/lib/zstd/fse.h b/lib/zstd/fse.h
+new file mode 100644
+index 0000000..7460ab0
+--- /dev/null
++++ b/lib/zstd/fse.h
+@@ -0,0 +1,575 @@
++/*
++ * FSE : Finite State Entropy codec
++ * Public Prototypes declaration
++ * Copyright (C) 2013-2016, 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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at :
++ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
++ */
++#ifndef FSE_H
++#define FSE_H
++
++/*-*****************************************
++* Dependencies
++******************************************/
++#include /* size_t, ptrdiff_t */
++
++/*-*****************************************
++* FSE_PUBLIC_API : control library symbols visibility
++******************************************/
++#define FSE_PUBLIC_API
++
++/*------ Version ------*/
++#define FSE_VERSION_MAJOR 0
++#define FSE_VERSION_MINOR 9
++#define FSE_VERSION_RELEASE 0
++
++#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
++#define FSE_QUOTE(str) #str
++#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
++#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
++
++#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR * 100 * 100 + FSE_VERSION_MINOR * 100 + FSE_VERSION_RELEASE)
++FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
++
++/*-*****************************************
++* Tool functions
++******************************************/
++FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
++
++/* Error Management */
++FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
++
++/*-*****************************************
++* FSE detailed API
++******************************************/
++/*!
++FSE_compress() does the following:
++1. count symbol occurrence from source[] into table count[]
++2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
++3. save normalized counters to memory buffer using writeNCount()
++4. build encoding table 'CTable' from normalized counters
++5. encode the data stream using encoding table 'CTable'
++
++FSE_decompress() does the following:
++1. read normalized counters with readNCount()
++2. build decoding table 'DTable' from normalized counters
++3. decode the data stream using decoding table 'DTable'
++
++The following API allows targeting specific sub-functions for advanced tasks.
++For example, it's possible to compress several blocks using the same 'CTable',
++or to save and provide normalized distribution using external method.
++*/
++
++/* *** COMPRESSION *** */
++/*! FSE_optimalTableLog():
++ dynamically downsize 'tableLog' when conditions are met.
++ It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
++ @return : recommended tableLog (necessarily <= 'maxTableLog') */
++FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
++
++/*! FSE_normalizeCount():
++ normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
++ 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
++ @return : tableLog,
++ or an errorCode, which can be tested using FSE_isError() */
++FSE_PUBLIC_API size_t FSE_normalizeCount(short *normalizedCounter, unsigned tableLog, const unsigned *count, size_t srcSize, unsigned maxSymbolValue);
++
++/*! FSE_NCountWriteBound():
++ Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
++ Typically useful for allocation purpose. */
++FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
++
++/*! FSE_writeNCount():
++ Compactly save 'normalizedCounter' into 'buffer'.
++ @return : size of the compressed table,
++ or an errorCode, which can be tested using FSE_isError(). */
++FSE_PUBLIC_API size_t FSE_writeNCount(void *buffer, size_t bufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
++
++/*! Constructor and Destructor of FSE_CTable.
++ Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
++typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
++
++/*! FSE_compress_usingCTable():
++ Compress `src` using `ct` into `dst` which must be already allocated.
++ @return : size of compressed data (<= `dstCapacity`),
++ or 0 if compressed data could not fit into `dst`,
++ or an errorCode, which can be tested using FSE_isError() */
++FSE_PUBLIC_API size_t FSE_compress_usingCTable(void *dst, size_t dstCapacity, const void *src, size_t srcSize, const FSE_CTable *ct);
++
++/*!
++Tutorial :
++----------
++The first step is to count all symbols. FSE_count() does this job very fast.
++Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
++'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
++maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
++FSE_count() will return the number of occurrence of the most frequent symbol.
++This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
++If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
++
++The next step is to normalize the frequencies.
++FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
++It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
++You can use 'tableLog'==0 to mean "use default tableLog value".
++If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
++which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
++
++The result of FSE_normalizeCount() will be saved into a table,
++called 'normalizedCounter', which is a table of signed short.
++'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
++The return value is tableLog if everything proceeded as expected.
++It is 0 if there is a single symbol within distribution.
++If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
++
++'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
++'buffer' must be already allocated.
++For guaranteed success, buffer size must be at least FSE_headerBound().
++The result of the function is the number of bytes written into 'buffer'.
++If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
++
++'normalizedCounter' can then be used to create the compression table 'CTable'.
++The space required by 'CTable' must be already allocated, using FSE_createCTable().
++You can then use FSE_buildCTable() to fill 'CTable'.
++If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
++
++'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
++Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
++The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
++If it returns '0', compressed data could not fit into 'dst'.
++If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
++*/
++
++/* *** DECOMPRESSION *** */
++
++/*! FSE_readNCount():
++ Read compactly saved 'normalizedCounter' from 'rBuffer'.
++ @return : size read from 'rBuffer',
++ or an errorCode, which can be tested using FSE_isError().
++ maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
++FSE_PUBLIC_API size_t FSE_readNCount(short *normalizedCounter, unsigned *maxSymbolValuePtr, unsigned *tableLogPtr, const void *rBuffer, size_t rBuffSize);
++
++/*! Constructor and Destructor of FSE_DTable.
++ Note that its size depends on 'tableLog' */
++typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
++
++/*! FSE_buildDTable():
++ Builds 'dt', which must be already allocated, using FSE_createDTable().
++ return : 0, or an errorCode, which can be tested using FSE_isError() */
++FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize);
++
++/*! FSE_decompress_usingDTable():
++ Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
++ into `dst` which must be already allocated.
++ @return : size of regenerated data (necessarily <= `dstCapacity`),
++ or an errorCode, which can be tested using FSE_isError() */
++FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt);
++
++/*!
++Tutorial :
++----------
++(Note : these functions only decompress FSE-compressed blocks.
++ If block is uncompressed, use memcpy() instead
++ If block is a single repeated byte, use memset() instead )
++
++The first step is to obtain the normalized frequencies of symbols.
++This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
++'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
++In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
++or size the table to handle worst case situations (typically 256).
++FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
++The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
++Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
++If there is an error, the function will return an error code, which can be tested using FSE_isError().
++
++The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
++This is performed by the function FSE_buildDTable().
++The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
++If there is an error, the function will return an error code, which can be tested using FSE_isError().
++
++`FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
++`cSrcSize` must be strictly correct, otherwise decompression will fail.
++FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
++If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
++*/
++
++/* *** Dependency *** */
++#include "bitstream.h"
++
++/* *****************************************
++* Static allocation
++*******************************************/
++/* FSE buffer bounds */
++#define FSE_NCOUNTBOUND 512
++#define FSE_BLOCKBOUND(size) (size + (size >> 7))
++#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
++
++/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
++#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1 << (maxTableLog - 1)) + ((maxSymbolValue + 1) * 2))
++#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1 << maxTableLog))
++
++/* *****************************************
++* FSE advanced API
++*******************************************/
++/* FSE_count_wksp() :
++ * Same as FSE_count(), but using an externally provided scratch buffer.
++ * `workSpace` size must be table of >= `1024` unsigned
++ */
++size_t FSE_count_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace);
++
++/* FSE_countFast_wksp() :
++ * Same as FSE_countFast(), but using an externally provided scratch buffer.
++ * `workSpace` must be a table of minimum `1024` unsigned
++ */
++size_t FSE_countFast_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize, unsigned *workSpace);
++
++/*! FSE_count_simple
++ * Same as FSE_countFast(), but does not use any additional memory (not even on stack).
++ * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`).
++*/
++size_t FSE_count_simple(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize);
++
++unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
++/**< same as FSE_optimalTableLog(), which used `minus==2` */
++
++size_t FSE_buildCTable_raw(FSE_CTable *ct, unsigned nbBits);
++/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
++
++size_t FSE_buildCTable_rle(FSE_CTable *ct, unsigned char symbolValue);
++/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
++
++/* FSE_buildCTable_wksp() :
++ * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
++ * `wkspSize` must be >= `(1<= BIT_DStream_completed
++
++When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
++Checking if DStream has reached its end is performed by :
++ BIT_endOfDStream(&DStream);
++Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
++ FSE_endOfDState(&DState);
++*/
++
++/* *****************************************
++* FSE unsafe API
++*******************************************/
++static unsigned char FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD);
++/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
++
++/* *****************************************
++* Implementation of inlined functions
++*******************************************/
++typedef struct {
++ int deltaFindState;
++ U32 deltaNbBits;
++} FSE_symbolCompressionTransform; /* total 8 bytes */
++
++ZSTD_STATIC void FSE_initCState(FSE_CState_t *statePtr, const FSE_CTable *ct)
++{
++ const void *ptr = ct;
++ const U16 *u16ptr = (const U16 *)ptr;
++ const U32 tableLog = ZSTD_read16(ptr);
++ statePtr->value = (ptrdiff_t)1 << tableLog;
++ statePtr->stateTable = u16ptr + 2;
++ statePtr->symbolTT = ((const U32 *)ct + 1 + (tableLog ? (1 << (tableLog - 1)) : 1));
++ statePtr->stateLog = tableLog;
++}
++
++/*! FSE_initCState2() :
++* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
++* uses the smallest state value possible, saving the cost of this symbol */
++ZSTD_STATIC void FSE_initCState2(FSE_CState_t *statePtr, const FSE_CTable *ct, U32 symbol)
++{
++ FSE_initCState(statePtr, ct);
++ {
++ const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform *)(statePtr->symbolTT))[symbol];
++ const U16 *stateTable = (const U16 *)(statePtr->stateTable);
++ U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1 << 15)) >> 16);
++ statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
++ statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
++ }
++}
++
++ZSTD_STATIC void FSE_encodeSymbol(BIT_CStream_t *bitC, FSE_CState_t *statePtr, U32 symbol)
++{
++ const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform *)(statePtr->symbolTT))[symbol];
++ const U16 *const stateTable = (const U16 *)(statePtr->stateTable);
++ U32 nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
++ BIT_addBits(bitC, statePtr->value, nbBitsOut);
++ statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
++}
++
++ZSTD_STATIC void FSE_flushCState(BIT_CStream_t *bitC, const FSE_CState_t *statePtr)
++{
++ BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
++ BIT_flushBits(bitC);
++}
++
++/* ====== Decompression ====== */
++
++typedef struct {
++ U16 tableLog;
++ U16 fastMode;
++} FSE_DTableHeader; /* sizeof U32 */
++
++typedef struct {
++ unsigned short newState;
++ unsigned char symbol;
++ unsigned char nbBits;
++} FSE_decode_t; /* size == U32 */
++
++ZSTD_STATIC void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, const FSE_DTable *dt)
++{
++ const void *ptr = dt;
++ const FSE_DTableHeader *const DTableH = (const FSE_DTableHeader *)ptr;
++ DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
++ BIT_reloadDStream(bitD);
++ DStatePtr->table = dt + 1;
++}
++
++ZSTD_STATIC BYTE FSE_peekSymbol(const FSE_DState_t *DStatePtr)
++{
++ FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
++ return DInfo.symbol;
++}
++
++ZSTD_STATIC void FSE_updateState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
++{
++ FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
++ U32 const nbBits = DInfo.nbBits;
++ size_t const lowBits = BIT_readBits(bitD, nbBits);
++ DStatePtr->state = DInfo.newState + lowBits;
++}
++
++ZSTD_STATIC BYTE FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
++{
++ FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
++ U32 const nbBits = DInfo.nbBits;
++ BYTE const symbol = DInfo.symbol;
++ size_t const lowBits = BIT_readBits(bitD, nbBits);
++
++ DStatePtr->state = DInfo.newState + lowBits;
++ return symbol;
++}
++
++/*! FSE_decodeSymbolFast() :
++ unsafe, only works if no symbol has a probability > 50% */
++ZSTD_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
++{
++ FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
++ U32 const nbBits = DInfo.nbBits;
++ BYTE const symbol = DInfo.symbol;
++ size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
++
++ DStatePtr->state = DInfo.newState + lowBits;
++ return symbol;
++}
++
++ZSTD_STATIC unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr) { return DStatePtr->state == 0; }
++
++/* **************************************************************
++* Tuning parameters
++****************************************************************/
++/*!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
++* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
++#ifndef FSE_MAX_MEMORY_USAGE
++#define FSE_MAX_MEMORY_USAGE 14
++#endif
++#ifndef FSE_DEFAULT_MEMORY_USAGE
++#define FSE_DEFAULT_MEMORY_USAGE 13
++#endif
++
++/*!FSE_MAX_SYMBOL_VALUE :
++* Maximum symbol value authorized.
++* Required for proper stack allocation */
++#ifndef FSE_MAX_SYMBOL_VALUE
++#define FSE_MAX_SYMBOL_VALUE 255
++#endif
++
++/* **************************************************************
++* template functions type & suffix
++****************************************************************/
++#define FSE_FUNCTION_TYPE BYTE
++#define FSE_FUNCTION_EXTENSION
++#define FSE_DECODE_TYPE FSE_decode_t
++
++/* ***************************************************************
++* Constants
++*****************************************************************/
++#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE - 2)
++#define FSE_MAX_TABLESIZE (1U << FSE_MAX_TABLELOG)
++#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE - 1)
++#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE - 2)
++#define FSE_MIN_TABLELOG 5
++
++#define FSE_TABLELOG_ABSOLUTE_MAX 15
++#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
++#error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
++#endif
++
++#define FSE_TABLESTEP(tableSize) ((tableSize >> 1) + (tableSize >> 3) + 3)
++
++#endif /* FSE_H */
+diff --git a/lib/zstd/fse_compress.c b/lib/zstd/fse_compress.c
+new file mode 100644
+index 0000000..ef3d174
+--- /dev/null
++++ b/lib/zstd/fse_compress.c
+@@ -0,0 +1,795 @@
++/*
++ * FSE : Finite State Entropy encoder
++ * Copyright (C) 2013-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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at :
++ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
++ */
++
++/* **************************************************************
++* Compiler specifics
++****************************************************************/
++#define FORCE_INLINE static __always_inline
++
++/* **************************************************************
++* Includes
++****************************************************************/
++#include "bitstream.h"
++#include "fse.h"
++#include
++#include
++#include
++#include /* memcpy, memset */
++
++/* **************************************************************
++* Error Management
++****************************************************************/
++#define FSE_STATIC_ASSERT(c) \
++ { \
++ enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
++ } /* use only *after* variable declarations */
++
++/* **************************************************************
++* Templates
++****************************************************************/
++/*
++ designed to be included
++ for type-specific functions (template emulation in C)
++ Objective is to write these functions only once, for improved maintenance
++*/
++
++/* safety checks */
++#ifndef FSE_FUNCTION_EXTENSION
++#error "FSE_FUNCTION_EXTENSION must be defined"
++#endif
++#ifndef FSE_FUNCTION_TYPE
++#error "FSE_FUNCTION_TYPE must be defined"
++#endif
++
++/* Function names */
++#define FSE_CAT(X, Y) X##Y
++#define FSE_FUNCTION_NAME(X, Y) FSE_CAT(X, Y)
++#define FSE_TYPE_NAME(X, Y) FSE_CAT(X, Y)
++
++/* Function templates */
++
++/* FSE_buildCTable_wksp() :
++ * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
++ * wkspSize should be sized to handle worst case situation, which is `1<> 1 : 1);
++ FSE_symbolCompressionTransform *const symbolTT = (FSE_symbolCompressionTransform *)(FSCT);
++ U32 const step = FSE_TABLESTEP(tableSize);
++ U32 highThreshold = tableSize - 1;
++
++ U32 *cumul;
++ FSE_FUNCTION_TYPE *tableSymbol;
++ size_t spaceUsed32 = 0;
++
++ cumul = (U32 *)workspace + spaceUsed32;
++ spaceUsed32 += FSE_MAX_SYMBOL_VALUE + 2;
++ tableSymbol = (FSE_FUNCTION_TYPE *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(sizeof(FSE_FUNCTION_TYPE) * ((size_t)1 << tableLog), sizeof(U32)) >> 2;
++
++ if ((spaceUsed32 << 2) > workspaceSize)
++ return ERROR(tableLog_tooLarge);
++ workspace = (U32 *)workspace + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++
++ /* CTable header */
++ tableU16[-2] = (U16)tableLog;
++ tableU16[-1] = (U16)maxSymbolValue;
++
++ /* For explanations on how to distribute symbol values over the table :
++ * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
++
++ /* symbol start positions */
++ {
++ U32 u;
++ cumul[0] = 0;
++ for (u = 1; u <= maxSymbolValue + 1; u++) {
++ if (normalizedCounter[u - 1] == -1) { /* Low proba symbol */
++ cumul[u] = cumul[u - 1] + 1;
++ tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u - 1);
++ } else {
++ cumul[u] = cumul[u - 1] + normalizedCounter[u - 1];
++ }
++ }
++ cumul[maxSymbolValue + 1] = tableSize + 1;
++ }
++
++ /* Spread symbols */
++ {
++ U32 position = 0;
++ U32 symbol;
++ for (symbol = 0; symbol <= maxSymbolValue; symbol++) {
++ int nbOccurences;
++ for (nbOccurences = 0; nbOccurences < normalizedCounter[symbol]; nbOccurences++) {
++ tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
++ position = (position + step) & tableMask;
++ while (position > highThreshold)
++ position = (position + step) & tableMask; /* Low proba area */
++ }
++ }
++
++ if (position != 0)
++ return ERROR(GENERIC); /* Must have gone through all positions */
++ }
++
++ /* Build table */
++ {
++ U32 u;
++ for (u = 0; u < tableSize; u++) {
++ FSE_FUNCTION_TYPE s = tableSymbol[u]; /* note : static analyzer may not understand tableSymbol is properly initialized */
++ tableU16[cumul[s]++] = (U16)(tableSize + u); /* TableU16 : sorted by symbol order; gives next state value */
++ }
++ }
++
++ /* Build Symbol Transformation Table */
++ {
++ unsigned total = 0;
++ unsigned s;
++ for (s = 0; s <= maxSymbolValue; s++) {
++ switch (normalizedCounter[s]) {
++ case 0: break;
++
++ case -1:
++ case 1:
++ symbolTT[s].deltaNbBits = (tableLog << 16) - (1 << tableLog);
++ symbolTT[s].deltaFindState = total - 1;
++ total++;
++ break;
++ default: {
++ U32 const maxBitsOut = tableLog - BIT_highbit32(normalizedCounter[s] - 1);
++ U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
++ symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
++ symbolTT[s].deltaFindState = total - normalizedCounter[s];
++ total += normalizedCounter[s];
++ }
++ }
++ }
++ }
++
++ return 0;
++}
++
++/*-**************************************************************
++* FSE NCount encoding-decoding
++****************************************************************/
++size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
++{
++ size_t const maxHeaderSize = (((maxSymbolValue + 1) * tableLog) >> 3) + 3;
++ return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
++}
++
++static size_t FSE_writeNCount_generic(void *header, size_t headerBufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
++ unsigned writeIsSafe)
++{
++ BYTE *const ostart = (BYTE *)header;
++ BYTE *out = ostart;
++ BYTE *const oend = ostart + headerBufferSize;
++ int nbBits;
++ const int tableSize = 1 << tableLog;
++ int remaining;
++ int threshold;
++ U32 bitStream;
++ int bitCount;
++ unsigned charnum = 0;
++ int previous0 = 0;
++
++ bitStream = 0;
++ bitCount = 0;
++ /* Table Size */
++ bitStream += (tableLog - FSE_MIN_TABLELOG) << bitCount;
++ bitCount += 4;
++
++ /* Init */
++ remaining = tableSize + 1; /* +1 for extra accuracy */
++ threshold = tableSize;
++ nbBits = tableLog + 1;
++
++ while (remaining > 1) { /* stops at 1 */
++ if (previous0) {
++ unsigned start = charnum;
++ while (!normalizedCounter[charnum])
++ charnum++;
++ while (charnum >= start + 24) {
++ start += 24;
++ bitStream += 0xFFFFU << bitCount;
++ if ((!writeIsSafe) && (out > oend - 2))
++ return ERROR(dstSize_tooSmall); /* Buffer overflow */
++ out[0] = (BYTE)bitStream;
++ out[1] = (BYTE)(bitStream >> 8);
++ out += 2;
++ bitStream >>= 16;
++ }
++ while (charnum >= start + 3) {
++ start += 3;
++ bitStream += 3 << bitCount;
++ bitCount += 2;
++ }
++ bitStream += (charnum - start) << bitCount;
++ bitCount += 2;
++ if (bitCount > 16) {
++ if ((!writeIsSafe) && (out > oend - 2))
++ return ERROR(dstSize_tooSmall); /* Buffer overflow */
++ out[0] = (BYTE)bitStream;
++ out[1] = (BYTE)(bitStream >> 8);
++ out += 2;
++ bitStream >>= 16;
++ bitCount -= 16;
++ }
++ }
++ {
++ int count = normalizedCounter[charnum++];
++ int const max = (2 * threshold - 1) - remaining;
++ remaining -= count < 0 ? -count : count;
++ count++; /* +1 for extra accuracy */
++ if (count >= threshold)
++ count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
++ bitStream += count << bitCount;
++ bitCount += nbBits;
++ bitCount -= (count < max);
++ previous0 = (count == 1);
++ if (remaining < 1)
++ return ERROR(GENERIC);
++ while (remaining < threshold)
++ nbBits--, threshold >>= 1;
++ }
++ if (bitCount > 16) {
++ if ((!writeIsSafe) && (out > oend - 2))
++ return ERROR(dstSize_tooSmall); /* Buffer overflow */
++ out[0] = (BYTE)bitStream;
++ out[1] = (BYTE)(bitStream >> 8);
++ out += 2;
++ bitStream >>= 16;
++ bitCount -= 16;
++ }
++ }
++
++ /* flush remaining bitStream */
++ if ((!writeIsSafe) && (out > oend - 2))
++ return ERROR(dstSize_tooSmall); /* Buffer overflow */
++ out[0] = (BYTE)bitStream;
++ out[1] = (BYTE)(bitStream >> 8);
++ out += (bitCount + 7) / 8;
++
++ if (charnum > maxSymbolValue + 1)
++ return ERROR(GENERIC);
++
++ return (out - ostart);
++}
++
++size_t FSE_writeNCount(void *buffer, size_t bufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
++{
++ if (tableLog > FSE_MAX_TABLELOG)
++ return ERROR(tableLog_tooLarge); /* Unsupported */
++ if (tableLog < FSE_MIN_TABLELOG)
++ return ERROR(GENERIC); /* Unsupported */
++
++ if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
++ return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
++
++ return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1);
++}
++
++/*-**************************************************************
++* Counting histogram
++****************************************************************/
++/*! FSE_count_simple
++ This function counts byte values within `src`, and store the histogram into table `count`.
++ It doesn't use any additional memory.
++ But this function is unsafe : it doesn't check that all values within `src` can fit into `count`.
++ For this reason, prefer using a table `count` with 256 elements.
++ @return : count of most numerous element
++*/
++size_t FSE_count_simple(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize)
++{
++ const BYTE *ip = (const BYTE *)src;
++ const BYTE *const end = ip + srcSize;
++ unsigned maxSymbolValue = *maxSymbolValuePtr;
++ unsigned max = 0;
++
++ memset(count, 0, (maxSymbolValue + 1) * sizeof(*count));
++ if (srcSize == 0) {
++ *maxSymbolValuePtr = 0;
++ return 0;
++ }
++
++ while (ip < end)
++ count[*ip++]++;
++
++ while (!count[maxSymbolValue])
++ maxSymbolValue--;
++ *maxSymbolValuePtr = maxSymbolValue;
++
++ {
++ U32 s;
++ for (s = 0; s <= maxSymbolValue; s++)
++ if (count[s] > max)
++ max = count[s];
++ }
++
++ return (size_t)max;
++}
++
++/* FSE_count_parallel_wksp() :
++ * Same as FSE_count_parallel(), but using an externally provided scratch buffer.
++ * `workSpace` size must be a minimum of `1024 * sizeof(unsigned)`` */
++static size_t FSE_count_parallel_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned checkMax,
++ unsigned *const workSpace)
++{
++ const BYTE *ip = (const BYTE *)source;
++ const BYTE *const iend = ip + sourceSize;
++ unsigned maxSymbolValue = *maxSymbolValuePtr;
++ unsigned max = 0;
++ U32 *const Counting1 = workSpace;
++ U32 *const Counting2 = Counting1 + 256;
++ U32 *const Counting3 = Counting2 + 256;
++ U32 *const Counting4 = Counting3 + 256;
++
++ memset(Counting1, 0, 4 * 256 * sizeof(unsigned));
++
++ /* safety checks */
++ if (!sourceSize) {
++ memset(count, 0, maxSymbolValue + 1);
++ *maxSymbolValuePtr = 0;
++ return 0;
++ }
++ if (!maxSymbolValue)
++ maxSymbolValue = 255; /* 0 == default */
++
++ /* by stripes of 16 bytes */
++ {
++ U32 cached = ZSTD_read32(ip);
++ ip += 4;
++ while (ip < iend - 15) {
++ U32 c = cached;
++ cached = ZSTD_read32(ip);
++ ip += 4;
++ Counting1[(BYTE)c]++;
++ Counting2[(BYTE)(c >> 8)]++;
++ Counting3[(BYTE)(c >> 16)]++;
++ Counting4[c >> 24]++;
++ c = cached;
++ cached = ZSTD_read32(ip);
++ ip += 4;
++ Counting1[(BYTE)c]++;
++ Counting2[(BYTE)(c >> 8)]++;
++ Counting3[(BYTE)(c >> 16)]++;
++ Counting4[c >> 24]++;
++ c = cached;
++ cached = ZSTD_read32(ip);
++ ip += 4;
++ Counting1[(BYTE)c]++;
++ Counting2[(BYTE)(c >> 8)]++;
++ Counting3[(BYTE)(c >> 16)]++;
++ Counting4[c >> 24]++;
++ c = cached;
++ cached = ZSTD_read32(ip);
++ ip += 4;
++ Counting1[(BYTE)c]++;
++ Counting2[(BYTE)(c >> 8)]++;
++ Counting3[(BYTE)(c >> 16)]++;
++ Counting4[c >> 24]++;
++ }
++ ip -= 4;
++ }
++
++ /* finish last symbols */
++ while (ip < iend)
++ Counting1[*ip++]++;
++
++ if (checkMax) { /* verify stats will fit into destination table */
++ U32 s;
++ for (s = 255; s > maxSymbolValue; s--) {
++ Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
++ if (Counting1[s])
++ return ERROR(maxSymbolValue_tooSmall);
++ }
++ }
++
++ {
++ U32 s;
++ for (s = 0; s <= maxSymbolValue; s++) {
++ count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
++ if (count[s] > max)
++ max = count[s];
++ }
++ }
++
++ while (!count[maxSymbolValue])
++ maxSymbolValue--;
++ *maxSymbolValuePtr = maxSymbolValue;
++ return (size_t)max;
++}
++
++/* FSE_countFast_wksp() :
++ * Same as FSE_countFast(), but using an externally provided scratch buffer.
++ * `workSpace` size must be table of >= `1024` unsigned */
++size_t FSE_countFast_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace)
++{
++ if (sourceSize < 1500)
++ return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
++ return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
++}
++
++/* FSE_count_wksp() :
++ * Same as FSE_count(), but using an externally provided scratch buffer.
++ * `workSpace` size must be table of >= `1024` unsigned */
++size_t FSE_count_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace)
++{
++ if (*maxSymbolValuePtr < 255)
++ return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace);
++ *maxSymbolValuePtr = 255;
++ return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace);
++}
++
++/*-**************************************************************
++* FSE Compression Code
++****************************************************************/
++/*! FSE_sizeof_CTable() :
++ FSE_CTable is a variable size structure which contains :
++ `U16 tableLog;`
++ `U16 maxSymbolValue;`
++ `U16 nextStateNumber[1 << tableLog];` // This size is variable
++ `FSE_symbolCompressionTransform symbolTT[maxSymbolValue+1];` // This size is variable
++Allocation is manual (C standard does not support variable-size structures).
++*/
++size_t FSE_sizeof_CTable(unsigned maxSymbolValue, unsigned tableLog)
++{
++ if (tableLog > FSE_MAX_TABLELOG)
++ return ERROR(tableLog_tooLarge);
++ return FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue) * sizeof(U32);
++}
++
++/* provides the minimum logSize to safely represent a distribution */
++static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
++{
++ U32 minBitsSrc = BIT_highbit32((U32)(srcSize - 1)) + 1;
++ U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
++ U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
++ return minBits;
++}
++
++unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
++{
++ U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
++ U32 tableLog = maxTableLog;
++ U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
++ if (tableLog == 0)
++ tableLog = FSE_DEFAULT_TABLELOG;
++ if (maxBitsSrc < tableLog)
++ tableLog = maxBitsSrc; /* Accuracy can be reduced */
++ if (minBits > tableLog)
++ tableLog = minBits; /* Need a minimum to safely represent all symbol values */
++ if (tableLog < FSE_MIN_TABLELOG)
++ tableLog = FSE_MIN_TABLELOG;
++ if (tableLog > FSE_MAX_TABLELOG)
++ tableLog = FSE_MAX_TABLELOG;
++ return tableLog;
++}
++
++unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
++{
++ return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
++}
++
++/* Secondary normalization method.
++ To be used when primary method fails. */
++
++static size_t FSE_normalizeM2(short *norm, U32 tableLog, const unsigned *count, size_t total, U32 maxSymbolValue)
++{
++ short const NOT_YET_ASSIGNED = -2;
++ U32 s;
++ U32 distributed = 0;
++ U32 ToDistribute;
++
++ /* Init */
++ U32 const lowThreshold = (U32)(total >> tableLog);
++ U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
++
++ for (s = 0; s <= maxSymbolValue; s++) {
++ if (count[s] == 0) {
++ norm[s] = 0;
++ continue;
++ }
++ if (count[s] <= lowThreshold) {
++ norm[s] = -1;
++ distributed++;
++ total -= count[s];
++ continue;
++ }
++ if (count[s] <= lowOne) {
++ norm[s] = 1;
++ distributed++;
++ total -= count[s];
++ continue;
++ }
++
++ norm[s] = NOT_YET_ASSIGNED;
++ }
++ ToDistribute = (1 << tableLog) - distributed;
++
++ if ((total / ToDistribute) > lowOne) {
++ /* risk of rounding to zero */
++ lowOne = (U32)((total * 3) / (ToDistribute * 2));
++ for (s = 0; s <= maxSymbolValue; s++) {
++ if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
++ norm[s] = 1;
++ distributed++;
++ total -= count[s];
++ continue;
++ }
++ }
++ ToDistribute = (1 << tableLog) - distributed;
++ }
++
++ if (distributed == maxSymbolValue + 1) {
++ /* all values are pretty poor;
++ probably incompressible data (should have already been detected);
++ find max, then give all remaining points to max */
++ U32 maxV = 0, maxC = 0;
++ for (s = 0; s <= maxSymbolValue; s++)
++ if (count[s] > maxC)
++ maxV = s, maxC = count[s];
++ norm[maxV] += (short)ToDistribute;
++ return 0;
++ }
++
++ if (total == 0) {
++ /* all of the symbols were low enough for the lowOne or lowThreshold */
++ for (s = 0; ToDistribute > 0; s = (s + 1) % (maxSymbolValue + 1))
++ if (norm[s] > 0)
++ ToDistribute--, norm[s]++;
++ return 0;
++ }
++
++ {
++ U64 const vStepLog = 62 - tableLog;
++ U64 const mid = (1ULL << (vStepLog - 1)) - 1;
++ U64 const rStep = div_u64((((U64)1 << vStepLog) * ToDistribute) + mid, (U32)total); /* scale on remaining */
++ U64 tmpTotal = mid;
++ for (s = 0; s <= maxSymbolValue; s++) {
++ if (norm[s] == NOT_YET_ASSIGNED) {
++ U64 const end = tmpTotal + (count[s] * rStep);
++ U32 const sStart = (U32)(tmpTotal >> vStepLog);
++ U32 const sEnd = (U32)(end >> vStepLog);
++ U32 const weight = sEnd - sStart;
++ if (weight < 1)
++ return ERROR(GENERIC);
++ norm[s] = (short)weight;
++ tmpTotal = end;
++ }
++ }
++ }
++
++ return 0;
++}
++
++size_t FSE_normalizeCount(short *normalizedCounter, unsigned tableLog, const unsigned *count, size_t total, unsigned maxSymbolValue)
++{
++ /* Sanity checks */
++ if (tableLog == 0)
++ tableLog = FSE_DEFAULT_TABLELOG;
++ if (tableLog < FSE_MIN_TABLELOG)
++ return ERROR(GENERIC); /* Unsupported size */
++ if (tableLog > FSE_MAX_TABLELOG)
++ return ERROR(tableLog_tooLarge); /* Unsupported size */
++ if (tableLog < FSE_minTableLog(total, maxSymbolValue))
++ return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
++
++ {
++ U32 const rtbTable[] = {0, 473195, 504333, 520860, 550000, 700000, 750000, 830000};
++ U64 const scale = 62 - tableLog;
++ U64 const step = div_u64((U64)1 << 62, (U32)total); /* <== here, one division ! */
++ U64 const vStep = 1ULL << (scale - 20);
++ int stillToDistribute = 1 << tableLog;
++ unsigned s;
++ unsigned largest = 0;
++ short largestP = 0;
++ U32 lowThreshold = (U32)(total >> tableLog);
++
++ for (s = 0; s <= maxSymbolValue; s++) {
++ if (count[s] == total)
++ return 0; /* rle special case */
++ if (count[s] == 0) {
++ normalizedCounter[s] = 0;
++ continue;
++ }
++ if (count[s] <= lowThreshold) {
++ normalizedCounter[s] = -1;
++ stillToDistribute--;
++ } else {
++ short proba = (short)((count[s] * step) >> scale);
++ if (proba < 8) {
++ U64 restToBeat = vStep * rtbTable[proba];
++ proba += (count[s] * step) - ((U64)proba << scale) > restToBeat;
++ }
++ if (proba > largestP)
++ largestP = proba, largest = s;
++ normalizedCounter[s] = proba;
++ stillToDistribute -= proba;
++ }
++ }
++ if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
++ /* corner case, need another normalization method */
++ size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
++ if (FSE_isError(errorCode))
++ return errorCode;
++ } else
++ normalizedCounter[largest] += (short)stillToDistribute;
++ }
++
++ return tableLog;
++}
++
++/* fake FSE_CTable, for raw (uncompressed) input */
++size_t FSE_buildCTable_raw(FSE_CTable *ct, unsigned nbBits)
++{
++ const unsigned tableSize = 1 << nbBits;
++ const unsigned tableMask = tableSize - 1;
++ const unsigned maxSymbolValue = tableMask;
++ void *const ptr = ct;
++ U16 *const tableU16 = ((U16 *)ptr) + 2;
++ void *const FSCT = ((U32 *)ptr) + 1 /* header */ + (tableSize >> 1); /* assumption : tableLog >= 1 */
++ FSE_symbolCompressionTransform *const symbolTT = (FSE_symbolCompressionTransform *)(FSCT);
++ unsigned s;
++
++ /* Sanity checks */
++ if (nbBits < 1)
++ return ERROR(GENERIC); /* min size */
++
++ /* header */
++ tableU16[-2] = (U16)nbBits;
++ tableU16[-1] = (U16)maxSymbolValue;
++
++ /* Build table */
++ for (s = 0; s < tableSize; s++)
++ tableU16[s] = (U16)(tableSize + s);
++
++ /* Build Symbol Transformation Table */
++ {
++ const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
++ for (s = 0; s <= maxSymbolValue; s++) {
++ symbolTT[s].deltaNbBits = deltaNbBits;
++ symbolTT[s].deltaFindState = s - 1;
++ }
++ }
++
++ return 0;
++}
++
++/* fake FSE_CTable, for rle input (always same symbol) */
++size_t FSE_buildCTable_rle(FSE_CTable *ct, BYTE symbolValue)
++{
++ void *ptr = ct;
++ U16 *tableU16 = ((U16 *)ptr) + 2;
++ void *FSCTptr = (U32 *)ptr + 2;
++ FSE_symbolCompressionTransform *symbolTT = (FSE_symbolCompressionTransform *)FSCTptr;
++
++ /* header */
++ tableU16[-2] = (U16)0;
++ tableU16[-1] = (U16)symbolValue;
++
++ /* Build table */
++ tableU16[0] = 0;
++ tableU16[1] = 0; /* just in case */
++
++ /* Build Symbol Transformation Table */
++ symbolTT[symbolValue].deltaNbBits = 0;
++ symbolTT[symbolValue].deltaFindState = 0;
++
++ return 0;
++}
++
++static size_t FSE_compress_usingCTable_generic(void *dst, size_t dstSize, const void *src, size_t srcSize, const FSE_CTable *ct, const unsigned fast)
++{
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *ip = iend;
++
++ BIT_CStream_t bitC;
++ FSE_CState_t CState1, CState2;
++
++ /* init */
++ if (srcSize <= 2)
++ return 0;
++ {
++ size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
++ if (FSE_isError(initError))
++ return 0; /* not enough space available to write a bitstream */
++ }
++
++#define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
++
++ if (srcSize & 1) {
++ FSE_initCState2(&CState1, ct, *--ip);
++ FSE_initCState2(&CState2, ct, *--ip);
++ FSE_encodeSymbol(&bitC, &CState1, *--ip);
++ FSE_FLUSHBITS(&bitC);
++ } else {
++ FSE_initCState2(&CState2, ct, *--ip);
++ FSE_initCState2(&CState1, ct, *--ip);
++ }
++
++ /* join to mod 4 */
++ srcSize -= 2;
++ if ((sizeof(bitC.bitContainer) * 8 > FSE_MAX_TABLELOG * 4 + 7) && (srcSize & 2)) { /* test bit 2 */
++ FSE_encodeSymbol(&bitC, &CState2, *--ip);
++ FSE_encodeSymbol(&bitC, &CState1, *--ip);
++ FSE_FLUSHBITS(&bitC);
++ }
++
++ /* 2 or 4 encoding per loop */
++ while (ip > istart) {
++
++ FSE_encodeSymbol(&bitC, &CState2, *--ip);
++
++ if (sizeof(bitC.bitContainer) * 8 < FSE_MAX_TABLELOG * 2 + 7) /* this test must be static */
++ FSE_FLUSHBITS(&bitC);
++
++ FSE_encodeSymbol(&bitC, &CState1, *--ip);
++
++ if (sizeof(bitC.bitContainer) * 8 > FSE_MAX_TABLELOG * 4 + 7) { /* this test must be static */
++ FSE_encodeSymbol(&bitC, &CState2, *--ip);
++ FSE_encodeSymbol(&bitC, &CState1, *--ip);
++ }
++
++ FSE_FLUSHBITS(&bitC);
++ }
++
++ FSE_flushCState(&bitC, &CState2);
++ FSE_flushCState(&bitC, &CState1);
++ return BIT_closeCStream(&bitC);
++}
++
++size_t FSE_compress_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const FSE_CTable *ct)
++{
++ unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
++
++ if (fast)
++ return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
++ else
++ return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
++}
++
++size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
+diff --git a/lib/zstd/fse_decompress.c b/lib/zstd/fse_decompress.c
+new file mode 100644
+index 0000000..a84300e
+--- /dev/null
++++ b/lib/zstd/fse_decompress.c
+@@ -0,0 +1,332 @@
++/*
++ * FSE : Finite State Entropy decoder
++ * Copyright (C) 2013-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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at :
++ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
++ */
++
++/* **************************************************************
++* Compiler specifics
++****************************************************************/
++#define FORCE_INLINE static __always_inline
++
++/* **************************************************************
++* Includes
++****************************************************************/
++#include "bitstream.h"
++#include "fse.h"
++#include
++#include
++#include /* memcpy, memset */
++
++/* **************************************************************
++* Error Management
++****************************************************************/
++#define FSE_isError ERR_isError
++#define FSE_STATIC_ASSERT(c) \
++ { \
++ enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
++ } /* use only *after* variable declarations */
++
++/* check and forward error code */
++#define CHECK_F(f) \
++ { \
++ size_t const e = f; \
++ if (FSE_isError(e)) \
++ return e; \
++ }
++
++/* **************************************************************
++* Templates
++****************************************************************/
++/*
++ designed to be included
++ for type-specific functions (template emulation in C)
++ Objective is to write these functions only once, for improved maintenance
++*/
++
++/* safety checks */
++#ifndef FSE_FUNCTION_EXTENSION
++#error "FSE_FUNCTION_EXTENSION must be defined"
++#endif
++#ifndef FSE_FUNCTION_TYPE
++#error "FSE_FUNCTION_TYPE must be defined"
++#endif
++
++/* Function names */
++#define FSE_CAT(X, Y) X##Y
++#define FSE_FUNCTION_NAME(X, Y) FSE_CAT(X, Y)
++#define FSE_TYPE_NAME(X, Y) FSE_CAT(X, Y)
++
++/* Function templates */
++
++size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize)
++{
++ void *const tdPtr = dt + 1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
++ FSE_DECODE_TYPE *const tableDecode = (FSE_DECODE_TYPE *)(tdPtr);
++ U16 *symbolNext = (U16 *)workspace;
++
++ U32 const maxSV1 = maxSymbolValue + 1;
++ U32 const tableSize = 1 << tableLog;
++ U32 highThreshold = tableSize - 1;
++
++ /* Sanity Checks */
++ if (workspaceSize < sizeof(U16) * (FSE_MAX_SYMBOL_VALUE + 1))
++ return ERROR(tableLog_tooLarge);
++ if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE)
++ return ERROR(maxSymbolValue_tooLarge);
++ if (tableLog > FSE_MAX_TABLELOG)
++ return ERROR(tableLog_tooLarge);
++
++ /* Init, lay down lowprob symbols */
++ {
++ FSE_DTableHeader DTableH;
++ DTableH.tableLog = (U16)tableLog;
++ DTableH.fastMode = 1;
++ {
++ S16 const largeLimit = (S16)(1 << (tableLog - 1));
++ U32 s;
++ for (s = 0; s < maxSV1; s++) {
++ if (normalizedCounter[s] == -1) {
++ tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
++ symbolNext[s] = 1;
++ } else {
++ if (normalizedCounter[s] >= largeLimit)
++ DTableH.fastMode = 0;
++ symbolNext[s] = normalizedCounter[s];
++ }
++ }
++ }
++ memcpy(dt, &DTableH, sizeof(DTableH));
++ }
++
++ /* Spread symbols */
++ {
++ U32 const tableMask = tableSize - 1;
++ U32 const step = FSE_TABLESTEP(tableSize);
++ U32 s, position = 0;
++ for (s = 0; s < maxSV1; s++) {
++ int i;
++ for (i = 0; i < normalizedCounter[s]; i++) {
++ tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
++ position = (position + step) & tableMask;
++ while (position > highThreshold)
++ position = (position + step) & tableMask; /* lowprob area */
++ }
++ }
++ if (position != 0)
++ return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
++ }
++
++ /* Build Decoding table */
++ {
++ U32 u;
++ for (u = 0; u < tableSize; u++) {
++ FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
++ U16 nextState = symbolNext[symbol]++;
++ tableDecode[u].nbBits = (BYTE)(tableLog - BIT_highbit32((U32)nextState));
++ tableDecode[u].newState = (U16)((nextState << tableDecode[u].nbBits) - tableSize);
++ }
++ }
++
++ return 0;
++}
++
++/*-*******************************************************
++* Decompression (Byte symbols)
++*********************************************************/
++size_t FSE_buildDTable_rle(FSE_DTable *dt, BYTE symbolValue)
++{
++ void *ptr = dt;
++ FSE_DTableHeader *const DTableH = (FSE_DTableHeader *)ptr;
++ void *dPtr = dt + 1;
++ FSE_decode_t *const cell = (FSE_decode_t *)dPtr;
++
++ DTableH->tableLog = 0;
++ DTableH->fastMode = 0;
++
++ cell->newState = 0;
++ cell->symbol = symbolValue;
++ cell->nbBits = 0;
++
++ return 0;
++}
++
++size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits)
++{
++ void *ptr = dt;
++ FSE_DTableHeader *const DTableH = (FSE_DTableHeader *)ptr;
++ void *dPtr = dt + 1;
++ FSE_decode_t *const dinfo = (FSE_decode_t *)dPtr;
++ const unsigned tableSize = 1 << nbBits;
++ const unsigned tableMask = tableSize - 1;
++ const unsigned maxSV1 = tableMask + 1;
++ unsigned s;
++
++ /* Sanity checks */
++ if (nbBits < 1)
++ return ERROR(GENERIC); /* min size */
++
++ /* Build Decoding Table */
++ DTableH->tableLog = (U16)nbBits;
++ DTableH->fastMode = 1;
++ for (s = 0; s < maxSV1; s++) {
++ dinfo[s].newState = 0;
++ dinfo[s].symbol = (BYTE)s;
++ dinfo[s].nbBits = (BYTE)nbBits;
++ }
++
++ return 0;
++}
++
++FORCE_INLINE size_t FSE_decompress_usingDTable_generic(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt,
++ const unsigned fast)
++{
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *op = ostart;
++ BYTE *const omax = op + maxDstSize;
++ BYTE *const olimit = omax - 3;
++
++ BIT_DStream_t bitD;
++ FSE_DState_t state1;
++ FSE_DState_t state2;
++
++ /* Init */
++ CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
++
++ FSE_initDState(&state1, &bitD, dt);
++ FSE_initDState(&state2, &bitD, dt);
++
++#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
++
++ /* 4 symbols per loop */
++ for (; (BIT_reloadDStream(&bitD) == BIT_DStream_unfinished) & (op < olimit); op += 4) {
++ op[0] = FSE_GETSYMBOL(&state1);
++
++ if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
++ BIT_reloadDStream(&bitD);
++
++ op[1] = FSE_GETSYMBOL(&state2);
++
++ if (FSE_MAX_TABLELOG * 4 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
++ {
++ if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) {
++ op += 2;
++ break;
++ }
++ }
++
++ op[2] = FSE_GETSYMBOL(&state1);
++
++ if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
++ BIT_reloadDStream(&bitD);
++
++ op[3] = FSE_GETSYMBOL(&state2);
++ }
++
++ /* tail */
++ /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
++ while (1) {
++ if (op > (omax - 2))
++ return ERROR(dstSize_tooSmall);
++ *op++ = FSE_GETSYMBOL(&state1);
++ if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) {
++ *op++ = FSE_GETSYMBOL(&state2);
++ break;
++ }
++
++ if (op > (omax - 2))
++ return ERROR(dstSize_tooSmall);
++ *op++ = FSE_GETSYMBOL(&state2);
++ if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) {
++ *op++ = FSE_GETSYMBOL(&state1);
++ break;
++ }
++ }
++
++ return op - ostart;
++}
++
++size_t FSE_decompress_usingDTable(void *dst, size_t originalSize, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt)
++{
++ const void *ptr = dt;
++ const FSE_DTableHeader *DTableH = (const FSE_DTableHeader *)ptr;
++ const U32 fastMode = DTableH->fastMode;
++
++ /* select fast mode (static) */
++ if (fastMode)
++ return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
++ return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
++}
++
++size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize)
++{
++ const BYTE *const istart = (const BYTE *)cSrc;
++ const BYTE *ip = istart;
++ unsigned tableLog;
++ unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
++ size_t NCountLength;
++
++ FSE_DTable *dt;
++ short *counting;
++ size_t spaceUsed32 = 0;
++
++ FSE_STATIC_ASSERT(sizeof(FSE_DTable) == sizeof(U32));
++
++ dt = (FSE_DTable *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += FSE_DTABLE_SIZE_U32(maxLog);
++ counting = (short *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(sizeof(short) * (FSE_MAX_SYMBOL_VALUE + 1), sizeof(U32)) >> 2;
++
++ if ((spaceUsed32 << 2) > workspaceSize)
++ return ERROR(tableLog_tooLarge);
++ workspace = (U32 *)workspace + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++
++ /* normal FSE decoding mode */
++ NCountLength = FSE_readNCount(counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
++ if (FSE_isError(NCountLength))
++ return NCountLength;
++ // if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining
++ // case : NCountLength==cSrcSize */
++ if (tableLog > maxLog)
++ return ERROR(tableLog_tooLarge);
++ ip += NCountLength;
++ cSrcSize -= NCountLength;
++
++ CHECK_F(FSE_buildDTable_wksp(dt, counting, maxSymbolValue, tableLog, workspace, workspaceSize));
++
++ return FSE_decompress_usingDTable(dst, dstCapacity, ip, cSrcSize, dt); /* always return, even if it is an error code */
++}
+diff --git a/lib/zstd/huf.h b/lib/zstd/huf.h
+new file mode 100644
+index 0000000..2143da2
+--- /dev/null
++++ b/lib/zstd/huf.h
+@@ -0,0 +1,212 @@
++/*
++ * Huffman coder, part of New Generation Entropy library
++ * header file
++ * Copyright (C) 2013-2016, 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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at :
++ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
++ */
++#ifndef HUF_H_298734234
++#define HUF_H_298734234
++
++/* *** Dependencies *** */
++#include /* size_t */
++
++/* *** Tool functions *** */
++#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
++size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
++
++/* Error Management */
++unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
++
++/* *** Advanced function *** */
++
++/** HUF_compress4X_wksp() :
++* Same as HUF_compress2(), but uses externally allocated `workSpace`, which must be a table of >= 1024 unsigned */
++size_t HUF_compress4X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
++ size_t wkspSize); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
++
++/* *** Dependencies *** */
++#include "mem.h" /* U32 */
++
++/* *** Constants *** */
++#define HUF_TABLELOG_MAX 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
++#define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */
++#define HUF_SYMBOLVALUE_MAX 255
++
++#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
++#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
++#error "HUF_TABLELOG_MAX is too large !"
++#endif
++
++/* ****************************************
++* Static allocation
++******************************************/
++/* HUF buffer bounds */
++#define HUF_CTABLEBOUND 129
++#define HUF_BLOCKBOUND(size) (size + (size >> 8) + 8) /* only true if incompressible pre-filtered with fast heuristic */
++#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
++
++/* static allocation of HUF's Compression Table */
++#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
++ U32 name##hb[maxSymbolValue + 1]; \
++ void *name##hv = &(name##hb); \
++ HUF_CElt *name = (HUF_CElt *)(name##hv) /* no final ; */
++
++/* static allocation of HUF's DTable */
++typedef U32 HUF_DTable;
++#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1 << (maxTableLog)))
++#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = {((U32)((maxTableLog)-1) * 0x01000001)}
++#define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = {((U32)(maxTableLog)*0x01000001)}
++
++/* The workspace must have alignment at least 4 and be at least this large */
++#define HUF_COMPRESS_WORKSPACE_SIZE (6 << 10)
++#define HUF_COMPRESS_WORKSPACE_SIZE_U32 (HUF_COMPRESS_WORKSPACE_SIZE / sizeof(U32))
++
++/* The workspace must have alignment at least 4 and be at least this large */
++#define HUF_DECOMPRESS_WORKSPACE_SIZE (3 << 10)
++#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
++
++/* ****************************************
++* Advanced decompression functions
++******************************************/
++size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< decodes RLE and uncompressed */
++size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
++ size_t workspaceSize); /**< considers RLE and uncompressed as errors */
++size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
++ size_t workspaceSize); /**< single-symbol decoder */
++size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
++ size_t workspaceSize); /**< double-symbols decoder */
++
++/* ****************************************
++* HUF detailed API
++******************************************/
++/*!
++HUF_compress() does the following:
++1. count symbol occurrence from source[] into table count[] using FSE_count()
++2. (optional) refine tableLog using HUF_optimalTableLog()
++3. build Huffman table from count using HUF_buildCTable()
++4. save Huffman table to memory buffer using HUF_writeCTable_wksp()
++5. encode the data stream using HUF_compress4X_usingCTable()
++
++The following API allows targeting specific sub-functions for advanced tasks.
++For example, it's possible to compress several blocks using the same 'CTable',
++or to save and regenerate 'CTable' using external methods.
++*/
++/* FSE_count() : find it within "fse.h" */
++unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
++typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
++size_t HUF_writeCTable_wksp(void *dst, size_t maxDstSize, const HUF_CElt *CTable, unsigned maxSymbolValue, unsigned huffLog, void *workspace, size_t workspaceSize);
++size_t HUF_compress4X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable);
++
++typedef enum {
++ HUF_repeat_none, /**< Cannot use the previous table */
++ HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1,
++ 4}X_repeat */
++ HUF_repeat_valid /**< Can use the previous table and it is asumed to be valid */
++} HUF_repeat;
++/** HUF_compress4X_repeat() :
++* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
++* If it uses hufTable it does not modify hufTable or repeat.
++* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
++* If preferRepeat then the old table will always be used if valid. */
++size_t HUF_compress4X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
++ size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat,
++ int preferRepeat); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
++
++/** HUF_buildCTable_wksp() :
++ * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
++ * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
++ */
++size_t HUF_buildCTable_wksp(HUF_CElt *tree, const U32 *count, U32 maxSymbolValue, U32 maxNbBits, void *workSpace, size_t wkspSize);
++
++/*! HUF_readStats() :
++ Read compact Huffman tree, saved by HUF_writeCTable().
++ `huffWeight` is destination buffer.
++ @return : size read from `src` , or an error Code .
++ Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
++size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize,
++ void *workspace, size_t workspaceSize);
++
++/** HUF_readCTable() :
++* Loading a CTable saved with HUF_writeCTable() */
++size_t HUF_readCTable_wksp(HUF_CElt *CTable, unsigned maxSymbolValue, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
++
++/*
++HUF_decompress() does the following:
++1. select the decompression algorithm (X2, X4) based on pre-computed heuristics
++2. build Huffman table from save, using HUF_readDTableXn()
++3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable
++*/
++
++/** HUF_selectDecoder() :
++* Tells which decoder is likely to decode faster,
++* based on a set of pre-determined metrics.
++* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
++* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
++U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize);
++
++size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
++size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
++
++size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
++size_t HUF_decompress4X2_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
++size_t HUF_decompress4X4_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
++
++/* single stream variants */
++
++size_t HUF_compress1X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
++ size_t wkspSize); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
++size_t HUF_compress1X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable);
++/** HUF_compress1X_repeat() :
++* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
++* If it uses hufTable it does not modify hufTable or repeat.
++* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
++* If preferRepeat then the old table will always be used if valid. */
++size_t HUF_compress1X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
++ size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat,
++ int preferRepeat); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
++
++size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize);
++size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
++ size_t workspaceSize); /**< single-symbol decoder */
++size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
++ size_t workspaceSize); /**< double-symbols decoder */
++
++size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize,
++ const HUF_DTable *DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
++size_t HUF_decompress1X2_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
++size_t HUF_decompress1X4_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
++
++#endif /* HUF_H_298734234 */
+diff --git a/lib/zstd/huf_compress.c b/lib/zstd/huf_compress.c
+new file mode 100644
+index 0000000..0361f38
+--- /dev/null
++++ b/lib/zstd/huf_compress.c
+@@ -0,0 +1,771 @@
++/*
++ * Huffman encoder, part of New Generation Entropy library
++ * Copyright (C) 2013-2016, 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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at :
++ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
++ */
++
++/* **************************************************************
++* Includes
++****************************************************************/
++#include "bitstream.h"
++#include "fse.h" /* header compression */
++#include "huf.h"
++#include
++#include /* memcpy, memset */
++
++/* **************************************************************
++* Error Management
++****************************************************************/
++#define HUF_STATIC_ASSERT(c) \
++ { \
++ enum { HUF_static_assert = 1 / (int)(!!(c)) }; \
++ } /* use only *after* variable declarations */
++#define CHECK_V_F(e, f) \
++ size_t const e = f; \
++ if (ERR_isError(e)) \
++ return f
++#define CHECK_F(f) \
++ { \
++ CHECK_V_F(_var_err__, f); \
++ }
++
++/* **************************************************************
++* Utils
++****************************************************************/
++unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
++{
++ return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
++}
++
++/* *******************************************************
++* HUF : Huffman block compression
++*********************************************************/
++/* HUF_compressWeights() :
++ * Same as FSE_compress(), but dedicated to huff0's weights compression.
++ * The use case needs much less stack memory.
++ * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
++ */
++#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
++size_t HUF_compressWeights_wksp(void *dst, size_t dstSize, const void *weightTable, size_t wtSize, void *workspace, size_t workspaceSize)
++{
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *op = ostart;
++ BYTE *const oend = ostart + dstSize;
++
++ U32 maxSymbolValue = HUF_TABLELOG_MAX;
++ U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
++
++ FSE_CTable *CTable;
++ U32 *count;
++ S16 *norm;
++ size_t spaceUsed32 = 0;
++
++ HUF_STATIC_ASSERT(sizeof(FSE_CTable) == sizeof(U32));
++
++ CTable = (FSE_CTable *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX);
++ count = (U32 *)workspace + spaceUsed32;
++ spaceUsed32 += HUF_TABLELOG_MAX + 1;
++ norm = (S16 *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(sizeof(S16) * (HUF_TABLELOG_MAX + 1), sizeof(U32)) >> 2;
++
++ if ((spaceUsed32 << 2) > workspaceSize)
++ return ERROR(tableLog_tooLarge);
++ workspace = (U32 *)workspace + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++
++ /* init conditions */
++ if (wtSize <= 1)
++ return 0; /* Not compressible */
++
++ /* Scan input and build symbol stats */
++ {
++ CHECK_V_F(maxCount, FSE_count_simple(count, &maxSymbolValue, weightTable, wtSize));
++ if (maxCount == wtSize)
++ return 1; /* only a single symbol in src : rle */
++ if (maxCount == 1)
++ return 0; /* each symbol present maximum once => not compressible */
++ }
++
++ tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
++ CHECK_F(FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue));
++
++ /* Write table description header */
++ {
++ CHECK_V_F(hSize, FSE_writeNCount(op, oend - op, norm, maxSymbolValue, tableLog));
++ op += hSize;
++ }
++
++ /* Compress */
++ CHECK_F(FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, workspace, workspaceSize));
++ {
++ CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable));
++ if (cSize == 0)
++ return 0; /* not enough space for compressed data */
++ op += cSize;
++ }
++
++ return op - ostart;
++}
++
++struct HUF_CElt_s {
++ U16 val;
++ BYTE nbBits;
++}; /* typedef'd to HUF_CElt within "huf.h" */
++
++/*! HUF_writeCTable_wksp() :
++ `CTable` : Huffman tree to save, using huf representation.
++ @return : size of saved CTable */
++size_t HUF_writeCTable_wksp(void *dst, size_t maxDstSize, const HUF_CElt *CTable, U32 maxSymbolValue, U32 huffLog, void *workspace, size_t workspaceSize)
++{
++ BYTE *op = (BYTE *)dst;
++ U32 n;
++
++ BYTE *bitsToWeight;
++ BYTE *huffWeight;
++ size_t spaceUsed32 = 0;
++
++ bitsToWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(HUF_TABLELOG_MAX + 1, sizeof(U32)) >> 2;
++ huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX, sizeof(U32)) >> 2;
++
++ if ((spaceUsed32 << 2) > workspaceSize)
++ return ERROR(tableLog_tooLarge);
++ workspace = (U32 *)workspace + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++
++ /* check conditions */
++ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX)
++ return ERROR(maxSymbolValue_tooLarge);
++
++ /* convert to weight */
++ bitsToWeight[0] = 0;
++ for (n = 1; n < huffLog + 1; n++)
++ bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
++ for (n = 0; n < maxSymbolValue; n++)
++ huffWeight[n] = bitsToWeight[CTable[n].nbBits];
++
++ /* attempt weights compression by FSE */
++ {
++ CHECK_V_F(hSize, HUF_compressWeights_wksp(op + 1, maxDstSize - 1, huffWeight, maxSymbolValue, workspace, workspaceSize));
++ if ((hSize > 1) & (hSize < maxSymbolValue / 2)) { /* FSE compressed */
++ op[0] = (BYTE)hSize;
++ return hSize + 1;
++ }
++ }
++
++ /* write raw values as 4-bits (max : 15) */
++ if (maxSymbolValue > (256 - 128))
++ return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
++ if (((maxSymbolValue + 1) / 2) + 1 > maxDstSize)
++ return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
++ op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue - 1));
++ huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
++ for (n = 0; n < maxSymbolValue; n += 2)
++ op[(n / 2) + 1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n + 1]);
++ return ((maxSymbolValue + 1) / 2) + 1;
++}
++
++size_t HUF_readCTable_wksp(HUF_CElt *CTable, U32 maxSymbolValue, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
++{
++ U32 *rankVal;
++ BYTE *huffWeight;
++ U32 tableLog = 0;
++ U32 nbSymbols = 0;
++ size_t readSize;
++ size_t spaceUsed32 = 0;
++
++ rankVal = (U32 *)workspace + spaceUsed32;
++ spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
++ huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
++
++ if ((spaceUsed32 << 2) > workspaceSize)
++ return ERROR(tableLog_tooLarge);
++ workspace = (U32 *)workspace + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++
++ /* get symbol weights */
++ readSize = HUF_readStats_wksp(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
++ if (ERR_isError(readSize))
++ return readSize;
++
++ /* check result */
++ if (tableLog > HUF_TABLELOG_MAX)
++ return ERROR(tableLog_tooLarge);
++ if (nbSymbols > maxSymbolValue + 1)
++ return ERROR(maxSymbolValue_tooSmall);
++
++ /* Prepare base value per rank */
++ {
++ U32 n, nextRankStart = 0;
++ for (n = 1; n <= tableLog; n++) {
++ U32 curr = nextRankStart;
++ nextRankStart += (rankVal[n] << (n - 1));
++ rankVal[n] = curr;
++ }
++ }
++
++ /* fill nbBits */
++ {
++ U32 n;
++ for (n = 0; n < nbSymbols; n++) {
++ const U32 w = huffWeight[n];
++ CTable[n].nbBits = (BYTE)(tableLog + 1 - w);
++ }
++ }
++
++ /* fill val */
++ {
++ U16 nbPerRank[HUF_TABLELOG_MAX + 2] = {0}; /* support w=0=>n=tableLog+1 */
++ U16 valPerRank[HUF_TABLELOG_MAX + 2] = {0};
++ {
++ U32 n;
++ for (n = 0; n < nbSymbols; n++)
++ nbPerRank[CTable[n].nbBits]++;
++ }
++ /* determine stating value per rank */
++ valPerRank[tableLog + 1] = 0; /* for w==0 */
++ {
++ U16 min = 0;
++ U32 n;
++ for (n = tableLog; n > 0; n--) { /* start at n=tablelog <-> w=1 */
++ valPerRank[n] = min; /* get starting value within each rank */
++ min += nbPerRank[n];
++ min >>= 1;
++ }
++ }
++ /* assign value within rank, symbol order */
++ {
++ U32 n;
++ for (n = 0; n <= maxSymbolValue; n++)
++ CTable[n].val = valPerRank[CTable[n].nbBits]++;
++ }
++ }
++
++ return readSize;
++}
++
++typedef struct nodeElt_s {
++ U32 count;
++ U16 parent;
++ BYTE byte;
++ BYTE nbBits;
++} nodeElt;
++
++static U32 HUF_setMaxHeight(nodeElt *huffNode, U32 lastNonNull, U32 maxNbBits)
++{
++ const U32 largestBits = huffNode[lastNonNull].nbBits;
++ if (largestBits <= maxNbBits)
++ return largestBits; /* early exit : no elt > maxNbBits */
++
++ /* there are several too large elements (at least >= 2) */
++ {
++ int totalCost = 0;
++ const U32 baseCost = 1 << (largestBits - maxNbBits);
++ U32 n = lastNonNull;
++
++ while (huffNode[n].nbBits > maxNbBits) {
++ totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
++ huffNode[n].nbBits = (BYTE)maxNbBits;
++ n--;
++ } /* n stops at huffNode[n].nbBits <= maxNbBits */
++ while (huffNode[n].nbBits == maxNbBits)
++ n--; /* n end at index of smallest symbol using < maxNbBits */
++
++ /* renorm totalCost */
++ totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */
++
++ /* repay normalized cost */
++ {
++ U32 const noSymbol = 0xF0F0F0F0;
++ U32 rankLast[HUF_TABLELOG_MAX + 2];
++ int pos;
++
++ /* Get pos of last (smallest) symbol per rank */
++ memset(rankLast, 0xF0, sizeof(rankLast));
++ {
++ U32 currNbBits = maxNbBits;
++ for (pos = n; pos >= 0; pos--) {
++ if (huffNode[pos].nbBits >= currNbBits)
++ continue;
++ currNbBits = huffNode[pos].nbBits; /* < maxNbBits */
++ rankLast[maxNbBits - currNbBits] = pos;
++ }
++ }
++
++ while (totalCost > 0) {
++ U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1;
++ for (; nBitsToDecrease > 1; nBitsToDecrease--) {
++ U32 highPos = rankLast[nBitsToDecrease];
++ U32 lowPos = rankLast[nBitsToDecrease - 1];
++ if (highPos == noSymbol)
++ continue;
++ if (lowPos == noSymbol)
++ break;
++ {
++ U32 const highTotal = huffNode[highPos].count;
++ U32 const lowTotal = 2 * huffNode[lowPos].count;
++ if (highTotal <= lowTotal)
++ break;
++ }
++ }
++ /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
++ /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
++ while ((nBitsToDecrease <= HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol))
++ nBitsToDecrease++;
++ totalCost -= 1 << (nBitsToDecrease - 1);
++ if (rankLast[nBitsToDecrease - 1] == noSymbol)
++ rankLast[nBitsToDecrease - 1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */
++ huffNode[rankLast[nBitsToDecrease]].nbBits++;
++ if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */
++ rankLast[nBitsToDecrease] = noSymbol;
++ else {
++ rankLast[nBitsToDecrease]--;
++ if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits - nBitsToDecrease)
++ rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
++ }
++ } /* while (totalCost > 0) */
++
++ while (totalCost < 0) { /* Sometimes, cost correction overshoot */
++ if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0
++ (using maxNbBits) */
++ while (huffNode[n].nbBits == maxNbBits)
++ n--;
++ huffNode[n + 1].nbBits--;
++ rankLast[1] = n + 1;
++ totalCost++;
++ continue;
++ }
++ huffNode[rankLast[1] + 1].nbBits--;
++ rankLast[1]++;
++ totalCost++;
++ }
++ }
++ } /* there are several too large elements (at least >= 2) */
++
++ return maxNbBits;
++}
++
++typedef struct {
++ U32 base;
++ U32 curr;
++} rankPos;
++
++static void HUF_sort(nodeElt *huffNode, const U32 *count, U32 maxSymbolValue)
++{
++ rankPos rank[32];
++ U32 n;
++
++ memset(rank, 0, sizeof(rank));
++ for (n = 0; n <= maxSymbolValue; n++) {
++ U32 r = BIT_highbit32(count[n] + 1);
++ rank[r].base++;
++ }
++ for (n = 30; n > 0; n--)
++ rank[n - 1].base += rank[n].base;
++ for (n = 0; n < 32; n++)
++ rank[n].curr = rank[n].base;
++ for (n = 0; n <= maxSymbolValue; n++) {
++ U32 const c = count[n];
++ U32 const r = BIT_highbit32(c + 1) + 1;
++ U32 pos = rank[r].curr++;
++ while ((pos > rank[r].base) && (c > huffNode[pos - 1].count))
++ huffNode[pos] = huffNode[pos - 1], pos--;
++ huffNode[pos].count = c;
++ huffNode[pos].byte = (BYTE)n;
++ }
++}
++
++/** HUF_buildCTable_wksp() :
++ * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
++ * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
++ */
++#define STARTNODE (HUF_SYMBOLVALUE_MAX + 1)
++typedef nodeElt huffNodeTable[2 * HUF_SYMBOLVALUE_MAX + 1 + 1];
++size_t HUF_buildCTable_wksp(HUF_CElt *tree, const U32 *count, U32 maxSymbolValue, U32 maxNbBits, void *workSpace, size_t wkspSize)
++{
++ nodeElt *const huffNode0 = (nodeElt *)workSpace;
++ nodeElt *const huffNode = huffNode0 + 1;
++ U32 n, nonNullRank;
++ int lowS, lowN;
++ U16 nodeNb = STARTNODE;
++ U32 nodeRoot;
++
++ /* safety checks */
++ if (wkspSize < sizeof(huffNodeTable))
++ return ERROR(GENERIC); /* workSpace is not large enough */
++ if (maxNbBits == 0)
++ maxNbBits = HUF_TABLELOG_DEFAULT;
++ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX)
++ return ERROR(GENERIC);
++ memset(huffNode0, 0, sizeof(huffNodeTable));
++
++ /* sort, decreasing order */
++ HUF_sort(huffNode, count, maxSymbolValue);
++
++ /* init for parents */
++ nonNullRank = maxSymbolValue;
++ while (huffNode[nonNullRank].count == 0)
++ nonNullRank--;
++ lowS = nonNullRank;
++ nodeRoot = nodeNb + lowS - 1;
++ lowN = nodeNb;
++ huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS - 1].count;
++ huffNode[lowS].parent = huffNode[lowS - 1].parent = nodeNb;
++ nodeNb++;
++ lowS -= 2;
++ for (n = nodeNb; n <= nodeRoot; n++)
++ huffNode[n].count = (U32)(1U << 30);
++ huffNode0[0].count = (U32)(1U << 31); /* fake entry, strong barrier */
++
++ /* create parents */
++ while (nodeNb <= nodeRoot) {
++ U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
++ U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
++ huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count;
++ huffNode[n1].parent = huffNode[n2].parent = nodeNb;
++ nodeNb++;
++ }
++
++ /* distribute weights (unlimited tree height) */
++ huffNode[nodeRoot].nbBits = 0;
++ for (n = nodeRoot - 1; n >= STARTNODE; n--)
++ huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1;
++ for (n = 0; n <= nonNullRank; n++)
++ huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1;
++
++ /* enforce maxTableLog */
++ maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits);
++
++ /* fill result into tree (val, nbBits) */
++ {
++ U16 nbPerRank[HUF_TABLELOG_MAX + 1] = {0};
++ U16 valPerRank[HUF_TABLELOG_MAX + 1] = {0};
++ if (maxNbBits > HUF_TABLELOG_MAX)
++ return ERROR(GENERIC); /* check fit into table */
++ for (n = 0; n <= nonNullRank; n++)
++ nbPerRank[huffNode[n].nbBits]++;
++ /* determine stating value per rank */
++ {
++ U16 min = 0;
++ for (n = maxNbBits; n > 0; n--) {
++ valPerRank[n] = min; /* get starting value within each rank */
++ min += nbPerRank[n];
++ min >>= 1;
++ }
++ }
++ for (n = 0; n <= maxSymbolValue; n++)
++ tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */
++ for (n = 0; n <= maxSymbolValue; n++)
++ tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */
++ }
++
++ return maxNbBits;
++}
++
++static size_t HUF_estimateCompressedSize(HUF_CElt *CTable, const unsigned *count, unsigned maxSymbolValue)
++{
++ size_t nbBits = 0;
++ int s;
++ for (s = 0; s <= (int)maxSymbolValue; ++s) {
++ nbBits += CTable[s].nbBits * count[s];
++ }
++ return nbBits >> 3;
++}
++
++static int HUF_validateCTable(const HUF_CElt *CTable, const unsigned *count, unsigned maxSymbolValue)
++{
++ int bad = 0;
++ int s;
++ for (s = 0; s <= (int)maxSymbolValue; ++s) {
++ bad |= (count[s] != 0) & (CTable[s].nbBits == 0);
++ }
++ return !bad;
++}
++
++static void HUF_encodeSymbol(BIT_CStream_t *bitCPtr, U32 symbol, const HUF_CElt *CTable)
++{
++ BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
++}
++
++size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
++
++#define HUF_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
++
++#define HUF_FLUSHBITS_1(stream) \
++ if (sizeof((stream)->bitContainer) * 8 < HUF_TABLELOG_MAX * 2 + 7) \
++ HUF_FLUSHBITS(stream)
++
++#define HUF_FLUSHBITS_2(stream) \
++ if (sizeof((stream)->bitContainer) * 8 < HUF_TABLELOG_MAX * 4 + 7) \
++ HUF_FLUSHBITS(stream)
++
++size_t HUF_compress1X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable)
++{
++ const BYTE *ip = (const BYTE *)src;
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *const oend = ostart + dstSize;
++ BYTE *op = ostart;
++ size_t n;
++ const unsigned fast = (dstSize >= HUF_BLOCKBOUND(srcSize));
++ BIT_CStream_t bitC;
++
++ /* init */
++ if (dstSize < 8)
++ return 0; /* not enough space to compress */
++ {
++ size_t const initErr = BIT_initCStream(&bitC, op, oend - op);
++ if (HUF_isError(initErr))
++ return 0;
++ }
++
++ n = srcSize & ~3; /* join to mod 4 */
++ switch (srcSize & 3) {
++ case 3: HUF_encodeSymbol(&bitC, ip[n + 2], CTable); HUF_FLUSHBITS_2(&bitC);
++ case 2: HUF_encodeSymbol(&bitC, ip[n + 1], CTable); HUF_FLUSHBITS_1(&bitC);
++ case 1: HUF_encodeSymbol(&bitC, ip[n + 0], CTable); HUF_FLUSHBITS(&bitC);
++ case 0:
++ default:;
++ }
++
++ for (; n > 0; n -= 4) { /* note : n&3==0 at this stage */
++ HUF_encodeSymbol(&bitC, ip[n - 1], CTable);
++ HUF_FLUSHBITS_1(&bitC);
++ HUF_encodeSymbol(&bitC, ip[n - 2], CTable);
++ HUF_FLUSHBITS_2(&bitC);
++ HUF_encodeSymbol(&bitC, ip[n - 3], CTable);
++ HUF_FLUSHBITS_1(&bitC);
++ HUF_encodeSymbol(&bitC, ip[n - 4], CTable);
++ HUF_FLUSHBITS(&bitC);
++ }
++
++ return BIT_closeCStream(&bitC);
++}
++
++size_t HUF_compress4X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable)
++{
++ size_t const segmentSize = (srcSize + 3) / 4; /* first 3 segments */
++ const BYTE *ip = (const BYTE *)src;
++ const BYTE *const iend = ip + srcSize;
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *const oend = ostart + dstSize;
++ BYTE *op = ostart;
++
++ if (dstSize < 6 + 1 + 1 + 1 + 8)
++ return 0; /* minimum space to compress successfully */
++ if (srcSize < 12)
++ return 0; /* no saving possible : too small input */
++ op += 6; /* jumpTable */
++
++ {
++ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend - op, ip, segmentSize, CTable));
++ if (cSize == 0)
++ return 0;
++ ZSTD_writeLE16(ostart, (U16)cSize);
++ op += cSize;
++ }
++
++ ip += segmentSize;
++ {
++ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend - op, ip, segmentSize, CTable));
++ if (cSize == 0)
++ return 0;
++ ZSTD_writeLE16(ostart + 2, (U16)cSize);
++ op += cSize;
++ }
++
++ ip += segmentSize;
++ {
++ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend - op, ip, segmentSize, CTable));
++ if (cSize == 0)
++ return 0;
++ ZSTD_writeLE16(ostart + 4, (U16)cSize);
++ op += cSize;
++ }
++
++ ip += segmentSize;
++ {
++ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend - op, ip, iend - ip, CTable));
++ if (cSize == 0)
++ return 0;
++ op += cSize;
++ }
++
++ return op - ostart;
++}
++
++static size_t HUF_compressCTable_internal(BYTE *const ostart, BYTE *op, BYTE *const oend, const void *src, size_t srcSize, unsigned singleStream,
++ const HUF_CElt *CTable)
++{
++ size_t const cSize =
++ singleStream ? HUF_compress1X_usingCTable(op, oend - op, src, srcSize, CTable) : HUF_compress4X_usingCTable(op, oend - op, src, srcSize, CTable);
++ if (HUF_isError(cSize)) {
++ return cSize;
++ }
++ if (cSize == 0) {
++ return 0;
++ } /* uncompressible */
++ op += cSize;
++ /* check compressibility */
++ if ((size_t)(op - ostart) >= srcSize - 1) {
++ return 0;
++ }
++ return op - ostart;
++}
++
++/* `workSpace` must a table of at least 1024 unsigned */
++static size_t HUF_compress_internal(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog,
++ unsigned singleStream, void *workSpace, size_t wkspSize, HUF_CElt *oldHufTable, HUF_repeat *repeat, int preferRepeat)
++{
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *const oend = ostart + dstSize;
++ BYTE *op = ostart;
++
++ U32 *count;
++ size_t const countSize = sizeof(U32) * (HUF_SYMBOLVALUE_MAX + 1);
++ HUF_CElt *CTable;
++ size_t const CTableSize = sizeof(HUF_CElt) * (HUF_SYMBOLVALUE_MAX + 1);
++
++ /* checks & inits */
++ if (wkspSize < sizeof(huffNodeTable) + countSize + CTableSize)
++ return ERROR(GENERIC);
++ if (!srcSize)
++ return 0; /* Uncompressed (note : 1 means rle, so first byte must be correct) */
++ if (!dstSize)
++ return 0; /* cannot fit within dst budget */
++ if (srcSize > HUF_BLOCKSIZE_MAX)
++ return ERROR(srcSize_wrong); /* curr block size limit */
++ if (huffLog > HUF_TABLELOG_MAX)
++ return ERROR(tableLog_tooLarge);
++ if (!maxSymbolValue)
++ maxSymbolValue = HUF_SYMBOLVALUE_MAX;
++ if (!huffLog)
++ huffLog = HUF_TABLELOG_DEFAULT;
++
++ count = (U32 *)workSpace;
++ workSpace = (BYTE *)workSpace + countSize;
++ wkspSize -= countSize;
++ CTable = (HUF_CElt *)workSpace;
++ workSpace = (BYTE *)workSpace + CTableSize;
++ wkspSize -= CTableSize;
++
++ /* Heuristic : If we don't need to check the validity of the old table use the old table for small inputs */
++ if (preferRepeat && repeat && *repeat == HUF_repeat_valid) {
++ return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
++ }
++
++ /* Scan input and build symbol stats */
++ {
++ CHECK_V_F(largest, FSE_count_wksp(count, &maxSymbolValue, (const BYTE *)src, srcSize, (U32 *)workSpace));
++ if (largest == srcSize) {
++ *ostart = ((const BYTE *)src)[0];
++ return 1;
++ } /* single symbol, rle */
++ if (largest <= (srcSize >> 7) + 1)
++ return 0; /* Fast heuristic : not compressible enough */
++ }
++
++ /* Check validity of previous table */
++ if (repeat && *repeat == HUF_repeat_check && !HUF_validateCTable(oldHufTable, count, maxSymbolValue)) {
++ *repeat = HUF_repeat_none;
++ }
++ /* Heuristic : use existing table for small inputs */
++ if (preferRepeat && repeat && *repeat != HUF_repeat_none) {
++ return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
++ }
++
++ /* Build Huffman Tree */
++ huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
++ {
++ CHECK_V_F(maxBits, HUF_buildCTable_wksp(CTable, count, maxSymbolValue, huffLog, workSpace, wkspSize));
++ huffLog = (U32)maxBits;
++ /* Zero the unused symbols so we can check it for validity */
++ memset(CTable + maxSymbolValue + 1, 0, CTableSize - (maxSymbolValue + 1) * sizeof(HUF_CElt));
++ }
++
++ /* Write table description header */
++ {
++ CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, CTable, maxSymbolValue, huffLog, workSpace, wkspSize));
++ /* Check if using the previous table will be beneficial */
++ if (repeat && *repeat != HUF_repeat_none) {
++ size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, count, maxSymbolValue);
++ size_t const newSize = HUF_estimateCompressedSize(CTable, count, maxSymbolValue);
++ if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) {
++ return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable);
++ }
++ }
++ /* Use the new table */
++ if (hSize + 12ul >= srcSize) {
++ return 0;
++ }
++ op += hSize;
++ if (repeat) {
++ *repeat = HUF_repeat_none;
++ }
++ if (oldHufTable) {
++ memcpy(oldHufTable, CTable, CTableSize);
++ } /* Save the new table */
++ }
++ return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, CTable);
++}
++
++size_t HUF_compress1X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void *workSpace,
++ size_t wkspSize)
++{
++ return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, NULL, NULL, 0);
++}
++
++size_t HUF_compress1X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void *workSpace,
++ size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat, int preferRepeat)
++{
++ return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, hufTable, repeat,
++ preferRepeat);
++}
++
++size_t HUF_compress4X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void *workSpace,
++ size_t wkspSize)
++{
++ return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, NULL, NULL, 0);
++}
++
++size_t HUF_compress4X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void *workSpace,
++ size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat, int preferRepeat)
++{
++ return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, hufTable, repeat,
++ preferRepeat);
++}
+diff --git a/lib/zstd/huf_decompress.c b/lib/zstd/huf_decompress.c
+new file mode 100644
+index 0000000..6526482
+--- /dev/null
++++ b/lib/zstd/huf_decompress.c
+@@ -0,0 +1,960 @@
++/*
++ * Huffman decoder, part of New Generation Entropy library
++ * Copyright (C) 2013-2016, 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.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ *
++ * You can contact the author at :
++ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
++ */
++
++/* **************************************************************
++* Compiler specifics
++****************************************************************/
++#define FORCE_INLINE static __always_inline
++
++/* **************************************************************
++* Dependencies
++****************************************************************/
++#include "bitstream.h" /* BIT_* */
++#include "fse.h" /* header compression */
++#include "huf.h"
++#include
++#include
++#include /* memcpy, memset */
++
++/* **************************************************************
++* Error Management
++****************************************************************/
++#define HUF_STATIC_ASSERT(c) \
++ { \
++ enum { HUF_static_assert = 1 / (int)(!!(c)) }; \
++ } /* use only *after* variable declarations */
++
++/*-***************************/
++/* generic DTableDesc */
++/*-***************************/
++
++typedef struct {
++ BYTE maxTableLog;
++ BYTE tableType;
++ BYTE tableLog;
++ BYTE reserved;
++} DTableDesc;
++
++static DTableDesc HUF_getDTableDesc(const HUF_DTable *table)
++{
++ DTableDesc dtd;
++ memcpy(&dtd, table, sizeof(dtd));
++ return dtd;
++}
++
++/*-***************************/
++/* single-symbol decoding */
++/*-***************************/
++
++typedef struct {
++ BYTE byte;
++ BYTE nbBits;
++} HUF_DEltX2; /* single-symbol decoding */
++
++size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
++{
++ U32 tableLog = 0;
++ U32 nbSymbols = 0;
++ size_t iSize;
++ void *const dtPtr = DTable + 1;
++ HUF_DEltX2 *const dt = (HUF_DEltX2 *)dtPtr;
++
++ U32 *rankVal;
++ BYTE *huffWeight;
++ size_t spaceUsed32 = 0;
++
++ rankVal = (U32 *)workspace + spaceUsed32;
++ spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
++ huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
++
++ if ((spaceUsed32 << 2) > workspaceSize)
++ return ERROR(tableLog_tooLarge);
++ workspace = (U32 *)workspace + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++
++ HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
++ /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
++
++ iSize = HUF_readStats_wksp(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
++ if (HUF_isError(iSize))
++ return iSize;
++
++ /* Table header */
++ {
++ DTableDesc dtd = HUF_getDTableDesc(DTable);
++ if (tableLog > (U32)(dtd.maxTableLog + 1))
++ return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
++ dtd.tableType = 0;
++ dtd.tableLog = (BYTE)tableLog;
++ memcpy(DTable, &dtd, sizeof(dtd));
++ }
++
++ /* Calculate starting value for each rank */
++ {
++ U32 n, nextRankStart = 0;
++ for (n = 1; n < tableLog + 1; n++) {
++ U32 const curr = nextRankStart;
++ nextRankStart += (rankVal[n] << (n - 1));
++ rankVal[n] = curr;
++ }
++ }
++
++ /* fill DTable */
++ {
++ U32 n;
++ for (n = 0; n < nbSymbols; n++) {
++ U32 const w = huffWeight[n];
++ U32 const length = (1 << w) >> 1;
++ U32 u;
++ HUF_DEltX2 D;
++ D.byte = (BYTE)n;
++ D.nbBits = (BYTE)(tableLog + 1 - w);
++ for (u = rankVal[w]; u < rankVal[w] + length; u++)
++ dt[u] = D;
++ rankVal[w] += length;
++ }
++ }
++
++ return iSize;
++}
++
++static BYTE HUF_decodeSymbolX2(BIT_DStream_t *Dstream, const HUF_DEltX2 *dt, const U32 dtLog)
++{
++ size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
++ BYTE const c = dt[val].byte;
++ BIT_skipBits(Dstream, dt[val].nbBits);
++ return c;
++}
++
++#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) *ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
++
++#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
++ if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
++ HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
++
++#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
++ if (ZSTD_64bits()) \
++ HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
++
++FORCE_INLINE size_t HUF_decodeStreamX2(BYTE *p, BIT_DStream_t *const bitDPtr, BYTE *const pEnd, const HUF_DEltX2 *const dt, const U32 dtLog)
++{
++ BYTE *const pStart = p;
++
++ /* up to 4 symbols at a time */
++ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd - 4)) {
++ HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
++ HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
++ HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
++ HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
++ }
++
++ /* closer to the end */
++ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd))
++ HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
++
++ /* no more data to retrieve from bitstream, hence no need to reload */
++ while (p < pEnd)
++ HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
++
++ return pEnd - pStart;
++}
++
++static size_t HUF_decompress1X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ BYTE *op = (BYTE *)dst;
++ BYTE *const oend = op + dstSize;
++ const void *dtPtr = DTable + 1;
++ const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
++ BIT_DStream_t bitD;
++ DTableDesc const dtd = HUF_getDTableDesc(DTable);
++ U32 const dtLog = dtd.tableLog;
++
++ {
++ size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++
++ HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
++
++ /* check */
++ if (!BIT_endOfDStream(&bitD))
++ return ERROR(corruption_detected);
++
++ return dstSize;
++}
++
++size_t HUF_decompress1X2_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ DTableDesc dtd = HUF_getDTableDesc(DTable);
++ if (dtd.tableType != 0)
++ return ERROR(GENERIC);
++ return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
++}
++
++size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
++{
++ const BYTE *ip = (const BYTE *)cSrc;
++
++ size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize);
++ if (HUF_isError(hSize))
++ return hSize;
++ if (hSize >= cSrcSize)
++ return ERROR(srcSize_wrong);
++ ip += hSize;
++ cSrcSize -= hSize;
++
++ return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx);
++}
++
++static size_t HUF_decompress4X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ /* Check */
++ if (cSrcSize < 10)
++ return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
++
++ {
++ const BYTE *const istart = (const BYTE *)cSrc;
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *const oend = ostart + dstSize;
++ const void *const dtPtr = DTable + 1;
++ const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
++
++ /* Init */
++ BIT_DStream_t bitD1;
++ BIT_DStream_t bitD2;
++ BIT_DStream_t bitD3;
++ BIT_DStream_t bitD4;
++ size_t const length1 = ZSTD_readLE16(istart);
++ size_t const length2 = ZSTD_readLE16(istart + 2);
++ size_t const length3 = ZSTD_readLE16(istart + 4);
++ size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
++ const BYTE *const istart1 = istart + 6; /* jumpTable */
++ const BYTE *const istart2 = istart1 + length1;
++ const BYTE *const istart3 = istart2 + length2;
++ const BYTE *const istart4 = istart3 + length3;
++ const size_t segmentSize = (dstSize + 3) / 4;
++ BYTE *const opStart2 = ostart + segmentSize;
++ BYTE *const opStart3 = opStart2 + segmentSize;
++ BYTE *const opStart4 = opStart3 + segmentSize;
++ BYTE *op1 = ostart;
++ BYTE *op2 = opStart2;
++ BYTE *op3 = opStart3;
++ BYTE *op4 = opStart4;
++ U32 endSignal;
++ DTableDesc const dtd = HUF_getDTableDesc(DTable);
++ U32 const dtLog = dtd.tableLog;
++
++ if (length4 > cSrcSize)
++ return ERROR(corruption_detected); /* overflow */
++ {
++ size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++ {
++ size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++ {
++ size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++ {
++ size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++
++ /* 16-32 symbols per loop (4-8 symbols per stream) */
++ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
++ for (; (endSignal == BIT_DStream_unfinished) && (op4 < (oend - 7));) {
++ HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
++ HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
++ HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
++ HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
++ HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
++ HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
++ HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
++ HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
++ HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
++ HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
++ HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
++ HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
++ HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
++ HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
++ HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
++ HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
++ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
++ }
++
++ /* check corruption */
++ if (op1 > opStart2)
++ return ERROR(corruption_detected);
++ if (op2 > opStart3)
++ return ERROR(corruption_detected);
++ if (op3 > opStart4)
++ return ERROR(corruption_detected);
++ /* note : op4 supposed already verified within main loop */
++
++ /* finish bitStreams one by one */
++ HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
++ HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
++ HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
++ HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
++
++ /* check */
++ endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
++ if (!endSignal)
++ return ERROR(corruption_detected);
++
++ /* decoded size */
++ return dstSize;
++ }
++}
++
++size_t HUF_decompress4X2_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ DTableDesc dtd = HUF_getDTableDesc(DTable);
++ if (dtd.tableType != 0)
++ return ERROR(GENERIC);
++ return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
++}
++
++size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
++{
++ const BYTE *ip = (const BYTE *)cSrc;
++
++ size_t const hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize);
++ if (HUF_isError(hSize))
++ return hSize;
++ if (hSize >= cSrcSize)
++ return ERROR(srcSize_wrong);
++ ip += hSize;
++ cSrcSize -= hSize;
++
++ return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
++}
++
++/* *************************/
++/* double-symbols decoding */
++/* *************************/
++typedef struct {
++ U16 sequence;
++ BYTE nbBits;
++ BYTE length;
++} HUF_DEltX4; /* double-symbols decoding */
++
++typedef struct {
++ BYTE symbol;
++ BYTE weight;
++} sortedSymbol_t;
++
++/* HUF_fillDTableX4Level2() :
++ * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
++static void HUF_fillDTableX4Level2(HUF_DEltX4 *DTable, U32 sizeLog, const U32 consumed, const U32 *rankValOrigin, const int minWeight,
++ const sortedSymbol_t *sortedSymbols, const U32 sortedListSize, U32 nbBitsBaseline, U16 baseSeq)
++{
++ HUF_DEltX4 DElt;
++ U32 rankVal[HUF_TABLELOG_MAX + 1];
++
++ /* get pre-calculated rankVal */
++ memcpy(rankVal, rankValOrigin, sizeof(rankVal));
++
++ /* fill skipped values */
++ if (minWeight > 1) {
++ U32 i, skipSize = rankVal[minWeight];
++ ZSTD_writeLE16(&(DElt.sequence), baseSeq);
++ DElt.nbBits = (BYTE)(consumed);
++ DElt.length = 1;
++ for (i = 0; i < skipSize; i++)
++ DTable[i] = DElt;
++ }
++
++ /* fill DTable */
++ {
++ U32 s;
++ for (s = 0; s < sortedListSize; s++) { /* note : sortedSymbols already skipped */
++ const U32 symbol = sortedSymbols[s].symbol;
++ const U32 weight = sortedSymbols[s].weight;
++ const U32 nbBits = nbBitsBaseline - weight;
++ const U32 length = 1 << (sizeLog - nbBits);
++ const U32 start = rankVal[weight];
++ U32 i = start;
++ const U32 end = start + length;
++
++ ZSTD_writeLE16(&(DElt.sequence), (U16)(baseSeq + (symbol << 8)));
++ DElt.nbBits = (BYTE)(nbBits + consumed);
++ DElt.length = 2;
++ do {
++ DTable[i++] = DElt;
++ } while (i < end); /* since length >= 1 */
++
++ rankVal[weight] += length;
++ }
++ }
++}
++
++typedef U32 rankVal_t[HUF_TABLELOG_MAX][HUF_TABLELOG_MAX + 1];
++typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
++
++static void HUF_fillDTableX4(HUF_DEltX4 *DTable, const U32 targetLog, const sortedSymbol_t *sortedList, const U32 sortedListSize, const U32 *rankStart,
++ rankVal_t rankValOrigin, const U32 maxWeight, const U32 nbBitsBaseline)
++{
++ U32 rankVal[HUF_TABLELOG_MAX + 1];
++ const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
++ const U32 minBits = nbBitsBaseline - maxWeight;
++ U32 s;
++
++ memcpy(rankVal, rankValOrigin, sizeof(rankVal));
++
++ /* fill DTable */
++ for (s = 0; s < sortedListSize; s++) {
++ const U16 symbol = sortedList[s].symbol;
++ const U32 weight = sortedList[s].weight;
++ const U32 nbBits = nbBitsBaseline - weight;
++ const U32 start = rankVal[weight];
++ const U32 length = 1 << (targetLog - nbBits);
++
++ if (targetLog - nbBits >= minBits) { /* enough room for a second symbol */
++ U32 sortedRank;
++ int minWeight = nbBits + scaleLog;
++ if (minWeight < 1)
++ minWeight = 1;
++ sortedRank = rankStart[minWeight];
++ HUF_fillDTableX4Level2(DTable + start, targetLog - nbBits, nbBits, rankValOrigin[nbBits], minWeight, sortedList + sortedRank,
++ sortedListSize - sortedRank, nbBitsBaseline, symbol);
++ } else {
++ HUF_DEltX4 DElt;
++ ZSTD_writeLE16(&(DElt.sequence), symbol);
++ DElt.nbBits = (BYTE)(nbBits);
++ DElt.length = 1;
++ {
++ U32 const end = start + length;
++ U32 u;
++ for (u = start; u < end; u++)
++ DTable[u] = DElt;
++ }
++ }
++ rankVal[weight] += length;
++ }
++}
++
++size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
++{
++ U32 tableLog, maxW, sizeOfSort, nbSymbols;
++ DTableDesc dtd = HUF_getDTableDesc(DTable);
++ U32 const maxTableLog = dtd.maxTableLog;
++ size_t iSize;
++ void *dtPtr = DTable + 1; /* force compiler to avoid strict-aliasing */
++ HUF_DEltX4 *const dt = (HUF_DEltX4 *)dtPtr;
++ U32 *rankStart;
++
++ rankValCol_t *rankVal;
++ U32 *rankStats;
++ U32 *rankStart0;
++ sortedSymbol_t *sortedSymbol;
++ BYTE *weightList;
++ size_t spaceUsed32 = 0;
++
++ HUF_STATIC_ASSERT((sizeof(rankValCol_t) & 3) == 0);
++
++ rankVal = (rankValCol_t *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
++ rankStats = (U32 *)workspace + spaceUsed32;
++ spaceUsed32 += HUF_TABLELOG_MAX + 1;
++ rankStart0 = (U32 *)workspace + spaceUsed32;
++ spaceUsed32 += HUF_TABLELOG_MAX + 2;
++ sortedSymbol = (sortedSymbol_t *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
++ weightList = (BYTE *)((U32 *)workspace + spaceUsed32);
++ spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
++
++ if ((spaceUsed32 << 2) > workspaceSize)
++ return ERROR(tableLog_tooLarge);
++ workspace = (U32 *)workspace + spaceUsed32;
++ workspaceSize -= (spaceUsed32 << 2);
++
++ rankStart = rankStart0 + 1;
++ memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
++
++ HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
++ if (maxTableLog > HUF_TABLELOG_MAX)
++ return ERROR(tableLog_tooLarge);
++ /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
++
++ iSize = HUF_readStats_wksp(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
++ if (HUF_isError(iSize))
++ return iSize;
++
++ /* check result */
++ if (tableLog > maxTableLog)
++ return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
++
++ /* find maxWeight */
++ for (maxW = tableLog; rankStats[maxW] == 0; maxW--) {
++ } /* necessarily finds a solution before 0 */
++
++ /* Get start index of each weight */
++ {
++ U32 w, nextRankStart = 0;
++ for (w = 1; w < maxW + 1; w++) {
++ U32 curr = nextRankStart;
++ nextRankStart += rankStats[w];
++ rankStart[w] = curr;
++ }
++ rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/
++ sizeOfSort = nextRankStart;
++ }
++
++ /* sort symbols by weight */
++ {
++ U32 s;
++ for (s = 0; s < nbSymbols; s++) {
++ U32 const w = weightList[s];
++ U32 const r = rankStart[w]++;
++ sortedSymbol[r].symbol = (BYTE)s;
++ sortedSymbol[r].weight = (BYTE)w;
++ }
++ rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */
++ }
++
++ /* Build rankVal */
++ {
++ U32 *const rankVal0 = rankVal[0];
++ {
++ int const rescale = (maxTableLog - tableLog) - 1; /* tableLog <= maxTableLog */
++ U32 nextRankVal = 0;
++ U32 w;
++ for (w = 1; w < maxW + 1; w++) {
++ U32 curr = nextRankVal;
++ nextRankVal += rankStats[w] << (w + rescale);
++ rankVal0[w] = curr;
++ }
++ }
++ {
++ U32 const minBits = tableLog + 1 - maxW;
++ U32 consumed;
++ for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) {
++ U32 *const rankValPtr = rankVal[consumed];
++ U32 w;
++ for (w = 1; w < maxW + 1; w++) {
++ rankValPtr[w] = rankVal0[w] >> consumed;
++ }
++ }
++ }
++ }
++
++ HUF_fillDTableX4(dt, maxTableLog, sortedSymbol, sizeOfSort, rankStart0, rankVal, maxW, tableLog + 1);
++
++ dtd.tableLog = (BYTE)maxTableLog;
++ dtd.tableType = 1;
++ memcpy(DTable, &dtd, sizeof(dtd));
++ return iSize;
++}
++
++static U32 HUF_decodeSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog)
++{
++ size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
++ memcpy(op, dt + val, 2);
++ BIT_skipBits(DStream, dt[val].nbBits);
++ return dt[val].length;
++}
++
++static U32 HUF_decodeLastSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog)
++{
++ size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
++ memcpy(op, dt + val, 1);
++ if (dt[val].length == 1)
++ BIT_skipBits(DStream, dt[val].nbBits);
++ else {
++ if (DStream->bitsConsumed < (sizeof(DStream->bitContainer) * 8)) {
++ BIT_skipBits(DStream, dt[val].nbBits);
++ if (DStream->bitsConsumed > (sizeof(DStream->bitContainer) * 8))
++ /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
++ DStream->bitsConsumed = (sizeof(DStream->bitContainer) * 8);
++ }
++ }
++ return 1;
++}
++
++#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
++
++#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
++ if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
++ ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
++
++#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
++ if (ZSTD_64bits()) \
++ ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
++
++FORCE_INLINE size_t HUF_decodeStreamX4(BYTE *p, BIT_DStream_t *bitDPtr, BYTE *const pEnd, const HUF_DEltX4 *const dt, const U32 dtLog)
++{
++ BYTE *const pStart = p;
++
++ /* up to 8 symbols at a time */
++ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd - (sizeof(bitDPtr->bitContainer) - 1))) {
++ HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
++ HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
++ HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
++ HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
++ }
++
++ /* closer to end : up to 2 symbols at a time */
++ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd - 2))
++ HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
++
++ while (p <= pEnd - 2)
++ HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
++
++ if (p < pEnd)
++ p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
++
++ return p - pStart;
++}
++
++static size_t HUF_decompress1X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ BIT_DStream_t bitD;
++
++ /* Init */
++ {
++ size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++
++ /* decode */
++ {
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *const oend = ostart + dstSize;
++ const void *const dtPtr = DTable + 1; /* force compiler to not use strict-aliasing */
++ const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
++ DTableDesc const dtd = HUF_getDTableDesc(DTable);
++ HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
++ }
++
++ /* check */
++ if (!BIT_endOfDStream(&bitD))
++ return ERROR(corruption_detected);
++
++ /* decoded size */
++ return dstSize;
++}
++
++size_t HUF_decompress1X4_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ DTableDesc dtd = HUF_getDTableDesc(DTable);
++ if (dtd.tableType != 1)
++ return ERROR(GENERIC);
++ return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
++}
++
++size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
++{
++ const BYTE *ip = (const BYTE *)cSrc;
++
++ size_t const hSize = HUF_readDTableX4_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize);
++ if (HUF_isError(hSize))
++ return hSize;
++ if (hSize >= cSrcSize)
++ return ERROR(srcSize_wrong);
++ ip += hSize;
++ cSrcSize -= hSize;
++
++ return HUF_decompress1X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx);
++}
++
++static size_t HUF_decompress4X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ if (cSrcSize < 10)
++ return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
++
++ {
++ const BYTE *const istart = (const BYTE *)cSrc;
++ BYTE *const ostart = (BYTE *)dst;
++ BYTE *const oend = ostart + dstSize;
++ const void *const dtPtr = DTable + 1;
++ const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
++
++ /* Init */
++ BIT_DStream_t bitD1;
++ BIT_DStream_t bitD2;
++ BIT_DStream_t bitD3;
++ BIT_DStream_t bitD4;
++ size_t const length1 = ZSTD_readLE16(istart);
++ size_t const length2 = ZSTD_readLE16(istart + 2);
++ size_t const length3 = ZSTD_readLE16(istart + 4);
++ size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
++ const BYTE *const istart1 = istart + 6; /* jumpTable */
++ const BYTE *const istart2 = istart1 + length1;
++ const BYTE *const istart3 = istart2 + length2;
++ const BYTE *const istart4 = istart3 + length3;
++ size_t const segmentSize = (dstSize + 3) / 4;
++ BYTE *const opStart2 = ostart + segmentSize;
++ BYTE *const opStart3 = opStart2 + segmentSize;
++ BYTE *const opStart4 = opStart3 + segmentSize;
++ BYTE *op1 = ostart;
++ BYTE *op2 = opStart2;
++ BYTE *op3 = opStart3;
++ BYTE *op4 = opStart4;
++ U32 endSignal;
++ DTableDesc const dtd = HUF_getDTableDesc(DTable);
++ U32 const dtLog = dtd.tableLog;
++
++ if (length4 > cSrcSize)
++ return ERROR(corruption_detected); /* overflow */
++ {
++ size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++ {
++ size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++ {
++ size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++ {
++ size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
++ if (HUF_isError(errorCode))
++ return errorCode;
++ }
++
++ /* 16-32 symbols per loop (4-8 symbols per stream) */
++ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
++ for (; (endSignal == BIT_DStream_unfinished) & (op4 < (oend - (sizeof(bitD4.bitContainer) - 1)));) {
++ HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
++ HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
++ HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
++ HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
++ HUF_DECODE_SYMBOLX4_1(op1, &bitD1);
++ HUF_DECODE_SYMBOLX4_1(op2, &bitD2);
++ HUF_DECODE_SYMBOLX4_1(op3, &bitD3);
++ HUF_DECODE_SYMBOLX4_1(op4, &bitD4);
++ HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
++ HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
++ HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
++ HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
++ HUF_DECODE_SYMBOLX4_0(op1, &bitD1);
++ HUF_DECODE_SYMBOLX4_0(op2, &bitD2);
++ HUF_DECODE_SYMBOLX4_0(op3, &bitD3);
++ HUF_DECODE_SYMBOLX4_0(op4, &bitD4);
++
++ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
++ }
++
++ /* check corruption */
++ if (op1 > opStart2)
++ return ERROR(corruption_detected);
++ if (op2 > opStart3)
++ return ERROR(corruption_detected);
++ if (op3 > opStart4)
++ return ERROR(corruption_detected);
++ /* note : op4 already verified within main loop */
++
++ /* finish bitStreams one by one */
++ HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
++ HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
++ HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
++ HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
++
++ /* check */
++ {
++ U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
++ if (!endCheck)
++ return ERROR(corruption_detected);
++ }
++
++ /* decoded size */
++ return dstSize;
++ }
++}
++
++size_t HUF_decompress4X4_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ DTableDesc dtd = HUF_getDTableDesc(DTable);
++ if (dtd.tableType != 1)
++ return ERROR(GENERIC);
++ return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
++}
++
++size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
++{
++ const BYTE *ip = (const BYTE *)cSrc;
++
++ size_t hSize = HUF_readDTableX4_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize);
++ if (HUF_isError(hSize))
++ return hSize;
++ if (hSize >= cSrcSize)
++ return ERROR(srcSize_wrong);
++ ip += hSize;
++ cSrcSize -= hSize;
++
++ return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
++}
++
++/* ********************************/
++/* Generic decompression selector */
++/* ********************************/
++
++size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ DTableDesc const dtd = HUF_getDTableDesc(DTable);
++ return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable)
++ : HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
++}
++
++size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
++{
++ DTableDesc const dtd = HUF_getDTableDesc(DTable);
++ return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable)
++ : HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
++}
++
++typedef struct {
++ U32 tableTime;
++ U32 decode256Time;
++} algo_time_t;
++static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = {
++ /* single, double, quad */
++ {{0, 0}, {1, 1}, {2, 2}}, /* Q==0 : impossible */
++ {{0, 0}, {1, 1}, {2, 2}}, /* Q==1 : impossible */
++ {{38, 130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */
++ {{448, 128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */
++ {{556, 128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */
++ {{714, 128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */
++ {{883, 128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */
++ {{897, 128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */
++ {{926, 128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */
++ {{947, 128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */
++ {{1107, 128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */
++ {{1177, 128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */
++ {{1242, 128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */
++ {{1349, 128}, {2644, 106}, {5260, 106}}, /* Q ==13 : 81-87% */
++ {{1455, 128}, {2422, 124}, {4174, 124}}, /* Q ==14 : 87-93% */
++ {{722, 128}, {1891, 145}, {1936, 146}}, /* Q ==15 : 93-99% */
++};
++
++/** HUF_selectDecoder() :
++* Tells which decoder is likely to decode faster,
++* based on a set of pre-determined metrics.
++* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
++* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
++U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize)
++{
++ /* decoder timing evaluation */
++ U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */
++ U32 const D256 = (U32)(dstSize >> 8);
++ U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
++ U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
++ DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, for cache eviction */
++
++ return DTime1 < DTime0;
++}
++
++typedef size_t (*decompressionAlgo)(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize);
++
++size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
++{
++ /* validation checks */
++ if (dstSize == 0)
++ return ERROR(dstSize_tooSmall);
++ if (cSrcSize > dstSize)
++ return ERROR(corruption_detected); /* invalid */
++ if (cSrcSize == dstSize) {
++ memcpy(dst, cSrc, dstSize);
++ return dstSize;
++ } /* not compressed */
++ if (cSrcSize == 1) {
++ memset(dst, *(const BYTE *)cSrc, dstSize);
++ return dstSize;
++ } /* RLE */
++
++ {
++ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
++ return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
++ : HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
++ }
++}
++
++size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
++{
++ /* validation checks */
++ if (dstSize == 0)
++ return ERROR(dstSize_tooSmall);
++ if ((cSrcSize >= dstSize) || (cSrcSize <= 1))
++ return ERROR(corruption_detected); /* invalid */
++
++ {
++ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
++ return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
++ : HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
++ }
++}
++
++size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
++{
++ /* validation checks */
++ if (dstSize == 0)
++ return ERROR(dstSize_tooSmall);
++ if (cSrcSize > dstSize)
++ return ERROR(corruption_detected); /* invalid */
++ if (cSrcSize == dstSize) {
++ memcpy(dst, cSrc, dstSize);
++ return dstSize;
++ } /* not compressed */
++ if (cSrcSize == 1) {
++ memset(dst, *(const BYTE *)cSrc, dstSize);
++ return dstSize;
++ } /* RLE */
++
++ {
++ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
++ return algoNb ? HUF_decompress1X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
++ : HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
++ }
++}
+diff --git a/lib/zstd/mem.h b/lib/zstd/mem.h
+new file mode 100644
+index 0000000..3a0f34c
+--- /dev/null
++++ b/lib/zstd/mem.h
+@@ -0,0 +1,151 @@
++/**
++ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This source code is licensed under the BSD-style license found in the
++ * LICENSE file in the root directory of https://github.com/facebook/zstd.
++ * An additional grant of patent rights can be found in the PATENTS file in the
++ * same directory.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ */
++
++#ifndef MEM_H_MODULE
++#define MEM_H_MODULE
++
++/*-****************************************
++* Dependencies
++******************************************/
++#include
++#include /* memcpy */
++#include /* size_t, ptrdiff_t */
++
++/*-****************************************
++* Compiler specifics
++******************************************/
++#define ZSTD_STATIC static __inline __attribute__((unused))
++
++/*-**************************************************************
++* Basic Types
++*****************************************************************/
++typedef uint8_t BYTE;
++typedef uint16_t U16;
++typedef int16_t S16;
++typedef uint32_t U32;
++typedef int32_t S32;
++typedef uint64_t U64;
++typedef int64_t S64;
++typedef ptrdiff_t iPtrDiff;
++typedef uintptr_t uPtrDiff;
++
++/*-**************************************************************
++* Memory I/O
++*****************************************************************/
++ZSTD_STATIC unsigned ZSTD_32bits(void) { return sizeof(size_t) == 4; }
++ZSTD_STATIC unsigned ZSTD_64bits(void) { return sizeof(size_t) == 8; }
++
++#if defined(__LITTLE_ENDIAN)
++#define ZSTD_LITTLE_ENDIAN 1
++#else
++#define ZSTD_LITTLE_ENDIAN 0
++#endif
++
++ZSTD_STATIC unsigned ZSTD_isLittleEndian(void) { return ZSTD_LITTLE_ENDIAN; }
++
++ZSTD_STATIC U16 ZSTD_read16(const void *memPtr) { return get_unaligned((const U16 *)memPtr); }
++
++ZSTD_STATIC U32 ZSTD_read32(const void *memPtr) { return get_unaligned((const U32 *)memPtr); }
++
++ZSTD_STATIC U64 ZSTD_read64(const void *memPtr) { return get_unaligned((const U64 *)memPtr); }
++
++ZSTD_STATIC size_t ZSTD_readST(const void *memPtr) { return get_unaligned((const size_t *)memPtr); }
++
++ZSTD_STATIC void ZSTD_write16(void *memPtr, U16 value) { put_unaligned(value, (U16 *)memPtr); }
++
++ZSTD_STATIC void ZSTD_write32(void *memPtr, U32 value) { put_unaligned(value, (U32 *)memPtr); }
++
++ZSTD_STATIC void ZSTD_write64(void *memPtr, U64 value) { put_unaligned(value, (U64 *)memPtr); }
++
++/*=== Little endian r/w ===*/
++
++ZSTD_STATIC U16 ZSTD_readLE16(const void *memPtr) { return get_unaligned_le16(memPtr); }
++
++ZSTD_STATIC void ZSTD_writeLE16(void *memPtr, U16 val) { put_unaligned_le16(val, memPtr); }
++
++ZSTD_STATIC U32 ZSTD_readLE24(const void *memPtr) { return ZSTD_readLE16(memPtr) + (((const BYTE *)memPtr)[2] << 16); }
++
++ZSTD_STATIC void ZSTD_writeLE24(void *memPtr, U32 val)
++{
++ ZSTD_writeLE16(memPtr, (U16)val);
++ ((BYTE *)memPtr)[2] = (BYTE)(val >> 16);
++}
++
++ZSTD_STATIC U32 ZSTD_readLE32(const void *memPtr) { return get_unaligned_le32(memPtr); }
++
++ZSTD_STATIC void ZSTD_writeLE32(void *memPtr, U32 val32) { put_unaligned_le32(val32, memPtr); }
++
++ZSTD_STATIC U64 ZSTD_readLE64(const void *memPtr) { return get_unaligned_le64(memPtr); }
++
++ZSTD_STATIC void ZSTD_writeLE64(void *memPtr, U64 val64) { put_unaligned_le64(val64, memPtr); }
++
++ZSTD_STATIC size_t ZSTD_readLEST(const void *memPtr)
++{
++ if (ZSTD_32bits())
++ return (size_t)ZSTD_readLE32(memPtr);
++ else
++ return (size_t)ZSTD_readLE64(memPtr);
++}
++
++ZSTD_STATIC void ZSTD_writeLEST(void *memPtr, size_t val)
++{
++ if (ZSTD_32bits())
++ ZSTD_writeLE32(memPtr, (U32)val);
++ else
++ ZSTD_writeLE64(memPtr, (U64)val);
++}
++
++/*=== Big endian r/w ===*/
++
++ZSTD_STATIC U32 ZSTD_readBE32(const void *memPtr) { return get_unaligned_be32(memPtr); }
++
++ZSTD_STATIC void ZSTD_writeBE32(void *memPtr, U32 val32) { put_unaligned_be32(val32, memPtr); }
++
++ZSTD_STATIC U64 ZSTD_readBE64(const void *memPtr) { return get_unaligned_be64(memPtr); }
++
++ZSTD_STATIC void ZSTD_writeBE64(void *memPtr, U64 val64) { put_unaligned_be64(val64, memPtr); }
++
++ZSTD_STATIC size_t ZSTD_readBEST(const void *memPtr)
++{
++ if (ZSTD_32bits())
++ return (size_t)ZSTD_readBE32(memPtr);
++ else
++ return (size_t)ZSTD_readBE64(memPtr);
++}
++
++ZSTD_STATIC void ZSTD_writeBEST(void *memPtr, size_t val)
++{
++ if (ZSTD_32bits())
++ ZSTD_writeBE32(memPtr, (U32)val);
++ else
++ ZSTD_writeBE64(memPtr, (U64)val);
++}
++
++/* function safe only for comparisons */
++ZSTD_STATIC U32 ZSTD_readMINMATCH(const void *memPtr, U32 length)
++{
++ switch (length) {
++ default:
++ case 4: return ZSTD_read32(memPtr);
++ case 3:
++ if (ZSTD_isLittleEndian())
++ return ZSTD_read32(memPtr) << 8;
++ else
++ return ZSTD_read32(memPtr) >> 8;
++ }
++}
++
++#endif /* MEM_H_MODULE */
+diff --git a/lib/zstd/zstd_common.c b/lib/zstd/zstd_common.c
+new file mode 100644
+index 0000000..a282624
+--- /dev/null
++++ b/lib/zstd/zstd_common.c
+@@ -0,0 +1,75 @@
++/**
++ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This source code is licensed under the BSD-style license found in the
++ * LICENSE file in the root directory of https://github.com/facebook/zstd.
++ * An additional grant of patent rights can be found in the PATENTS file in the
++ * same directory.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ */
++
++/*-*************************************
++* Dependencies
++***************************************/
++#include "error_private.h"
++#include "zstd_internal.h" /* declaration of ZSTD_isError, ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber */
++#include
++
++/*=**************************************************************
++* Custom allocator
++****************************************************************/
++
++#define stack_push(stack, size) \
++ ({ \
++ void *const ptr = ZSTD_PTR_ALIGN((stack)->ptr); \
++ (stack)->ptr = (char *)ptr + (size); \
++ (stack)->ptr <= (stack)->end ? ptr : NULL; \
++ })
++
++ZSTD_customMem ZSTD_initStack(void *workspace, size_t workspaceSize)
++{
++ ZSTD_customMem stackMem = {ZSTD_stackAlloc, ZSTD_stackFree, workspace};
++ ZSTD_stack *stack = (ZSTD_stack *)workspace;
++ /* Verify preconditions */
++ if (!workspace || workspaceSize < sizeof(ZSTD_stack) || workspace != ZSTD_PTR_ALIGN(workspace)) {
++ ZSTD_customMem error = {NULL, NULL, NULL};
++ return error;
++ }
++ /* Initialize the stack */
++ stack->ptr = workspace;
++ stack->end = (char *)workspace + workspaceSize;
++ stack_push(stack, sizeof(ZSTD_stack));
++ return stackMem;
++}
++
++void *ZSTD_stackAllocAll(void *opaque, size_t *size)
++{
++ ZSTD_stack *stack = (ZSTD_stack *)opaque;
++ *size = (BYTE const *)stack->end - (BYTE *)ZSTD_PTR_ALIGN(stack->ptr);
++ return stack_push(stack, *size);
++}
++
++void *ZSTD_stackAlloc(void *opaque, size_t size)
++{
++ ZSTD_stack *stack = (ZSTD_stack *)opaque;
++ return stack_push(stack, size);
++}
++void ZSTD_stackFree(void *opaque, void *address)
++{
++ (void)opaque;
++ (void)address;
++}
++
++void *ZSTD_malloc(size_t size, ZSTD_customMem customMem) { return customMem.customAlloc(customMem.opaque, size); }
++
++void ZSTD_free(void *ptr, ZSTD_customMem customMem)
++{
++ if (ptr != NULL)
++ customMem.customFree(customMem.opaque, ptr);
++}
+diff --git a/lib/zstd/zstd_internal.h b/lib/zstd/zstd_internal.h
+new file mode 100644
+index 0000000..6748719
+--- /dev/null
++++ b/lib/zstd/zstd_internal.h
+@@ -0,0 +1,269 @@
++/**
++ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This source code is licensed under the BSD-style license found in the
++ * LICENSE file in the root directory of https://github.com/facebook/zstd.
++ * An additional grant of patent rights can be found in the PATENTS file in the
++ * same directory.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ */
++
++#ifndef ZSTD_CCOMMON_H_MODULE
++#define ZSTD_CCOMMON_H_MODULE
++
++/*-*******************************************************
++* Compiler specifics
++*********************************************************/
++#define FORCE_INLINE static __always_inline
++#define FORCE_NOINLINE static noinline
++
++/*-*************************************
++* Dependencies
++***************************************/
++#include "error_private.h"
++#include "mem.h"
++#include
++#include
++#include
++#include
++
++/*-*************************************
++* shared macros
++***************************************/
++#define MIN(a, b) ((a) < (b) ? (a) : (b))
++#define MAX(a, b) ((a) > (b) ? (a) : (b))
++#define CHECK_F(f) \
++ { \
++ size_t const errcod = f; \
++ if (ERR_isError(errcod)) \
++ return errcod; \
++ } /* check and Forward error code */
++#define CHECK_E(f, e) \
++ { \
++ size_t const errcod = f; \
++ if (ERR_isError(errcod)) \
++ return ERROR(e); \
++ } /* check and send Error code */
++#define ZSTD_STATIC_ASSERT(c) \
++ { \
++ enum { ZSTD_static_assert = 1 / (int)(!!(c)) }; \
++ }
++
++/*-*************************************
++* Common constants
++***************************************/
++#define ZSTD_OPT_NUM (1 << 12)
++#define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */
++
++#define ZSTD_REP_NUM 3 /* number of repcodes */
++#define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */
++#define ZSTD_REP_MOVE (ZSTD_REP_NUM - 1)
++#define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM)
++static const U32 repStartValue[ZSTD_REP_NUM] = {1, 4, 8};
++
++#define KB *(1 << 10)
++#define MB *(1 << 20)
++#define GB *(1U << 30)
++
++#define BIT7 128
++#define BIT6 64
++#define BIT5 32
++#define BIT4 16
++#define BIT1 2
++#define BIT0 1
++
++#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
++static const size_t ZSTD_fcs_fieldSize[4] = {0, 2, 4, 8};
++static const size_t ZSTD_did_fieldSize[4] = {0, 1, 2, 4};
++
++#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
++static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
++typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
++
++#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
++#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
++
++#define HufLog 12
++typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
++
++#define LONGNBSEQ 0x7F00
++
++#define MINMATCH 3
++#define EQUAL_READ32 4
++
++#define Litbits 8
++#define MaxLit ((1 << Litbits) - 1)
++#define MaxML 52
++#define MaxLL 35
++#define MaxOff 28
++#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
++#define MLFSELog 9
++#define LLFSELog 9
++#define OffFSELog 8
++
++static const U32 LL_bits[MaxLL + 1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
++static const S16 LL_defaultNorm[MaxLL + 1] = {4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, -1, -1, -1, -1};
++#define LL_DEFAULTNORMLOG 6 /* for static allocation */
++static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
++
++static const U32 ML_bits[MaxML + 1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
++static const S16 ML_defaultNorm[MaxML + 1] = {1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1};
++#define ML_DEFAULTNORMLOG 6 /* for static allocation */
++static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
++
++static const S16 OF_defaultNorm[MaxOff + 1] = {1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1};
++#define OF_DEFAULTNORMLOG 5 /* for static allocation */
++static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
++
++/*-*******************************************
++* Shared functions to include for inlining
++*********************************************/
++static void ZSTD_copy8(void *dst, const void *src) { memcpy(dst, src, 8); }
++#define COPY8(d, s) \
++ { \
++ ZSTD_copy8(d, s); \
++ d += 8; \
++ s += 8; \
++ }
++
++/*! ZSTD_wildcopy() :
++* custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */
++#define WILDCOPY_OVERLENGTH 8
++ZSTD_STATIC void ZSTD_wildcopy(void *dst, const void *src, ptrdiff_t length)
++{
++ const BYTE *ip = (const BYTE *)src;
++ BYTE *op = (BYTE *)dst;
++ BYTE *const oend = op + length;
++ do
++ COPY8(op, ip)
++ while (op < oend);
++}
++
++ZSTD_STATIC void ZSTD_wildcopy_e(void *dst, const void *src, void *dstEnd) /* should be faster for decoding, but strangely, not verified on all platform */
++{
++ const BYTE *ip = (const BYTE *)src;
++ BYTE *op = (BYTE *)dst;
++ BYTE *const oend = (BYTE *)dstEnd;
++ do
++ COPY8(op, ip)
++ while (op < oend);
++}
++
++/*-*******************************************
++* Private interfaces
++*********************************************/
++typedef struct ZSTD_stats_s ZSTD_stats_t;
++
++typedef struct {
++ U32 off;
++ U32 len;
++} ZSTD_match_t;
++
++typedef struct {
++ U32 price;
++ U32 off;
++ U32 mlen;
++ U32 litlen;
++ U32 rep[ZSTD_REP_NUM];
++} ZSTD_optimal_t;
++
++typedef struct seqDef_s {
++ U32 offset;
++ U16 litLength;
++ U16 matchLength;
++} seqDef;
++
++typedef struct {
++ seqDef *sequencesStart;
++ seqDef *sequences;
++ BYTE *litStart;
++ BYTE *lit;
++ BYTE *llCode;
++ BYTE *mlCode;
++ BYTE *ofCode;
++ U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
++ U32 longLengthPos;
++ /* opt */
++ ZSTD_optimal_t *priceTable;
++ ZSTD_match_t *matchTable;
++ U32 *matchLengthFreq;
++ U32 *litLengthFreq;
++ U32 *litFreq;
++ U32 *offCodeFreq;
++ U32 matchLengthSum;
++ U32 matchSum;
++ U32 litLengthSum;
++ U32 litSum;
++ U32 offCodeSum;
++ U32 log2matchLengthSum;
++ U32 log2matchSum;
++ U32 log2litLengthSum;
++ U32 log2litSum;
++ U32 log2offCodeSum;
++ U32 factor;
++ U32 staticPrices;
++ U32 cachedPrice;
++ U32 cachedLitLength;
++ const BYTE *cachedLiterals;
++} seqStore_t;
++
++const seqStore_t *ZSTD_getSeqStore(const ZSTD_CCtx *ctx);
++void ZSTD_seqToCodes(const seqStore_t *seqStorePtr);
++int ZSTD_isSkipFrame(ZSTD_DCtx *dctx);
++
++/*= Custom memory allocation functions */
++typedef void *(*ZSTD_allocFunction)(void *opaque, size_t size);
++typedef void (*ZSTD_freeFunction)(void *opaque, void *address);
++typedef struct {
++ ZSTD_allocFunction customAlloc;
++ ZSTD_freeFunction customFree;
++ void *opaque;
++} ZSTD_customMem;
++
++void *ZSTD_malloc(size_t size, ZSTD_customMem customMem);
++void ZSTD_free(void *ptr, ZSTD_customMem customMem);
++
++/*====== stack allocation ======*/
++
++typedef struct {
++ void *ptr;
++ const void *end;
++} ZSTD_stack;
++
++#define ZSTD_ALIGN(x) ALIGN(x, sizeof(size_t))
++#define ZSTD_PTR_ALIGN(p) PTR_ALIGN(p, sizeof(size_t))
++
++ZSTD_customMem ZSTD_initStack(void *workspace, size_t workspaceSize);
++
++void *ZSTD_stackAllocAll(void *opaque, size_t *size);
++void *ZSTD_stackAlloc(void *opaque, size_t size);
++void ZSTD_stackFree(void *opaque, void *address);
++
++/*====== common function ======*/
++
++ZSTD_STATIC U32 ZSTD_highbit32(U32 val) { return 31 - __builtin_clz(val); }
++
++/* hidden functions */
++
++/* ZSTD_invalidateRepCodes() :
++ * ensures next compression will not use repcodes from previous block.
++ * Note : only works with regular variant;
++ * do not use with extDict variant ! */
++void ZSTD_invalidateRepCodes(ZSTD_CCtx *cctx);
++
++size_t ZSTD_freeCCtx(ZSTD_CCtx *cctx);
++size_t ZSTD_freeDCtx(ZSTD_DCtx *dctx);
++size_t ZSTD_freeCDict(ZSTD_CDict *cdict);
++size_t ZSTD_freeDDict(ZSTD_DDict *cdict);
++size_t ZSTD_freeCStream(ZSTD_CStream *zcs);
++size_t ZSTD_freeDStream(ZSTD_DStream *zds);
++
++#endif /* ZSTD_CCOMMON_H_MODULE */
+diff --git a/lib/zstd/zstd_opt.h b/lib/zstd/zstd_opt.h
+new file mode 100644
+index 0000000..55e1b4c
+--- /dev/null
++++ b/lib/zstd/zstd_opt.h
+@@ -0,0 +1,1014 @@
++/**
++ * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This source code is licensed under the BSD-style license found in the
++ * LICENSE file in the root directory of https://github.com/facebook/zstd.
++ * An additional grant of patent rights can be found in the PATENTS file in the
++ * same directory.
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation. This program is dual-licensed; you may select
++ * either version 2 of the GNU General Public License ("GPL") or BSD license
++ * ("BSD").
++ */
++
++/* Note : this file is intended to be included within zstd_compress.c */
++
++#ifndef ZSTD_OPT_H_91842398743
++#define ZSTD_OPT_H_91842398743
++
++#define ZSTD_LITFREQ_ADD 2
++#define ZSTD_FREQ_DIV 4
++#define ZSTD_MAX_PRICE (1 << 30)
++
++/*-*************************************
++* Price functions for optimal parser
++***************************************/
++FORCE_INLINE void ZSTD_setLog2Prices(seqStore_t *ssPtr)
++{
++ ssPtr->log2matchLengthSum = ZSTD_highbit32(ssPtr->matchLengthSum + 1);
++ ssPtr->log2litLengthSum = ZSTD_highbit32(ssPtr->litLengthSum + 1);
++ ssPtr->log2litSum = ZSTD_highbit32(ssPtr->litSum + 1);
++ ssPtr->log2offCodeSum = ZSTD_highbit32(ssPtr->offCodeSum + 1);
++ ssPtr->factor = 1 + ((ssPtr->litSum >> 5) / ssPtr->litLengthSum) + ((ssPtr->litSum << 1) / (ssPtr->litSum + ssPtr->matchSum));
++}
++
++ZSTD_STATIC void ZSTD_rescaleFreqs(seqStore_t *ssPtr, const BYTE *src, size_t srcSize)
++{
++ unsigned u;
++
++ ssPtr->cachedLiterals = NULL;
++ ssPtr->cachedPrice = ssPtr->cachedLitLength = 0;
++ ssPtr->staticPrices = 0;
++
++ if (ssPtr->litLengthSum == 0) {
++ if (srcSize <= 1024)
++ ssPtr->staticPrices = 1;
++
++ for (u = 0; u <= MaxLit; u++)
++ ssPtr->litFreq[u] = 0;
++ for (u = 0; u < srcSize; u++)
++ ssPtr->litFreq[src[u]]++;
++
++ ssPtr->litSum = 0;
++ ssPtr->litLengthSum = MaxLL + 1;
++ ssPtr->matchLengthSum = MaxML + 1;
++ ssPtr->offCodeSum = (MaxOff + 1);
++ ssPtr->matchSum = (ZSTD_LITFREQ_ADD << Litbits);
++
++ for (u = 0; u <= MaxLit; u++) {
++ ssPtr->litFreq[u] = 1 + (ssPtr->litFreq[u] >> ZSTD_FREQ_DIV);
++ ssPtr->litSum += ssPtr->litFreq[u];
++ }
++ for (u = 0; u <= MaxLL; u++)
++ ssPtr->litLengthFreq[u] = 1;
++ for (u = 0; u <= MaxML; u++)
++ ssPtr->matchLengthFreq[u] = 1;
++ for (u = 0; u <= MaxOff; u++)
++ ssPtr->offCodeFreq[u] = 1;
++ } else {
++ ssPtr->matchLengthSum = 0;
++ ssPtr->litLengthSum = 0;
++ ssPtr->offCodeSum = 0;
++ ssPtr->matchSum = 0;
++ ssPtr->litSum = 0;
++
++ for (u = 0; u <= MaxLit; u++) {
++ ssPtr->litFreq[u] = 1 + (ssPtr->litFreq[u] >> (ZSTD_FREQ_DIV + 1));
++ ssPtr->litSum += ssPtr->litFreq[u];
++ }
++ for (u = 0; u <= MaxLL; u++) {
++ ssPtr->litLengthFreq[u] = 1 + (ssPtr->litLengthFreq[u] >> (ZSTD_FREQ_DIV + 1));
++ ssPtr->litLengthSum += ssPtr->litLengthFreq[u];
++ }
++ for (u = 0; u <= MaxML; u++) {
++ ssPtr->matchLengthFreq[u] = 1 + (ssPtr->matchLengthFreq[u] >> ZSTD_FREQ_DIV);
++ ssPtr->matchLengthSum += ssPtr->matchLengthFreq[u];
++ ssPtr->matchSum += ssPtr->matchLengthFreq[u] * (u + 3);
++ }
++ ssPtr->matchSum *= ZSTD_LITFREQ_ADD;
++ for (u = 0; u <= MaxOff; u++) {
++ ssPtr->offCodeFreq[u] = 1 + (ssPtr->offCodeFreq[u] >> ZSTD_FREQ_DIV);
++ ssPtr->offCodeSum += ssPtr->offCodeFreq[u];
++ }
++ }
++
++ ZSTD_setLog2Prices(ssPtr);
++}
++
++FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t *ssPtr, U32 litLength, const BYTE *literals)
++{
++ U32 price, u;
++
++ if (ssPtr->staticPrices)
++ return ZSTD_highbit32((U32)litLength + 1) + (litLength * 6);
++
++ if (litLength == 0)
++ return ssPtr->log2litLengthSum - ZSTD_highbit32(ssPtr->litLengthFreq[0] + 1);
++
++ /* literals */
++ if (ssPtr->cachedLiterals == literals) {
++ U32 const additional = litLength - ssPtr->cachedLitLength;
++ const BYTE *literals2 = ssPtr->cachedLiterals + ssPtr->cachedLitLength;
++ price = ssPtr->cachedPrice + additional * ssPtr->log2litSum;
++ for (u = 0; u < additional; u++)
++ price -= ZSTD_highbit32(ssPtr->litFreq[literals2[u]] + 1);
++ ssPtr->cachedPrice = price;
++ ssPtr->cachedLitLength = litLength;
++ } else {
++ price = litLength * ssPtr->log2litSum;
++ for (u = 0; u < litLength; u++)
++ price -= ZSTD_highbit32(ssPtr->litFreq[literals[u]] + 1);
++
++ if (litLength >= 12) {
++ ssPtr->cachedLiterals = literals;
++ ssPtr->cachedPrice = price;
++ ssPtr->cachedLitLength = litLength;
++ }
++ }
++
++ /* literal Length */
++ {
++ const BYTE LL_deltaCode = 19;
++ const BYTE llCode = (litLength > 63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
++ price += LL_bits[llCode] + ssPtr->log2litLengthSum - ZSTD_highbit32(ssPtr->litLengthFreq[llCode] + 1);
++ }
++
++ return price;
++}
++
++FORCE_INLINE U32 ZSTD_getPrice(seqStore_t *seqStorePtr, U32 litLength, const BYTE *literals, U32 offset, U32 matchLength, const int ultra)
++{
++ /* offset */
++ U32 price;
++ BYTE const offCode = (BYTE)ZSTD_highbit32(offset + 1);
++
++ if (seqStorePtr->staticPrices)
++ return ZSTD_getLiteralPrice(seqStorePtr, litLength, literals) + ZSTD_highbit32((U32)matchLength + 1) + 16 + offCode;
++
++ price = offCode + seqStorePtr->log2offCodeSum - ZSTD_highbit32(seqStorePtr->offCodeFreq[offCode] + 1);
++ if (!ultra && offCode >= 20)
++ price += (offCode - 19) * 2;
++
++ /* match Length */
++ {
++ const BYTE ML_deltaCode = 36;
++ const BYTE mlCode = (matchLength > 127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
++ price += ML_bits[mlCode] + seqStorePtr->log2matchLengthSum - ZSTD_highbit32(seqStorePtr->matchLengthFreq[mlCode] + 1);
++ }
++
++ return price + ZSTD_getLiteralPrice(seqStorePtr, litLength, literals) + seqStorePtr->factor;
++}
++
++ZSTD_STATIC void ZSTD_updatePrice(seqStore_t *seqStorePtr, U32 litLength, const BYTE *literals, U32 offset, U32 matchLength)
++{
++ U32 u;
++
++ /* literals */
++ seqStorePtr->litSum += litLength * ZSTD_LITFREQ_ADD;
++ for (u = 0; u < litLength; u++)
++ seqStorePtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
++
++ /* literal Length */
++ {
++ const BYTE LL_deltaCode = 19;
++ const BYTE llCode = (litLength > 63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
++ seqStorePtr->litLengthFreq[llCode]++;
++ seqStorePtr->litLengthSum++;
++ }
++
++ /* match offset */
++ {
++ BYTE const offCode = (BYTE)ZSTD_highbit32(offset + 1);
++ seqStorePtr->offCodeSum++;
++ seqStorePtr->offCodeFreq[offCode]++;
++ }
++
++ /* match Length */
++ {
++ const BYTE ML_deltaCode = 36;
++ const BYTE mlCode = (matchLength > 127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
++ seqStorePtr->matchLengthFreq[mlCode]++;
++ seqStorePtr->matchLengthSum++;
++ }
++
++ ZSTD_setLog2Prices(seqStorePtr);
++}
++
++#define SET_PRICE(pos, mlen_, offset_, litlen_, price_) \
++ { \
++ while (last_pos < pos) { \
++ opt[last_pos + 1].price = ZSTD_MAX_PRICE; \
++ last_pos++; \
++ } \
++ opt[pos].mlen = mlen_; \
++ opt[pos].off = offset_; \
++ opt[pos].litlen = litlen_; \
++ opt[pos].price = price_; \
++ }
++
++/* Update hashTable3 up to ip (excluded)
++ Assumption : always within prefix (i.e. not within extDict) */
++FORCE_INLINE
++U32 ZSTD_insertAndFindFirstIndexHash3(ZSTD_CCtx *zc, const BYTE *ip)
++{
++ U32 *const hashTable3 = zc->hashTable3;
++ U32 const hashLog3 = zc->hashLog3;
++ const BYTE *const base = zc->base;
++ U32 idx = zc->nextToUpdate3;
++ const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
++ const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
++
++ while (idx < target) {
++ hashTable3[ZSTD_hash3Ptr(base + idx, hashLog3)] = idx;
++ idx++;
++ }
++
++ return hashTable3[hash3];
++}
++
++/*-*************************************
++* Binary Tree search
++***************************************/
++static U32 ZSTD_insertBtAndGetAllMatches(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, U32 nbCompares, const U32 mls, U32 extDict,
++ ZSTD_match_t *matches, const U32 minMatchLen)
++{
++ const BYTE *const base = zc->base;
++ const U32 curr = (U32)(ip - base);
++ const U32 hashLog = zc->params.cParams.hashLog;
++ const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
++ U32 *const hashTable = zc->hashTable;
++ U32 matchIndex = hashTable[h];
++ U32 *const bt = zc->chainTable;
++ const U32 btLog = zc->params.cParams.chainLog - 1;
++ const U32 btMask = (1U << btLog) - 1;
++ size_t commonLengthSmaller = 0, commonLengthLarger = 0;
++ const BYTE *const dictBase = zc->dictBase;
++ const U32 dictLimit = zc->dictLimit;
++ const BYTE *const dictEnd = dictBase + dictLimit;
++ const BYTE *const prefixStart = base + dictLimit;
++ const U32 btLow = btMask >= curr ? 0 : curr - btMask;
++ const U32 windowLow = zc->lowLimit;
++ U32 *smallerPtr = bt + 2 * (curr & btMask);
++ U32 *largerPtr = bt + 2 * (curr & btMask) + 1;
++ U32 matchEndIdx = curr + 8;
++ U32 dummy32; /* to be nullified at the end */
++ U32 mnum = 0;
++
++ const U32 minMatch = (mls == 3) ? 3 : 4;
++ size_t bestLength = minMatchLen - 1;
++
++ if (minMatch == 3) { /* HC3 match finder */
++ U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(zc, ip);
++ if (matchIndex3 > windowLow && (curr - matchIndex3 < (1 << 18))) {
++ const BYTE *match;
++ size_t currMl = 0;
++ if ((!extDict) || matchIndex3 >= dictLimit) {
++ match = base + matchIndex3;
++ if (match[bestLength] == ip[bestLength])
++ currMl = ZSTD_count(ip, match, iLimit);
++ } else {
++ match = dictBase + matchIndex3;
++ if (ZSTD_readMINMATCH(match, MINMATCH) ==
++ ZSTD_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
++ currMl = ZSTD_count_2segments(ip + MINMATCH, match + MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
++ }
++
++ /* save best solution */
++ if (currMl > bestLength) {
++ bestLength = currMl;
++ matches[mnum].off = ZSTD_REP_MOVE_OPT + curr - matchIndex3;
++ matches[mnum].len = (U32)currMl;
++ mnum++;
++ if (currMl > ZSTD_OPT_NUM)
++ goto update;
++ if (ip + currMl == iLimit)
++ goto update; /* best possible, and avoid read overflow*/
++ }
++ }
++ }
++
++ hashTable[h] = curr; /* Update Hash Table */
++
++ while (nbCompares-- && (matchIndex > windowLow)) {
++ U32 *nextPtr = bt + 2 * (matchIndex & btMask);
++ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
++ const BYTE *match;
++
++ if ((!extDict) || (matchIndex + matchLength >= dictLimit)) {
++ match = base + matchIndex;
++ if (match[matchLength] == ip[matchLength]) {
++ matchLength += ZSTD_count(ip + matchLength + 1, match + matchLength + 1, iLimit) + 1;
++ }
++ } else {
++ match = dictBase + matchIndex;
++ matchLength += ZSTD_count_2segments(ip + matchLength, match + matchLength, iLimit, dictEnd, prefixStart);
++ if (matchIndex + matchLength >= dictLimit)
++ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
++ }
++
++ if (matchLength > bestLength) {
++ if (matchLength > matchEndIdx - matchIndex)
++ matchEndIdx = matchIndex + (U32)matchLength;
++ bestLength = matchLength;
++ matches[mnum].off = ZSTD_REP_MOVE_OPT + curr - matchIndex;
++ matches[mnum].len = (U32)matchLength;
++ mnum++;
++ if (matchLength > ZSTD_OPT_NUM)
++ break;
++ if (ip + matchLength == iLimit) /* equal : no way to know if inf or sup */
++ break; /* drop, to guarantee consistency (miss a little bit of compression) */
++ }
++
++ if (match[matchLength] < ip[matchLength]) {
++ /* match is smaller than curr */
++ *smallerPtr = matchIndex; /* update smaller idx */
++ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
++ if (matchIndex <= btLow) {
++ smallerPtr = &dummy32;
++ break;
++ } /* beyond tree size, stop the search */
++ smallerPtr = nextPtr + 1; /* new "smaller" => larger of match */
++ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to curr) */
++ } else {
++ /* match is larger than curr */
++ *largerPtr = matchIndex;
++ commonLengthLarger = matchLength;
++ if (matchIndex <= btLow) {
++ largerPtr = &dummy32;
++ break;
++ } /* beyond tree size, stop the search */
++ largerPtr = nextPtr;
++ matchIndex = nextPtr[0];
++ }
++ }
++
++ *smallerPtr = *largerPtr = 0;
++
++update:
++ zc->nextToUpdate = (matchEndIdx > curr + 8) ? matchEndIdx - 8 : curr + 1;
++ return mnum;
++}
++
++/** Tree updater, providing best match */
++static U32 ZSTD_BtGetAllMatches(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, const U32 maxNbAttempts, const U32 mls, ZSTD_match_t *matches,
++ const U32 minMatchLen)
++{
++ if (ip < zc->base + zc->nextToUpdate)
++ return 0; /* skipped area */
++ ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
++ return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
++}
++
++static U32 ZSTD_BtGetAllMatches_selectMLS(ZSTD_CCtx *zc, /* Index table will be updated */
++ const BYTE *ip, const BYTE *const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch,
++ ZSTD_match_t *matches, const U32 minMatchLen)
++{
++ switch (matchLengthSearch) {
++ case 3: return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
++ default:
++ case 4: return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
++ case 5: return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
++ case 7:
++ case 6: return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
++ }
++}
++
++/** Tree updater, providing best match */
++static U32 ZSTD_BtGetAllMatches_extDict(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, const U32 maxNbAttempts, const U32 mls,
++ ZSTD_match_t *matches, const U32 minMatchLen)
++{
++ if (ip < zc->base + zc->nextToUpdate)
++ return 0; /* skipped area */
++ ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
++ return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
++}
++
++static U32 ZSTD_BtGetAllMatches_selectMLS_extDict(ZSTD_CCtx *zc, /* Index table will be updated */
++ const BYTE *ip, const BYTE *const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch,
++ ZSTD_match_t *matches, const U32 minMatchLen)
++{
++ switch (matchLengthSearch) {
++ case 3: return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
++ default:
++ case 4: return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
++ case 5: return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
++ case 7:
++ case 6: return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
++ }
++}
++
++/*-*******************************
++* Optimal parser
++*********************************/
++FORCE_INLINE
++void ZSTD_compressBlock_opt_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const int ultra)
++{
++ seqStore_t *seqStorePtr = &(ctx->seqStore);
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *ip = istart;
++ const BYTE *anchor = istart;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *const ilimit = iend - 8;
++ const BYTE *const base = ctx->base;
++ const BYTE *const prefixStart = base + ctx->dictLimit;
++
++ const U32 maxSearches = 1U << ctx->params.cParams.searchLog;
++ const U32 sufficient_len = ctx->params.cParams.targetLength;
++ const U32 mls = ctx->params.cParams.searchLength;
++ const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4;
++
++ ZSTD_optimal_t *opt = seqStorePtr->priceTable;
++ ZSTD_match_t *matches = seqStorePtr->matchTable;
++ const BYTE *inr;
++ U32 offset, rep[ZSTD_REP_NUM];
++
++ /* init */
++ ctx->nextToUpdate3 = ctx->nextToUpdate;
++ ZSTD_rescaleFreqs(seqStorePtr, (const BYTE *)src, srcSize);
++ ip += (ip == prefixStart);
++ {
++ U32 i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ rep[i] = ctx->rep[i];
++ }
++
++ /* Match Loop */
++ while (ip < ilimit) {
++ U32 cur, match_num, last_pos, litlen, price;
++ U32 u, mlen, best_mlen, best_off, litLength;
++ memset(opt, 0, sizeof(ZSTD_optimal_t));
++ last_pos = 0;
++ litlen = (U32)(ip - anchor);
++
++ /* check repCode */
++ {
++ U32 i, last_i = ZSTD_REP_CHECK + (ip == anchor);
++ for (i = (ip == anchor); i < last_i; i++) {
++ const S32 repCur = (i == ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
++ if ((repCur > 0) && (repCur < (S32)(ip - prefixStart)) &&
++ (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) {
++ mlen = (U32)ZSTD_count(ip + minMatch, ip + minMatch - repCur, iend) + minMatch;
++ if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
++ best_mlen = mlen;
++ best_off = i;
++ cur = 0;
++ last_pos = 1;
++ goto _storeSequence;
++ }
++ best_off = i - (ip == anchor);
++ do {
++ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
++ if (mlen > last_pos || price < opt[mlen].price)
++ SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
++ mlen--;
++ } while (mlen >= minMatch);
++ }
++ }
++ }
++
++ match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
++
++ if (!last_pos && !match_num) {
++ ip++;
++ continue;
++ }
++
++ if (match_num && (matches[match_num - 1].len > sufficient_len || matches[match_num - 1].len >= ZSTD_OPT_NUM)) {
++ best_mlen = matches[match_num - 1].len;
++ best_off = matches[match_num - 1].off;
++ cur = 0;
++ last_pos = 1;
++ goto _storeSequence;
++ }
++
++ /* set prices using matches at position = 0 */
++ best_mlen = (last_pos) ? last_pos : minMatch;
++ for (u = 0; u < match_num; u++) {
++ mlen = (u > 0) ? matches[u - 1].len + 1 : best_mlen;
++ best_mlen = matches[u].len;
++ while (mlen <= best_mlen) {
++ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
++ if (mlen > last_pos || price < opt[mlen].price)
++ SET_PRICE(mlen, mlen, matches[u].off, litlen, price); /* note : macro modifies last_pos */
++ mlen++;
++ }
++ }
++
++ if (last_pos < minMatch) {
++ ip++;
++ continue;
++ }
++
++ /* initialize opt[0] */
++ {
++ U32 i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ opt[0].rep[i] = rep[i];
++ }
++ opt[0].mlen = 1;
++ opt[0].litlen = litlen;
++
++ /* check further positions */
++ for (cur = 1; cur <= last_pos; cur++) {
++ inr = ip + cur;
++
++ if (opt[cur - 1].mlen == 1) {
++ litlen = opt[cur - 1].litlen + 1;
++ if (cur > litlen) {
++ price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr - litlen);
++ } else
++ price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor);
++ } else {
++ litlen = 1;
++ price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr - 1);
++ }
++
++ if (cur > last_pos || price <= opt[cur].price)
++ SET_PRICE(cur, 1, 0, litlen, price);
++
++ if (cur == last_pos)
++ break;
++
++ if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
++ continue;
++
++ mlen = opt[cur].mlen;
++ if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
++ opt[cur].rep[2] = opt[cur - mlen].rep[1];
++ opt[cur].rep[1] = opt[cur - mlen].rep[0];
++ opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
++ } else {
++ opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur - mlen].rep[1] : opt[cur - mlen].rep[2];
++ opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur - mlen].rep[0] : opt[cur - mlen].rep[1];
++ opt[cur].rep[0] =
++ ((opt[cur].off == ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur - mlen].rep[0] - 1) : (opt[cur - mlen].rep[opt[cur].off]);
++ }
++
++ best_mlen = minMatch;
++ {
++ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
++ for (i = (opt[cur].mlen != 1); i < last_i; i++) { /* check rep */
++ const S32 repCur = (i == ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
++ if ((repCur > 0) && (repCur < (S32)(inr - prefixStart)) &&
++ (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) {
++ mlen = (U32)ZSTD_count(inr + minMatch, inr + minMatch - repCur, iend) + minMatch;
++
++ if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
++ best_mlen = mlen;
++ best_off = i;
++ last_pos = cur + 1;
++ goto _storeSequence;
++ }
++
++ best_off = i - (opt[cur].mlen != 1);
++ if (mlen > best_mlen)
++ best_mlen = mlen;
++
++ do {
++ if (opt[cur].mlen == 1) {
++ litlen = opt[cur].litlen;
++ if (cur > litlen) {
++ price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr - litlen,
++ best_off, mlen - MINMATCH, ultra);
++ } else
++ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
++ } else {
++ litlen = 0;
++ price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
++ }
++
++ if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
++ SET_PRICE(cur + mlen, mlen, i, litlen, price);
++ mlen--;
++ } while (mlen >= minMatch);
++ }
++ }
++ }
++
++ match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
++
++ if (match_num > 0 && (matches[match_num - 1].len > sufficient_len || cur + matches[match_num - 1].len >= ZSTD_OPT_NUM)) {
++ best_mlen = matches[match_num - 1].len;
++ best_off = matches[match_num - 1].off;
++ last_pos = cur + 1;
++ goto _storeSequence;
++ }
++
++ /* set prices using matches at position = cur */
++ for (u = 0; u < match_num; u++) {
++ mlen = (u > 0) ? matches[u - 1].len + 1 : best_mlen;
++ best_mlen = matches[u].len;
++
++ while (mlen <= best_mlen) {
++ if (opt[cur].mlen == 1) {
++ litlen = opt[cur].litlen;
++ if (cur > litlen)
++ price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip + cur - litlen,
++ matches[u].off - 1, mlen - MINMATCH, ultra);
++ else
++ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
++ } else {
++ litlen = 0;
++ price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off - 1, mlen - MINMATCH, ultra);
++ }
++
++ if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
++ SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
++
++ mlen++;
++ }
++ }
++ }
++
++ best_mlen = opt[last_pos].mlen;
++ best_off = opt[last_pos].off;
++ cur = last_pos - best_mlen;
++
++ /* store sequence */
++_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
++ opt[0].mlen = 1;
++
++ while (1) {
++ mlen = opt[cur].mlen;
++ offset = opt[cur].off;
++ opt[cur].mlen = best_mlen;
++ opt[cur].off = best_off;
++ best_mlen = mlen;
++ best_off = offset;
++ if (mlen > cur)
++ break;
++ cur -= mlen;
++ }
++
++ for (u = 0; u <= last_pos;) {
++ u += opt[u].mlen;
++ }
++
++ for (cur = 0; cur < last_pos;) {
++ mlen = opt[cur].mlen;
++ if (mlen == 1) {
++ ip++;
++ cur++;
++ continue;
++ }
++ offset = opt[cur].off;
++ cur += mlen;
++ litLength = (U32)(ip - anchor);
++
++ if (offset > ZSTD_REP_MOVE_OPT) {
++ rep[2] = rep[1];
++ rep[1] = rep[0];
++ rep[0] = offset - ZSTD_REP_MOVE_OPT;
++ offset--;
++ } else {
++ if (offset != 0) {
++ best_off = (offset == ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
++ if (offset != 1)
++ rep[2] = rep[1];
++ rep[1] = rep[0];
++ rep[0] = best_off;
++ }
++ if (litLength == 0)
++ offset--;
++ }
++
++ ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen - MINMATCH);
++ ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen - MINMATCH);
++ anchor = ip = ip + mlen;
++ }
++ } /* for (cur=0; cur < last_pos; ) */
++
++ /* Save reps for next block */
++ {
++ int i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ ctx->repToConfirm[i] = rep[i];
++ }
++
++ /* Last Literals */
++ {
++ size_t const lastLLSize = iend - anchor;
++ memcpy(seqStorePtr->lit, anchor, lastLLSize);
++ seqStorePtr->lit += lastLLSize;
++ }
++}
++
++FORCE_INLINE
++void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const int ultra)
++{
++ seqStore_t *seqStorePtr = &(ctx->seqStore);
++ const BYTE *const istart = (const BYTE *)src;
++ const BYTE *ip = istart;
++ const BYTE *anchor = istart;
++ const BYTE *const iend = istart + srcSize;
++ const BYTE *const ilimit = iend - 8;
++ const BYTE *const base = ctx->base;
++ const U32 lowestIndex = ctx->lowLimit;
++ const U32 dictLimit = ctx->dictLimit;
++ const BYTE *const prefixStart = base + dictLimit;
++ const BYTE *const dictBase = ctx->dictBase;
++ const BYTE *const dictEnd = dictBase + dictLimit;
++
++ const U32 maxSearches = 1U << ctx->params.cParams.searchLog;
++ const U32 sufficient_len = ctx->params.cParams.targetLength;
++ const U32 mls = ctx->params.cParams.searchLength;
++ const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4;
++
++ ZSTD_optimal_t *opt = seqStorePtr->priceTable;
++ ZSTD_match_t *matches = seqStorePtr->matchTable;
++ const BYTE *inr;
++
++ /* init */
++ U32 offset, rep[ZSTD_REP_NUM];
++ {
++ U32 i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ rep[i] = ctx->rep[i];
++ }
++
++ ctx->nextToUpdate3 = ctx->nextToUpdate;
++ ZSTD_rescaleFreqs(seqStorePtr, (const BYTE *)src, srcSize);
++ ip += (ip == prefixStart);
++
++ /* Match Loop */
++ while (ip < ilimit) {
++ U32 cur, match_num, last_pos, litlen, price;
++ U32 u, mlen, best_mlen, best_off, litLength;
++ U32 curr = (U32)(ip - base);
++ memset(opt, 0, sizeof(ZSTD_optimal_t));
++ last_pos = 0;
++ opt[0].litlen = (U32)(ip - anchor);
++
++ /* check repCode */
++ {
++ U32 i, last_i = ZSTD_REP_CHECK + (ip == anchor);
++ for (i = (ip == anchor); i < last_i; i++) {
++ const S32 repCur = (i == ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
++ const U32 repIndex = (U32)(curr - repCur);
++ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
++ const BYTE *const repMatch = repBase + repIndex;
++ if ((repCur > 0 && repCur <= (S32)curr) &&
++ (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
++ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch))) {
++ /* repcode detected we should take it */
++ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
++ mlen = (U32)ZSTD_count_2segments(ip + minMatch, repMatch + minMatch, iend, repEnd, prefixStart) + minMatch;
++
++ if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
++ best_mlen = mlen;
++ best_off = i;
++ cur = 0;
++ last_pos = 1;
++ goto _storeSequence;
++ }
++
++ best_off = i - (ip == anchor);
++ litlen = opt[0].litlen;
++ do {
++ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
++ if (mlen > last_pos || price < opt[mlen].price)
++ SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
++ mlen--;
++ } while (mlen >= minMatch);
++ }
++ }
++ }
++
++ match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch); /* first search (depth 0) */
++
++ if (!last_pos && !match_num) {
++ ip++;
++ continue;
++ }
++
++ {
++ U32 i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ opt[0].rep[i] = rep[i];
++ }
++ opt[0].mlen = 1;
++
++ if (match_num && (matches[match_num - 1].len > sufficient_len || matches[match_num - 1].len >= ZSTD_OPT_NUM)) {
++ best_mlen = matches[match_num - 1].len;
++ best_off = matches[match_num - 1].off;
++ cur = 0;
++ last_pos = 1;
++ goto _storeSequence;
++ }
++
++ best_mlen = (last_pos) ? last_pos : minMatch;
++
++ /* set prices using matches at position = 0 */
++ for (u = 0; u < match_num; u++) {
++ mlen = (u > 0) ? matches[u - 1].len + 1 : best_mlen;
++ best_mlen = matches[u].len;
++ litlen = opt[0].litlen;
++ while (mlen <= best_mlen) {
++ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
++ if (mlen > last_pos || price < opt[mlen].price)
++ SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
++ mlen++;
++ }
++ }
++
++ if (last_pos < minMatch) {
++ ip++;
++ continue;
++ }
++
++ /* check further positions */
++ for (cur = 1; cur <= last_pos; cur++) {
++ inr = ip + cur;
++
++ if (opt[cur - 1].mlen == 1) {
++ litlen = opt[cur - 1].litlen + 1;
++ if (cur > litlen) {
++ price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr - litlen);
++ } else
++ price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor);
++ } else {
++ litlen = 1;
++ price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr - 1);
++ }
++
++ if (cur > last_pos || price <= opt[cur].price)
++ SET_PRICE(cur, 1, 0, litlen, price);
++
++ if (cur == last_pos)
++ break;
++
++ if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
++ continue;
++
++ mlen = opt[cur].mlen;
++ if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
++ opt[cur].rep[2] = opt[cur - mlen].rep[1];
++ opt[cur].rep[1] = opt[cur - mlen].rep[0];
++ opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
++ } else {
++ opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur - mlen].rep[1] : opt[cur - mlen].rep[2];
++ opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur - mlen].rep[0] : opt[cur - mlen].rep[1];
++ opt[cur].rep[0] =
++ ((opt[cur].off == ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur - mlen].rep[0] - 1) : (opt[cur - mlen].rep[opt[cur].off]);
++ }
++
++ best_mlen = minMatch;
++ {
++ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
++ for (i = (mlen != 1); i < last_i; i++) {
++ const S32 repCur = (i == ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
++ const U32 repIndex = (U32)(curr + cur - repCur);
++ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
++ const BYTE *const repMatch = repBase + repIndex;
++ if ((repCur > 0 && repCur <= (S32)(curr + cur)) &&
++ (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
++ && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch))) {
++ /* repcode detected */
++ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
++ mlen = (U32)ZSTD_count_2segments(inr + minMatch, repMatch + minMatch, iend, repEnd, prefixStart) + minMatch;
++
++ if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
++ best_mlen = mlen;
++ best_off = i;
++ last_pos = cur + 1;
++ goto _storeSequence;
++ }
++
++ best_off = i - (opt[cur].mlen != 1);
++ if (mlen > best_mlen)
++ best_mlen = mlen;
++
++ do {
++ if (opt[cur].mlen == 1) {
++ litlen = opt[cur].litlen;
++ if (cur > litlen) {
++ price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr - litlen,
++ best_off, mlen - MINMATCH, ultra);
++ } else
++ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
++ } else {
++ litlen = 0;
++ price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
++ }
++
++ if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
++ SET_PRICE(cur + mlen, mlen, i, litlen, price);
++ mlen--;
++ } while (mlen >= minMatch);
++ }
++ }
++ }
++
++ match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
++
++ if (match_num > 0 && (matches[match_num - 1].len > sufficient_len || cur + matches[match_num - 1].len >= ZSTD_OPT_NUM)) {
++ best_mlen = matches[match_num - 1].len;
++ best_off = matches[match_num - 1].off;
++ last_pos = cur + 1;
++ goto _storeSequence;
++ }
++
++ /* set prices using matches at position = cur */
++ for (u = 0; u < match_num; u++) {
++ mlen = (u > 0) ? matches[u - 1].len + 1 : best_mlen;
++ best_mlen = matches[u].len;
++
++ while (mlen <= best_mlen) {
++ if (opt[cur].mlen == 1) {
++ litlen = opt[cur].litlen;
++ if (cur > litlen)
++ price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip + cur - litlen,
++ matches[u].off - 1, mlen - MINMATCH, ultra);
++ else
++ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
++ } else {
++ litlen = 0;
++ price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off - 1, mlen - MINMATCH, ultra);
++ }
++
++ if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
++ SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
++
++ mlen++;
++ }
++ }
++ } /* for (cur = 1; cur <= last_pos; cur++) */
++
++ best_mlen = opt[last_pos].mlen;
++ best_off = opt[last_pos].off;
++ cur = last_pos - best_mlen;
++
++ /* store sequence */
++_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
++ opt[0].mlen = 1;
++
++ while (1) {
++ mlen = opt[cur].mlen;
++ offset = opt[cur].off;
++ opt[cur].mlen = best_mlen;
++ opt[cur].off = best_off;
++ best_mlen = mlen;
++ best_off = offset;
++ if (mlen > cur)
++ break;
++ cur -= mlen;
++ }
++
++ for (u = 0; u <= last_pos;) {
++ u += opt[u].mlen;
++ }
++
++ for (cur = 0; cur < last_pos;) {
++ mlen = opt[cur].mlen;
++ if (mlen == 1) {
++ ip++;
++ cur++;
++ continue;
++ }
++ offset = opt[cur].off;
++ cur += mlen;
++ litLength = (U32)(ip - anchor);
++
++ if (offset > ZSTD_REP_MOVE_OPT) {
++ rep[2] = rep[1];
++ rep[1] = rep[0];
++ rep[0] = offset - ZSTD_REP_MOVE_OPT;
++ offset--;
++ } else {
++ if (offset != 0) {
++ best_off = (offset == ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
++ if (offset != 1)
++ rep[2] = rep[1];
++ rep[1] = rep[0];
++ rep[0] = best_off;
++ }
++
++ if (litLength == 0)
++ offset--;
++ }
++
++ ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen - MINMATCH);
++ ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen - MINMATCH);
++ anchor = ip = ip + mlen;
++ }
++ } /* for (cur=0; cur < last_pos; ) */
++
++ /* Save reps for next block */
++ {
++ int i;
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ ctx->repToConfirm[i] = rep[i];
++ }
++
++ /* Last Literals */
++ {
++ size_t lastLLSize = iend - anchor;
++ memcpy(seqStorePtr->lit, anchor, lastLLSize);
++ seqStorePtr->lit += lastLLSize;
++ }
++}
++
++#endif /* ZSTD_OPT_H_91842398743 */
+--
+2.9.3
diff --git a/contrib/linux-kernel/btrfs.diff b/contrib/linux-kernel/0003-btrfs-Add-zstd-support.patch
similarity index 76%
rename from contrib/linux-kernel/btrfs.diff
rename to contrib/linux-kernel/0003-btrfs-Add-zstd-support.patch
index 92a6e2057..abc8326cc 100644
--- a/contrib/linux-kernel/btrfs.diff
+++ b/contrib/linux-kernel/0003-btrfs-Add-zstd-support.patch
@@ -1,3 +1,83 @@
+From 599f8f2aaace3df939cb145368574a52268d82d0 Mon Sep 17 00:00:00 2001
+From: Nick Terrell
+Date: Wed, 21 Jun 2017 17:31:39 -0700
+Subject: [PATCH v2 3/4] btrfs: Add zstd support
+
+Add zstd compression and decompression support to BtrFS. zstd at its
+fastest level compresses almost as well as zlib, while offering much
+faster compression and decompression, approaching lzo speeds.
+
+I benchmarked btrfs with zstd compression against no compression, lzo
+compression, and zlib compression. I benchmarked two scenarios. Copying
+a set of files to btrfs, and then reading the files. Copying a tarball
+to btrfs, extracting it to btrfs, and then reading the extracted files.
+After every operation, I call `sync` and include the sync time.
+Between every pair of operations I unmount and remount the filesystem
+to avoid caching. The benchmark files can be found in the upstream
+zstd source repository under
+`contrib/linux-kernel/{btrfs-benchmark.sh,btrfs-extract-benchmark.sh}`
+[1] [2].
+
+I ran the benchmarks on a Ubuntu 14.04 VM with 2 cores and 4 GiB of RAM.
+The VM is running on a MacBook Pro with a 3.1 GHz Intel Core i7 processor,
+16 GB of RAM, and a SSD.
+
+The first compression benchmark is copying 10 copies of the unzipped
+Silesia corpus [3] into a BtrFS filesystem mounted with
+`-o compress-force=Method`. The decompression benchmark times how long
+it takes to `tar` all 10 copies into `/dev/null`. The compression ratio is
+measured by comparing the output of `df` and `du`. See the benchmark file
+[1] for details. I benchmarked multiple zstd compression levels, although
+the patch uses zstd level 1.
+
+| Method | Ratio | Compression MB/s | Decompression speed |
+|---------|-------|------------------|---------------------|
+| None | 0.99 | 504 | 686 |
+| lzo | 1.66 | 398 | 442 |
+| zlib | 2.58 | 65 | 241 |
+| zstd 1 | 2.57 | 260 | 383 |
+| zstd 3 | 2.71 | 174 | 408 |
+| zstd 6 | 2.87 | 70 | 398 |
+| zstd 9 | 2.92 | 43 | 406 |
+| zstd 12 | 2.93 | 21 | 408 |
+| zstd 15 | 3.01 | 11 | 354 |
+
+The next benchmark first copies `linux-4.11.6.tar` [4] to btrfs. Then it
+measures the compression ratio, extracts the tar, and deletes the tar.
+Then it measures the compression ratio again, and `tar`s the extracted
+files into `/dev/null`. See the benchmark file [2] for details.
+
+| Method | Tar Ratio | Extract Ratio | Copy (s) | Extract (s)| Read (s) |
+|--------|-----------|---------------|----------|------------|----------|
+| None | 0.97 | 0.78 | 0.981 | 5.501 | 8.807 |
+| lzo | 2.06 | 1.38 | 1.631 | 8.458 | 8.585 |
+| zlib | 3.40 | 1.86 | 7.750 | 21.544 | 11.744 |
+| zstd 1 | 3.57 | 1.85 | 2.579 | 11.479 | 9.389 |
+
+[1] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/btrfs-benchmark.sh
+[2] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/btrfs-extract-benchmark.sh
+[3] http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
+[4] https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.11.6.tar.xz
+
+zstd source repository: https://github.com/facebook/zstd
+
+Signed-off-by: Nick Terrell
+---
+ fs/btrfs/Kconfig | 2 +
+ fs/btrfs/Makefile | 2 +-
+ fs/btrfs/compression.c | 1 +
+ fs/btrfs/compression.h | 6 +-
+ fs/btrfs/ctree.h | 1 +
+ fs/btrfs/disk-io.c | 2 +
+ fs/btrfs/ioctl.c | 6 +-
+ fs/btrfs/props.c | 6 +
+ fs/btrfs/super.c | 12 +-
+ fs/btrfs/sysfs.c | 2 +
+ fs/btrfs/zstd.c | 433 +++++++++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/btrfs.h | 8 +-
+ 12 files changed, 469 insertions(+), 12 deletions(-)
+ create mode 100644 fs/btrfs/zstd.c
+
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index 80e9c18..a26c63b 100644
--- a/fs/btrfs/Kconfig
@@ -25,7 +105,7 @@ index 128ce17..962a95a 100644
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
uuid-tree.o props.o hash.o free-space-tree.o
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
-index c7721a6..66d4ced 100644
+index 10e6b28..3beb0d0 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -761,6 +761,7 @@ static struct {
@@ -34,7 +114,7 @@ index c7721a6..66d4ced 100644
&btrfs_lzo_compress,
+ &btrfs_zstd_compress,
};
-
+
void __init btrfs_init_compress(void)
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h
index 39ec43a..d99fc21 100644
@@ -50,20 +130,20 @@ index 39ec43a..d99fc21 100644
+ BTRFS_COMPRESS_TYPES = 3,
+ BTRFS_COMPRESS_LAST = 4,
};
-
+
struct btrfs_compress_op {
@@ -92,5 +93,6 @@ struct btrfs_compress_op {
-
+
extern const struct btrfs_compress_op btrfs_zlib_compress;
extern const struct btrfs_compress_op btrfs_lzo_compress;
+extern const struct btrfs_compress_op btrfs_zstd_compress;
-
+
#endif
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
-index 29b7fc2..878b23b9 100644
+index 4f8f75d..61dd3dd 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
-@@ -270,6 +270,7 @@ struct btrfs_super_block {
+@@ -271,6 +271,7 @@ struct btrfs_super_block {
BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
@@ -72,24 +152,24 @@ index 29b7fc2..878b23b9 100644
BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \
BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
-index 08b74da..0c43e4e 100644
+index 5f678dc..49c0e91 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
-@@ -2853,6 +2853,8 @@ int open_ctree(struct super_block *sb,
+@@ -2831,6 +2831,8 @@ int open_ctree(struct super_block *sb,
features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
if (fs_info->compress_type == BTRFS_COMPRESS_LZO)
features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
-+ else if (tree_root->fs_info->compress_type == BTRFS_COMPRESS_ZSTD)
++ else if (fs_info->compress_type == BTRFS_COMPRESS_ZSTD)
+ features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD;
-
+
if (features & BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA)
btrfs_info(fs_info, "has skinny extents");
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
-index dabfc7a..d8ea727 100644
+index e176375..f732cfd 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -327,8 +327,10 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
-
+
if (fs_info->compress_type == BTRFS_COMPRESS_LZO)
comp = "lzo";
- else
@@ -101,13 +181,13 @@ index dabfc7a..d8ea727 100644
comp, strlen(comp), 0);
if (ret)
@@ -1463,6 +1465,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
-
+
if (range->compress_type == BTRFS_COMPRESS_LZO) {
btrfs_set_fs_incompat(fs_info, COMPRESS_LZO);
+ } else if (range->compress_type == BTRFS_COMPRESS_ZSTD) {
+ btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
}
-
+
ret = defrag_count;
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index d6cb155..162105f 100644
@@ -119,7 +199,7 @@ index d6cb155..162105f 100644
return 0;
+ else if (!strncmp("zstd", value, len))
+ return 0;
-
+
return -EINVAL;
}
@@ -405,6 +407,8 @@ static int prop_compression_apply(struct inode *inode,
@@ -130,7 +210,7 @@ index d6cb155..162105f 100644
+ type = BTRFS_COMPRESS_ZSTD;
else
return -EINVAL;
-
+
@@ -422,6 +426,8 @@ static const char *prop_compression_extract(struct inode *inode)
return "zlib";
case BTRFS_COMPRESS_LZO:
@@ -138,10 +218,10 @@ index d6cb155..162105f 100644
+ case BTRFS_COMPRESS_ZSTD:
+ return "zstd";
}
-
+
return NULL;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
-index da687dc..b064456 100644
+index 4f1cdd5..4f792d5 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -513,6 +513,14 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
@@ -159,7 +239,7 @@ index da687dc..b064456 100644
} else if (strncmp(args[0].from, "no", 2) == 0) {
compress_type = "no";
btrfs_clear_opt(info->mount_opt, COMPRESS);
-@@ -1230,8 +1238,10 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
+@@ -1240,8 +1248,10 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
if (btrfs_test_opt(info, COMPRESS)) {
if (info->compress_type == BTRFS_COMPRESS_ZLIB)
compress_type = "zlib";
@@ -193,10 +273,28 @@ index 1f157fb..b0dec90 100644
BTRFS_FEAT_ATTR_PTR(raid56),
diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
new file mode 100644
-index 0000000..010548c
+index 0000000..838741b
--- /dev/null
+++ b/fs/btrfs/zstd.c
-@@ -0,0 +1,415 @@
+@@ -0,0 +1,433 @@
++/*
++ * Copyright (c) 2016-present, Facebook, Inc.
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License v2 as published by the Free Software Foundation.
++ *
++ * 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., 59 Temple Place - Suite 330,
++ * Boston, MA 021110-1307, USA.
++ */
+#include
+#include
+#include
@@ -213,7 +311,7 @@ index 0000000..010548c
+
+static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len)
+{
-+ ZSTD_parameters params = ZSTD_getParams(3, src_len, 0);
++ ZSTD_parameters params = ZSTD_getParams(1, src_len, 0);
+
+ if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG)
+ params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG;
@@ -613,7 +711,7 @@ index 0000000..010548c
+ .decompress = zstd_decompress,
+};
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
-index db4c253..f26c34f 100644
+index a456e53..992c150 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -255,13 +255,7 @@ struct btrfs_ioctl_fs_info_args {
@@ -628,6 +726,8 @@ index db4c253..f26c34f 100644
- */
-#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2 (1ULL << 4)
+#define BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD (1ULL << 4)
-
+
/*
* older kernels tried to do bigger metadata blocks, but the
+--
+2.9.3
diff --git a/contrib/linux-kernel/squashfs.diff b/contrib/linux-kernel/0004-squashfs-Add-zstd-support.patch
similarity index 69%
rename from contrib/linux-kernel/squashfs.diff
rename to contrib/linux-kernel/0004-squashfs-Add-zstd-support.patch
index ddf7b3578..b638194f6 100644
--- a/contrib/linux-kernel/squashfs.diff
+++ b/contrib/linux-kernel/0004-squashfs-Add-zstd-support.patch
@@ -1,17 +1,67 @@
-commit 16bb6b9fd684eadba41a36223d67805d7ea741e7
-Author: Sean Purcell
-Date: Thu Apr 27 17:17:58 2017 -0700
+From 5ff6a64abaea7b7f11d37cb0fdf08642316a3a90 Mon Sep 17 00:00:00 2001
+From: Nick Terrell
+Date: Mon, 12 Jun 2017 12:18:23 -0700
+Subject: [PATCH v2 4/4] squashfs: Add zstd support
- Add zstd support to squashfs
+Add zstd compression and decompression support to SquashFS. zstd is a
+great fit for SquashFS because it can compress at ratios approaching xz,
+while decompressing twice as fast as zlib. For SquashFS in particular,
+it can decompress as fast as lzo and lz4. It also has the flexibility
+to turn down the compression ratio for faster compression times.
+
+The compression benchmark is run on the file tree from the SquashFS archive
+found in ubuntu-16.10-desktop-amd64.iso [1]. It uses `mksquashfs` with the
+default block size (128 KB) and and various compression algorithms/levels.
+xz and zstd are also benchmarked with 256 KB blocks. The decompression
+benchmark times how long it takes to `tar` the file tree into `/dev/null`.
+See the benchmark file in the upstream zstd source repository located under
+`contrib/linux-kernel/squashfs-benchmark.sh` [2] for details.
+
+I ran the benchmarks on a Ubuntu 14.04 VM with 2 cores and 4 GiB of RAM.
+The VM is running on a MacBook Pro with a 3.1 GHz Intel Core i7 processor,
+16 GB of RAM, and a SSD.
+
+| Method | Ratio | Compression MB/s | Decompression MB/s |
+|----------------|-------|------------------|--------------------|
+| gzip | 2.92 | 15 | 128 |
+| lzo | 2.64 | 9.5 | 217 |
+| lz4 | 2.12 | 94 | 218 |
+| xz | 3.43 | 5.5 | 35 |
+| xz 256 KB | 3.53 | 5.4 | 40 |
+| zstd 1 | 2.71 | 96 | 210 |
+| zstd 5 | 2.93 | 69 | 198 |
+| zstd 10 | 3.01 | 41 | 225 |
+| zstd 15 | 3.13 | 11.4 | 224 |
+| zstd 16 256 KB | 3.24 | 8.1 | 210 |
+
+This patch was written by Sean Purcell , but I will be
+taking over the submission process.
+
+[1] http://releases.ubuntu.com/16.10/
+[2] https://github.com/facebook/zstd/blob/dev/contrib/linux-kernel/squashfs-benchmark.sh
+
+zstd source repository: https://github.com/facebook/zstd
+
+Cc: Sean Purcell
+Signed-off-by: Nick Terrell
+---
+ fs/squashfs/Kconfig | 14 +++++
+ fs/squashfs/Makefile | 1 +
+ fs/squashfs/decompressor.c | 7 +++
+ fs/squashfs/decompressor.h | 4 ++
+ fs/squashfs/squashfs_fs.h | 1 +
+ fs/squashfs/zstd_wrapper.c | 150 +++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 177 insertions(+)
+ create mode 100644 fs/squashfs/zstd_wrapper.c
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
index ffb093e..1adb334 100644
--- a/fs/squashfs/Kconfig
+++ b/fs/squashfs/Kconfig
@@ -165,6 +165,20 @@ config SQUASHFS_XZ
-
+
If unsure, say N.
-
+
+config SQUASHFS_ZSTD
+ bool "Include support for ZSTD compressed file systems"
+ depends on SQUASHFS
@@ -45,7 +95,7 @@ index d2bc136..8366398 100644
@@ -65,6 +65,12 @@ static const struct squashfs_decompressor squashfs_zlib_comp_ops = {
};
#endif
-
+
+#ifndef CONFIG_SQUASHFS_ZSTD
+static const struct squashfs_decompressor squashfs_zstd_comp_ops = {
+ NULL, NULL, NULL, NULL, ZSTD_COMPRESSION, "zstd", 0
@@ -62,7 +112,7 @@ index d2bc136..8366398 100644
+ &squashfs_zstd_comp_ops,
&squashfs_unknown_comp_ops
};
-
+
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
index a25713c..0f5a8e4 100644
--- a/fs/squashfs/decompressor.h
@@ -70,7 +120,7 @@ index a25713c..0f5a8e4 100644
@@ -58,4 +58,8 @@ extern const struct squashfs_decompressor squashfs_lzo_comp_ops;
extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
#endif
-
+
+#ifdef CONFIG_SQUASHFS_ZSTD
+extern const struct squashfs_decompressor squashfs_zstd_comp_ops;
+#endif
@@ -85,19 +135,20 @@ index 506f4ba..24d12fd 100644
#define XZ_COMPRESSION 4
#define LZ4_COMPRESSION 5
+#define ZSTD_COMPRESSION 6
-
+
struct squashfs_super_block {
__le32 s_magic;
diff --git a/fs/squashfs/zstd_wrapper.c b/fs/squashfs/zstd_wrapper.c
new file mode 100644
-index 0000000..7cc9303
+index 0000000..8cb7c76
--- /dev/null
+++ b/fs/squashfs/zstd_wrapper.c
-@@ -0,0 +1,149 @@
+@@ -0,0 +1,150 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
-+ * Copyright (c) 2017 Facebook
++ * Copyright (c) 2016-present, Facebook, Inc.
++ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
@@ -243,3 +294,5 @@ index 0000000..7cc9303
+ .name = "zstd",
+ .supported = 1
+};
+--
+2.9.3
diff --git a/contrib/linux-kernel/COPYING b/contrib/linux-kernel/COPYING
new file mode 100644
index 000000000..ecbc05937
--- /dev/null
+++ b/contrib/linux-kernel/COPYING
@@ -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.
+
+
+ Copyright (C)
+
+ 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.
+
+ , 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.
\ No newline at end of file
diff --git a/contrib/linux-kernel/README.md b/contrib/linux-kernel/README.md
index 16bc2d48f..214c520bd 100644
--- a/contrib/linux-kernel/README.md
+++ b/contrib/linux-kernel/README.md
@@ -1,21 +1,33 @@
# Linux Kernel Patch
-There are three pieces, the `zstd_compress` and `zstd_decompress` kernel modules, the BtrFS patch, and the SquashFS patch.
+There are four pieces, the `xxhash` kernel module, the `zstd_compress` and `zstd_decompress` kernel modules, the BtrFS patch, and the SquashFS patch.
The patches are based off of the linux kernel master branch (version 4.10).
+## xxHash kernel module
+
+* The patch is locaed in `xxhash.diff`.
+* The header is in `include/linux/xxhash.h`.
+* The source is in `lib/xxhash.c`.
+* `test/XXHashUserLandTest.cpp` contains tests for the patch in userland by mocking the kernel headers.
+ I tested the tests by commenting a line of of each branch in `xxhash.c` one line at a time, and made sure the tests failed.
+ It can be run with the following commands:
+ ```
+ cd test && make googletest && make XXHashUserLandTest && ./XXHashUserLandTest
+ ```
+* I also benchmarked the `xxhash` module against upstream xxHash, and made sure that they ran at the same speed.
+
## Zstd Kernel modules
+* The (large) patch is locaed in `zstd.diff`, which depends on `xxhash.diff`.
* The header is in `include/linux/zstd.h`.
* It is split up into `zstd_compress` and `zstd_decompress`, which can be loaded independently.
* Source files are in `lib/zstd/`.
* `lib/Kconfig` and `lib/Makefile` need to be modified by applying `lib/Kconfig.diff` and `lib/Makefile.diff` respectively.
+ These changes are also included in the `zstd.diff`.
* `test/UserlandTest.cpp` contains tests for the patch in userland by mocking the kernel headers.
It can be run with the following commands:
```
- cd test
- make googletest
- make UserlandTest
- ./UserlandTest
+ cd test && make googletest && make UserlandTest && ./UserlandTest
```
## BtrFS
diff --git a/contrib/linux-kernel/btrfs-extract-benchmark.sh b/contrib/linux-kernel/btrfs-extract-benchmark.sh
new file mode 100755
index 000000000..69721d093
--- /dev/null
+++ b/contrib/linux-kernel/btrfs-extract-benchmark.sh
@@ -0,0 +1,99 @@
+# !/bin/sh
+set -e
+
+# Benchmarks run on a Ubuntu 14.04 VM with 2 cores and 4 GiB of RAM.
+# The VM is running on a Macbook Pro with a 3.1 GHz Intel Core i7 processor and
+# 16 GB of RAM and an SSD.
+
+# silesia is a directory that can be downloaded from
+# http://mattmahoney.net/dc/silesia.html
+# ls -l silesia/
+# total 203M
+# -rwxr-xr-x 1 terrelln 9.8M Apr 12 2002 dickens
+# -rwxr-xr-x 1 terrelln 49M May 31 2002 mozilla
+# -rwxr-xr-x 1 terrelln 9.6M Mar 20 2003 mr
+# -rwxr-xr-x 1 terrelln 32M Apr 2 2002 nci
+# -rwxr-xr-x 1 terrelln 5.9M Jul 4 2002 ooffice
+# -rwxr-xr-x 1 terrelln 9.7M Apr 11 2002 osdb
+# -rwxr-xr-x 1 terrelln 6.4M Apr 2 2002 reymont
+# -rwxr-xr-x 1 terrelln 21M Mar 25 2002 samba
+# -rwxr-xr-x 1 terrelln 7.0M Mar 24 2002 sao
+# -rwxr-xr-x 1 terrelln 40M Mar 25 2002 webster
+# -rwxr-xr-x 1 terrelln 8.1M Apr 4 2002 x-ray
+# -rwxr-xr-x 1 terrelln 5.1M Nov 30 2000 xml
+
+# $HOME is on a ext4 filesystem
+BENCHMARK_FILE="linux-4.11.6.tar"
+BENCHMARK_DIR="$HOME/$BENCHMARK_FILE"
+
+# Normalize the environment
+sudo umount /mnt/btrfs 2> /dev/null > /dev/null || true
+sudo mount -t btrfs $@ /dev/sda3 /mnt/btrfs
+sudo rm -rf /mnt/btrfs/*
+sync
+sudo umount /mnt/btrfs
+sudo mount -t btrfs $@ /dev/sda3 /mnt/btrfs
+
+# Run the benchmark
+echo "Copy"
+time sh -c "sudo cp -r $BENCHMARK_DIR /mnt/btrfs/$BENCHMARK_FILE && sync"
+
+echo "Approximate tarred compression ratio"
+printf "%d / %d\n" \
+ $(df /mnt/btrfs --output=used -B 1 | tail -n 1) \
+ $(sudo du /mnt/btrfs -b -d 0 | tr '\t' '\n' | head -n 1);
+
+# Unmount and remount to avoid any caching
+sudo umount /mnt/btrfs
+sudo mount -t btrfs $@ /dev/sda3 /mnt/btrfs
+
+echo "Extract"
+time sh -c "sudo tar -C /mnt/btrfs -xf /mnt/btrfs/$BENCHMARK_FILE && sync"
+
+# Remove the tarball, leaving only the extracted data
+sudo rm /mnt/btrfs/$BENCHMARK_FILE
+# Unmount and remount to avoid any caching
+sudo umount /mnt/btrfs
+sudo mount -t btrfs $@ /dev/sda3 /mnt/btrfs
+
+echo "Approximate extracted compression ratio"
+printf "%d / %d\n" \
+ $(df /mnt/btrfs --output=used -B 1 | tail -n 1) \
+ $(sudo du /mnt/btrfs -b -d 0 | tr '\t' '\n' | head -n 1);
+
+echo "Read"
+time sudo tar -c /mnt/btrfs 2> /dev/null | wc -c > /dev/null
+
+sudo rm -rf /mnt/btrfs/*
+sudo umount /mnt/btrfs
+
+# Run for each of -o compress-force={none, lzo, zlib, zstd} 5 times and take the
+# min time and ratio.
+
+# none
+# copy: 0.981 s
+# extract: 5.501 s
+# read: 8.807 s
+# tarball ratio: 0.97
+# extracted ratio: 0.78
+
+# lzo
+# copy: 1.631 s
+# extract: 8.458 s
+# read: 8.585 s
+# tarball ratio: 2.06
+# extracted ratio: 1.38
+
+# zlib
+# copy: 7.750 s
+# extract: 21.544 s
+# read: 11.744 s
+# tarball ratio : 3.40
+# extracted ratio: 1.86
+
+# zstd 1
+# copy: 2.579 s
+# extract: 11.479 s
+# read: 9.389 s
+# tarball ratio : 3.57
+# extracted ratio: 1.85
diff --git a/contrib/linux-kernel/fs/btrfs/zstd.c b/contrib/linux-kernel/fs/btrfs/zstd.c
index 706fa66ef..838741b37 100644
--- a/contrib/linux-kernel/fs/btrfs/zstd.c
+++ b/contrib/linux-kernel/fs/btrfs/zstd.c
@@ -1,3 +1,21 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
#include
#include
#include
@@ -14,7 +32,7 @@
static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len)
{
- ZSTD_parameters params = ZSTD_getParams(3, src_len, 0);
+ ZSTD_parameters params = ZSTD_getParams(1, src_len, 0);
if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG)
params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG;
diff --git a/contrib/linux-kernel/fs/squashfs/zstd_wrapper.c b/contrib/linux-kernel/fs/squashfs/zstd_wrapper.c
index 7cc93030b..8cb7c76d6 100644
--- a/contrib/linux-kernel/fs/squashfs/zstd_wrapper.c
+++ b/contrib/linux-kernel/fs/squashfs/zstd_wrapper.c
@@ -1,7 +1,8 @@
/*
* Squashfs - a compressed read only filesystem for Linux
*
- * Copyright (c) 2017 Facebook
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/contrib/linux-kernel/include/linux/xxhash.h b/contrib/linux-kernel/include/linux/xxhash.h
new file mode 100644
index 000000000..9e1f42cb5
--- /dev/null
+++ b/contrib/linux-kernel/include/linux/xxhash.h
@@ -0,0 +1,236 @@
+/*
+ * xxHash - Extremely Fast Hash algorithm
+ * Copyright (C) 2012-2016, 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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at:
+ * - xxHash homepage: http://cyan4973.github.io/xxHash/
+ * - xxHash source repository: https://github.com/Cyan4973/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.
+ *
+ * A 64-bits version, named xxh64 offers much better speed,
+ * but for 64-bits applications only.
+ * Name Speed on 64 bits Speed on 32 bits
+ * xxh64 13.8 GB/s 1.9 GB/s
+ * xxh32 6.8 GB/s 6.0 GB/s
+ */
+
+#ifndef XXHASH_H
+#define XXHASH_H
+
+#include
+
+/*-****************************
+ * Simple Hash Functions
+ *****************************/
+
+/**
+ * xxh32() - calculate the 32-bit hash of the input with a given seed.
+ *
+ * @input: The data to hash.
+ * @length: The length of the data to hash.
+ * @seed: The seed can be used to alter the result predictably.
+ *
+ * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
+ *
+ * Return: The 32-bit hash of the data.
+ */
+uint32_t xxh32(const void *input, size_t length, uint32_t seed);
+
+/**
+ * xxh64() - calculate the 64-bit hash of the input with a given seed.
+ *
+ * @input: The data to hash.
+ * @length: The length of the data to hash.
+ * @seed: The seed can be used to alter the result predictably.
+ *
+ * This function runs 2x faster on 64-bit systems, but slower on 32-bit systems.
+ *
+ * Return: The 64-bit hash of the data.
+ */
+uint64_t xxh64(const void *input, size_t length, uint64_t seed);
+
+/*-****************************
+ * Streaming Hash Functions
+ *****************************/
+
+/*
+ * These definitions are only meant to allow allocation of XXH state
+ * statically, on stack, or in a struct for example.
+ * Do not use members directly.
+ */
+
+/**
+ * struct xxh32_state - private xxh32 state, do not use members directly
+ */
+struct xxh32_state {
+ uint32_t total_len_32;
+ uint32_t large_len;
+ uint32_t v1;
+ uint32_t v2;
+ uint32_t v3;
+ uint32_t v4;
+ uint32_t mem32[4];
+ uint32_t memsize;
+};
+
+/**
+ * struct xxh32_state - private xxh64 state, do not use members directly
+ */
+struct xxh64_state {
+ uint64_t total_len;
+ uint64_t v1;
+ uint64_t v2;
+ uint64_t v3;
+ uint64_t v4;
+ uint64_t mem64[4];
+ uint32_t memsize;
+};
+
+/**
+ * xxh32_reset() - reset the xxh32 state to start a new hashing operation
+ *
+ * @state: The xxh32 state to reset.
+ * @seed: Initialize the hash state with this seed.
+ *
+ * Call this function on any xxh32_state to prepare for a new hashing operation.
+ */
+void xxh32_reset(struct xxh32_state *state, uint32_t seed);
+
+/**
+ * xxh32_update() - hash the data given and update the xxh32 state
+ *
+ * @state: The xxh32 state to update.
+ * @input: The data to hash.
+ * @length: The length of the data to hash.
+ *
+ * After calling xxh32_reset() call xxh32_update() as many times as necessary.
+ *
+ * Return: Zero on success, otherwise an error code.
+ */
+int xxh32_update(struct xxh32_state *state, const void *input, size_t length);
+
+/**
+ * xxh32_digest() - produce the current xxh32 hash
+ *
+ * @state: Produce the current xxh32 hash of this state.
+ *
+ * A hash value can be produced at any time. It is still possible to continue
+ * inserting input into the hash state after a call to xxh32_digest(), and
+ * generate new hashes later on, by calling xxh32_digest() again.
+ *
+ * Return: The xxh32 hash stored in the state.
+ */
+uint32_t xxh32_digest(const struct xxh32_state *state);
+
+/**
+ * xxh64_reset() - reset the xxh64 state to start a new hashing operation
+ *
+ * @state: The xxh64 state to reset.
+ * @seed: Initialize the hash state with this seed.
+ */
+void xxh64_reset(struct xxh64_state *state, uint64_t seed);
+
+/**
+ * xxh64_update() - hash the data given and update the xxh64 state
+ * @state: The xxh64 state to update.
+ * @input: The data to hash.
+ * @length: The length of the data to hash.
+ *
+ * After calling xxh64_reset() call xxh64_update() as many times as necessary.
+ *
+ * Return: Zero on success, otherwise an error code.
+ */
+int xxh64_update(struct xxh64_state *state, const void *input, size_t length);
+
+/**
+ * xxh64_digest() - produce the current xxh64 hash
+ *
+ * @state: Produce the current xxh64 hash of this state.
+ *
+ * A hash value can be produced at any time. It is still possible to continue
+ * inserting input into the hash state after a call to xxh64_digest(), and
+ * generate new hashes later on, by calling xxh64_digest() again.
+ *
+ * Return: The xxh64 hash stored in the state.
+ */
+uint64_t xxh64_digest(const struct xxh64_state *state);
+
+/*-**************************
+ * Utils
+ ***************************/
+
+/**
+ * xxh32_copy_state() - copy the source state into the destination state
+ *
+ * @src: The source xxh32 state.
+ * @dst: The destination xxh32 state.
+ */
+void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src);
+
+/**
+ * xxh64_copy_state() - copy the source state into the destination state
+ *
+ * @src: The source xxh64 state.
+ * @dst: The destination xxh64 state.
+ */
+void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src);
+
+#endif /* XXHASH_H */
diff --git a/contrib/linux-kernel/include/linux/zstd.h b/contrib/linux-kernel/include/linux/zstd.h
index ee7bd8207..249575e24 100644
--- a/contrib/linux-kernel/include/linux/zstd.h
+++ b/contrib/linux-kernel/include/linux/zstd.h
@@ -3,8 +3,15 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
+ * LICENSE file in the root directory of https://github.com/facebook/zstd.
+ * An additional grant of patent rights can be found in the PATENTS file in the
+ * same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
*/
#ifndef ZSTD_H
diff --git a/contrib/linux-kernel/kernelize.sh b/contrib/linux-kernel/kernelize.sh
new file mode 100755
index 000000000..21aa2ecdc
--- /dev/null
+++ b/contrib/linux-kernel/kernelize.sh
@@ -0,0 +1,110 @@
+#!/bin/sh
+set -e
+
+# Constants
+SED_COMMANDS="commands.tmp"
+CLANG_FORMAT="clang-format-3.9"
+INCLUDE='include/linux/'
+LIB='lib/zstd/'
+SPACES=' '
+TAB=$'\t'
+TMP="replacements.tmp"
+
+function prompt() {
+ while true; do
+ read -p "$1 [Y/n]" yn
+ case $yn in
+ '' ) yes='yes'; break;;
+ [Yy]* ) yes='yes'; break;;
+ [Nn]* ) yes=''; break;;
+ * ) echo "Please answer yes or no.";;
+ esac
+done
+}
+
+function check_not_present() {
+ grep "$1" $INCLUDE*.h ${LIB}*.{h,c} && exit 1 || true
+}
+
+function check_not_present_in_file() {
+ grep "$1" "$2" && exit 1 || true
+}
+
+function check_present_in_file() {
+ grep "$1" "$2" > /dev/null 2> /dev/null || exit 1
+}
+
+echo "Files: " $INCLUDE*.h $LIB*.{h,c}
+
+prompt "Do you wish to replace 4 spaces with a tab?"
+if [ ! -z "$yes" ]
+then
+ # Check files for existing tabs
+ grep "$TAB" $INCLUDE*.h $LIB*.{h,c} && exit 1 || true
+ # Replace the first tab on every line
+ sed -i '' "s/^$SPACES/$TAB/" $INCLUDE*.h $LIB*.{h,c}
+
+ # Execute once and then execute as long as replacements are happening
+ more_work="yes"
+ while [ ! -z "$more_work" ]
+ do
+ rm -f $TMP
+ # Replaces $SPACES that directly follow a $TAB with a $TAB.
+ # $TMP will be non-empty if any replacements took place.
+ sed -i '' "s/$TAB$SPACES/$TAB$TAB/w $TMP" $INCLUDE*.h $LIB*.{h,c}
+ more_work=$(cat "$TMP")
+ done
+ rm -f $TMP
+fi
+
+prompt "Do you wish to replace '{ ' with a tab?"
+if [ ! -z "$yes" ]
+then
+ sed -i '' "s/$TAB{ /$TAB{$TAB/g" $INCLUDE*.h $LIB*.{h,c}
+fi
+
+rm -f $SED_COMMANDS
+cat > $SED_COMMANDS <
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*-*************************************
+ * Macros
+ **************************************/
+#define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
+#define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
+
+#ifdef __LITTLE_ENDIAN
+# define XXH_CPU_LITTLE_ENDIAN 1
+#else
+# define XXH_CPU_LITTLE_ENDIAN 0
+#endif
+
+/*-*************************************
+ * Constants
+ **************************************/
+static const uint32_t PRIME32_1 = 2654435761U;
+static const uint32_t PRIME32_2 = 2246822519U;
+static const uint32_t PRIME32_3 = 3266489917U;
+static const uint32_t PRIME32_4 = 668265263U;
+static const uint32_t PRIME32_5 = 374761393U;
+
+static const uint64_t PRIME64_1 = 11400714785074694791ULL;
+static const uint64_t PRIME64_2 = 14029467366897019727ULL;
+static const uint64_t PRIME64_3 = 1609587929392839161ULL;
+static const uint64_t PRIME64_4 = 9650029242287828579ULL;
+static const uint64_t PRIME64_5 = 2870177450012600261ULL;
+
+/*-**************************
+ * Utils
+ ***************************/
+void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+EXPORT_SYMBOL(xxh32_copy_state);
+
+void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+EXPORT_SYMBOL(xxh64_copy_state);
+
+/*-***************************
+ * Simple Hash Functions
+ ****************************/
+static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
+{
+ seed += input * PRIME32_2;
+ seed = xxh_rotl32(seed, 13);
+ seed *= PRIME32_1;
+ return seed;
+}
+
+uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
+{
+ const uint8_t *p = (const uint8_t *)input;
+ const uint8_t *b_end = p + len;
+ uint32_t h32;
+
+ if (len >= 16) {
+ const uint8_t *const limit = b_end - 16;
+ uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
+ uint32_t v2 = seed + PRIME32_2;
+ uint32_t v3 = seed + 0;
+ uint32_t v4 = seed - PRIME32_1;
+
+ do {
+ v1 = xxh32_round(v1, get_unaligned_le32(p));
+ p += 4;
+ v2 = xxh32_round(v2, get_unaligned_le32(p));
+ p += 4;
+ v3 = xxh32_round(v3, get_unaligned_le32(p));
+ p += 4;
+ v4 = xxh32_round(v4, get_unaligned_le32(p));
+ 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 += (uint32_t)len;
+
+ while (p + 4 <= b_end) {
+ h32 += get_unaligned_le32(p) * PRIME32_3;
+ h32 = xxh_rotl32(h32, 17) * PRIME32_4;
+ p += 4;
+ }
+
+ while (p < b_end) {
+ 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;
+}
+EXPORT_SYMBOL(xxh32);
+
+static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
+{
+ acc += input * PRIME64_2;
+ acc = xxh_rotl64(acc, 31);
+ acc *= PRIME64_1;
+ return acc;
+}
+
+static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
+{
+ val = xxh64_round(0, val);
+ acc ^= val;
+ acc = acc * PRIME64_1 + PRIME64_4;
+ return acc;
+}
+
+uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
+{
+ const uint8_t *p = (const uint8_t *)input;
+ const uint8_t *const b_end = p + len;
+ uint64_t h64;
+
+ if (len >= 32) {
+ const uint8_t *const limit = b_end - 32;
+ uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
+ uint64_t v2 = seed + PRIME64_2;
+ uint64_t v3 = seed + 0;
+ uint64_t v4 = seed - PRIME64_1;
+
+ do {
+ v1 = xxh64_round(v1, get_unaligned_le64(p));
+ p += 8;
+ v2 = xxh64_round(v2, get_unaligned_le64(p));
+ p += 8;
+ v3 = xxh64_round(v3, get_unaligned_le64(p));
+ p += 8;
+ v4 = xxh64_round(v4, get_unaligned_le64(p));
+ p += 8;
+ } while (p <= limit);
+
+ h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
+ xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
+ h64 = xxh64_merge_round(h64, v1);
+ h64 = xxh64_merge_round(h64, v2);
+ h64 = xxh64_merge_round(h64, v3);
+ h64 = xxh64_merge_round(h64, v4);
+
+ } else {
+ h64 = seed + PRIME64_5;
+ }
+
+ h64 += (uint64_t)len;
+
+ while (p + 8 <= b_end) {
+ const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
+
+ h64 ^= k1;
+ h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
+ p += 8;
+ }
+
+ if (p + 4 <= b_end) {
+ h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
+ h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+ p += 4;
+ }
+
+ while (p < b_end) {
+ 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;
+}
+EXPORT_SYMBOL(xxh64);
+
+/*-**************************************************
+ * Advanced Hash Functions
+ ***************************************************/
+void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
+{
+ /* use a local state for memcpy() to avoid strict-aliasing warnings */
+ struct xxh32_state state;
+
+ memset(&state, 0, sizeof(state));
+ state.v1 = seed + PRIME32_1 + PRIME32_2;
+ state.v2 = seed + PRIME32_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - PRIME32_1;
+ memcpy(statePtr, &state, sizeof(state));
+}
+EXPORT_SYMBOL(xxh32_reset);
+
+void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
+{
+ /* use a local state for memcpy() to avoid strict-aliasing warnings */
+ struct xxh64_state state;
+
+ memset(&state, 0, sizeof(state));
+ state.v1 = seed + PRIME64_1 + PRIME64_2;
+ state.v2 = seed + PRIME64_2;
+ state.v3 = seed + 0;
+ state.v4 = seed - PRIME64_1;
+ memcpy(statePtr, &state, sizeof(state));
+}
+EXPORT_SYMBOL(xxh64_reset);
+
+int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
+{
+ const uint8_t *p = (const uint8_t *)input;
+ const uint8_t *const b_end = p + len;
+
+ if (input == NULL)
+ return -EINVAL;
+
+ state->total_len_32 += (uint32_t)len;
+ state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
+
+ if (state->memsize + len < 16) { /* fill in tmp buffer */
+ memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
+ state->memsize += (uint32_t)len;
+ return 0;
+ }
+
+ if (state->memsize) { /* some data left from previous update */
+ const uint32_t *p32 = state->mem32;
+
+ memcpy((uint8_t *)(state->mem32) + state->memsize, input,
+ 16 - state->memsize);
+
+ state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
+ p32++;
+ state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
+ p32++;
+ state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
+ p32++;
+ state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
+ p32++;
+
+ p += 16-state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p <= b_end - 16) {
+ const uint8_t *const limit = b_end - 16;
+ uint32_t v1 = state->v1;
+ uint32_t v2 = state->v2;
+ uint32_t v3 = state->v3;
+ uint32_t v4 = state->v4;
+
+ do {
+ v1 = xxh32_round(v1, get_unaligned_le32(p));
+ p += 4;
+ v2 = xxh32_round(v2, get_unaligned_le32(p));
+ p += 4;
+ v3 = xxh32_round(v3, get_unaligned_le32(p));
+ p += 4;
+ v4 = xxh32_round(v4, get_unaligned_le32(p));
+ p += 4;
+ } while (p <= limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < b_end) {
+ memcpy(state->mem32, p, (size_t)(b_end-p));
+ state->memsize = (uint32_t)(b_end-p);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(xxh32_update);
+
+uint32_t xxh32_digest(const struct xxh32_state *state)
+{
+ const uint8_t *p = (const uint8_t *)state->mem32;
+ const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
+ state->memsize;
+ uint32_t h32;
+
+ if (state->large_len) {
+ h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
+ xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
+ } else {
+ h32 = state->v3 /* == seed */ + PRIME32_5;
+ }
+
+ h32 += state->total_len_32;
+
+ while (p + 4 <= b_end) {
+ h32 += get_unaligned_le32(p) * PRIME32_3;
+ h32 = xxh_rotl32(h32, 17) * PRIME32_4;
+ p += 4;
+ }
+
+ while (p < b_end) {
+ 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;
+}
+EXPORT_SYMBOL(xxh32_digest);
+
+int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
+{
+ const uint8_t *p = (const uint8_t *)input;
+ const uint8_t *const b_end = p + len;
+
+ if (input == NULL)
+ return -EINVAL;
+
+ state->total_len += len;
+
+ if (state->memsize + len < 32) { /* fill in tmp buffer */
+ memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
+ state->memsize += (uint32_t)len;
+ return 0;
+ }
+
+ if (state->memsize) { /* tmp buffer is full */
+ uint64_t *p64 = state->mem64;
+
+ memcpy(((uint8_t *)p64) + state->memsize, input,
+ 32 - state->memsize);
+
+ state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
+ p64++;
+ state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
+ p64++;
+ state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
+ p64++;
+ state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
+
+ p += 32 - state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p + 32 <= b_end) {
+ const uint8_t *const limit = b_end - 32;
+ uint64_t v1 = state->v1;
+ uint64_t v2 = state->v2;
+ uint64_t v3 = state->v3;
+ uint64_t v4 = state->v4;
+
+ do {
+ v1 = xxh64_round(v1, get_unaligned_le64(p));
+ p += 8;
+ v2 = xxh64_round(v2, get_unaligned_le64(p));
+ p += 8;
+ v3 = xxh64_round(v3, get_unaligned_le64(p));
+ p += 8;
+ v4 = xxh64_round(v4, get_unaligned_le64(p));
+ p += 8;
+ } while (p <= limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < b_end) {
+ memcpy(state->mem64, p, (size_t)(b_end-p));
+ state->memsize = (uint32_t)(b_end - p);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(xxh64_update);
+
+uint64_t xxh64_digest(const struct xxh64_state *state)
+{
+ const uint8_t *p = (const uint8_t *)state->mem64;
+ const uint8_t *const b_end = (const uint8_t *)state->mem64 +
+ state->memsize;
+ uint64_t h64;
+
+ if (state->total_len >= 32) {
+ const uint64_t v1 = state->v1;
+ const uint64_t v2 = state->v2;
+ const uint64_t v3 = state->v3;
+ const uint64_t v4 = state->v4;
+
+ h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
+ xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
+ h64 = xxh64_merge_round(h64, v1);
+ h64 = xxh64_merge_round(h64, v2);
+ h64 = xxh64_merge_round(h64, v3);
+ h64 = xxh64_merge_round(h64, v4);
+ } else {
+ h64 = state->v3 + PRIME64_5;
+ }
+
+ h64 += (uint64_t)state->total_len;
+
+ while (p + 8 <= b_end) {
+ const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
+
+ h64 ^= k1;
+ h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
+ p += 8;
+ }
+
+ if (p + 4 <= b_end) {
+ h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
+ h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
+ p += 4;
+ }
+
+ while (p < b_end) {
+ 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;
+}
+EXPORT_SYMBOL(xxh64_digest);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("xxHash");
diff --git a/contrib/linux-kernel/lib/zstd/.clang-format b/contrib/linux-kernel/lib/zstd/.clang-format
new file mode 100644
index 000000000..0c6cf3ba7
--- /dev/null
+++ b/contrib/linux-kernel/lib/zstd/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: LLVM
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Linux
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+
+ColumnLimit: 160
+AlignEscapedNewlinesLeft: true
+ReflowComments: true
+AllowShortCaseLabelsOnASingleLine: true
diff --git a/contrib/linux-kernel/lib/zstd/Makefile b/contrib/linux-kernel/lib/zstd/Makefile
index 067f68d19..dd0a359c1 100644
--- a/contrib/linux-kernel/lib/zstd/Makefile
+++ b/contrib/linux-kernel/lib/zstd/Makefile
@@ -3,7 +3,16 @@ obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd_decompress.o
ccflags-y += -O3
-zstd_compress-y := entropy_common.o fse_decompress.o xxhash.o zstd_common.o \
- fse_compress.o huf_compress.o compress.o
-zstd_decompress-y := entropy_common.o fse_decompress.o xxhash.o zstd_common.o \
- huf_decompress.o decompress.o
+# Object files unique to zstd_compress and zstd_decompress
+zstd_compress-y := fse_compress.o huf_compress.o compress.o
+zstd_decompress-y := huf_decompress.o decompress.o
+
+# These object files are shared between the modules.
+# Always add them to zstd_compress.
+# Unless both zstd_compress and zstd_decompress are built in
+# then also add them to zstd_decompress.
+zstd_compress-y += entropy_common.o fse_decompress.o zstd_common.o
+
+ifneq ($(CONFIG_ZSTD_COMPRESS)$(CONFIG_ZSTD_DECOMPRESS),yy)
+ zstd_decompress-y += entropy_common.o fse_decompress.o zstd_common.o
+endif
diff --git a/contrib/linux-kernel/lib/zstd/bitstream.h b/contrib/linux-kernel/lib/zstd/bitstream.h
index 9d2154082..a826b99e1 100644
--- a/contrib/linux-kernel/lib/zstd/bitstream.h
+++ b/contrib/linux-kernel/lib/zstd/bitstream.h
@@ -1,37 +1,43 @@
-/* ******************************************************************
- bitstream
- Part of FSE library
- header file (to include)
- Copyright (C) 2013-2016, 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 :
- - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
-****************************************************************** */
+/*
+ * bitstream
+ * Part of FSE library
+ * header file (to include)
+ * Copyright (C) 2013-2016, 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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ */
#ifndef BITSTREAM_H_MODULE
#define BITSTREAM_H_MODULE
@@ -44,16 +50,15 @@
/*-****************************************
* Dependencies
******************************************/
-#include "mem.h" /* unaligned access routines */
-#include "error_private.h" /* error codes and messages */
-
+#include "error_private.h" /* error codes and messages */
+#include "mem.h" /* unaligned access routines */
/*=========================================
* Target specific
=========================================*/
-#define STREAM_ACCUMULATOR_MIN_32 25
-#define STREAM_ACCUMULATOR_MIN_64 57
-#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
+#define STREAM_ACCUMULATOR_MIN_32 25
+#define STREAM_ACCUMULATOR_MIN_64 57
+#define STREAM_ACCUMULATOR_MIN ((U32)(ZSTD_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
/*-******************************************
* bitStream encoding API (write forward)
@@ -62,19 +67,18 @@
* A critical property of these streams is that they encode and decode in **reverse** direction.
* So the first bit sequence you add will be the last to be read, like a LIFO stack.
*/
-typedef struct
-{
+typedef struct {
size_t bitContainer;
- int bitPos;
- char* startPtr;
- char* ptr;
- char* endPtr;
+ int bitPos;
+ char *startPtr;
+ char *ptr;
+ char *endPtr;
} BIT_CStream_t;
-MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
-MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
-MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
-MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
+ZSTD_STATIC size_t BIT_initCStream(BIT_CStream_t *bitC, void *dstBuffer, size_t dstCapacity);
+ZSTD_STATIC void BIT_addBits(BIT_CStream_t *bitC, size_t value, unsigned nbBits);
+ZSTD_STATIC void BIT_flushBits(BIT_CStream_t *bitC);
+ZSTD_STATIC size_t BIT_closeCStream(BIT_CStream_t *bitC);
/* Start with initCStream, providing the size of buffer to write into.
* bitStream will never write outside of this buffer.
@@ -93,29 +97,28 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
*/
-
/*-********************************************
* bitStream decoding API (read backward)
**********************************************/
-typedef struct
-{
- size_t bitContainer;
+typedef struct {
+ size_t bitContainer;
unsigned bitsConsumed;
- const char* ptr;
- const char* start;
+ const char *ptr;
+ const char *start;
} BIT_DStream_t;
-typedef enum { BIT_DStream_unfinished = 0,
- BIT_DStream_endOfBuffer = 1,
- BIT_DStream_completed = 2,
- BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
- /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
-
-MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
-MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
-MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
-MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
+typedef enum {
+ BIT_DStream_unfinished = 0,
+ BIT_DStream_endOfBuffer = 1,
+ BIT_DStream_completed = 2,
+ BIT_DStream_overflow = 3
+} BIT_DStream_status; /* result of BIT_reloadDStream() */
+/* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
+ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void *srcBuffer, size_t srcSize);
+ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, unsigned nbBits);
+ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD);
+ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *bitD);
/* Start by invoking BIT_initDStream().
* A chunk of the bitStream is then stored into a local register.
@@ -127,47 +130,27 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
*/
-
/*-****************************************
* unsafe API
******************************************/
-MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+ZSTD_STATIC void BIT_addBitsFast(BIT_CStream_t *bitC, size_t value, unsigned nbBits);
/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
-MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
+ZSTD_STATIC void BIT_flushBitsFast(BIT_CStream_t *bitC);
/* unsafe version; does not check buffer overflow */
-MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
+ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, unsigned nbBits);
/* faster, but works only if nbBits >= 1 */
-
-
/*-**************************************************************
* Internal functions
****************************************************************/
-MEM_STATIC unsigned BIT_highbit32 (register U32 val)
-{
-# if defined(_MSC_VER) /* Visual */
- unsigned long r=0;
- _BitScanReverse ( &r, val );
- return (unsigned) r;
-# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
- return 31 - __builtin_clz (val);
-# else /* Software version */
- static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
- U32 v = val;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
-# endif
-}
+ZSTD_STATIC unsigned BIT_highbit32(register U32 val) { return 31 - __builtin_clz(val); }
/*===== Local Constants =====*/
-static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF }; /* up to 26 bits */
-
+static const unsigned BIT_mask[] = {0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF,
+ 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF,
+ 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF}; /* up to 26 bits */
/*-**************************************************************
* bitStream encoding
@@ -176,21 +159,22 @@ static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x
* `dstCapacity` must be > sizeof(void*)
* @return : 0 if success,
otherwise an error code (can be tested using ERR_isError() ) */
-MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* startPtr, size_t dstCapacity)
+ZSTD_STATIC size_t BIT_initCStream(BIT_CStream_t *bitC, void *startPtr, size_t dstCapacity)
{
bitC->bitContainer = 0;
bitC->bitPos = 0;
- bitC->startPtr = (char*)startPtr;
+ bitC->startPtr = (char *)startPtr;
bitC->ptr = bitC->startPtr;
bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->ptr);
- if (dstCapacity <= sizeof(bitC->ptr)) return ERROR(dstSize_tooSmall);
+ if (dstCapacity <= sizeof(bitC->ptr))
+ return ERROR(dstSize_tooSmall);
return 0;
}
/*! BIT_addBits() :
can add up to 26 bits into `bitC`.
Does not check for register overflow ! */
-MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
+ZSTD_STATIC void BIT_addBits(BIT_CStream_t *bitC, size_t value, unsigned nbBits)
{
bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
bitC->bitPos += nbBits;
@@ -198,7 +182,7 @@ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
/*! BIT_addBitsFast() :
* works only if `value` is _clean_, meaning all high bits above nbBits are 0 */
-MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
+ZSTD_STATIC void BIT_addBitsFast(BIT_CStream_t *bitC, size_t value, unsigned nbBits)
{
bitC->bitContainer |= value << bitC->bitPos;
bitC->bitPos += nbBits;
@@ -206,42 +190,43 @@ MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBi
/*! BIT_flushBitsFast() :
* unsafe version; does not check buffer overflow */
-MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
+ZSTD_STATIC void BIT_flushBitsFast(BIT_CStream_t *bitC)
{
size_t const nbBytes = bitC->bitPos >> 3;
- MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+ ZSTD_writeLEST(bitC->ptr, bitC->bitContainer);
bitC->ptr += nbBytes;
bitC->bitPos &= 7;
- bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
+ bitC->bitContainer >>= nbBytes * 8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
}
/*! BIT_flushBits() :
* safe version; check for buffer overflow, and prevents it.
* note : does not signal buffer overflow. This will be revealed later on using BIT_closeCStream() */
-MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
+ZSTD_STATIC void BIT_flushBits(BIT_CStream_t *bitC)
{
size_t const nbBytes = bitC->bitPos >> 3;
- MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+ ZSTD_writeLEST(bitC->ptr, bitC->bitContainer);
bitC->ptr += nbBytes;
- if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
+ if (bitC->ptr > bitC->endPtr)
+ bitC->ptr = bitC->endPtr;
bitC->bitPos &= 7;
- bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
+ bitC->bitContainer >>= nbBytes * 8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
}
/*! BIT_closeCStream() :
* @return : size of CStream, in bytes,
or 0 if it could not fit into dstBuffer */
-MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
+ZSTD_STATIC size_t BIT_closeCStream(BIT_CStream_t *bitC)
{
- BIT_addBitsFast(bitC, 1, 1); /* endMark */
+ BIT_addBitsFast(bitC, 1, 1); /* endMark */
BIT_flushBits(bitC);
- if (bitC->ptr >= bitC->endPtr) return 0; /* doesn't fit within authorized budget : cancel */
+ if (bitC->ptr >= bitC->endPtr)
+ return 0; /* doesn't fit within authorized budget : cancel */
return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
}
-
/*-********************************************************
* bitStream decoding
**********************************************************/
@@ -251,54 +236,53 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
* `srcSize` must be the *exact* size of the bitStream, in bytes.
* @return : size of stream (== srcSize) or an errorCode if a problem is detected
*/
-MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
+ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void *srcBuffer, size_t srcSize)
{
- if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
+ if (srcSize < 1) {
+ memset(bitD, 0, sizeof(*bitD));
+ return ERROR(srcSize_wrong);
+ }
- if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
- bitD->start = (const char*)srcBuffer;
- bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
- bitD->bitContainer = MEM_readLEST(bitD->ptr);
- { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
- bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
- if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
- } else {
- bitD->start = (const char*)srcBuffer;
- bitD->ptr = bitD->start;
- bitD->bitContainer = *(const BYTE*)(bitD->start);
- switch(srcSize)
+ if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
+ bitD->start = (const char *)srcBuffer;
+ bitD->ptr = (const char *)srcBuffer + srcSize - sizeof(bitD->bitContainer);
+ bitD->bitContainer = ZSTD_readLEST(bitD->ptr);
{
- case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
- case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
- case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
- case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
- case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
- case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
- default:;
+ BYTE const lastByte = ((const BYTE *)srcBuffer)[srcSize - 1];
+ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
+ if (lastByte == 0)
+ return ERROR(GENERIC); /* endMark not present */
}
- { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
- bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
- if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
- bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
+ } else {
+ bitD->start = (const char *)srcBuffer;
+ bitD->ptr = bitD->start;
+ bitD->bitContainer = *(const BYTE *)(bitD->start);
+ switch (srcSize) {
+ case 7: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[6]) << (sizeof(bitD->bitContainer) * 8 - 16);
+ case 6: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[5]) << (sizeof(bitD->bitContainer) * 8 - 24);
+ case 5: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[4]) << (sizeof(bitD->bitContainer) * 8 - 32);
+ case 4: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[3]) << 24;
+ case 3: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[2]) << 16;
+ case 2: bitD->bitContainer += (size_t)(((const BYTE *)(srcBuffer))[1]) << 8;
+ default:;
+ }
+ {
+ BYTE const lastByte = ((const BYTE *)srcBuffer)[srcSize - 1];
+ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
+ if (lastByte == 0)
+ return ERROR(GENERIC); /* endMark not present */
+ }
+ bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize) * 8;
}
return srcSize;
}
-MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
-{
- return bitContainer >> start;
-}
+ZSTD_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) { return bitContainer >> start; }
-MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
-{
- return (bitContainer >> start) & BIT_mask[nbBits];
-}
+ZSTD_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) { return (bitContainer >> start) & BIT_mask[nbBits]; }
-MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
-{
- return bitContainer & BIT_mask[nbBits];
-}
+ZSTD_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) { return bitContainer & BIT_mask[nbBits]; }
/*! BIT_lookBits() :
* Provides next n bits from local register.
@@ -307,31 +291,28 @@ MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
* On 64-bits, maxNbBits==56.
* @return : value extracted
*/
- MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
+ZSTD_STATIC size_t BIT_lookBits(const BIT_DStream_t *bitD, U32 nbBits)
{
- U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
- return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask);
+ U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1;
+ return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask - nbBits) & bitMask);
}
/*! BIT_lookBitsFast() :
* unsafe version; only works only if nbBits >= 1 */
-MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
+ZSTD_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t *bitD, U32 nbBits)
{
- U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
- return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask);
+ U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1;
+ return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask + 1) - nbBits) & bitMask);
}
-MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
-{
- bitD->bitsConsumed += nbBits;
-}
+ZSTD_STATIC void BIT_skipBits(BIT_DStream_t *bitD, U32 nbBits) { bitD->bitsConsumed += nbBits; }
/*! BIT_readBits() :
* Read (consume) next n bits from local register and update.
* Pay attention to not read more than nbBits contained into local register.
* @return : extracted value.
*/
-MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
+ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, U32 nbBits)
{
size_t const value = BIT_lookBits(bitD, nbBits);
BIT_skipBits(bitD, nbBits);
@@ -340,7 +321,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
/*! BIT_readBitsFast() :
* unsafe version; only works only if nbBits >= 1 */
-MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits)
+ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, U32 nbBits)
{
size_t const value = BIT_lookBitsFast(bitD, nbBits);
BIT_skipBits(bitD, nbBits);
@@ -352,30 +333,32 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits)
* This function is safe, it guarantees it will not read beyond src buffer.
* @return : status of `BIT_DStream_t` internal register.
if status == BIT_DStream_unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
-MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
+ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD)
{
- if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should not happen => corruption detected */
+ if (bitD->bitsConsumed > (sizeof(bitD->bitContainer) * 8)) /* should not happen => corruption detected */
return BIT_DStream_overflow;
if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
bitD->ptr -= bitD->bitsConsumed >> 3;
bitD->bitsConsumed &= 7;
- bitD->bitContainer = MEM_readLEST(bitD->ptr);
+ bitD->bitContainer = ZSTD_readLEST(bitD->ptr);
return BIT_DStream_unfinished;
}
if (bitD->ptr == bitD->start) {
- if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
+ if (bitD->bitsConsumed < sizeof(bitD->bitContainer) * 8)
+ return BIT_DStream_endOfBuffer;
return BIT_DStream_completed;
}
- { U32 nbBytes = bitD->bitsConsumed >> 3;
+ {
+ U32 nbBytes = bitD->bitsConsumed >> 3;
BIT_DStream_status result = BIT_DStream_unfinished;
if (bitD->ptr - nbBytes < bitD->start) {
- nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
+ nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
result = BIT_DStream_endOfBuffer;
}
bitD->ptr -= nbBytes;
- bitD->bitsConsumed -= nbBytes*8;
- bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */
+ bitD->bitsConsumed -= nbBytes * 8;
+ bitD->bitContainer = ZSTD_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */
return result;
}
}
@@ -383,9 +366,9 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
/*! BIT_endOfDStream() :
* @return Tells if DStream has exactly reached its end (all bits consumed).
*/
-MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
+ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *DStream)
{
- return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
+ return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer) * 8));
}
#endif /* BITSTREAM_H_MODULE */
diff --git a/contrib/linux-kernel/lib/zstd/compress.c b/contrib/linux-kernel/lib/zstd/compress.c
index 5f6d955a4..d60ab7d4f 100644
--- a/contrib/linux-kernel/lib/zstd/compress.c
+++ b/contrib/linux-kernel/lib/zstd/compress.c
@@ -3,165 +3,166 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
+ * LICENSE file in the root directory of https://github.com/facebook/zstd.
+ * An additional grant of patent rights can be found in the PATENTS file in the
+ * same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
*/
-
/*-*************************************
* Dependencies
***************************************/
-#include
-#include
-#include /* memset */
-#include "mem.h"
#include "fse.h"
#include "huf.h"
-#include "zstd_internal.h" /* includes zstd.h */
-
-#ifdef current
-# undef current
-#endif
+#include "mem.h"
+#include "zstd_internal.h" /* includes zstd.h */
+#include
+#include
+#include /* memset */
/*-*************************************
* Constants
***************************************/
-static const U32 g_searchStrength = 8; /* control skip over incompressible data */
+static const U32 g_searchStrength = 8; /* control skip over incompressible data */
#define HASH_READ_SIZE 8
-typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
-
+typedef enum { ZSTDcs_created = 0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
/*-*************************************
* Helper functions
***************************************/
-#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
-
/*-*************************************
* Sequence storage
***************************************/
-static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
+static void ZSTD_resetSeqStore(seqStore_t *ssPtr)
{
ssPtr->lit = ssPtr->litStart;
ssPtr->sequences = ssPtr->sequencesStart;
ssPtr->longLengthID = 0;
}
-
/*-*************************************
* Context memory management
***************************************/
struct ZSTD_CCtx_s {
- const BYTE* nextSrc; /* next block here to continue on current prefix */
- const BYTE* base; /* All regular indexes relative to this position */
- const BYTE* dictBase; /* extDict indexes relative to this position */
- U32 dictLimit; /* below that point, need extDict */
- U32 lowLimit; /* below that point, no more data */
- U32 nextToUpdate; /* index from which to continue dictionary update */
- U32 nextToUpdate3; /* index from which to continue dictionary update */
- U32 hashLog3; /* dispatch table : larger == faster, more memory */
- U32 loadedDictEnd; /* index of end of dictionary */
- U32 forceWindow; /* force back-references to respect limit of 1<3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
+ U32 const hashLog3 = (cParams.searchLength > 3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
size_t const h3Size = ((size_t)1) << hashLog3;
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
- size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<customMem = customMem;
return cctx;
}
-ZSTD_CCtx* ZSTD_initCCtx(void* workspace, size_t workspaceSize)
+ZSTD_CCtx *ZSTD_initCCtx(void *workspace, size_t workspaceSize)
{
ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
- ZSTD_CCtx* cctx = ZSTD_createCCtx_advanced(stackMem);
+ ZSTD_CCtx *cctx = ZSTD_createCCtx_advanced(stackMem);
if (cctx) {
cctx->workSpace = ZSTD_stackAllocAll(cctx->customMem.opaque, &cctx->workSpaceSize);
}
return cctx;
}
-size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
+size_t ZSTD_freeCCtx(ZSTD_CCtx *cctx)
{
- if (cctx==NULL) return 0; /* support free on NULL */
+ if (cctx == NULL)
+ return 0; /* support free on NULL */
ZSTD_free(cctx->workSpace, cctx->customMem);
ZSTD_free(cctx, cctx->customMem);
- return 0; /* reserved as a potential error code in the future */
+ return 0; /* reserved as a potential error code in the future */
}
-const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
-{
- return &(ctx->seqStore);
-}
-
-static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
-{
- return cctx->params;
-}
+const seqStore_t *ZSTD_getSeqStore(const ZSTD_CCtx *ctx) /* hidden interface */ { return &(ctx->seqStore); }
+static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx *cctx) { return cctx->params; }
/** ZSTD_checkParams() :
ensure param values remain within authorized range.
@return : 0, or an error code if one value is beyond authorized range */
size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
{
-# define CLAMPCHECK(val,min,max) { if ((valmax)) return ERROR(compressionParameter_unsupported); }
+#define CLAMPCHECK(val, min, max) \
+ { \
+ if ((val < min) | (val > max)) \
+ return ERROR(compressionParameter_unsupported); \
+ }
CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
- if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
+ if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2)
+ return ERROR(compressionParameter_unsupported);
return 0;
}
-
/** ZSTD_cycleLog() :
* condition for correct operation : hashLog > 1 */
static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
@@ -178,50 +179,59 @@ static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
{
- if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
+ if (srcSize + dictSize == 0)
+ return cPar; /* no size information available : no adjustment */
/* resize params, to use less memory when necessary */
- { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
+ {
+ U32 const minSrcSize = (srcSize == 0) ? 500 : 0;
U64 const rSize = srcSize + dictSize + minSrcSize;
- if (rSize < ((U64)1< srcLog) cPar.windowLog = srcLog;
- } }
- if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
- { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
- if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
+ if (cPar.windowLog > srcLog)
+ cPar.windowLog = srcLog;
+ }
+ }
+ if (cPar.hashLog > cPar.windowLog)
+ cPar.hashLog = cPar.windowLog;
+ {
+ U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
+ if (cycleLog > cPar.windowLog)
+ cPar.chainLog -= (cycleLog - cPar.windowLog);
}
- if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
+ if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
+ cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
return cPar;
}
-
static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
{
- return (param1.cParams.hashLog == param2.cParams.hashLog)
- & (param1.cParams.chainLog == param2.cParams.chainLog)
- & (param1.cParams.strategy == param2.cParams.strategy)
- & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
+ return (param1.cParams.hashLog == param2.cParams.hashLog) & (param1.cParams.chainLog == param2.cParams.chainLog) &
+ (param1.cParams.strategy == param2.cParams.strategy) & ((param1.cParams.searchLength == 3) == (param2.cParams.searchLength == 3));
}
/*! ZSTD_continueCCtx() :
reuse CCtx without reset (note : requires no dictionary) */
-static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
+static size_t ZSTD_continueCCtx(ZSTD_CCtx *cctx, ZSTD_parameters params, U64 frameContentSize)
{
U32 const end = (U32)(cctx->nextSrc - cctx->base);
cctx->params = params;
cctx->frameContentSize = frameContentSize;
cctx->lowLimit = end;
cctx->dictLimit = end;
- cctx->nextToUpdate = end+1;
+ cctx->nextToUpdate = end + 1;
cctx->stage = ZSTDcs_init;
cctx->dictID = 0;
cctx->loadedDictEnd = 0;
- { int i; for (i=0; irep[i] = repStartValue[i]; }
- cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
- XXH64_reset(&cctx->xxhState, 0);
+ {
+ int i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ cctx->rep[i] = repStartValue[i];
+ }
+ cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
+ xxh64_reset(&cctx->xxhState, 0);
return 0;
}
@@ -229,9 +239,7 @@ typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_comp
/*! ZSTD_resetCCtx_advanced() :
note : `params` must be validated */
-static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
- ZSTD_parameters params, U64 frameContentSize,
- ZSTD_compResetPolicy_e const crp)
+static size_t ZSTD_resetCCtx_advanced(ZSTD_CCtx *zc, ZSTD_parameters params, U64 frameContentSize, ZSTD_compResetPolicy_e const crp)
{
if (crp == ZSTDcrp_continue)
if (ZSTD_equivalentParams(params, zc->params)) {
@@ -240,40 +248,45 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
return ZSTD_continueCCtx(zc, params, frameContentSize);
}
- { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
- U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
+ {
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
+ U32 const divider = (params.cParams.searchLength == 3) ? 3 : 4;
size_t const maxNbSeq = blockSize / divider;
- size_t const tokenSpace = blockSize + 11*maxNbSeq;
+ size_t const tokenSpace = blockSize + 11 * maxNbSeq;
size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
size_t const hSize = ((size_t)1) << params.cParams.hashLog;
- U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
+ U32 const hashLog3 = (params.cParams.searchLength > 3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
size_t const h3Size = ((size_t)1) << hashLog3;
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
- void* ptr;
+ void *ptr;
/* Check if workSpace is large enough, alloc a new one if needed */
- { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<workSpaceSize < neededSpace) {
ZSTD_free(zc->workSpace, zc->customMem);
zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
- if (zc->workSpace == NULL) return ERROR(memory_allocation);
+ if (zc->workSpace == NULL)
+ return ERROR(memory_allocation);
zc->workSpaceSize = neededSpace;
- } }
+ }
+ }
- if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
- XXH64_reset(&zc->xxhState, 0);
+ if (crp != ZSTDcrp_noMemset)
+ memset(zc->workSpace, 0, tableSpace); /* reset tables only */
+ xxh64_reset(&zc->xxhState, 0);
zc->hashLog3 = hashLog3;
- zc->hashTable = (U32*)(zc->workSpace);
+ zc->hashTable = (U32 *)(zc->workSpace);
zc->chainTable = zc->hashTable + hSize;
zc->hashTable3 = zc->chainTable + chainSize;
ptr = zc->hashTable3 + h3Size;
- zc->hufTable = (HUF_CElt*)ptr;
+ zc->hufTable = (HUF_CElt *)ptr;
zc->flagStaticTables = 0;
zc->flagStaticHufTable = HUF_repeat_none;
- ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
+ ptr = ((U32 *)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
zc->nextToUpdate = 1;
zc->nextSrc = NULL;
@@ -284,23 +297,27 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
zc->params = params;
zc->blockSize = blockSize;
zc->frameContentSize = frameContentSize;
- { int i; for (i=0; irep[i] = repStartValue[i]; }
+ {
+ int i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ zc->rep[i] = repStartValue[i];
+ }
if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
- zc->seqStore.litFreq = (U32*)ptr;
- zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
- zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
- ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
- zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
- ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
- zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
- ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
+ zc->seqStore.litFreq = (U32 *)ptr;
+ zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1 << Litbits);
+ zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL + 1);
+ zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML + 1);
+ ptr = zc->seqStore.offCodeFreq + (MaxOff + 1);
+ zc->seqStore.matchTable = (ZSTD_match_t *)ptr;
+ ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM + 1;
+ zc->seqStore.priceTable = (ZSTD_optimal_t *)ptr;
+ ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM + 1;
zc->seqStore.litLengthSum = 0;
}
- zc->seqStore.sequencesStart = (seqDef*)ptr;
+ zc->seqStore.sequencesStart = (seqDef *)ptr;
ptr = zc->seqStore.sequencesStart + maxNbSeq;
- zc->seqStore.llCode = (BYTE*) ptr;
+ zc->seqStore.llCode = (BYTE *)ptr;
zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
@@ -317,28 +334,32 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
* ensures next compression will not use repcodes from previous block.
* Note : only works with regular variant;
* do not use with extDict variant ! */
-void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
+void ZSTD_invalidateRepCodes(ZSTD_CCtx *cctx)
+{
int i;
- for (i=0; irep[i] = 0;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ cctx->rep[i] = 0;
}
/*! ZSTD_copyCCtx() :
* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
* @return : 0, or an error code */
-size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
+size_t ZSTD_copyCCtx(ZSTD_CCtx *dstCCtx, const ZSTD_CCtx *srcCCtx, unsigned long long pledgedSrcSize)
{
- if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
-
+ if (srcCCtx->stage != ZSTDcs_init)
+ return ERROR(stage_wrong);
memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
- { ZSTD_parameters params = srcCCtx->params;
+ {
+ ZSTD_parameters params = srcCCtx->params;
params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
ZSTD_resetCCtx_advanced(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
}
/* copy tables */
- { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
+ {
+ size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
@@ -347,14 +368,14 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long
/* copy dictionary offsets */
dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
- dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
- dstCCtx->nextSrc = srcCCtx->nextSrc;
- dstCCtx->base = srcCCtx->base;
- dstCCtx->dictBase = srcCCtx->dictBase;
- dstCCtx->dictLimit = srcCCtx->dictLimit;
- dstCCtx->lowLimit = srcCCtx->lowLimit;
- dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
- dstCCtx->dictID = srcCCtx->dictID;
+ dstCCtx->nextToUpdate3 = srcCCtx->nextToUpdate3;
+ dstCCtx->nextSrc = srcCCtx->nextSrc;
+ dstCCtx->base = srcCCtx->base;
+ dstCCtx->dictBase = srcCCtx->dictBase;
+ dstCCtx->dictLimit = srcCCtx->dictLimit;
+ dstCCtx->lowLimit = srcCCtx->lowLimit;
+ dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd;
+ dstCCtx->dictID = srcCCtx->dictID;
/* copy entropy tables */
dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
@@ -365,536 +386,545 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long
memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
}
if (srcCCtx->flagStaticHufTable) {
- memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
+ memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256 * 4);
}
return 0;
}
-
/*! ZSTD_reduceTable() :
* reduce table indexes by `reducerValue` */
-static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
+static void ZSTD_reduceTable(U32 *const table, U32 const size, U32 const reducerValue)
{
U32 u;
- for (u=0 ; u < size ; u++) {
- if (table[u] < reducerValue) table[u] = 0;
- else table[u] -= reducerValue;
+ for (u = 0; u < size; u++) {
+ if (table[u] < reducerValue)
+ table[u] = 0;
+ else
+ table[u] -= reducerValue;
}
}
/*! ZSTD_reduceIndex() :
* rescale all indexes to avoid future overflow (indexes are U32) */
-static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
+static void ZSTD_reduceIndex(ZSTD_CCtx *zc, const U32 reducerValue)
{
- { U32 const hSize = 1 << zc->params.cParams.hashLog;
- ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
+ {
+ U32 const hSize = 1 << zc->params.cParams.hashLog;
+ ZSTD_reduceTable(zc->hashTable, hSize, reducerValue);
+ }
- { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
- ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
+ {
+ U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
+ ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
+ }
- { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
- ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
+ {
+ U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
+ ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue);
+ }
}
-
/*-*******************************************************
* Block entropic compression
*********************************************************/
/* See doc/zstd_compression_format.md for detailed format description */
-size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+size_t ZSTD_noCompressBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
- if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
- memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
- MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
- return ZSTD_blockHeaderSize+srcSize;
+ if (srcSize + ZSTD_blockHeaderSize > dstCapacity)
+ return ERROR(dstSize_tooSmall);
+ memcpy((BYTE *)dst + ZSTD_blockHeaderSize, src, srcSize);
+ ZSTD_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
+ return ZSTD_blockHeaderSize + srcSize;
}
-
-static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+static size_t ZSTD_noCompressLiterals(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
- BYTE* const ostart = (BYTE* const)dst;
- U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
+ BYTE *const ostart = (BYTE * const)dst;
+ U32 const flSize = 1 + (srcSize > 31) + (srcSize > 4095);
- if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
+ if (srcSize + flSize > dstCapacity)
+ return ERROR(dstSize_tooSmall);
- switch(flSize)
- {
- case 1: /* 2 - 1 - 5 */
- ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
- break;
- case 2: /* 2 - 2 - 12 */
- MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
- break;
- default: /*note : should not be necessary : flSize is within {1,2,3} */
- case 3: /* 2 - 2 - 20 */
- MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
- break;
+ switch (flSize) {
+ case 1: /* 2 - 1 - 5 */ ostart[0] = (BYTE)((U32)set_basic + (srcSize << 3)); break;
+ case 2: /* 2 - 2 - 12 */ ZSTD_writeLE16(ostart, (U16)((U32)set_basic + (1 << 2) + (srcSize << 4))); break;
+ default: /*note : should not be necessary : flSize is within {1,2,3} */
+ case 3: /* 2 - 2 - 20 */ ZSTD_writeLE32(ostart, (U32)((U32)set_basic + (3 << 2) + (srcSize << 4))); break;
}
memcpy(ostart + flSize, src, srcSize);
return srcSize + flSize;
}
-static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+static size_t ZSTD_compressRleLiteralsBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
- BYTE* const ostart = (BYTE* const)dst;
- U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
+ BYTE *const ostart = (BYTE * const)dst;
+ U32 const flSize = 1 + (srcSize > 31) + (srcSize > 4095);
- (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
+ (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
- switch(flSize)
- {
- case 1: /* 2 - 1 - 5 */
- ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
- break;
- case 2: /* 2 - 2 - 12 */
- MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
- break;
- default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
- case 3: /* 2 - 2 - 20 */
- MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
- break;
+ switch (flSize) {
+ case 1: /* 2 - 1 - 5 */ ostart[0] = (BYTE)((U32)set_rle + (srcSize << 3)); break;
+ case 2: /* 2 - 2 - 12 */ ZSTD_writeLE16(ostart, (U16)((U32)set_rle + (1 << 2) + (srcSize << 4))); break;
+ default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
+ case 3: /* 2 - 2 - 20 */ ZSTD_writeLE32(ostart, (U32)((U32)set_rle + (3 << 2) + (srcSize << 4))); break;
}
- ostart[flSize] = *(const BYTE*)src;
- return flSize+1;
+ ostart[flSize] = *(const BYTE *)src;
+ return flSize + 1;
}
-
static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
-static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
+static size_t ZSTD_compressLiterals(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
size_t const minGain = ZSTD_minGain(srcSize);
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
- BYTE* const ostart = (BYTE*)dst;
+ BYTE *const ostart = (BYTE *)dst;
U32 singleStream = srcSize < 256;
symbolEncodingType_e hType = set_compressed;
size_t cLitSize;
-
- /* small ? don't even attempt compression (speed opt) */
-# define LITERAL_NOENTROPY 63
- { size_t const minLitSize = zc->flagStaticHufTable == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
- if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
+/* small ? don't even attempt compression (speed opt) */
+#define LITERAL_NOENTROPY 63
+ {
+ size_t const minLitSize = zc->flagStaticHufTable == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
+ if (srcSize <= minLitSize)
+ return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
}
- if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
- { HUF_repeat repeat = zc->flagStaticHufTable;
+ if (dstCapacity < lhSize + 1)
+ return ERROR(dstSize_tooSmall); /* not enough space for compression */
+ {
+ HUF_repeat repeat = zc->flagStaticHufTable;
int const preferRepeat = zc->params.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
- if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
- cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters), zc->hufTable, &repeat, preferRepeat)
- : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters), zc->hufTable, &repeat, preferRepeat);
- if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
- else { zc->flagStaticHufTable = HUF_repeat_check; } /* now have a table to reuse */
+ if (repeat == HUF_repeat_valid && lhSize == 3)
+ singleStream = 1;
+ cLitSize = singleStream ? HUF_compress1X_repeat(ostart + lhSize, dstCapacity - lhSize, src, srcSize, 255, 11, zc->tmpCounters,
+ sizeof(zc->tmpCounters), zc->hufTable, &repeat, preferRepeat)
+ : HUF_compress4X_repeat(ostart + lhSize, dstCapacity - lhSize, src, srcSize, 255, 11, zc->tmpCounters,
+ sizeof(zc->tmpCounters), zc->hufTable, &repeat, preferRepeat);
+ if (repeat != HUF_repeat_none) {
+ hType = set_repeat;
+ } /* reused the existing table */
+ else {
+ zc->flagStaticHufTable = HUF_repeat_check;
+ } /* now have a table to reuse */
}
- if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
+ if ((cLitSize == 0) | (cLitSize >= srcSize - minGain)) {
zc->flagStaticHufTable = HUF_repeat_none;
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
}
- if (cLitSize==1) {
+ if (cLitSize == 1) {
zc->flagStaticHufTable = HUF_repeat_none;
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
}
/* Build header */
- switch(lhSize)
- {
+ switch (lhSize) {
case 3: /* 2 - 2 - 10 - 10 */
- { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
- MEM_writeLE24(ostart, lhc);
- break;
- }
- case 4: /* 2 - 2 - 14 - 14 */
- { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
- MEM_writeLE32(ostart, lhc);
- break;
- }
- default: /* should not be necessary, lhSize is only {3,4,5} */
- case 5: /* 2 - 2 - 18 - 18 */
- { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
- MEM_writeLE32(ostart, lhc);
- ostart[4] = (BYTE)(cLitSize >> 10);
- break;
- }
+ {
+ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize << 4) + ((U32)cLitSize << 14);
+ ZSTD_writeLE24(ostart, lhc);
+ break;
}
- return lhSize+cLitSize;
+ case 4: /* 2 - 2 - 14 - 14 */
+ {
+ U32 const lhc = hType + (2 << 2) + ((U32)srcSize << 4) + ((U32)cLitSize << 18);
+ ZSTD_writeLE32(ostart, lhc);
+ break;
+ }
+ default: /* should not be necessary, lhSize is only {3,4,5} */
+ case 5: /* 2 - 2 - 18 - 18 */
+ {
+ U32 const lhc = hType + (3 << 2) + ((U32)srcSize << 4) + ((U32)cLitSize << 22);
+ ZSTD_writeLE32(ostart, lhc);
+ ostart[4] = (BYTE)(cLitSize >> 10);
+ break;
+ }
+ }
+ return lhSize + cLitSize;
}
-static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 16, 17, 17, 18, 18, 19, 19,
- 20, 20, 20, 20, 21, 21, 21, 21,
- 22, 22, 22, 22, 22, 22, 22, 22,
- 23, 23, 23, 23, 23, 23, 23, 23,
- 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24 };
+static const BYTE LL_Code[64] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18, 18,
+ 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23,
+ 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24};
-static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
- 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
- 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
+static const BYTE ML_Code[128] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38,
+ 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42};
-
-void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
+void ZSTD_seqToCodes(const seqStore_t *seqStorePtr)
{
BYTE const LL_deltaCode = 19;
BYTE const ML_deltaCode = 36;
- const seqDef* const sequences = seqStorePtr->sequencesStart;
- BYTE* const llCodeTable = seqStorePtr->llCode;
- BYTE* const ofCodeTable = seqStorePtr->ofCode;
- BYTE* const mlCodeTable = seqStorePtr->mlCode;
+ const seqDef *const sequences = seqStorePtr->sequencesStart;
+ BYTE *const llCodeTable = seqStorePtr->llCode;
+ BYTE *const ofCodeTable = seqStorePtr->ofCode;
+ BYTE *const mlCodeTable = seqStorePtr->mlCode;
U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
U32 u;
- for (u=0; u 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
+ llCodeTable[u] = (llv > 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
- mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
+ mlCodeTable[u] = (mlv > 127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
}
- if (seqStorePtr->longLengthID==1)
+ if (seqStorePtr->longLengthID == 1)
llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
- if (seqStorePtr->longLengthID==2)
+ if (seqStorePtr->longLengthID == 2)
mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
}
-MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
- void* dst, size_t dstCapacity,
- size_t srcSize)
+ZSTD_STATIC size_t ZSTD_compressSequences(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, size_t srcSize)
{
const int longOffsets = zc->params.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
- const seqStore_t* seqStorePtr = &(zc->seqStore);
- U32 count[MaxSeq+1];
- S16 norm[MaxSeq+1];
- FSE_CTable* CTable_LitLength = zc->litlengthCTable;
- FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
- FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
- U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
- const seqDef* const sequences = seqStorePtr->sequencesStart;
- const BYTE* const ofCodeTable = seqStorePtr->ofCode;
- const BYTE* const llCodeTable = seqStorePtr->llCode;
- const BYTE* const mlCodeTable = seqStorePtr->mlCode;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstCapacity;
- BYTE* op = ostart;
+ const seqStore_t *seqStorePtr = &(zc->seqStore);
+ FSE_CTable *CTable_LitLength = zc->litlengthCTable;
+ FSE_CTable *CTable_OffsetBits = zc->offcodeCTable;
+ FSE_CTable *CTable_MatchLength = zc->matchlengthCTable;
+ U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
+ const seqDef *const sequences = seqStorePtr->sequencesStart;
+ const BYTE *const ofCodeTable = seqStorePtr->ofCode;
+ const BYTE *const llCodeTable = seqStorePtr->llCode;
+ const BYTE *const mlCodeTable = seqStorePtr->mlCode;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *const oend = ostart + dstCapacity;
+ BYTE *op = ostart;
size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
- BYTE* seqHead;
- BYTE scratchBuffer[1<tmpCounters);
+ {
+ size_t spaceUsed32 = 0;
+ count = (U32 *)zc->tmpCounters + spaceUsed32;
+ spaceUsed32 += MaxSeq + 1;
+ norm = (S16 *)((U32 *)zc->tmpCounters + spaceUsed32);
+ spaceUsed32 += ALIGN(sizeof(S16) * (MaxSeq + 1), sizeof(U32)) >> 2;
+
+ workspace = (U32 *)zc->tmpCounters + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
+ }
/* Compress literals */
- { const BYTE* const literals = seqStorePtr->litStart;
+ {
+ const BYTE *const literals = seqStorePtr->litStart;
size_t const litSize = seqStorePtr->lit - literals;
size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
- if (ZSTD_isError(cSize)) return cSize;
+ if (ZSTD_isError(cSize))
+ return cSize;
op += cSize;
}
/* Sequences Header */
- if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
- if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
- else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
- else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
- if (nbSeq==0) goto _check_compressibility;
+ if ((oend - op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */)
+ return ERROR(dstSize_tooSmall);
+ if (nbSeq < 0x7F)
+ *op++ = (BYTE)nbSeq;
+ else if (nbSeq < LONGNBSEQ)
+ op[0] = (BYTE)((nbSeq >> 8) + 0x80), op[1] = (BYTE)nbSeq, op += 2;
+ else
+ op[0] = 0xFF, ZSTD_writeLE16(op + 1, (U16)(nbSeq - LONGNBSEQ)), op += 3;
+ if (nbSeq == 0)
+ goto _check_compressibility;
/* seqHead : flags for FSE encoding type */
seqHead = op++;
-#define MIN_SEQ_FOR_DYNAMIC_FSE 64
-#define MAX_SEQ_FOR_STATIC_FSE 1000
+#define MIN_SEQ_FOR_DYNAMIC_FSE 64
+#define MAX_SEQ_FOR_STATIC_FSE 1000
/* convert length/distances into codes */
ZSTD_seqToCodes(seqStorePtr);
/* CTable for Literal Lengths */
- { U32 max = MaxLL;
- size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);
+ {
+ U32 max = MaxLL;
+ size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace);
if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
*op++ = llCodeTable[0];
FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
LLtype = set_rle;
} else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
LLtype = set_repeat;
- } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
- FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
+ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog - 1)))) {
+ FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, workspace, workspaceSize);
LLtype = set_basic;
} else {
size_t nbSeq_1 = nbSeq;
const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
- if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
+ if (count[llCodeTable[nbSeq - 1]] > 1) {
+ count[llCodeTable[nbSeq - 1]]--;
+ nbSeq_1--;
+ }
FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
- { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
- if (FSE_isError(NCountSize)) return NCountSize;
- op += NCountSize; }
- FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
+ {
+ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
+ if (FSE_isError(NCountSize))
+ return NCountSize;
+ op += NCountSize;
+ }
+ FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, workspace, workspaceSize);
LLtype = set_compressed;
- } }
+ }
+ }
/* CTable for Offsets */
- { U32 max = MaxOff;
- size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);
+ {
+ U32 max = MaxOff;
+ size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace);
if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
*op++ = ofCodeTable[0];
FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Offtype = set_rle;
} else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Offtype = set_repeat;
- } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
- FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
+ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog - 1)))) {
+ FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, workspace, workspaceSize);
Offtype = set_basic;
} else {
size_t nbSeq_1 = nbSeq;
const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
- if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
+ if (count[ofCodeTable[nbSeq - 1]] > 1) {
+ count[ofCodeTable[nbSeq - 1]]--;
+ nbSeq_1--;
+ }
FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
- { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
- if (FSE_isError(NCountSize)) return NCountSize;
- op += NCountSize; }
- FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
+ {
+ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
+ if (FSE_isError(NCountSize))
+ return NCountSize;
+ op += NCountSize;
+ }
+ FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, workspace, workspaceSize);
Offtype = set_compressed;
- } }
+ }
+ }
/* CTable for MatchLengths */
- { U32 max = MaxML;
- size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);
+ {
+ U32 max = MaxML;
+ size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace);
if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
*op++ = *mlCodeTable;
FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
MLtype = set_rle;
} else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
MLtype = set_repeat;
- } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
- FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
+ } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog - 1)))) {
+ FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, workspace, workspaceSize);
MLtype = set_basic;
} else {
size_t nbSeq_1 = nbSeq;
const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
- if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
+ if (count[mlCodeTable[nbSeq - 1]] > 1) {
+ count[mlCodeTable[nbSeq - 1]]--;
+ nbSeq_1--;
+ }
FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
- { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
- if (FSE_isError(NCountSize)) return NCountSize;
- op += NCountSize; }
- FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
+ {
+ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
+ if (FSE_isError(NCountSize))
+ return NCountSize;
+ op += NCountSize;
+ }
+ FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, workspace, workspaceSize);
MLtype = set_compressed;
- } }
+ }
+ }
- *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
+ *seqHead = (BYTE)((LLtype << 6) + (Offtype << 4) + (MLtype << 2));
zc->flagStaticTables = 0;
/* Encoding Sequences */
- { BIT_CStream_t blockStream;
- FSE_CState_t stateMatchLength;
- FSE_CState_t stateOffsetBits;
- FSE_CState_t stateLitLength;
+ {
+ BIT_CStream_t blockStream;
+ FSE_CState_t stateMatchLength;
+ FSE_CState_t stateOffsetBits;
+ FSE_CState_t stateLitLength;
- CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
+ CHECK_E(BIT_initCStream(&blockStream, op, oend - op), dstSize_tooSmall); /* not enough space remaining */
/* first symbols */
- FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
- FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
- FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
- BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
- if (MEM_32bits()) BIT_flushBits(&blockStream);
- BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
- if (MEM_32bits()) BIT_flushBits(&blockStream);
+ FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq - 1]);
+ FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq - 1]);
+ FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq - 1]);
+ BIT_addBits(&blockStream, sequences[nbSeq - 1].litLength, LL_bits[llCodeTable[nbSeq - 1]]);
+ if (ZSTD_32bits())
+ BIT_flushBits(&blockStream);
+ BIT_addBits(&blockStream, sequences[nbSeq - 1].matchLength, ML_bits[mlCodeTable[nbSeq - 1]]);
+ if (ZSTD_32bits())
+ BIT_flushBits(&blockStream);
if (longOffsets) {
- U32 const ofBits = ofCodeTable[nbSeq-1];
- int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
+ U32 const ofBits = ofCodeTable[nbSeq - 1];
+ int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN - 1);
if (extraBits) {
- BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
+ BIT_addBits(&blockStream, sequences[nbSeq - 1].offset, extraBits);
BIT_flushBits(&blockStream);
}
- BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
- ofBits - extraBits);
+ BIT_addBits(&blockStream, sequences[nbSeq - 1].offset >> extraBits, ofBits - extraBits);
} else {
- BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
+ BIT_addBits(&blockStream, sequences[nbSeq - 1].offset, ofCodeTable[nbSeq - 1]);
}
BIT_flushBits(&blockStream);
- { size_t n;
- for (n=nbSeq-2 ; n= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
- BIT_flushBits(&blockStream); /* (7)*/
+ U32 const llBits = LL_bits[llCode];
+ U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
+ U32 const mlBits = ML_bits[mlCode];
+ /* (7)*/ /* (7)*/
+ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
+ FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
+ if (ZSTD_32bits())
+ BIT_flushBits(&blockStream); /* (7)*/
+ FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
+ if (ZSTD_32bits() || (ofBits + mlBits + llBits >= 64 - 7 - (LLFSELog + MLFSELog + OffFSELog)))
+ BIT_flushBits(&blockStream); /* (7)*/
BIT_addBits(&blockStream, sequences[n].litLength, llBits);
- if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
+ if (ZSTD_32bits() && ((llBits + mlBits) > 24))
+ BIT_flushBits(&blockStream);
BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
- if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
+ if (ZSTD_32bits())
+ BIT_flushBits(&blockStream); /* (7)*/
if (longOffsets) {
- int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
+ int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN - 1);
if (extraBits) {
BIT_addBits(&blockStream, sequences[n].offset, extraBits);
- BIT_flushBits(&blockStream); /* (7)*/
+ BIT_flushBits(&blockStream); /* (7)*/
}
- BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
- ofBits - extraBits); /* 31 */
+ BIT_addBits(&blockStream, sequences[n].offset >> extraBits, ofBits - extraBits); /* 31 */
} else {
- BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
+ BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
}
- BIT_flushBits(&blockStream); /* (7)*/
- } }
+ BIT_flushBits(&blockStream); /* (7)*/
+ }
+ }
FSE_flushCState(&blockStream, &stateMatchLength);
FSE_flushCState(&blockStream, &stateOffsetBits);
FSE_flushCState(&blockStream, &stateLitLength);
- { size_t const streamSize = BIT_closeCStream(&blockStream);
- if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
+ {
+ size_t const streamSize = BIT_closeCStream(&blockStream);
+ if (streamSize == 0)
+ return ERROR(dstSize_tooSmall); /* not enough space */
op += streamSize;
- } }
+ }
+ }
- /* check compressibility */
+/* check compressibility */
_check_compressibility:
- { size_t const minGain = ZSTD_minGain(srcSize);
+ {
+ size_t const minGain = ZSTD_minGain(srcSize);
size_t const maxCSize = srcSize - minGain;
- if ((size_t)(op-ostart) >= maxCSize) {
+ if ((size_t)(op - ostart) >= maxCSize) {
zc->flagStaticHufTable = HUF_repeat_none;
return 0;
- } }
+ }
+ }
/* confirm repcodes */
- { int i; for (i=0; irep[i] = zc->repToConfirm[i]; }
+ {
+ int i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ zc->rep[i] = zc->repToConfirm[i];
+ }
return op - ostart;
}
-#if 0 /* for debug */
-# define STORESEQ_DEBUG
-U32 g_startDebug = 0;
-const BYTE* g_start = NULL;
-#endif
-
/*! ZSTD_storeSeq() :
Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
`offsetCode` : distance to match, or 0 == repCode.
`matchCode` : matchLength - MINMATCH
*/
-MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
+ZSTD_STATIC void ZSTD_storeSeq(seqStore_t *seqStorePtr, size_t litLength, const void *literals, U32 offsetCode, size_t matchCode)
{
-#ifdef STORESEQ_DEBUG
- if (g_startDebug) {
- const U32 pos = (U32)((const BYTE*)literals - g_start);
- if (g_start==NULL) g_start = (const BYTE*)literals;
- if ((pos > 1895000) && (pos < 1895300))
- fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
- pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
- }
-#endif
/* copy Literals */
ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
seqStorePtr->lit += litLength;
/* literal Length */
- if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
+ if (litLength > 0xFFFF) {
+ seqStorePtr->longLengthID = 1;
+ seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ }
seqStorePtr->sequences[0].litLength = (U16)litLength;
/* match offset */
seqStorePtr->sequences[0].offset = offsetCode + 1;
/* match Length */
- if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
+ if (matchCode > 0xFFFF) {
+ seqStorePtr->longLengthID = 2;
+ seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
+ }
seqStorePtr->sequences[0].matchLength = (U16)matchCode;
seqStorePtr->sequences++;
}
-
/*-*************************************
* Match length counter
***************************************/
-static unsigned ZSTD_NbCommonBytes (register size_t val)
+static unsigned ZSTD_NbCommonBytes(register size_t val)
{
- if (MEM_isLittleEndian()) {
- if (MEM_64bits()) {
-# if defined(_MSC_VER) && defined(_WIN64)
- unsigned long r = 0;
- _BitScanForward64( &r, (U64)val );
- return (unsigned)(r>>3);
-# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ if (ZSTD_isLittleEndian()) {
+ if (ZSTD_64bits()) {
return (__builtin_ctzll((U64)val) >> 3);
-# else
- static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
- return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
-# endif
} else { /* 32 bits */
-# if defined(_MSC_VER)
- unsigned long r=0;
- _BitScanForward( &r, (U32)val );
- return (unsigned)(r>>3);
-# elif defined(__GNUC__) && (__GNUC__ >= 3)
return (__builtin_ctz((U32)val) >> 3);
-# else
- static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
- return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
-# endif
}
- } else { /* Big Endian CPU */
- if (MEM_64bits()) {
-# if defined(_MSC_VER) && defined(_WIN64)
- unsigned long r = 0;
- _BitScanReverse64( &r, val );
- return (unsigned)(r>>3);
-# elif defined(__GNUC__) && (__GNUC__ >= 3)
+ } else { /* Big Endian CPU */
+ if (ZSTD_64bits()) {
return (__builtin_clzll(val) >> 3);
-# else
- unsigned r;
- const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
- if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
- if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
- r += (!val);
- return r;
-# endif
} else { /* 32 bits */
-# if defined(_MSC_VER)
- unsigned long r = 0;
- _BitScanReverse( &r, (unsigned long)val );
- return (unsigned)(r>>3);
-# elif defined(__GNUC__) && (__GNUC__ >= 3)
return (__builtin_clz((U32)val) >> 3);
-# else
- unsigned r;
- if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
- r += (!val);
- return r;
-# endif
- } }
+ }
+ }
}
-
-static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
+static size_t ZSTD_count(const BYTE *pIn, const BYTE *pMatch, const BYTE *const pInLimit)
{
- const BYTE* const pStart = pIn;
- const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
+ const BYTE *const pStart = pIn;
+ const BYTE *const pInLoopLimit = pInLimit - (sizeof(size_t) - 1);
while (pIn < pInLoopLimit) {
- size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
- if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
+ size_t const diff = ZSTD_readST(pMatch) ^ ZSTD_readST(pIn);
+ if (!diff) {
+ pIn += sizeof(size_t);
+ pMatch += sizeof(size_t);
+ continue;
+ }
pIn += ZSTD_NbCommonBytes(diff);
return (size_t)(pIn - pStart);
}
- if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
- if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
- if ((pIn> (32-h) ; }
-MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
+static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32 - 24)) * prime3bytes) >> (32 - h); }
+ZSTD_STATIC size_t ZSTD_hash3Ptr(const void *ptr, U32 h) { return ZSTD_hash3(ZSTD_readLE32(ptr), h); } /* only in zstd_opt.h */
static const U32 prime4bytes = 2654435761U;
-static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
-static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
+static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32 - h); }
+static size_t ZSTD_hash4Ptr(const void *ptr, U32 h) { return ZSTD_hash4(ZSTD_read32(ptr), h); }
static const U64 prime5bytes = 889523592379ULL;
-static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
-static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
+static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64 - 40)) * prime5bytes) >> (64 - h)); }
+static size_t ZSTD_hash5Ptr(const void *p, U32 h) { return ZSTD_hash5(ZSTD_readLE64(p), h); }
static const U64 prime6bytes = 227718039650203ULL;
-static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
-static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
+static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64 - 48)) * prime6bytes) >> (64 - h)); }
+static size_t ZSTD_hash6Ptr(const void *p, U32 h) { return ZSTD_hash6(ZSTD_readLE64(p), h); }
static const U64 prime7bytes = 58295818150454627ULL;
-static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
-static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
+static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64 - 56)) * prime7bytes) >> (64 - h)); }
+static size_t ZSTD_hash7Ptr(const void *p, U32 h) { return ZSTD_hash7(ZSTD_readLE64(p), h); }
static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
-static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
-static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
+static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u)*prime8bytes) >> (64 - h)); }
+static size_t ZSTD_hash8Ptr(const void *p, U32 h) { return ZSTD_hash8(ZSTD_readLE64(p), h); }
-static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
+static size_t ZSTD_hashPtr(const void *p, U32 hBits, U32 mls)
{
- switch(mls)
- {
- //case 3: return ZSTD_hash3Ptr(p, hBits);
+ switch (mls) {
+ // case 3: return ZSTD_hash3Ptr(p, hBits);
default:
case 4: return ZSTD_hash4Ptr(p, hBits);
case 5: return ZSTD_hash5Ptr(p, hBits);
@@ -952,78 +981,81 @@ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
}
}
-
/*-*************************************
* Fast Scan
***************************************/
-static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
+static void ZSTD_fillHashTable(ZSTD_CCtx *zc, const void *end, const U32 mls)
{
- U32* const hashTable = zc->hashTable;
- U32 const hBits = zc->params.cParams.hashLog;
- const BYTE* const base = zc->base;
- const BYTE* ip = base + zc->nextToUpdate;
- const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
+ U32 *const hashTable = zc->hashTable;
+ U32 const hBits = zc->params.cParams.hashLog;
+ const BYTE *const base = zc->base;
+ const BYTE *ip = base + zc->nextToUpdate;
+ const BYTE *const iend = ((const BYTE *)end) - HASH_READ_SIZE;
const size_t fastHashFillStep = 3;
- while(ip <= iend) {
+ while (ip <= iend) {
hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
ip += fastHashFillStep;
}
}
-
FORCE_INLINE
-void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
- const void* src, size_t srcSize,
- const U32 mls)
+void ZSTD_compressBlock_fast_generic(ZSTD_CCtx *cctx, const void *src, size_t srcSize, const U32 mls)
{
- U32* const hashTable = cctx->hashTable;
- U32 const hBits = cctx->params.cParams.hashLog;
- seqStore_t* seqStorePtr = &(cctx->seqStore);
- const BYTE* const base = cctx->base;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const U32 lowestIndex = cctx->dictLimit;
- const BYTE* const lowest = base + lowestIndex;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - HASH_READ_SIZE;
- U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
+ U32 *const hashTable = cctx->hashTable;
+ U32 const hBits = cctx->params.cParams.hashLog;
+ seqStore_t *seqStorePtr = &(cctx->seqStore);
+ const BYTE *const base = cctx->base;
+ const BYTE *const istart = (const BYTE *)src;
+ const BYTE *ip = istart;
+ const BYTE *anchor = istart;
+ const U32 lowestIndex = cctx->dictLimit;
+ const BYTE *const lowest = base + lowestIndex;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *const ilimit = iend - HASH_READ_SIZE;
+ U32 offset_1 = cctx->rep[0], offset_2 = cctx->rep[1];
U32 offsetSaved = 0;
/* init */
- ip += (ip==lowest);
- { U32 const maxRep = (U32)(ip-lowest);
- if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
- if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
+ ip += (ip == lowest);
+ {
+ U32 const maxRep = (U32)(ip - lowest);
+ if (offset_2 > maxRep)
+ offsetSaved = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep)
+ offsetSaved = offset_1, offset_1 = 0;
}
/* Main Search Loop */
- while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
+ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
size_t mLength;
size_t const h = ZSTD_hashPtr(ip, hBits, mls);
- U32 const current = (U32)(ip-base);
+ U32 const curr = (U32)(ip - base);
U32 const matchIndex = hashTable[h];
- const BYTE* match = base + matchIndex;
- hashTable[h] = current; /* update hash table */
+ const BYTE *match = base + matchIndex;
+ hashTable[h] = curr; /* update hash table */
- if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
- mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+ if ((offset_1 > 0) & (ZSTD_read32(ip + 1 - offset_1) == ZSTD_read32(ip + 1))) {
+ mLength = ZSTD_count(ip + 1 + 4, ip + 1 + 4 - offset_1, iend) + 4;
ip++;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, 0, mLength - MINMATCH);
} else {
U32 offset;
- if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
- ip += ((ip-anchor) >> g_searchStrength) + 1;
+ if ((matchIndex <= lowestIndex) || (ZSTD_read32(match) != ZSTD_read32(ip))) {
+ ip += ((ip - anchor) >> g_searchStrength) + 1;
continue;
}
- mLength = ZSTD_count(ip+4, match+4, iend) + 4;
- offset = (U32)(ip-match);
- while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ mLength = ZSTD_count(ip + 4, match + 4, iend) + 4;
+ offset = (U32)(ip - match);
+ while (((ip > anchor) & (match > lowest)) && (ip[-1] == match[-1])) {
+ ip--;
+ match--;
+ mLength++;
+ } /* catch up */
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
}
/* match found */
@@ -1032,109 +1064,109 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
if (ip <= ilimit) {
/* Fill Table */
- hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
- hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
+ hashTable[ZSTD_hashPtr(base + curr + 2, hBits, mls)] = curr + 2; /* here because curr+2 could be > iend-8 */
+ hashTable[ZSTD_hashPtr(ip - 2, hBits, mls)] = (U32)(ip - 2 - base);
/* check immediate repcode */
- while ( (ip <= ilimit)
- && ( (offset_2>0)
- & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
+ while ((ip <= ilimit) && ((offset_2 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_2)))) {
/* store sequence */
- size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
- { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
- hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
+ size_t const rLength = ZSTD_count(ip + 4, ip + 4 - offset_2, iend) + 4;
+ {
+ U32 const tmpOff = offset_2;
+ offset_2 = offset_1;
+ offset_1 = tmpOff;
+ } /* swap offset_2 <=> offset_1 */
+ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength - MINMATCH);
ip += rLength;
anchor = ip;
- continue; /* faster when present ... (?) */
- } } }
+ continue; /* faster when present ... (?) */
+ }
+ }
+ }
/* save reps for next block */
cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
/* Last Literals */
- { size_t const lastLLSize = iend - anchor;
+ {
+ size_t const lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
}
-
-static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
+static void ZSTD_compressBlock_fast(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
const U32 mls = ctx->params.cParams.searchLength;
- switch(mls)
- {
+ switch (mls) {
default: /* includes case 3 */
- case 4 :
- ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
- case 5 :
- ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
- case 6 :
- ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
- case 7 :
- ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
+ case 4: ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
+ case 5: ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
+ case 6: ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
+ case 7: ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
}
}
-
-static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize,
- const U32 mls)
+static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const U32 mls)
{
- U32* hashTable = ctx->hashTable;
+ U32 *hashTable = ctx->hashTable;
const U32 hBits = ctx->params.cParams.hashLog;
- seqStore_t* seqStorePtr = &(ctx->seqStore);
- const BYTE* const base = ctx->base;
- const BYTE* const dictBase = ctx->dictBase;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const U32 lowestIndex = ctx->lowLimit;
- const BYTE* const dictStart = dictBase + lowestIndex;
- const U32 dictLimit = ctx->dictLimit;
- const BYTE* const lowPrefixPtr = base + dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
+ seqStore_t *seqStorePtr = &(ctx->seqStore);
+ const BYTE *const base = ctx->base;
+ const BYTE *const dictBase = ctx->dictBase;
+ const BYTE *const istart = (const BYTE *)src;
+ const BYTE *ip = istart;
+ const BYTE *anchor = istart;
+ const U32 lowestIndex = ctx->lowLimit;
+ const BYTE *const dictStart = dictBase + lowestIndex;
+ const U32 dictLimit = ctx->dictLimit;
+ const BYTE *const lowPrefixPtr = base + dictLimit;
+ const BYTE *const dictEnd = dictBase + dictLimit;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *const ilimit = iend - 8;
+ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
/* Search Loop */
- while (ip < ilimit) { /* < instead of <=, because (ip+1) */
+ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
const size_t h = ZSTD_hashPtr(ip, hBits, mls);
const U32 matchIndex = hashTable[h];
- const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
- const BYTE* match = matchBase + matchIndex;
- const U32 current = (U32)(ip-base);
- const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
- const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* repMatch = repBase + repIndex;
+ const BYTE *matchBase = matchIndex < dictLimit ? dictBase : base;
+ const BYTE *match = matchBase + matchIndex;
+ const U32 curr = (U32)(ip - base);
+ const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */
+ const BYTE *repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE *repMatch = repBase + repIndex;
size_t mLength;
- hashTable[h] = current; /* update hash table */
+ hashTable[h] = curr; /* update hash table */
- if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
- const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
- mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
+ if ((((U32)((dictLimit - 1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex)) &&
+ (ZSTD_read32(repMatch) == ZSTD_read32(ip + 1))) {
+ const BYTE *repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip + 1 + EQUAL_READ32, repMatch + EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
ip++;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, 0, mLength - MINMATCH);
} else {
- if ( (matchIndex < lowestIndex) ||
- (MEM_read32(match) != MEM_read32(ip)) ) {
- ip += ((ip-anchor) >> g_searchStrength) + 1;
+ if ((matchIndex < lowestIndex) || (ZSTD_read32(match) != ZSTD_read32(ip))) {
+ ip += ((ip - anchor) >> g_searchStrength) + 1;
continue;
}
- { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
- const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
+ {
+ const BYTE *matchEnd = matchIndex < dictLimit ? dictEnd : iend;
+ const BYTE *lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
U32 offset;
- mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
- while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
- offset = current - matchIndex;
+ mLength = ZSTD_count_2segments(ip + EQUAL_READ32, match + EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
+ while (((ip > anchor) & (match > lowMatchPtr)) && (ip[-1] == match[-1])) {
+ ip--;
+ match--;
+ mLength++;
+ } /* catch up */
+ offset = curr - matchIndex;
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
- } }
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
+ }
+ }
/* found a match : store it */
ip += mLength;
@@ -1142,153 +1174,164 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
if (ip <= ilimit) {
/* Fill Table */
- hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
- hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
+ hashTable[ZSTD_hashPtr(base + curr + 2, hBits, mls)] = curr + 2;
+ hashTable[ZSTD_hashPtr(ip - 2, hBits, mls)] = (U32)(ip - 2 - base);
/* check immediate repcode */
while (ip <= ilimit) {
- U32 const current2 = (U32)(ip-base);
- U32 const repIndex2 = current2 - offset_2;
- const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
- if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
- && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
- const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
- size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
- U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
- hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
+ U32 const curr2 = (U32)(ip - base);
+ U32 const repIndex2 = curr2 - offset_2;
+ const BYTE *repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
+ if ((((U32)((dictLimit - 1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
+ && (ZSTD_read32(repMatch2) == ZSTD_read32(ip))) {
+ const BYTE *const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
+ size_t repLength2 =
+ ZSTD_count_2segments(ip + EQUAL_READ32, repMatch2 + EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
+ U32 tmpOffset = offset_2;
+ offset_2 = offset_1;
+ offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2 - MINMATCH);
+ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = curr2;
ip += repLength2;
anchor = ip;
continue;
}
break;
- } } }
+ }
+ }
+ }
/* save reps for next block */
- ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
+ ctx->repToConfirm[0] = offset_1;
+ ctx->repToConfirm[1] = offset_2;
/* Last Literals */
- { size_t const lastLLSize = iend - anchor;
+ {
+ size_t const lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
}
-
-static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
+static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
U32 const mls = ctx->params.cParams.searchLength;
- switch(mls)
- {
+ switch (mls) {
default: /* includes case 3 */
- case 4 :
- ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
- case 5 :
- ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
- case 6 :
- ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
- case 7 :
- ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
+ case 4: ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
+ case 5: ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
+ case 6: ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
+ case 7: ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
}
}
-
/*-*************************************
* Double Fast
***************************************/
-static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
+static void ZSTD_fillDoubleHashTable(ZSTD_CCtx *cctx, const void *end, const U32 mls)
{
- U32* const hashLarge = cctx->hashTable;
- U32 const hBitsL = cctx->params.cParams.hashLog;
- U32* const hashSmall = cctx->chainTable;
- U32 const hBitsS = cctx->params.cParams.chainLog;
- const BYTE* const base = cctx->base;
- const BYTE* ip = base + cctx->nextToUpdate;
- const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
+ U32 *const hashLarge = cctx->hashTable;
+ U32 const hBitsL = cctx->params.cParams.hashLog;
+ U32 *const hashSmall = cctx->chainTable;
+ U32 const hBitsS = cctx->params.cParams.chainLog;
+ const BYTE *const base = cctx->base;
+ const BYTE *ip = base + cctx->nextToUpdate;
+ const BYTE *const iend = ((const BYTE *)end) - HASH_READ_SIZE;
const size_t fastHashFillStep = 3;
- while(ip <= iend) {
+ while (ip <= iend) {
hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
ip += fastHashFillStep;
}
}
-
FORCE_INLINE
-void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
- const void* src, size_t srcSize,
- const U32 mls)
+void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx *cctx, const void *src, size_t srcSize, const U32 mls)
{
- U32* const hashLong = cctx->hashTable;
+ U32 *const hashLong = cctx->hashTable;
const U32 hBitsL = cctx->params.cParams.hashLog;
- U32* const hashSmall = cctx->chainTable;
+ U32 *const hashSmall = cctx->chainTable;
const U32 hBitsS = cctx->params.cParams.chainLog;
- seqStore_t* seqStorePtr = &(cctx->seqStore);
- const BYTE* const base = cctx->base;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
+ seqStore_t *seqStorePtr = &(cctx->seqStore);
+ const BYTE *const base = cctx->base;
+ const BYTE *const istart = (const BYTE *)src;
+ const BYTE *ip = istart;
+ const BYTE *anchor = istart;
const U32 lowestIndex = cctx->dictLimit;
- const BYTE* const lowest = base + lowestIndex;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - HASH_READ_SIZE;
- U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
+ const BYTE *const lowest = base + lowestIndex;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *const ilimit = iend - HASH_READ_SIZE;
+ U32 offset_1 = cctx->rep[0], offset_2 = cctx->rep[1];
U32 offsetSaved = 0;
/* init */
- ip += (ip==lowest);
- { U32 const maxRep = (U32)(ip-lowest);
- if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
- if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
+ ip += (ip == lowest);
+ {
+ U32 const maxRep = (U32)(ip - lowest);
+ if (offset_2 > maxRep)
+ offsetSaved = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep)
+ offsetSaved = offset_1, offset_1 = 0;
}
/* Main Search Loop */
- while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
+ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
size_t mLength;
size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
- U32 const current = (U32)(ip-base);
+ U32 const curr = (U32)(ip - base);
U32 const matchIndexL = hashLong[h2];
U32 const matchIndexS = hashSmall[h];
- const BYTE* matchLong = base + matchIndexL;
- const BYTE* match = base + matchIndexS;
- hashLong[h2] = hashSmall[h] = current; /* update hash tables */
+ const BYTE *matchLong = base + matchIndexL;
+ const BYTE *match = base + matchIndexS;
+ hashLong[h2] = hashSmall[h] = curr; /* update hash tables */
- if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
- mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
+ if ((offset_1 > 0) & (ZSTD_read32(ip + 1 - offset_1) == ZSTD_read32(ip + 1))) { /* note : by construction, offset_1 <= curr */
+ mLength = ZSTD_count(ip + 1 + 4, ip + 1 + 4 - offset_1, iend) + 4;
ip++;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, 0, mLength - MINMATCH);
} else {
U32 offset;
- if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
- mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
- offset = (U32)(ip-matchLong);
- while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
- } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
- size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
+ if ((matchIndexL > lowestIndex) && (ZSTD_read64(matchLong) == ZSTD_read64(ip))) {
+ mLength = ZSTD_count(ip + 8, matchLong + 8, iend) + 8;
+ offset = (U32)(ip - matchLong);
+ while (((ip > anchor) & (matchLong > lowest)) && (ip[-1] == matchLong[-1])) {
+ ip--;
+ matchLong--;
+ mLength++;
+ } /* catch up */
+ } else if ((matchIndexS > lowestIndex) && (ZSTD_read32(match) == ZSTD_read32(ip))) {
+ size_t const h3 = ZSTD_hashPtr(ip + 1, hBitsL, 8);
U32 const matchIndex3 = hashLong[h3];
- const BYTE* match3 = base + matchIndex3;
- hashLong[h3] = current + 1;
- if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
- mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
+ const BYTE *match3 = base + matchIndex3;
+ hashLong[h3] = curr + 1;
+ if ((matchIndex3 > lowestIndex) && (ZSTD_read64(match3) == ZSTD_read64(ip + 1))) {
+ mLength = ZSTD_count(ip + 9, match3 + 8, iend) + 8;
ip++;
- offset = (U32)(ip-match3);
- while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
+ offset = (U32)(ip - match3);
+ while (((ip > anchor) & (match3 > lowest)) && (ip[-1] == match3[-1])) {
+ ip--;
+ match3--;
+ mLength++;
+ } /* catch up */
} else {
- mLength = ZSTD_count(ip+4, match+4, iend) + 4;
- offset = (U32)(ip-match);
- while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ mLength = ZSTD_count(ip + 4, match + 4, iend) + 4;
+ offset = (U32)(ip - match);
+ while (((ip > anchor) & (match > lowest)) && (ip[-1] == match[-1])) {
+ ip--;
+ match--;
+ mLength++;
+ } /* catch up */
}
} else {
- ip += ((ip-anchor) >> g_searchStrength) + 1;
+ ip += ((ip - anchor) >> g_searchStrength) + 1;
continue;
}
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
}
/* match found */
@@ -1297,145 +1340,153 @@ void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
if (ip <= ilimit) {
/* Fill Table */
- hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
- hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
- hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
- hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
+ hashLong[ZSTD_hashPtr(base + curr + 2, hBitsL, 8)] = hashSmall[ZSTD_hashPtr(base + curr + 2, hBitsS, mls)] =
+ curr + 2; /* here because curr+2 could be > iend-8 */
+ hashLong[ZSTD_hashPtr(ip - 2, hBitsL, 8)] = hashSmall[ZSTD_hashPtr(ip - 2, hBitsS, mls)] = (U32)(ip - 2 - base);
/* check immediate repcode */
- while ( (ip <= ilimit)
- && ( (offset_2>0)
- & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
+ while ((ip <= ilimit) && ((offset_2 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_2)))) {
/* store sequence */
- size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
- { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
- hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
- hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
+ size_t const rLength = ZSTD_count(ip + 4, ip + 4 - offset_2, iend) + 4;
+ {
+ U32 const tmpOff = offset_2;
+ offset_2 = offset_1;
+ offset_1 = tmpOff;
+ } /* swap offset_2 <=> offset_1 */
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength - MINMATCH);
ip += rLength;
anchor = ip;
- continue; /* faster when present ... (?) */
- } } }
+ continue; /* faster when present ... (?) */
+ }
+ }
+ }
/* save reps for next block */
cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
/* Last Literals */
- { size_t const lastLLSize = iend - anchor;
+ {
+ size_t const lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
}
-
-static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
const U32 mls = ctx->params.cParams.searchLength;
- switch(mls)
- {
+ switch (mls) {
default: /* includes case 3 */
- case 4 :
- ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
- case 5 :
- ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
- case 6 :
- ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
- case 7 :
- ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
+ case 4: ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
+ case 5: ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
+ case 6: ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
+ case 7: ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
}
}
-
-static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize,
- const U32 mls)
+static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const U32 mls)
{
- U32* const hashLong = ctx->hashTable;
- U32 const hBitsL = ctx->params.cParams.hashLog;
- U32* const hashSmall = ctx->chainTable;
- U32 const hBitsS = ctx->params.cParams.chainLog;
- seqStore_t* seqStorePtr = &(ctx->seqStore);
- const BYTE* const base = ctx->base;
- const BYTE* const dictBase = ctx->dictBase;
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const U32 lowestIndex = ctx->lowLimit;
- const BYTE* const dictStart = dictBase + lowestIndex;
- const U32 dictLimit = ctx->dictLimit;
- const BYTE* const lowPrefixPtr = base + dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
+ U32 *const hashLong = ctx->hashTable;
+ U32 const hBitsL = ctx->params.cParams.hashLog;
+ U32 *const hashSmall = ctx->chainTable;
+ U32 const hBitsS = ctx->params.cParams.chainLog;
+ seqStore_t *seqStorePtr = &(ctx->seqStore);
+ const BYTE *const base = ctx->base;
+ const BYTE *const dictBase = ctx->dictBase;
+ const BYTE *const istart = (const BYTE *)src;
+ const BYTE *ip = istart;
+ const BYTE *anchor = istart;
+ const U32 lowestIndex = ctx->lowLimit;
+ const BYTE *const dictStart = dictBase + lowestIndex;
+ const U32 dictLimit = ctx->dictLimit;
+ const BYTE *const lowPrefixPtr = base + dictLimit;
+ const BYTE *const dictEnd = dictBase + dictLimit;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *const ilimit = iend - 8;
+ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
/* Search Loop */
- while (ip < ilimit) { /* < instead of <=, because (ip+1) */
+ while (ip < ilimit) { /* < instead of <=, because (ip+1) */
const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
const U32 matchIndex = hashSmall[hSmall];
- const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
- const BYTE* match = matchBase + matchIndex;
+ const BYTE *matchBase = matchIndex < dictLimit ? dictBase : base;
+ const BYTE *match = matchBase + matchIndex;
const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
const U32 matchLongIndex = hashLong[hLong];
- const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
- const BYTE* matchLong = matchLongBase + matchLongIndex;
+ const BYTE *matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
+ const BYTE *matchLong = matchLongBase + matchLongIndex;
- const U32 current = (U32)(ip-base);
- const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
- const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* repMatch = repBase + repIndex;
+ const U32 curr = (U32)(ip - base);
+ const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */
+ const BYTE *repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE *repMatch = repBase + repIndex;
size_t mLength;
- hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
+ hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */
- if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
- const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
- mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
+ if ((((U32)((dictLimit - 1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex)) &&
+ (ZSTD_read32(repMatch) == ZSTD_read32(ip + 1))) {
+ const BYTE *repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
+ mLength = ZSTD_count_2segments(ip + 1 + 4, repMatch + 4, iend, repMatchEnd, lowPrefixPtr) + 4;
ip++;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, 0, mLength - MINMATCH);
} else {
- if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
- const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
- const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
+ if ((matchLongIndex > lowestIndex) && (ZSTD_read64(matchLong) == ZSTD_read64(ip))) {
+ const BYTE *matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
+ const BYTE *lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
U32 offset;
- mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
- offset = current - matchLongIndex;
- while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
+ mLength = ZSTD_count_2segments(ip + 8, matchLong + 8, iend, matchEnd, lowPrefixPtr) + 8;
+ offset = curr - matchLongIndex;
+ while (((ip > anchor) & (matchLong > lowMatchPtr)) && (ip[-1] == matchLong[-1])) {
+ ip--;
+ matchLong--;
+ mLength++;
+ } /* catch up */
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
- } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
- size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
+ } else if ((matchIndex > lowestIndex) && (ZSTD_read32(match) == ZSTD_read32(ip))) {
+ size_t const h3 = ZSTD_hashPtr(ip + 1, hBitsL, 8);
U32 const matchIndex3 = hashLong[h3];
- const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
- const BYTE* match3 = match3Base + matchIndex3;
+ const BYTE *const match3Base = matchIndex3 < dictLimit ? dictBase : base;
+ const BYTE *match3 = match3Base + matchIndex3;
U32 offset;
- hashLong[h3] = current + 1;
- if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
- const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
- const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
- mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
+ hashLong[h3] = curr + 1;
+ if ((matchIndex3 > lowestIndex) && (ZSTD_read64(match3) == ZSTD_read64(ip + 1))) {
+ const BYTE *matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
+ const BYTE *lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
+ mLength = ZSTD_count_2segments(ip + 9, match3 + 8, iend, matchEnd, lowPrefixPtr) + 8;
ip++;
- offset = current+1 - matchIndex3;
- while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
+ offset = curr + 1 - matchIndex3;
+ while (((ip > anchor) & (match3 > lowMatchPtr)) && (ip[-1] == match3[-1])) {
+ ip--;
+ match3--;
+ mLength++;
+ } /* catch up */
} else {
- const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
- const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
- mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
- offset = current - matchIndex;
- while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
+ const BYTE *matchEnd = matchIndex < dictLimit ? dictEnd : iend;
+ const BYTE *lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
+ mLength = ZSTD_count_2segments(ip + 4, match + 4, iend, matchEnd, lowPrefixPtr) + 4;
+ offset = curr - matchIndex;
+ while (((ip > anchor) & (match > lowMatchPtr)) && (ip[-1] == match[-1])) {
+ ip--;
+ match--;
+ mLength++;
+ } /* catch up */
}
offset_2 = offset_1;
offset_1 = offset;
- ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, ip - anchor, anchor, offset + ZSTD_REP_MOVE, mLength - MINMATCH);
} else {
- ip += ((ip-anchor) >> g_searchStrength) + 1;
+ ip += ((ip - anchor) >> g_searchStrength) + 1;
continue;
- } }
+ }
+ }
/* found a match : store it */
ip += mLength;
@@ -1443,133 +1494,105 @@ static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
if (ip <= ilimit) {
/* Fill Table */
- hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
- hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
- hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
- hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
+ hashSmall[ZSTD_hashPtr(base + curr + 2, hBitsS, mls)] = curr + 2;
+ hashLong[ZSTD_hashPtr(base + curr + 2, hBitsL, 8)] = curr + 2;
+ hashSmall[ZSTD_hashPtr(ip - 2, hBitsS, mls)] = (U32)(ip - 2 - base);
+ hashLong[ZSTD_hashPtr(ip - 2, hBitsL, 8)] = (U32)(ip - 2 - base);
/* check immediate repcode */
while (ip <= ilimit) {
- U32 const current2 = (U32)(ip-base);
- U32 const repIndex2 = current2 - offset_2;
- const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
- if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
- && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
- const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
- size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
- U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
- hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
- hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
+ U32 const curr2 = (U32)(ip - base);
+ U32 const repIndex2 = curr2 - offset_2;
+ const BYTE *repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
+ if ((((U32)((dictLimit - 1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
+ && (ZSTD_read32(repMatch2) == ZSTD_read32(ip))) {
+ const BYTE *const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
+ size_t const repLength2 =
+ ZSTD_count_2segments(ip + EQUAL_READ32, repMatch2 + EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
+ U32 tmpOffset = offset_2;
+ offset_2 = offset_1;
+ offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2 - MINMATCH);
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = curr2;
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = curr2;
ip += repLength2;
anchor = ip;
continue;
}
break;
- } } }
+ }
+ }
+ }
/* save reps for next block */
- ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
+ ctx->repToConfirm[0] = offset_1;
+ ctx->repToConfirm[1] = offset_2;
/* Last Literals */
- { size_t const lastLLSize = iend - anchor;
+ {
+ size_t const lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
}
-
-static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize)
+static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
U32 const mls = ctx->params.cParams.searchLength;
- switch(mls)
- {
+ switch (mls) {
default: /* includes case 3 */
- case 4 :
- ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
- case 5 :
- ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
- case 6 :
- ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
- case 7 :
- ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
+ case 4: ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
+ case 5: ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
+ case 6: ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
+ case 7: ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
}
}
-
/*-*************************************
* Binary Tree search
***************************************/
/** ZSTD_insertBt1() : add one or multiple positions to tree.
* ip : assumed <= iend-8 .
* @return : nb of positions added */
-static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
- U32 extDict)
+static U32 ZSTD_insertBt1(ZSTD_CCtx *zc, const BYTE *const ip, const U32 mls, const BYTE *const iend, U32 nbCompares, U32 extDict)
{
- U32* const hashTable = zc->hashTable;
- U32 const hashLog = zc->params.cParams.hashLog;
- size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
- U32* const bt = zc->chainTable;
- U32 const btLog = zc->params.cParams.chainLog - 1;
- U32 const btMask = (1 << btLog) - 1;
+ U32 *const hashTable = zc->hashTable;
+ U32 const hashLog = zc->params.cParams.hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 *const bt = zc->chainTable;
+ U32 const btLog = zc->params.cParams.chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
U32 matchIndex = hashTable[h];
- size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const base = zc->base;
- const BYTE* const dictBase = zc->dictBase;
+ size_t commonLengthSmaller = 0, commonLengthLarger = 0;
+ const BYTE *const base = zc->base;
+ const BYTE *const dictBase = zc->dictBase;
const U32 dictLimit = zc->dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const BYTE* match;
- const U32 current = (U32)(ip-base);
- const U32 btLow = btMask >= current ? 0 : current - btMask;
- U32* smallerPtr = bt + 2*(current&btMask);
- U32* largerPtr = smallerPtr + 1;
- U32 dummy32; /* to be nullified at the end */
+ const BYTE *const dictEnd = dictBase + dictLimit;
+ const BYTE *const prefixStart = base + dictLimit;
+ const BYTE *match;
+ const U32 curr = (U32)(ip - base);
+ const U32 btLow = btMask >= curr ? 0 : curr - btMask;
+ U32 *smallerPtr = bt + 2 * (curr & btMask);
+ U32 *largerPtr = smallerPtr + 1;
+ U32 dummy32; /* to be nullified at the end */
U32 const windowLow = zc->lowLimit;
- U32 matchEndIdx = current+8;
+ U32 matchEndIdx = curr + 8;
size_t bestLength = 8;
-#ifdef ZSTD_C_PREDICT
- U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
- U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
- predictedSmall += (predictedSmall>0);
- predictedLarge += (predictedLarge>0);
-#endif /* ZSTD_C_PREDICT */
- hashTable[h] = current; /* Update Hash Table */
+ hashTable[h] = curr; /* Update Hash Table */
while (nbCompares-- && (matchIndex > windowLow)) {
- U32* const nextPtr = bt + 2*(matchIndex & btMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ U32 *const nextPtr = bt + 2 * (matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
-#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
- const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
- if (matchIndex == predictedSmall) {
- /* no need to check length, result known */
- *smallerPtr = matchIndex;
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
- matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
- predictedSmall = predictPtr[1] + (predictPtr[1]>0);
- continue;
- }
- if (matchIndex == predictedLarge) {
- *largerPtr = matchIndex;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- largerPtr = nextPtr;
- matchIndex = nextPtr[0];
- predictedLarge = predictPtr[0] + (predictPtr[0]>0);
- continue;
- }
-#endif
- if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
+ if ((!extDict) || (matchIndex + matchLength >= dictLimit)) {
match = base + matchIndex;
if (match[matchLength] == ip[matchLength])
- matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
+ matchLength += ZSTD_count(ip + matchLength + 1, match + matchLength + 1, iend) + 1;
} else {
match = dictBase + matchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
- if (matchIndex+matchLength >= dictLimit)
- match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
+ matchLength += ZSTD_count_2segments(ip + matchLength, match + matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex + matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
}
if (matchLength > bestLength) {
@@ -1578,212 +1601,205 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co
matchEndIdx = matchIndex + (U32)matchLength;
}
- if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
- break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
+ if (ip + matchLength == iend) /* equal : no way to know if inf or sup */
+ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
- if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
- /* match is smaller than current */
- *smallerPtr = matchIndex; /* update smaller idx */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
- matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
+ /* match is smaller than curr */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) {
+ smallerPtr = &dummy32;
+ break;
+ } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr + 1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to curr) */
} else {
- /* match is larger than current */
+ /* match is larger than curr */
*largerPtr = matchIndex;
commonLengthLarger = matchLength;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ if (matchIndex <= btLow) {
+ largerPtr = &dummy32;
+ break;
+ } /* beyond tree size, stop the search */
largerPtr = nextPtr;
matchIndex = nextPtr[0];
- } }
+ }
+ }
*smallerPtr = *largerPtr = 0;
- if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
- if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
+ if (bestLength > 384)
+ return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
+ if (matchEndIdx > curr + 8)
+ return matchEndIdx - curr - 8;
return 1;
}
-
-static size_t ZSTD_insertBtAndFindBestMatch (
- ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iend,
- size_t* offsetPtr,
- U32 nbCompares, const U32 mls,
- U32 extDict)
+static size_t ZSTD_insertBtAndFindBestMatch(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iend, size_t *offsetPtr, U32 nbCompares, const U32 mls,
+ U32 extDict)
{
- U32* const hashTable = zc->hashTable;
- U32 const hashLog = zc->params.cParams.hashLog;
- size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
- U32* const bt = zc->chainTable;
- U32 const btLog = zc->params.cParams.chainLog - 1;
- U32 const btMask = (1 << btLog) - 1;
- U32 matchIndex = hashTable[h];
- size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const base = zc->base;
- const BYTE* const dictBase = zc->dictBase;
+ U32 *const hashTable = zc->hashTable;
+ U32 const hashLog = zc->params.cParams.hashLog;
+ size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 *const bt = zc->chainTable;
+ U32 const btLog = zc->params.cParams.chainLog - 1;
+ U32 const btMask = (1 << btLog) - 1;
+ U32 matchIndex = hashTable[h];
+ size_t commonLengthSmaller = 0, commonLengthLarger = 0;
+ const BYTE *const base = zc->base;
+ const BYTE *const dictBase = zc->dictBase;
const U32 dictLimit = zc->dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const U32 current = (U32)(ip-base);
- const U32 btLow = btMask >= current ? 0 : current - btMask;
+ const BYTE *const dictEnd = dictBase + dictLimit;
+ const BYTE *const prefixStart = base + dictLimit;
+ const U32 curr = (U32)(ip - base);
+ const U32 btLow = btMask >= curr ? 0 : curr - btMask;
const U32 windowLow = zc->lowLimit;
- U32* smallerPtr = bt + 2*(current&btMask);
- U32* largerPtr = bt + 2*(current&btMask) + 1;
- U32 matchEndIdx = current+8;
- U32 dummy32; /* to be nullified at the end */
+ U32 *smallerPtr = bt + 2 * (curr & btMask);
+ U32 *largerPtr = bt + 2 * (curr & btMask) + 1;
+ U32 matchEndIdx = curr + 8;
+ U32 dummy32; /* to be nullified at the end */
size_t bestLength = 0;
- hashTable[h] = current; /* Update Hash Table */
+ hashTable[h] = curr; /* Update Hash Table */
while (nbCompares-- && (matchIndex > windowLow)) {
- U32* const nextPtr = bt + 2*(matchIndex & btMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- const BYTE* match;
+ U32 *const nextPtr = bt + 2 * (matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE *match;
- if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
+ if ((!extDict) || (matchIndex + matchLength >= dictLimit)) {
match = base + matchIndex;
if (match[matchLength] == ip[matchLength])
- matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
+ matchLength += ZSTD_count(ip + matchLength + 1, match + matchLength + 1, iend) + 1;
} else {
match = dictBase + matchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
- if (matchIndex+matchLength >= dictLimit)
- match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
+ matchLength += ZSTD_count_2segments(ip + matchLength, match + matchLength, iend, dictEnd, prefixStart);
+ if (matchIndex + matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
}
if (matchLength > bestLength) {
if (matchLength > matchEndIdx - matchIndex)
matchEndIdx = matchIndex + (U32)matchLength;
- if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
- bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
- if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
- break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ if ((4 * (int)(matchLength - bestLength)) > (int)(ZSTD_highbit32(curr - matchIndex + 1) - ZSTD_highbit32((U32)offsetPtr[0] + 1)))
+ bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + curr - matchIndex;
+ if (ip + matchLength == iend) /* equal : no way to know if inf or sup */
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
}
if (match[matchLength] < ip[matchLength]) {
- /* match is smaller than current */
- *smallerPtr = matchIndex; /* update smaller idx */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
- matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ /* match is smaller than curr */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) {
+ smallerPtr = &dummy32;
+ break;
+ } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr + 1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to curr) */
} else {
- /* match is larger than current */
+ /* match is larger than curr */
*largerPtr = matchIndex;
commonLengthLarger = matchLength;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ if (matchIndex <= btLow) {
+ largerPtr = &dummy32;
+ break;
+ } /* beyond tree size, stop the search */
largerPtr = nextPtr;
matchIndex = nextPtr[0];
- } }
+ }
+ }
*smallerPtr = *largerPtr = 0;
- zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
+ zc->nextToUpdate = (matchEndIdx > curr + 8) ? matchEndIdx - 8 : curr + 1;
return bestLength;
}
-
-static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
+static void ZSTD_updateTree(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iend, const U32 nbCompares, const U32 mls)
{
- const BYTE* const base = zc->base;
+ const BYTE *const base = zc->base;
const U32 target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
- while(idx < target)
- idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
+ while (idx < target)
+ idx += ZSTD_insertBt1(zc, base + idx, mls, iend, nbCompares, 0);
}
/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
-static size_t ZSTD_BtFindBestMatch (
- ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 mls)
+static size_t ZSTD_BtFindBestMatch(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts, const U32 mls)
{
- if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
+ if (ip < zc->base + zc->nextToUpdate)
+ return 0; /* skipped area */
ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
}
-
-static size_t ZSTD_BtFindBestMatch_selectMLS (
- ZSTD_CCtx* zc, /* Index table will be updated */
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 matchLengthSearch)
+static size_t ZSTD_BtFindBestMatch_selectMLS(ZSTD_CCtx *zc, /* Index table will be updated */
+ const BYTE *ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts, const U32 matchLengthSearch)
{
- switch(matchLengthSearch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
- case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
- case 7 :
- case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
+ switch (matchLengthSearch) {
+ default: /* includes case 3 */
+ case 4: return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
+ case 5: return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
+ case 7:
+ case 6: return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
}
}
-
-static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
+static void ZSTD_updateTree_extDict(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iend, const U32 nbCompares, const U32 mls)
{
- const BYTE* const base = zc->base;
+ const BYTE *const base = zc->base;
const U32 target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
- while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
+ while (idx < target)
+ idx += ZSTD_insertBt1(zc, base + idx, mls, iend, nbCompares, 1);
}
-
/** Tree updater, providing best match */
-static size_t ZSTD_BtFindBestMatch_extDict (
- ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 mls)
+static size_t ZSTD_BtFindBestMatch_extDict(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts,
+ const U32 mls)
{
- if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
+ if (ip < zc->base + zc->nextToUpdate)
+ return 0; /* skipped area */
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
}
-
-static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
- ZSTD_CCtx* zc, /* Index table will be updated */
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 matchLengthSearch)
+static size_t ZSTD_BtFindBestMatch_selectMLS_extDict(ZSTD_CCtx *zc, /* Index table will be updated */
+ const BYTE *ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts,
+ const U32 matchLengthSearch)
{
- switch(matchLengthSearch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
- case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
- case 7 :
- case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
+ switch (matchLengthSearch) {
+ default: /* includes case 3 */
+ case 4: return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
+ case 5: return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
+ case 7:
+ case 6: return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
}
}
-
-
/* *********************************
* Hash Chain
***********************************/
-#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
+#define NEXT_IN_CHAIN(d, mask) chainTable[(d)&mask]
/* Update chains up to ip (excluded)
Assumption : always within prefix (i.e. not within extDict) */
FORCE_INLINE
-U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
+U32 ZSTD_insertAndFindFirstIndex(ZSTD_CCtx *zc, const BYTE *ip, U32 mls)
{
- U32* const hashTable = zc->hashTable;
+ U32 *const hashTable = zc->hashTable;
const U32 hashLog = zc->params.cParams.hashLog;
- U32* const chainTable = zc->chainTable;
+ U32 *const chainTable = zc->chainTable;
const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
- const BYTE* const base = zc->base;
+ const BYTE *const base = zc->base;
const U32 target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
- while(idx < target) { /* catch up */
- size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
+ while (idx < target) { /* catch up */
+ size_t const h = ZSTD_hashPtr(base + idx, hashLog, mls);
NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
hashTable[h] = idx;
idx++;
@@ -1793,274 +1809,267 @@ U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
}
-
-
-FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
-size_t ZSTD_HcFindBestMatch_generic (
- ZSTD_CCtx* zc, /* Index table will be updated */
- const BYTE* const ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 mls, const U32 extDict)
+/* inlining is important to hardwire a hot branch (template emulation) */
+FORCE_INLINE
+size_t ZSTD_HcFindBestMatch_generic(ZSTD_CCtx *zc, /* Index table will be updated */
+ const BYTE *const ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts, const U32 mls,
+ const U32 extDict)
{
- U32* const chainTable = zc->chainTable;
+ U32 *const chainTable = zc->chainTable;
const U32 chainSize = (1 << zc->params.cParams.chainLog);
- const U32 chainMask = chainSize-1;
- const BYTE* const base = zc->base;
- const BYTE* const dictBase = zc->dictBase;
+ const U32 chainMask = chainSize - 1;
+ const BYTE *const base = zc->base;
+ const BYTE *const dictBase = zc->dictBase;
const U32 dictLimit = zc->dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE *const prefixStart = base + dictLimit;
+ const BYTE *const dictEnd = dictBase + dictLimit;
const U32 lowLimit = zc->lowLimit;
- const U32 current = (U32)(ip-base);
- const U32 minChain = current > chainSize ? current - chainSize : 0;
- int nbAttempts=maxNbAttempts;
- size_t ml=EQUAL_READ32-1;
+ const U32 curr = (U32)(ip - base);
+ const U32 minChain = curr > chainSize ? curr - chainSize : 0;
+ int nbAttempts = maxNbAttempts;
+ size_t ml = EQUAL_READ32 - 1;
/* HC4 match finder */
- U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
+ U32 matchIndex = ZSTD_insertAndFindFirstIndex(zc, ip, mls);
- for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
- const BYTE* match;
- size_t currentMl=0;
+ for (; (matchIndex > lowLimit) & (nbAttempts > 0); nbAttempts--) {
+ const BYTE *match;
+ size_t currMl = 0;
if ((!extDict) || matchIndex >= dictLimit) {
match = base + matchIndex;
- if (match[ml] == ip[ml]) /* potentially better */
- currentMl = ZSTD_count(ip, match, iLimit);
+ if (match[ml] == ip[ml]) /* potentially better */
+ currMl = ZSTD_count(ip, match, iLimit);
} else {
match = dictBase + matchIndex;
- if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
- currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
+ if (ZSTD_read32(match) == ZSTD_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
+ currMl = ZSTD_count_2segments(ip + EQUAL_READ32, match + EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
}
/* save best solution */
- if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
+ if (currMl > ml) {
+ ml = currMl;
+ *offsetPtr = curr - matchIndex + ZSTD_REP_MOVE;
+ if (ip + currMl == iLimit)
+ break; /* best possible, and avoid read overflow*/
+ }
- if (matchIndex <= minChain) break;
+ if (matchIndex <= minChain)
+ break;
matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
}
return ml;
}
-
-FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
- ZSTD_CCtx* zc,
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 matchLengthSearch)
+FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS(ZSTD_CCtx *zc, const BYTE *ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts,
+ const U32 matchLengthSearch)
{
- switch(matchLengthSearch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
- case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
- case 7 :
- case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
+ switch (matchLengthSearch) {
+ default: /* includes case 3 */
+ case 4: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
+ case 5: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
+ case 7:
+ case 6: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
}
}
-
-FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
- ZSTD_CCtx* zc,
- const BYTE* ip, const BYTE* const iLimit,
- size_t* offsetPtr,
- const U32 maxNbAttempts, const U32 matchLengthSearch)
+FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS(ZSTD_CCtx *zc, const BYTE *ip, const BYTE *const iLimit, size_t *offsetPtr, const U32 maxNbAttempts,
+ const U32 matchLengthSearch)
{
- switch(matchLengthSearch)
- {
- default : /* includes case 3 */
- case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
- case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
- case 7 :
- case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
+ switch (matchLengthSearch) {
+ default: /* includes case 3 */
+ case 4: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
+ case 5: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
+ case 7:
+ case 6: return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
}
}
-
/* *******************************
* Common parser - lazy strategy
*********************************/
FORCE_INLINE
-void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize,
- const U32 searchMethod, const U32 depth)
+void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const U32 searchMethod, const U32 depth)
{
- seqStore_t* seqStorePtr = &(ctx->seqStore);
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ctx->base + ctx->dictLimit;
+ seqStore_t *seqStorePtr = &(ctx->seqStore);
+ const BYTE *const istart = (const BYTE *)src;
+ const BYTE *ip = istart;
+ const BYTE *anchor = istart;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *const ilimit = iend - 8;
+ const BYTE *const base = ctx->base + ctx->dictLimit;
U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
U32 const mls = ctx->params.cParams.searchLength;
- typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
- size_t* offsetPtr,
- U32 maxNbAttempts, U32 matchLengthSearch);
+ typedef size_t (*searchMax_f)(ZSTD_CCtx * zc, const BYTE *ip, const BYTE *iLimit, size_t *offsetPtr, U32 maxNbAttempts, U32 matchLengthSearch);
searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
- U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
+ U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset = 0;
/* init */
- ip += (ip==base);
+ ip += (ip == base);
ctx->nextToUpdate3 = ctx->nextToUpdate;
- { U32 const maxRep = (U32)(ip-base);
- if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
- if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
+ {
+ U32 const maxRep = (U32)(ip - base);
+ if (offset_2 > maxRep)
+ savedOffset = offset_2, offset_2 = 0;
+ if (offset_1 > maxRep)
+ savedOffset = offset_1, offset_1 = 0;
}
/* Match Loop */
while (ip < ilimit) {
- size_t matchLength=0;
- size_t offset=0;
- const BYTE* start=ip+1;
+ size_t matchLength = 0;
+ size_t offset = 0;
+ const BYTE *start = ip + 1;
/* check repCode */
- if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
+ if ((offset_1 > 0) & (ZSTD_read32(ip + 1) == ZSTD_read32(ip + 1 - offset_1))) {
/* repcode : we take it */
- matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
- if (depth==0) goto _storeSequence;
+ matchLength = ZSTD_count(ip + 1 + EQUAL_READ32, ip + 1 + EQUAL_READ32 - offset_1, iend) + EQUAL_READ32;
+ if (depth == 0)
+ goto _storeSequence;
}
/* first search (depth 0) */
- { size_t offsetFound = 99999999;
+ {
+ size_t offsetFound = 99999999;
size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
if (ml2 > matchLength)
- matchLength = ml2, start = ip, offset=offsetFound;
+ matchLength = ml2, start = ip, offset = offsetFound;
}
if (matchLength < EQUAL_READ32) {
- ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
+ ip += ((ip - anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
continue;
}
/* let's try to find a better solution */
- if (depth>=1)
- while (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
- size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
- int const gain2 = (int)(mlRep * 3);
- int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
- matchLength = mlRep, offset = 0, start = ip;
- }
- { size_t offset2=99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
- int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
- if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
- matchLength = ml2, offset = offset2, start = ip;
- continue; /* search a better one */
- } }
-
- /* let's find an even better one */
- if ((depth==2) && (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
- size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
- int const gain2 = (int)(ml2 * 4);
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
- matchLength = ml2, offset = 0, start = ip;
+ if (depth >= 1)
+ while (ip < ilimit) {
+ ip++;
+ if ((offset) && ((offset_1 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_1)))) {
+ size_t const mlRep = ZSTD_count(ip + EQUAL_READ32, ip + EQUAL_READ32 - offset_1, iend) + EQUAL_READ32;
+ int const gain2 = (int)(mlRep * 3);
+ int const gain1 = (int)(matchLength * 3 - ZSTD_highbit32((U32)offset + 1) + 1);
+ if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
+ matchLength = mlRep, offset = 0, start = ip;
}
- { size_t offset2=99999999;
+ {
+ size_t offset2 = 99999999;
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
- int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
+ int const gain2 = (int)(ml2 * 4 - ZSTD_highbit32((U32)offset2 + 1)); /* raw approx */
+ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 4);
if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
matchLength = ml2, offset = offset2, start = ip;
- continue;
- } } }
- break; /* nothing found : store previous solution */
- }
+ continue; /* search a better one */
+ }
+ }
+ /* let's find an even better one */
+ if ((depth == 2) && (ip < ilimit)) {
+ ip++;
+ if ((offset) && ((offset_1 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_1)))) {
+ size_t const ml2 = ZSTD_count(ip + EQUAL_READ32, ip + EQUAL_READ32 - offset_1, iend) + EQUAL_READ32;
+ int const gain2 = (int)(ml2 * 4);
+ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 1);
+ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
+ matchLength = ml2, offset = 0, start = ip;
+ }
+ {
+ size_t offset2 = 99999999;
+ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
+ int const gain2 = (int)(ml2 * 4 - ZSTD_highbit32((U32)offset2 + 1)); /* raw approx */
+ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 7);
+ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue;
+ }
+ }
+ }
+ break; /* nothing found : store previous solution */
+ }
+
+ /* NOTE:
+ * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
+ * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
+ * overflows the pointer, which is undefined behavior.
+ */
/* catch up */
if (offset) {
- while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
- { start--; matchLength++; }
- offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
+ while ((start > anchor) && (start > base + offset - ZSTD_REP_MOVE) &&
+ (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1])) /* only search for offset within prefix */
+ {
+ start--;
+ matchLength++;
+ }
+ offset_2 = offset_1;
+ offset_1 = (U32)(offset - ZSTD_REP_MOVE);
}
- /* store sequence */
+ /* store sequence */
_storeSequence:
- { size_t const litLength = start - anchor;
- ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
+ {
+ size_t const litLength = start - anchor;
+ ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength - MINMATCH);
anchor = ip = start + matchLength;
}
/* check immediate repcode */
- while ( (ip <= ilimit)
- && ((offset_2>0)
- & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
+ while ((ip <= ilimit) && ((offset_2 > 0) & (ZSTD_read32(ip) == ZSTD_read32(ip - offset_2)))) {
/* store sequence */
- matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
- offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
+ matchLength = ZSTD_count(ip + EQUAL_READ32, ip + EQUAL_READ32 - offset_2, iend) + EQUAL_READ32;
+ offset = offset_2;
+ offset_2 = offset_1;
+ offset_1 = (U32)offset; /* swap repcodes */
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength - MINMATCH);
ip += matchLength;
anchor = ip;
- continue; /* faster when present ... (?) */
- } }
+ continue; /* faster when present ... (?) */
+ }
+ }
/* Save reps for next block */
ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
/* Last Literals */
- { size_t const lastLLSize = iend - anchor;
+ {
+ size_t const lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
}
+static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); }
-static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
-{
- ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
-}
+static void ZSTD_compressBlock_lazy2(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2); }
-static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
-{
- ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
-}
-
-static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
-{
- ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
-}
-
-static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
-{
- ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
-}
+static void ZSTD_compressBlock_lazy(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1); }
+static void ZSTD_compressBlock_greedy(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0); }
FORCE_INLINE
-void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize,
- const U32 searchMethod, const U32 depth)
+void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const U32 searchMethod, const U32 depth)
{
- seqStore_t* seqStorePtr = &(ctx->seqStore);
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ctx->base;
+ seqStore_t *seqStorePtr = &(ctx->seqStore);
+ const BYTE *const istart = (const BYTE *)src;
+ const BYTE *ip = istart;
+ const BYTE *anchor = istart;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *const ilimit = iend - 8;
+ const BYTE *const base = ctx->base;
const U32 dictLimit = ctx->dictLimit;
const U32 lowestIndex = ctx->lowLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const BYTE* const dictBase = ctx->dictBase;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const dictStart = dictBase + ctx->lowLimit;
+ const BYTE *const prefixStart = base + dictLimit;
+ const BYTE *const dictBase = ctx->dictBase;
+ const BYTE *const dictEnd = dictBase + dictLimit;
+ const BYTE *const dictStart = dictBase + ctx->lowLimit;
const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
const U32 mls = ctx->params.cParams.searchLength;
- typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
- size_t* offsetPtr,
- U32 maxNbAttempts, U32 matchLengthSearch);
+ typedef size_t (*searchMax_f)(ZSTD_CCtx * zc, const BYTE *ip, const BYTE *iLimit, size_t *offsetPtr, U32 maxNbAttempts, U32 matchLengthSearch);
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
@@ -2071,237 +2080,266 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
/* Match Loop */
while (ip < ilimit) {
- size_t matchLength=0;
- size_t offset=0;
- const BYTE* start=ip+1;
- U32 current = (U32)(ip-base);
+ size_t matchLength = 0;
+ size_t offset = 0;
+ const BYTE *start = ip + 1;
+ U32 curr = (U32)(ip - base);
/* check repCode */
- { const U32 repIndex = (U32)(current+1 - offset_1);
- const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
- if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
- /* repcode detected we should take it */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
- if (depth==0) goto _storeSequence;
- } }
-
- /* first search (depth 0) */
- { size_t offsetFound = 99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
- if (ml2 > matchLength)
- matchLength = ml2, start = ip, offset=offsetFound;
+ {
+ const U32 repIndex = (U32)(curr + 1 - offset_1);
+ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE *const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ if (ZSTD_read32(ip + 1) == ZSTD_read32(repMatch)) {
+ /* repcode detected we should take it */
+ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ matchLength =
+ ZSTD_count_2segments(ip + 1 + EQUAL_READ32, repMatch + EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
+ if (depth == 0)
+ goto _storeSequence;
+ }
}
- if (matchLength < EQUAL_READ32) {
- ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
+ /* first search (depth 0) */
+ {
+ size_t offsetFound = 99999999;
+ size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
+ if (ml2 > matchLength)
+ matchLength = ml2, start = ip, offset = offsetFound;
+ }
+
+ if (matchLength < EQUAL_READ32) {
+ ip += ((ip - anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
continue;
}
/* let's try to find a better solution */
- if (depth>=1)
- while (ip= 3) & (repIndex > lowestIndex)) /* intentional overflow */
- if (MEM_read32(ip) == MEM_read32(repMatch)) {
- /* repcode detected */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
- int const gain2 = (int)(repLength * 3);
- int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
- matchLength = repLength, offset = 0, start = ip;
- } }
-
- /* search match, depth 1 */
- { size_t offset2=99999999;
- size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
- int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
- if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
- matchLength = ml2, offset = offset2, start = ip;
- continue; /* search a better one */
- } }
-
- /* let's find an even better one */
- if ((depth==2) && (ip= 1)
+ while (ip < ilimit) {
+ ip++;
+ curr++;
/* check repCode */
if (offset) {
- const U32 repIndex = (U32)(current - offset_1);
- const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
- if (MEM_read32(ip) == MEM_read32(repMatch)) {
- /* repcode detected */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
- int gain2 = (int)(repLength * 4);
- int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
- if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
- matchLength = repLength, offset = 0, start = ip;
- } }
+ const U32 repIndex = (U32)(curr - offset_1);
+ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE *const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ if (ZSTD_read32(ip) == ZSTD_read32(repMatch)) {
+ /* repcode detected */
+ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ size_t const repLength =
+ ZSTD_count_2segments(ip + EQUAL_READ32, repMatch + EQUAL_READ32, iend, repEnd, prefixStart) +
+ EQUAL_READ32;
+ int const gain2 = (int)(repLength * 3);
+ int const gain1 = (int)(matchLength * 3 - ZSTD_highbit32((U32)offset + 1) + 1);
+ if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
+ matchLength = repLength, offset = 0, start = ip;
+ }
+ }
- /* search match, depth 2 */
- { size_t offset2=99999999;
+ /* search match, depth 1 */
+ {
+ size_t offset2 = 99999999;
size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
- int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
- int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
+ int const gain2 = (int)(ml2 * 4 - ZSTD_highbit32((U32)offset2 + 1)); /* raw approx */
+ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 4);
if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
matchLength = ml2, offset = offset2, start = ip;
- continue;
- } } }
- break; /* nothing found : store previous solution */
- }
+ continue; /* search a better one */
+ }
+ }
+
+ /* let's find an even better one */
+ if ((depth == 2) && (ip < ilimit)) {
+ ip++;
+ curr++;
+ /* check repCode */
+ if (offset) {
+ const U32 repIndex = (U32)(curr - offset_1);
+ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE *const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ if (ZSTD_read32(ip) == ZSTD_read32(repMatch)) {
+ /* repcode detected */
+ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ size_t repLength = ZSTD_count_2segments(ip + EQUAL_READ32, repMatch + EQUAL_READ32, iend,
+ repEnd, prefixStart) +
+ EQUAL_READ32;
+ int gain2 = (int)(repLength * 4);
+ int gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 1);
+ if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
+ matchLength = repLength, offset = 0, start = ip;
+ }
+ }
+
+ /* search match, depth 2 */
+ {
+ size_t offset2 = 99999999;
+ size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
+ int const gain2 = (int)(ml2 * 4 - ZSTD_highbit32((U32)offset2 + 1)); /* raw approx */
+ int const gain1 = (int)(matchLength * 4 - ZSTD_highbit32((U32)offset + 1) + 7);
+ if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
+ matchLength = ml2, offset = offset2, start = ip;
+ continue;
+ }
+ }
+ }
+ break; /* nothing found : store previous solution */
+ }
/* catch up */
if (offset) {
- U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
- const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
- const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
- while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
- offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
+ U32 const matchIndex = (U32)((start - base) - (offset - ZSTD_REP_MOVE));
+ const BYTE *match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
+ const BYTE *const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
+ while ((start > anchor) && (match > mStart) && (start[-1] == match[-1])) {
+ start--;
+ match--;
+ matchLength++;
+ } /* catch up */
+ offset_2 = offset_1;
+ offset_1 = (U32)(offset - ZSTD_REP_MOVE);
}
- /* store sequence */
-_storeSequence:
- { size_t const litLength = start - anchor;
- ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
- anchor = ip = start + matchLength;
- }
+ /* store sequence */
+ _storeSequence : {
+ size_t const litLength = start - anchor;
+ ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength - MINMATCH);
+ anchor = ip = start + matchLength;
+ }
/* check immediate repcode */
while (ip <= ilimit) {
- const U32 repIndex = (U32)((ip-base) - offset_2);
- const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
- const BYTE* const repMatch = repBase + repIndex;
- if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
- if (MEM_read32(ip) == MEM_read32(repMatch)) {
- /* repcode detected we should take it */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
- offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
- ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
- ip += matchLength;
- anchor = ip;
- continue; /* faster when present ... (?) */
- }
+ const U32 repIndex = (U32)((ip - base) - offset_2);
+ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE *const repMatch = repBase + repIndex;
+ if (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ if (ZSTD_read32(ip) == ZSTD_read32(repMatch)) {
+ /* repcode detected we should take it */
+ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ matchLength =
+ ZSTD_count_2segments(ip + EQUAL_READ32, repMatch + EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
+ offset = offset_2;
+ offset_2 = offset_1;
+ offset_1 = (U32)offset; /* swap offset history */
+ ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength - MINMATCH);
+ ip += matchLength;
+ anchor = ip;
+ continue; /* faster when present ... (?) */
+ }
break;
- } }
+ }
+ }
/* Save reps for next block */
- ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
+ ctx->repToConfirm[0] = offset_1;
+ ctx->repToConfirm[1] = offset_2;
/* Last Literals */
- { size_t const lastLLSize = iend - anchor;
+ {
+ size_t const lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
}
+void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize) { ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0); }
-void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
-{
- ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
-}
-
-static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
}
-static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
}
-static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
}
-
/* The optimal parser */
#include "zstd_opt.h"
-static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+static void ZSTD_compressBlock_btopt(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
#ifdef ZSTD_OPT_H_91842398743
ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
#else
- (void)ctx; (void)src; (void)srcSize;
+ (void)ctx;
+ (void)src;
+ (void)srcSize;
return;
#endif
}
-static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+static void ZSTD_compressBlock_btopt2(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
#ifdef ZSTD_OPT_H_91842398743
ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
#else
- (void)ctx; (void)src; (void)srcSize;
+ (void)ctx;
+ (void)src;
+ (void)srcSize;
return;
#endif
}
-static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
#ifdef ZSTD_OPT_H_91842398743
ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
#else
- (void)ctx; (void)src; (void)srcSize;
+ (void)ctx;
+ (void)src;
+ (void)srcSize;
return;
#endif
}
-static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
+static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx *ctx, const void *src, size_t srcSize)
{
#ifdef ZSTD_OPT_H_91842398743
ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
#else
- (void)ctx; (void)src; (void)srcSize;
+ (void)ctx;
+ (void)src;
+ (void)srcSize;
return;
#endif
}
-
-typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
+typedef void (*ZSTD_blockCompressor)(ZSTD_CCtx *ctx, const void *src, size_t srcSize);
static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
{
static const ZSTD_blockCompressor blockCompressor[2][8] = {
- { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
- { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btopt2_extDict }
- };
+ {ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2,
+ ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2},
+ {ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,
+ ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btopt2_extDict}};
return blockCompressor[extDict][(U32)strat];
}
-
-static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+static size_t ZSTD_compressBlock_internal(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
- const BYTE* const base = zc->base;
- const BYTE* const istart = (const BYTE*)src;
- const U32 current = (U32)(istart-base);
- if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
+ const BYTE *const base = zc->base;
+ const BYTE *const istart = (const BYTE *)src;
+ const U32 curr = (U32)(istart - base);
+ if (srcSize < MIN_CBLOCK_SIZE + ZSTD_blockHeaderSize + 1)
+ return 0; /* don't even attempt compression below a certain srcSize */
ZSTD_resetSeqStore(&(zc->seqStore));
- if (current > zc->nextToUpdate + 384)
- zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* update tree not updated after finding very long rep matches */
+ if (curr > zc->nextToUpdate + 384)
+ zc->nextToUpdate = curr - MIN(192, (U32)(curr - zc->nextToUpdate - 384)); /* update tree not updated after finding very long rep matches */
blockCompressor(zc, src, srcSize);
return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
}
-
/*! ZSTD_compress_generic() :
* Compress a chunk of data into one or multiple blocks.
* All blocks will be terminated, all input will be consumed.
@@ -2309,63 +2347,68 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCa
* Frame is supposed already started (header already produced)
* @return : compressed size, or an error code
*/
-static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- U32 lastFrameChunk)
+static size_t ZSTD_compress_generic(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, U32 lastFrameChunk)
{
size_t blockSize = cctx->blockSize;
size_t remaining = srcSize;
- const BYTE* ip = (const BYTE*)src;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* op = ostart;
+ const BYTE *ip = (const BYTE *)src;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *op = ostart;
U32 const maxDist = 1 << cctx->params.cParams.windowLog;
if (cctx->params.fParams.checksumFlag && srcSize)
- XXH64_update(&cctx->xxhState, src, srcSize);
+ xxh64_update(&cctx->xxhState, src, srcSize);
while (remaining) {
U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
size_t cSize;
- if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
- if (remaining < blockSize) blockSize = remaining;
+ if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
+ return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
+ if (remaining < blockSize)
+ blockSize = remaining;
/* preemptive overflow correction */
- if (cctx->lowLimit > (3U<<29)) {
+ if (cctx->lowLimit > (3U << 29)) {
U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
- U32 const current = (U32)(ip - cctx->base);
- U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
- U32 const correction = current - newCurrent;
+ U32 const curr = (U32)(ip - cctx->base);
+ U32 const newCurr = (curr & cycleMask) + (1 << cctx->params.cParams.windowLog);
+ U32 const correction = curr - newCurr;
ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
ZSTD_reduceIndex(cctx, correction);
cctx->base += correction;
cctx->dictBase += correction;
cctx->lowLimit -= correction;
cctx->dictLimit -= correction;
- if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
- else cctx->nextToUpdate -= correction;
+ if (cctx->nextToUpdate < correction)
+ cctx->nextToUpdate = 0;
+ else
+ cctx->nextToUpdate -= correction;
}
- if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
+ if ((U32)(ip + blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
/* enforce maxDist */
- U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
- if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
- if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
+ U32 const newLowLimit = (U32)(ip + blockSize - cctx->base) - maxDist;
+ if (cctx->lowLimit < newLowLimit)
+ cctx->lowLimit = newLowLimit;
+ if (cctx->dictLimit < cctx->lowLimit)
+ cctx->dictLimit = cctx->lowLimit;
}
- cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
- if (ZSTD_isError(cSize)) return cSize;
+ cSize = ZSTD_compressBlock_internal(cctx, op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize, ip, blockSize);
+ if (ZSTD_isError(cSize))
+ return cSize;
- if (cSize == 0) { /* block is not compressible */
- U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
- if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
- MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
+ if (cSize == 0) { /* block is not compressible */
+ U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw) << 1) + (U32)(blockSize << 3);
+ if (blockSize + ZSTD_blockHeaderSize > dstCapacity)
+ return ERROR(dstSize_tooSmall);
+ ZSTD_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
- cSize = ZSTD_blockHeaderSize+blockSize;
+ cSize = ZSTD_blockHeaderSize + blockSize;
} else {
- U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
- MEM_writeLE24(op, cBlockHeader24);
+ U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed) << 1) + (U32)(cSize << 3);
+ ZSTD_writeLE24(op, cBlockHeader24);
cSize += ZSTD_blockHeaderSize;
}
@@ -2375,65 +2418,84 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
op += cSize;
}
- if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
- return op-ostart;
+ if (lastFrameChunk && (op > ostart))
+ cctx->stage = ZSTDcs_ending;
+ return op - ostart;
}
-
-static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
- ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
-{ BYTE* const op = (BYTE*)dst;
- U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
- U32 const checksumFlag = params.fParams.checksumFlag>0;
- U32 const windowSize = 1U << params.cParams.windowLog;
- U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
- BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
- U32 const fcsCode = params.fParams.contentSizeFlag ?
- (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
- 0;
- BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
+static size_t ZSTD_writeFrameHeader(void *dst, size_t dstCapacity, ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
+{
+ BYTE *const op = (BYTE *)dst;
+ U32 const dictIDSizeCode = (dictID > 0) + (dictID >= 256) + (dictID >= 65536); /* 0-3 */
+ U32 const checksumFlag = params.fParams.checksumFlag > 0;
+ U32 const windowSize = 1U << params.cParams.windowLog;
+ U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
+ BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
+ U32 const fcsCode =
+ params.fParams.contentSizeFlag ? (pledgedSrcSize >= 256) + (pledgedSrcSize >= 65536 + 256) + (pledgedSrcSize >= 0xFFFFFFFFU) : 0; /* 0-3 */
+ BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag << 2) + (singleSegment << 5) + (fcsCode << 6));
size_t pos;
- if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
+ if (dstCapacity < ZSTD_frameHeaderSize_max)
+ return ERROR(dstSize_tooSmall);
- MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
- op[4] = frameHeaderDecriptionByte; pos=5;
- if (!singleSegment) op[pos++] = windowLogByte;
- switch(dictIDSizeCode)
- {
- default: /* impossible */
- case 0 : break;
- case 1 : op[pos] = (BYTE)(dictID); pos++; break;
- case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
- case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
+ ZSTD_writeLE32(dst, ZSTD_MAGICNUMBER);
+ op[4] = frameHeaderDecriptionByte;
+ pos = 5;
+ if (!singleSegment)
+ op[pos++] = windowLogByte;
+ switch (dictIDSizeCode) {
+ default: /* impossible */
+ case 0: break;
+ case 1:
+ op[pos] = (BYTE)(dictID);
+ pos++;
+ break;
+ case 2:
+ ZSTD_writeLE16(op + pos, (U16)dictID);
+ pos += 2;
+ break;
+ case 3:
+ ZSTD_writeLE32(op + pos, dictID);
+ pos += 4;
+ break;
}
- switch(fcsCode)
- {
- default: /* impossible */
- case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
- case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
- case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
- case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
+ switch (fcsCode) {
+ default: /* impossible */
+ case 0:
+ if (singleSegment)
+ op[pos++] = (BYTE)(pledgedSrcSize);
+ break;
+ case 1:
+ ZSTD_writeLE16(op + pos, (U16)(pledgedSrcSize - 256));
+ pos += 2;
+ break;
+ case 2:
+ ZSTD_writeLE32(op + pos, (U32)(pledgedSrcSize));
+ pos += 4;
+ break;
+ case 3:
+ ZSTD_writeLE64(op + pos, (U64)(pledgedSrcSize));
+ pos += 8;
+ break;
}
return pos;
}
-
-static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- U32 frame, U32 lastFrameChunk)
+static size_t ZSTD_compressContinue_internal(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, U32 frame, U32 lastFrameChunk)
{
- const BYTE* const ip = (const BYTE*) src;
+ const BYTE *const ip = (const BYTE *)src;
size_t fhSize = 0;
- if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
+ if (cctx->stage == ZSTDcs_created)
+ return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
- if (frame && (cctx->stage==ZSTDcs_init)) {
+ if (frame && (cctx->stage == ZSTDcs_init)) {
fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
- if (ZSTD_isError(fhSize)) return fhSize;
+ if (ZSTD_isError(fhSize))
+ return fhSize;
dstCapacity -= fhSize;
- dst = (char*)dst + fhSize;
+ dst = (char *)dst + fhSize;
cctx->stage = ZSTDcs_ongoing;
}
@@ -2446,11 +2508,12 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
cctx->dictBase = cctx->base;
cctx->base -= delta;
cctx->nextToUpdate = cctx->dictLimit;
- if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
+ if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE)
+ cctx->lowLimit = cctx->dictLimit; /* too small extDict */
}
/* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
- if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
+ if ((ip + srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
cctx->lowLimit = lowLimitMax;
@@ -2459,45 +2522,39 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
cctx->nextSrc = ip + srcSize;
if (srcSize) {
- size_t const cSize = frame ?
- ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
- ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
- if (ZSTD_isError(cSize)) return cSize;
+ size_t const cSize = frame ? ZSTD_compress_generic(cctx, dst, dstCapacity, src, srcSize, lastFrameChunk)
+ : ZSTD_compressBlock_internal(cctx, dst, dstCapacity, src, srcSize);
+ if (ZSTD_isError(cSize))
+ return cSize;
return cSize + fhSize;
} else
return fhSize;
}
-
-size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
+size_t ZSTD_compressContinue(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
}
+size_t ZSTD_getBlockSizeMax(ZSTD_CCtx *cctx) { return MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog); }
-size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
-{
- return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
-}
-
-size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+size_t ZSTD_compressBlock(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
- if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
+ if (srcSize > blockSizeMax)
+ return ERROR(srcSize_wrong);
return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
}
/*! ZSTD_loadDictionaryContent() :
* @return : 0, or an error code
*/
-static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
+static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx *zc, const void *src, size_t srcSize)
{
- const BYTE* const ip = (const BYTE*) src;
- const BYTE* const iend = ip + srcSize;
+ const BYTE *const ip = (const BYTE *)src;
+ const BYTE *const iend = ip + srcSize;
- /* input becomes current prefix */
+ /* input becomes curr prefix */
zc->lowLimit = zc->dictLimit;
zc->dictLimit = (U32)(zc->nextSrc - zc->base);
zc->dictBase = zc->base;
@@ -2506,55 +2563,52 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t
zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
zc->nextSrc = iend;
- if (srcSize <= HASH_READ_SIZE) return 0;
+ if (srcSize <= HASH_READ_SIZE)
+ return 0;
- switch(zc->params.cParams.strategy)
- {
- case ZSTD_fast:
- ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
- break;
+ switch (zc->params.cParams.strategy) {
+ case ZSTD_fast: ZSTD_fillHashTable(zc, iend, zc->params.cParams.searchLength); break;
- case ZSTD_dfast:
- ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
- break;
+ case ZSTD_dfast: ZSTD_fillDoubleHashTable(zc, iend, zc->params.cParams.searchLength); break;
case ZSTD_greedy:
case ZSTD_lazy:
case ZSTD_lazy2:
if (srcSize >= HASH_READ_SIZE)
- ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
+ ZSTD_insertAndFindFirstIndex(zc, iend - HASH_READ_SIZE, zc->params.cParams.searchLength);
break;
case ZSTD_btlazy2:
case ZSTD_btopt:
case ZSTD_btopt2:
if (srcSize >= HASH_READ_SIZE)
- ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
+ ZSTD_updateTree(zc, iend - HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
break;
default:
- return ERROR(GENERIC); /* strategy doesn't exist; impossible */
+ return ERROR(GENERIC); /* strategy doesn't exist; impossible */
}
zc->nextToUpdate = (U32)(iend - zc->base);
return 0;
}
-
/* Dictionaries that assign zero probability to symbols that show up causes problems
when FSE encoding. Refuse dictionaries that assign zero probability to symbols
that we may encounter during compression.
NOTE: This behavior is not standard and could be improved in the future. */
-static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
+static size_t ZSTD_checkDictNCount(short *normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue)
+{
U32 s;
- if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
+ if (dictMaxSymbolValue < maxSymbolValue)
+ return ERROR(dictionary_corrupted);
for (s = 0; s <= maxSymbolValue; ++s) {
- if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
+ if (normalizedCounter[s] == 0)
+ return ERROR(dictionary_corrupted);
}
return 0;
}
-
/* Dictionary format :
* See :
* https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
@@ -2564,74 +2618,94 @@ static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSym
* assumptions : magic number supposed already checked
* dictSize supposed > 8
*/
-static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx *cctx, const void *dict, size_t dictSize)
{
- const BYTE* dictPtr = (const BYTE*)dict;
- const BYTE* const dictEnd = dictPtr + dictSize;
- short offcodeNCount[MaxOff+1];
+ const BYTE *dictPtr = (const BYTE *)dict;
+ const BYTE *const dictEnd = dictPtr + dictSize;
+ short offcodeNCount[MaxOff + 1];
unsigned offcodeMaxValue = MaxOff;
- BYTE scratchBuffer[1<dictID = cctx->params.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
+ dictPtr += 4; /* skip magic number */
+ cctx->dictID = cctx->params.fParams.noDictIDFlag ? 0 : ZSTD_readLE32(dictPtr);
dictPtr += 4;
- { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dictPtr, dictEnd-dictPtr);
- if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
+ {
+ size_t const hufHeaderSize = HUF_readCTable_wksp(cctx->hufTable, 255, dictPtr, dictEnd - dictPtr, cctx->tmpCounters, sizeof(cctx->tmpCounters));
+ if (HUF_isError(hufHeaderSize))
+ return ERROR(dictionary_corrupted);
dictPtr += hufHeaderSize;
}
- { unsigned offcodeLog;
- size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
- if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
- if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
+ {
+ unsigned offcodeLog;
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd - dictPtr);
+ if (FSE_isError(offcodeHeaderSize))
+ return ERROR(dictionary_corrupted);
+ if (offcodeLog > OffFSELog)
+ return ERROR(dictionary_corrupted);
/* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
- CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
+ CHECK_E(FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, cctx->tmpCounters, sizeof(cctx->tmpCounters)),
+ dictionary_corrupted);
dictPtr += offcodeHeaderSize;
}
- { short matchlengthNCount[MaxML+1];
+ {
+ short matchlengthNCount[MaxML + 1];
unsigned matchlengthMaxValue = MaxML, matchlengthLog;
- size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
- if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
- if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
+ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd - dictPtr);
+ if (FSE_isError(matchlengthHeaderSize))
+ return ERROR(dictionary_corrupted);
+ if (matchlengthLog > MLFSELog)
+ return ERROR(dictionary_corrupted);
/* Every match length code must have non-zero probability */
- CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
- CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
+ CHECK_F(ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
+ CHECK_E(
+ FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, cctx->tmpCounters, sizeof(cctx->tmpCounters)),
+ dictionary_corrupted);
dictPtr += matchlengthHeaderSize;
}
- { short litlengthNCount[MaxLL+1];
+ {
+ short litlengthNCount[MaxLL + 1];
unsigned litlengthMaxValue = MaxLL, litlengthLog;
- size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
- if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
- if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
+ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd - dictPtr);
+ if (FSE_isError(litlengthHeaderSize))
+ return ERROR(dictionary_corrupted);
+ if (litlengthLog > LLFSELog)
+ return ERROR(dictionary_corrupted);
/* Every literal length code must have non-zero probability */
- CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
- CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
+ CHECK_F(ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
+ CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, cctx->tmpCounters, sizeof(cctx->tmpCounters)),
+ dictionary_corrupted);
dictPtr += litlengthHeaderSize;
}
- if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
- cctx->rep[0] = MEM_readLE32(dictPtr+0);
- cctx->rep[1] = MEM_readLE32(dictPtr+4);
- cctx->rep[2] = MEM_readLE32(dictPtr+8);
+ if (dictPtr + 12 > dictEnd)
+ return ERROR(dictionary_corrupted);
+ cctx->rep[0] = ZSTD_readLE32(dictPtr + 0);
+ cctx->rep[1] = ZSTD_readLE32(dictPtr + 4);
+ cctx->rep[2] = ZSTD_readLE32(dictPtr + 8);
dictPtr += 12;
- { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
+ {
+ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
U32 offcodeMax = MaxOff;
if (dictContentSize <= ((U32)-1) - 128 KB) {
U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
- offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
+ offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
}
/* All offset values <= dictContentSize + 128 KB must be representable */
- CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
+ CHECK_F(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
/* All repCodes must be <= dictContentSize and != 0*/
- { U32 u;
- for (u=0; u<3; u++) {
- if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
- if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
- } }
+ {
+ U32 u;
+ for (u = 0; u < 3; u++) {
+ if (cctx->rep[u] == 0)
+ return ERROR(dictionary_corrupted);
+ if (cctx->rep[u] > dictContentSize)
+ return ERROR(dictionary_corrupted);
+ }
+ }
cctx->flagStaticTables = 1;
cctx->flagStaticHufTable = HUF_repeat_valid;
@@ -2641,12 +2715,13 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
/** ZSTD_compress_insertDictionary() :
* @return : 0, or an error code */
-static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
+static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx *cctx, const void *dict, size_t dictSize)
{
- if ((dict==NULL) || (dictSize<=8)) return 0;
+ if ((dict == NULL) || (dictSize <= 8))
+ return 0;
/* dict as pure content */
- if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
+ if ((ZSTD_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
/* dict as zstd dictionary */
@@ -2655,56 +2730,47 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict,
/*! ZSTD_compressBegin_internal() :
* @return : 0, or an error code */
-static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
- const void* dict, size_t dictSize,
- ZSTD_parameters params, U64 pledgedSrcSize)
+static size_t ZSTD_compressBegin_internal(ZSTD_CCtx *cctx, const void *dict, size_t dictSize, ZSTD_parameters params, U64 pledgedSrcSize)
{
ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
}
-
/*! ZSTD_compressBegin_advanced() :
* @return : 0, or an error code */
-size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
- const void* dict, size_t dictSize,
- ZSTD_parameters params, unsigned long long pledgedSrcSize)
+size_t ZSTD_compressBegin_advanced(ZSTD_CCtx *cctx, const void *dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize)
{
/* compression parameters verification and optimization */
CHECK_F(ZSTD_checkCParams(params.cParams));
return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
}
-
-size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
+size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx *cctx, const void *dict, size_t dictSize, int compressionLevel)
{
ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
}
-
-size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
-{
- return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
-}
-
+size_t ZSTD_compressBegin(ZSTD_CCtx *cctx, int compressionLevel) { return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); }
/*! ZSTD_writeEpilogue() :
* Ends a frame.
* @return : nb of bytes written into dst (or an error code) */
-static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
+static size_t ZSTD_writeEpilogue(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity)
{
- BYTE* const ostart = (BYTE*)dst;
- BYTE* op = ostart;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *op = ostart;
size_t fhSize = 0;
- if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
+ if (cctx->stage == ZSTDcs_created)
+ return ERROR(stage_wrong); /* init missing */
/* special case : empty frame */
if (cctx->stage == ZSTDcs_init) {
fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
- if (ZSTD_isError(fhSize)) return fhSize;
+ if (ZSTD_isError(fhSize))
+ return fhSize;
dstCapacity -= fhSize;
op += fhSize;
cctx->stage = ZSTDcs_ongoing;
@@ -2712,81 +2778,75 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
if (cctx->stage != ZSTDcs_ending) {
/* write one last empty block, make it the "last" block */
- U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
- if (dstCapacity<4) return ERROR(dstSize_tooSmall);
- MEM_writeLE32(op, cBlockHeader24);
+ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw) << 1) + 0;
+ if (dstCapacity < 4)
+ return ERROR(dstSize_tooSmall);
+ ZSTD_writeLE32(op, cBlockHeader24);
op += ZSTD_blockHeaderSize;
dstCapacity -= ZSTD_blockHeaderSize;
}
if (cctx->params.fParams.checksumFlag) {
- U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
- if (dstCapacity<4) return ERROR(dstSize_tooSmall);
- MEM_writeLE32(op, checksum);
+ U32 const checksum = (U32)xxh64_digest(&cctx->xxhState);
+ if (dstCapacity < 4)
+ return ERROR(dstSize_tooSmall);
+ ZSTD_writeLE32(op, checksum);
op += 4;
}
- cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
- return op-ostart;
+ cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
+ return op - ostart;
}
-
-size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
+size_t ZSTD_compressEnd(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
size_t endResult;
size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
- if (ZSTD_isError(cSize)) return cSize;
- endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
- if (ZSTD_isError(endResult)) return endResult;
+ if (ZSTD_isError(cSize))
+ return cSize;
+ endResult = ZSTD_writeEpilogue(cctx, (char *)dst + cSize, dstCapacity - cSize);
+ if (ZSTD_isError(endResult))
+ return endResult;
return cSize + endResult;
}
-
-static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void* dict,size_t dictSize,
- ZSTD_parameters params)
+static size_t ZSTD_compress_internal(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize,
+ ZSTD_parameters params)
{
CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
- return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
+ return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
}
-size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, ZSTD_parameters params)
+size_t ZSTD_compress_usingDict(ZSTD_CCtx *ctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize,
+ ZSTD_parameters params)
{
return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
}
-
-size_t ZSTD_compressCCtx(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, ZSTD_parameters params)
+size_t ZSTD_compressCCtx(ZSTD_CCtx *ctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, ZSTD_parameters params)
{
return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, NULL, 0, params);
}
-
/* ===== Dictionary API ===== */
struct ZSTD_CDict_s {
- void* dictBuffer;
- const void* dictContent;
+ void *dictBuffer;
+ const void *dictContent;
size_t dictContentSize;
- ZSTD_CCtx* refContext;
-}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
+ ZSTD_CCtx *refContext;
+}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
-size_t ZSTD_CDictWorkspaceBound(ZSTD_compressionParameters cParams)
+size_t ZSTD_CDictWorkspaceBound(ZSTD_compressionParameters cParams) { return ZSTD_CCtxWorkspaceBound(cParams) + ZSTD_ALIGN(sizeof(ZSTD_CDict)); }
+
+static ZSTD_CDict *ZSTD_createCDict_advanced(const void *dictBuffer, size_t dictSize, unsigned byReference, ZSTD_parameters params, ZSTD_customMem customMem)
{
- return ZSTD_CCtxWorkspaceBound(cParams) + ZSTD_ALIGN(sizeof(ZSTD_CDict));
-}
+ if (!customMem.customAlloc || !customMem.customFree)
+ return NULL;
-static ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
- ZSTD_parameters params, ZSTD_customMem customMem)
-{
- if (!customMem.customAlloc || !customMem.customFree) return NULL;
-
- { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
- ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
+ {
+ ZSTD_CDict *const cdict = (ZSTD_CDict *)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
+ ZSTD_CCtx *const cctx = ZSTD_createCCtx_advanced(customMem);
if (!cdict || !cctx) {
ZSTD_free(cdict, customMem);
@@ -2798,20 +2858,26 @@ static ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dict
cdict->dictBuffer = NULL;
cdict->dictContent = dictBuffer;
} else {
- void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
- if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
+ void *const internalBuffer = ZSTD_malloc(dictSize, customMem);
+ if (!internalBuffer) {
+ ZSTD_free(cctx, customMem);
+ ZSTD_free(cdict, customMem);
+ return NULL;
+ }
memcpy(internalBuffer, dictBuffer, dictSize);
cdict->dictBuffer = internalBuffer;
cdict->dictContent = internalBuffer;
}
- { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
+ {
+ size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
if (ZSTD_isError(errorCode)) {
ZSTD_free(cdict->dictBuffer, customMem);
ZSTD_free(cdict, customMem);
ZSTD_freeCCtx(cctx);
return NULL;
- } }
+ }
+ }
cdict->refContext = cctx;
cdict->dictContentSize = dictSize;
@@ -2819,16 +2885,18 @@ static ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dict
}
}
-ZSTD_CDict* ZSTD_initCDict(const void* dict, size_t dictSize, ZSTD_parameters params, void* workspace, size_t workspaceSize)
+ZSTD_CDict *ZSTD_initCDict(const void *dict, size_t dictSize, ZSTD_parameters params, void *workspace, size_t workspaceSize)
{
ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
return ZSTD_createCDict_advanced(dict, dictSize, 1, params, stackMem);
}
-size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
+size_t ZSTD_freeCDict(ZSTD_CDict *cdict)
{
- if (cdict==NULL) return 0; /* support free on NULL */
- { ZSTD_customMem const cMem = cdict->refContext->customMem;
+ if (cdict == NULL)
+ return 0; /* support free on NULL */
+ {
+ ZSTD_customMem const cMem = cdict->refContext->customMem;
ZSTD_freeCCtx(cdict->refContext);
ZSTD_free(cdict->dictBuffer, cMem);
ZSTD_free(cdict, cMem);
@@ -2836,13 +2904,12 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
}
}
-static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
- return ZSTD_getParamsFromCCtx(cdict->refContext);
-}
+static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict *cdict) { return ZSTD_getParamsFromCCtx(cdict->refContext); }
-size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize)
+size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx *cctx, const ZSTD_CDict *cdict, unsigned long long pledgedSrcSize)
{
- if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
+ if (cdict->dictContentSize)
+ CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
else {
ZSTD_parameters params = cdict->refContext->params;
params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
@@ -2855,14 +2922,11 @@ size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, u
* Compression using a digested Dictionary.
* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
* Note that compression level is decided during dictionary creation */
-size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_CDict* cdict)
+size_t ZSTD_compress_usingCDict(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const ZSTD_CDict *cdict)
{
CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
- if (cdict->refContext->params.fParams.contentSizeFlag==1) {
+ if (cdict->refContext->params.fParams.contentSizeFlag == 1) {
cctx->params.fParams.contentSizeFlag = 1;
cctx->frameContentSize = srcSize;
} else {
@@ -2872,8 +2936,6 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
}
-
-
/* ******************************************************************
* Streaming
********************************************************************/
@@ -2881,27 +2943,27 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
struct ZSTD_CStream_s {
- ZSTD_CCtx* cctx;
- ZSTD_CDict* cdictLocal;
- const ZSTD_CDict* cdict;
- char* inBuff;
+ ZSTD_CCtx *cctx;
+ ZSTD_CDict *cdictLocal;
+ const ZSTD_CDict *cdict;
+ char *inBuff;
size_t inBuffSize;
size_t inToCompress;
size_t inBuffPos;
size_t inBuffTarget;
size_t blockSize;
- char* outBuff;
+ char *outBuff;
size_t outBuffSize;
size_t outBuffContentSize;
size_t outBuffFlushedSize;
ZSTD_cStreamStage stage;
- U32 checksum;
- U32 frameEnded;
- U64 pledgedSrcSize;
- U64 inputProcessed;
+ U32 checksum;
+ U32 frameEnded;
+ U64 pledgedSrcSize;
+ U64 inputProcessed;
ZSTD_parameters params;
ZSTD_customMem customMem;
-}; /* typedef'd to ZSTD_CStream within "zstd.h" */
+}; /* typedef'd to ZSTD_CStream within "zstd.h" */
size_t ZSTD_CStreamWorkspaceBound(ZSTD_compressionParameters cParams)
{
@@ -2912,25 +2974,32 @@ size_t ZSTD_CStreamWorkspaceBound(ZSTD_compressionParameters cParams)
return ZSTD_CCtxWorkspaceBound(cParams) + ZSTD_ALIGN(sizeof(ZSTD_CStream)) + ZSTD_ALIGN(inBuffSize) + ZSTD_ALIGN(outBuffSize);
}
-ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
+ZSTD_CStream *ZSTD_createCStream_advanced(ZSTD_customMem customMem)
{
- ZSTD_CStream* zcs;
+ ZSTD_CStream *zcs;
- if (!customMem.customAlloc || !customMem.customFree) return NULL;
+ if (!customMem.customAlloc || !customMem.customFree)
+ return NULL;
- zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
- if (zcs==NULL) return NULL;
+ zcs = (ZSTD_CStream *)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
+ if (zcs == NULL)
+ return NULL;
memset(zcs, 0, sizeof(ZSTD_CStream));
memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
zcs->cctx = ZSTD_createCCtx_advanced(customMem);
- if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
+ if (zcs->cctx == NULL) {
+ ZSTD_freeCStream(zcs);
+ return NULL;
+ }
return zcs;
}
-size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
+size_t ZSTD_freeCStream(ZSTD_CStream *zcs)
{
- if (zcs==NULL) return 0; /* support free on NULL */
- { ZSTD_customMem const cMem = zcs->customMem;
+ if (zcs == NULL)
+ return 0; /* support free on NULL */
+ {
+ ZSTD_customMem const cMem = zcs->customMem;
ZSTD_freeCCtx(zcs->cctx);
zcs->cctx = NULL;
ZSTD_freeCDict(zcs->cdictLocal);
@@ -2944,18 +3013,20 @@ size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
}
}
-
/*====== Initialization ======*/
-size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
-size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
+size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
+size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */; }
-static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
+static size_t ZSTD_resetCStream_internal(ZSTD_CStream *zcs, unsigned long long pledgedSrcSize)
{
- if (zcs->inBuffSize==0) return ERROR(stage_wrong); /* zcs has not been init at least once => can't reset */
+ if (zcs->inBuffSize == 0)
+ return ERROR(stage_wrong); /* zcs has not been init at least once => can't reset */
- if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
- else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
+ if (zcs->cdict)
+ CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
+ else
+ CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
zcs->inToCompress = 0;
zcs->inBuffPos = 0;
@@ -2965,10 +3036,10 @@ static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long p
zcs->frameEnded = 0;
zcs->pledgedSrcSize = pledgedSrcSize;
zcs->inputProcessed = 0;
- return 0; /* ready to go */
+ return 0; /* ready to go */
}
-size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
+size_t ZSTD_resetCStream(ZSTD_CStream *zcs, unsigned long long pledgedSrcSize)
{
zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
@@ -2976,33 +3047,36 @@ size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
}
-static size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
- const void* dict, size_t dictSize,
- ZSTD_parameters params, unsigned long long pledgedSrcSize)
+static size_t ZSTD_initCStream_advanced(ZSTD_CStream *zcs, const void *dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize)
{
/* allocate buffers */
- { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
+ {
+ size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
if (zcs->inBuffSize < neededInBuffSize) {
zcs->inBuffSize = neededInBuffSize;
ZSTD_free(zcs->inBuff, zcs->customMem);
- zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
- if (zcs->inBuff == NULL) return ERROR(memory_allocation);
+ zcs->inBuff = (char *)ZSTD_malloc(neededInBuffSize, zcs->customMem);
+ if (zcs->inBuff == NULL)
+ return ERROR(memory_allocation);
}
zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
}
- if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
- zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
+ if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize) + 1) {
+ zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize) + 1;
ZSTD_free(zcs->outBuff, zcs->customMem);
- zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
- if (zcs->outBuff == NULL) return ERROR(memory_allocation);
+ zcs->outBuff = (char *)ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
+ if (zcs->outBuff == NULL)
+ return ERROR(memory_allocation);
}
if (dict && dictSize >= 8) {
ZSTD_freeCDict(zcs->cdictLocal);
zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
- if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
+ if (zcs->cdictLocal == NULL)
+ return ERROR(memory_allocation);
zcs->cdict = zcs->cdictLocal;
- } else zcs->cdict = NULL;
+ } else
+ zcs->cdict = NULL;
zcs->checksum = params.fParams.checksumFlag > 0;
zcs->params = params;
@@ -3010,21 +3084,23 @@ static size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
}
-ZSTD_CStream* ZSTD_initCStream(ZSTD_parameters params, unsigned long long pledgedSrcSize, void* workspace, size_t workspaceSize)
+ZSTD_CStream *ZSTD_initCStream(ZSTD_parameters params, unsigned long long pledgedSrcSize, void *workspace, size_t workspaceSize)
{
ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
- ZSTD_CStream* const zcs = ZSTD_createCStream_advanced(stackMem);
+ ZSTD_CStream *const zcs = ZSTD_createCStream_advanced(stackMem);
if (zcs) {
size_t const code = ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
- if (ZSTD_isError(code)) { return NULL; }
+ if (ZSTD_isError(code)) {
+ return NULL;
+ }
}
return zcs;
}
-ZSTD_CStream* ZSTD_initCStream_usingCDict(const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize, void* workspace, size_t workspaceSize)
+ZSTD_CStream *ZSTD_initCStream_usingCDict(const ZSTD_CDict *cdict, unsigned long long pledgedSrcSize, void *workspace, size_t workspaceSize)
{
ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
- ZSTD_CStream* const zcs = ZSTD_initCStream(params, pledgedSrcSize, workspace, workspaceSize);
+ ZSTD_CStream *const zcs = ZSTD_initCStream(params, pledgedSrcSize, workspace, workspaceSize);
if (zcs) {
zcs->cdict = cdict;
if (ZSTD_isError(ZSTD_resetCStream_internal(zcs, pledgedSrcSize))) {
@@ -3038,140 +3114,149 @@ ZSTD_CStream* ZSTD_initCStream_usingCDict(const ZSTD_CDict* cdict, unsigned long
typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
-MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+ZSTD_STATIC size_t ZSTD_limitCopy(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
size_t const length = MIN(dstCapacity, srcSize);
memcpy(dst, src, length);
return length;
}
-static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
- void* dst, size_t* dstCapacityPtr,
- const void* src, size_t* srcSizePtr,
- ZSTD_flush_e const flush)
+static size_t ZSTD_compressStream_generic(ZSTD_CStream *zcs, void *dst, size_t *dstCapacityPtr, const void *src, size_t *srcSizePtr, ZSTD_flush_e const flush)
{
U32 someMoreWork = 1;
- const char* const istart = (const char*)src;
- const char* const iend = istart + *srcSizePtr;
- const char* ip = istart;
- char* const ostart = (char*)dst;
- char* const oend = ostart + *dstCapacityPtr;
- char* op = ostart;
+ const char *const istart = (const char *)src;
+ const char *const iend = istart + *srcSizePtr;
+ const char *ip = istart;
+ char *const ostart = (char *)dst;
+ char *const oend = ostart + *dstCapacityPtr;
+ char *op = ostart;
while (someMoreWork) {
- switch(zcs->stage)
- {
- case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
+ switch (zcs->stage) {
+ case zcss_init:
+ return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
case zcss_load:
/* complete inBuffer */
- { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
- size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
+ {
+ size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
+ size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend - ip);
zcs->inBuffPos += loaded;
ip += loaded;
- if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
- someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
- } }
- /* compress current block (note : this stage cannot be stopped in the middle) */
- { void* cDst;
+ if ((zcs->inBuffPos == zcs->inToCompress) || (!flush && (toLoad != loaded))) {
+ someMoreWork = 0;
+ break; /* not enough input to get a full block : stop there, wait for more */
+ }
+ }
+ /* compress curr block (note : this stage cannot be stopped in the middle) */
+ {
+ void *cDst;
size_t cSize;
size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
- size_t oSize = oend-op;
+ size_t oSize = oend - op;
if (oSize >= ZSTD_compressBound(iSize))
- cDst = op; /* compress directly into output buffer (avoid flush stage) */
+ cDst = op; /* compress directly into output buffer (avoid flush stage) */
else
cDst = zcs->outBuff, oSize = zcs->outBuffSize;
- cSize = (flush == zsf_end) ?
- ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
- ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
- if (ZSTD_isError(cSize)) return cSize;
- if (flush == zsf_end) zcs->frameEnded = 1;
+ cSize = (flush == zsf_end) ? ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize)
+ : ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
+ if (ZSTD_isError(cSize))
+ return cSize;
+ if (flush == zsf_end)
+ zcs->frameEnded = 1;
/* prepare next block */
zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
if (zcs->inBuffTarget > zcs->inBuffSize)
- zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
+ zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
zcs->inToCompress = zcs->inBuffPos;
- if (cDst == op) { op += cSize; break; } /* no need to flush */
+ if (cDst == op) {
+ op += cSize;
+ break;
+ } /* no need to flush */
zcs->outBuffContentSize = cSize;
zcs->outBuffFlushedSize = 0;
- zcs->stage = zcss_flush; /* pass-through to flush stage */
+ zcs->stage = zcss_flush; /* pass-through to flush stage */
}
- case zcss_flush:
- { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
- size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
- op += flushed;
- zcs->outBuffFlushedSize += flushed;
- if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
- zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
- zcs->stage = zcss_load;
+ case zcss_flush: {
+ size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
+ size_t const flushed = ZSTD_limitCopy(op, oend - op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
+ op += flushed;
+ zcs->outBuffFlushedSize += flushed;
+ if (toFlush != flushed) {
+ someMoreWork = 0;
break;
- }
+ } /* dst too small to store flushed data : stop there */
+ zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
+ zcs->stage = zcss_load;
+ break;
+ }
case zcss_final:
- someMoreWork = 0; /* do nothing */
+ someMoreWork = 0; /* do nothing */
break;
default:
- return ERROR(GENERIC); /* impossible */
+ return ERROR(GENERIC); /* impossible */
}
}
*srcSizePtr = ip - istart;
*dstCapacityPtr = op - ostart;
zcs->inputProcessed += *srcSizePtr;
- if (zcs->frameEnded) return 0;
- { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
- if (hintInSize==0) hintInSize = zcs->blockSize;
+ if (zcs->frameEnded)
+ return 0;
+ {
+ size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
+ if (hintInSize == 0)
+ hintInSize = zcs->blockSize;
return hintInSize;
}
}
-size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+size_t ZSTD_compressStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output, ZSTD_inBuffer *input)
{
size_t sizeRead = input->size - input->pos;
size_t sizeWritten = output->size - output->pos;
- size_t const result = ZSTD_compressStream_generic(zcs,
- (char*)(output->dst) + output->pos, &sizeWritten,
- (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
+ size_t const result =
+ ZSTD_compressStream_generic(zcs, (char *)(output->dst) + output->pos, &sizeWritten, (const char *)(input->src) + input->pos, &sizeRead, zsf_gather);
input->pos += sizeRead;
output->pos += sizeWritten;
return result;
}
-
/*====== Finalize ======*/
/*! ZSTD_flushStream() :
* @return : amount of data remaining to flush */
-size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
+size_t ZSTD_flushStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output)
{
size_t srcSize = 0;
size_t sizeWritten = output->size - output->pos;
- size_t const result = ZSTD_compressStream_generic(zcs,
- (char*)(output->dst) + output->pos, &sizeWritten,
- &srcSize, &srcSize, /* use a valid src address instead of NULL */
- zsf_flush);
+ size_t const result = ZSTD_compressStream_generic(zcs, (char *)(output->dst) + output->pos, &sizeWritten, &srcSize,
+ &srcSize, /* use a valid src address instead of NULL */
+ zsf_flush);
output->pos += sizeWritten;
- if (ZSTD_isError(result)) return result;
- return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
+ if (ZSTD_isError(result))
+ return result;
+ return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
}
-
-size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
+size_t ZSTD_endStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output)
{
- BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
- BYTE* const oend = (BYTE*)(output->dst) + output->size;
- BYTE* op = ostart;
+ BYTE *const ostart = (BYTE *)(output->dst) + output->pos;
+ BYTE *const oend = (BYTE *)(output->dst) + output->size;
+ BYTE *op = ostart;
if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
- return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
+ return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
if (zcs->stage != zcss_final) {
/* flush whatever remains */
size_t srcSize = 0;
size_t sizeWritten = output->size - output->pos;
- size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
+ size_t const notEnded =
+ ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
op += sizeWritten;
if (remainingToFlush) {
@@ -3180,134 +3265,138 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
}
/* create epilogue */
zcs->stage = zcss_final;
- zcs->outBuffContentSize = !notEnded ? 0 :
- ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL, 0); /* write epilogue, including final empty block, into outBuff */
+ zcs->outBuffContentSize = !notEnded ? 0 : ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL,
+ 0); /* write epilogue, including final empty block, into outBuff */
}
/* flush epilogue */
- { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
- size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
+ {
+ size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
+ size_t const flushed = ZSTD_limitCopy(op, oend - op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
op += flushed;
zcs->outBuffFlushedSize += flushed;
- output->pos += op-ostart;
- if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
+ output->pos += op - ostart;
+ if (toFlush == flushed)
+ zcs->stage = zcss_init; /* end reached */
return toFlush - flushed;
}
}
-
-
/*-===== Pre-defined compression levels =====-*/
#define ZSTD_DEFAULT_CLEVEL 1
-#define ZSTD_MAX_CLEVEL 22
+#define ZSTD_MAX_CLEVEL 22
int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
-static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
-{ /* "default" */
+static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL + 1] = {
+ {
+ /* "default" */
/* W, C, H, S, L, TL, strat */
- { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
- { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
- { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
- { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
- { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
- { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
- { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
- { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
- { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
- { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
- { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
- { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
- { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
- { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
- { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
- { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
- { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
- { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
- { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
- { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
- { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
- { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
- { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
-},
-{ /* for srcSize <= 256 KB */
+ {18, 12, 12, 1, 7, 16, ZSTD_fast}, /* level 0 - never used */
+ {19, 13, 14, 1, 7, 16, ZSTD_fast}, /* level 1 */
+ {19, 15, 16, 1, 6, 16, ZSTD_fast}, /* level 2 */
+ {20, 16, 17, 1, 5, 16, ZSTD_dfast}, /* level 3.*/
+ {20, 18, 18, 1, 5, 16, ZSTD_dfast}, /* level 4.*/
+ {20, 15, 18, 3, 5, 16, ZSTD_greedy}, /* level 5 */
+ {21, 16, 19, 2, 5, 16, ZSTD_lazy}, /* level 6 */
+ {21, 17, 20, 3, 5, 16, ZSTD_lazy}, /* level 7 */
+ {21, 18, 20, 3, 5, 16, ZSTD_lazy2}, /* level 8 */
+ {21, 20, 20, 3, 5, 16, ZSTD_lazy2}, /* level 9 */
+ {21, 19, 21, 4, 5, 16, ZSTD_lazy2}, /* level 10 */
+ {22, 20, 22, 4, 5, 16, ZSTD_lazy2}, /* level 11 */
+ {22, 20, 22, 5, 5, 16, ZSTD_lazy2}, /* level 12 */
+ {22, 21, 22, 5, 5, 16, ZSTD_lazy2}, /* level 13 */
+ {22, 21, 22, 6, 5, 16, ZSTD_lazy2}, /* level 14 */
+ {22, 21, 21, 5, 5, 16, ZSTD_btlazy2}, /* level 15 */
+ {23, 22, 22, 5, 5, 16, ZSTD_btlazy2}, /* level 16 */
+ {23, 21, 22, 4, 5, 24, ZSTD_btopt}, /* level 17 */
+ {23, 23, 22, 6, 5, 32, ZSTD_btopt}, /* level 18 */
+ {23, 23, 22, 6, 3, 48, ZSTD_btopt}, /* level 19 */
+ {25, 25, 23, 7, 3, 64, ZSTD_btopt2}, /* level 20 */
+ {26, 26, 23, 7, 3, 256, ZSTD_btopt2}, /* level 21 */
+ {27, 27, 25, 9, 3, 512, ZSTD_btopt2}, /* level 22 */
+ },
+ {
+ /* for srcSize <= 256 KB */
/* W, C, H, S, L, T, strat */
- { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
- { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
- { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
- { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
- { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
- { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
- { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
- { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
- { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
- { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
- { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
- { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
- { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
- { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
- { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
- { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
- { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
- { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
- { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
- { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
- { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
- { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
- { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
-},
-{ /* for srcSize <= 128 KB */
+ {0, 0, 0, 0, 0, 0, ZSTD_fast}, /* level 0 - not used */
+ {18, 13, 14, 1, 6, 8, ZSTD_fast}, /* level 1 */
+ {18, 14, 13, 1, 5, 8, ZSTD_dfast}, /* level 2 */
+ {18, 16, 15, 1, 5, 8, ZSTD_dfast}, /* level 3 */
+ {18, 15, 17, 1, 5, 8, ZSTD_greedy}, /* level 4.*/
+ {18, 16, 17, 4, 5, 8, ZSTD_greedy}, /* level 5.*/
+ {18, 16, 17, 3, 5, 8, ZSTD_lazy}, /* level 6.*/
+ {18, 17, 17, 4, 4, 8, ZSTD_lazy}, /* level 7 */
+ {18, 17, 17, 4, 4, 8, ZSTD_lazy2}, /* level 8 */
+ {18, 17, 17, 5, 4, 8, ZSTD_lazy2}, /* level 9 */
+ {18, 17, 17, 6, 4, 8, ZSTD_lazy2}, /* level 10 */
+ {18, 18, 17, 6, 4, 8, ZSTD_lazy2}, /* level 11.*/
+ {18, 18, 17, 7, 4, 8, ZSTD_lazy2}, /* level 12.*/
+ {18, 19, 17, 6, 4, 8, ZSTD_btlazy2}, /* level 13 */
+ {18, 18, 18, 4, 4, 16, ZSTD_btopt}, /* level 14.*/
+ {18, 18, 18, 4, 3, 16, ZSTD_btopt}, /* level 15.*/
+ {18, 19, 18, 6, 3, 32, ZSTD_btopt}, /* level 16.*/
+ {18, 19, 18, 8, 3, 64, ZSTD_btopt}, /* level 17.*/
+ {18, 19, 18, 9, 3, 128, ZSTD_btopt}, /* level 18.*/
+ {18, 19, 18, 10, 3, 256, ZSTD_btopt}, /* level 19.*/
+ {18, 19, 18, 11, 3, 512, ZSTD_btopt2}, /* level 20.*/
+ {18, 19, 18, 12, 3, 512, ZSTD_btopt2}, /* level 21.*/
+ {18, 19, 18, 13, 3, 512, ZSTD_btopt2}, /* level 22.*/
+ },
+ {
+ /* for srcSize <= 128 KB */
/* W, C, H, S, L, T, strat */
- { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
- { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
- { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
- { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
- { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
- { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
- { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
- { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
- { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
- { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
- { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
- { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
- { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
- { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
- { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
- { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
- { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
- { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
- { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
- { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
- { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
- { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
- { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
-},
-{ /* for srcSize <= 16 KB */
+ {17, 12, 12, 1, 7, 8, ZSTD_fast}, /* level 0 - not used */
+ {17, 12, 13, 1, 6, 8, ZSTD_fast}, /* level 1 */
+ {17, 13, 16, 1, 5, 8, ZSTD_fast}, /* level 2 */
+ {17, 16, 16, 2, 5, 8, ZSTD_dfast}, /* level 3 */
+ {17, 13, 15, 3, 4, 8, ZSTD_greedy}, /* level 4 */
+ {17, 15, 17, 4, 4, 8, ZSTD_greedy}, /* level 5 */
+ {17, 16, 17, 3, 4, 8, ZSTD_lazy}, /* level 6 */
+ {17, 15, 17, 4, 4, 8, ZSTD_lazy2}, /* level 7 */
+ {17, 17, 17, 4, 4, 8, ZSTD_lazy2}, /* level 8 */
+ {17, 17, 17, 5, 4, 8, ZSTD_lazy2}, /* level 9 */
+ {17, 17, 17, 6, 4, 8, ZSTD_lazy2}, /* level 10 */
+ {17, 17, 17, 7, 4, 8, ZSTD_lazy2}, /* level 11 */
+ {17, 17, 17, 8, 4, 8, ZSTD_lazy2}, /* level 12 */
+ {17, 18, 17, 6, 4, 8, ZSTD_btlazy2}, /* level 13.*/
+ {17, 17, 17, 7, 3, 8, ZSTD_btopt}, /* level 14.*/
+ {17, 17, 17, 7, 3, 16, ZSTD_btopt}, /* level 15.*/
+ {17, 18, 17, 7, 3, 32, ZSTD_btopt}, /* level 16.*/
+ {17, 18, 17, 7, 3, 64, ZSTD_btopt}, /* level 17.*/
+ {17, 18, 17, 7, 3, 256, ZSTD_btopt}, /* level 18.*/
+ {17, 18, 17, 8, 3, 256, ZSTD_btopt}, /* level 19.*/
+ {17, 18, 17, 9, 3, 256, ZSTD_btopt2}, /* level 20.*/
+ {17, 18, 17, 10, 3, 256, ZSTD_btopt2}, /* level 21.*/
+ {17, 18, 17, 11, 3, 512, ZSTD_btopt2}, /* level 22.*/
+ },
+ {
+ /* for srcSize <= 16 KB */
/* W, C, H, S, L, T, strat */
- { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
- { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
- { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
- { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
- { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
- { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
- { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
- { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
- { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
- { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
- { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
- { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
- { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
- { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
- { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
- { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
- { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
- { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
- { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
- { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
- { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
- { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
- { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
-},
+ {14, 12, 12, 1, 7, 6, ZSTD_fast}, /* level 0 - not used */
+ {14, 14, 14, 1, 6, 6, ZSTD_fast}, /* level 1 */
+ {14, 14, 14, 1, 4, 6, ZSTD_fast}, /* level 2 */
+ {14, 14, 14, 1, 4, 6, ZSTD_dfast}, /* level 3.*/
+ {14, 14, 14, 4, 4, 6, ZSTD_greedy}, /* level 4.*/
+ {14, 14, 14, 3, 4, 6, ZSTD_lazy}, /* level 5.*/
+ {14, 14, 14, 4, 4, 6, ZSTD_lazy2}, /* level 6 */
+ {14, 14, 14, 5, 4, 6, ZSTD_lazy2}, /* level 7 */
+ {14, 14, 14, 6, 4, 6, ZSTD_lazy2}, /* level 8.*/
+ {14, 15, 14, 6, 4, 6, ZSTD_btlazy2}, /* level 9.*/
+ {14, 15, 14, 3, 3, 6, ZSTD_btopt}, /* level 10.*/
+ {14, 15, 14, 6, 3, 8, ZSTD_btopt}, /* level 11.*/
+ {14, 15, 14, 6, 3, 16, ZSTD_btopt}, /* level 12.*/
+ {14, 15, 14, 6, 3, 24, ZSTD_btopt}, /* level 13.*/
+ {14, 15, 15, 6, 3, 48, ZSTD_btopt}, /* level 14.*/
+ {14, 15, 15, 6, 3, 64, ZSTD_btopt}, /* level 15.*/
+ {14, 15, 15, 6, 3, 96, ZSTD_btopt}, /* level 16.*/
+ {14, 15, 15, 6, 3, 128, ZSTD_btopt}, /* level 17.*/
+ {14, 15, 15, 6, 3, 256, ZSTD_btopt}, /* level 18.*/
+ {14, 15, 15, 7, 3, 256, ZSTD_btopt}, /* level 19.*/
+ {14, 15, 15, 8, 3, 256, ZSTD_btopt2}, /* level 20.*/
+ {14, 15, 15, 9, 3, 256, ZSTD_btopt2}, /* level 21.*/
+ {14, 15, 15, 10, 3, 256, ZSTD_btopt2}, /* level 22.*/
+ },
};
/*! ZSTD_getCParams() :
@@ -3317,15 +3406,20 @@ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long l
{
ZSTD_compressionParameters cp;
size_t const addedSize = srcSize ? 0 : 500;
- U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
- U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
- if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
- if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
+ U64 const rSize = srcSize + dictSize ? srcSize + dictSize + addedSize : (U64)-1;
+ U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
+ if (compressionLevel <= 0)
+ compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
+ if (compressionLevel > ZSTD_MAX_CLEVEL)
+ compressionLevel = ZSTD_MAX_CLEVEL;
cp = ZSTD_defaultCParameters[tableID][compressionLevel];
- if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
- if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
- if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
- if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
+ if (ZSTD_32bits()) { /* auto-correction, for 32-bits mode */
+ if (cp.windowLog > ZSTD_WINDOWLOG_MAX)
+ cp.windowLog = ZSTD_WINDOWLOG_MAX;
+ if (cp.chainLog > ZSTD_CHAINLOG_MAX)
+ cp.chainLog = ZSTD_CHAINLOG_MAX;
+ if (cp.hashLog > ZSTD_HASHLOG_MAX)
+ cp.hashLog = ZSTD_HASHLOG_MAX;
}
cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
return cp;
@@ -3334,7 +3428,8 @@ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long l
/*! ZSTD_getParams() :
* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
* All fields of `ZSTD_frameParameters` are set to default (0) */
-ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
+ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
+{
ZSTD_parameters params;
ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
memset(¶ms, 0, sizeof(params));
@@ -3380,5 +3475,5 @@ EXPORT_SYMBOL(ZSTD_compressEnd);
EXPORT_SYMBOL(ZSTD_getBlockSizeMax);
EXPORT_SYMBOL(ZSTD_compressBlock);
-MODULE_LICENSE("BSD");
+MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Zstd Compressor");
diff --git a/contrib/linux-kernel/lib/zstd/decompress.c b/contrib/linux-kernel/lib/zstd/decompress.c
index 94f5fd560..62449ae05 100644
--- a/contrib/linux-kernel/lib/zstd/decompress.c
+++ b/contrib/linux-kernel/lib/zstd/decompress.c
@@ -3,11 +3,17 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
+ * LICENSE file in the root directory of https://github.com/facebook/zstd.
+ * An additional grant of patent rights can be found in the PATENTS file in the
+ * same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
*/
-
/* ***************************************************************
* Tuning parameters
*****************************************************************/
@@ -17,87 +23,87 @@
* Frames requiring more memory will be rejected.
*/
#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
-# define ZSTD_MAXWINDOWSIZE_DEFAULT ((1 << ZSTD_WINDOWLOG_MAX) + 1) /* defined within zstd.h */
+#define ZSTD_MAXWINDOWSIZE_DEFAULT ((1 << ZSTD_WINDOWLOG_MAX) + 1) /* defined within zstd.h */
#endif
-
/*-*******************************************************
* Dependencies
*********************************************************/
-#include
-#include
-#include /* memcpy, memmove, memset */
-#include "mem.h" /* low level memory routines */
#include "fse.h"
#include "huf.h"
+#include "mem.h" /* low level memory routines */
#include "zstd_internal.h"
+#include
+#include
+#include /* memcpy, memmove, memset */
-#define ZSTD_PREFETCH(ptr) __builtin_prefetch(ptr, 0, 0)
+#define ZSTD_PREFETCH(ptr) __builtin_prefetch(ptr, 0, 0)
/*-*************************************
* Macros
***************************************/
-#define ZSTD_isError ERR_isError /* for inlining */
-#define FSE_isError ERR_isError
-#define HUF_isError ERR_isError
-
+#define ZSTD_isError ERR_isError /* for inlining */
+#define FSE_isError ERR_isError
+#define HUF_isError ERR_isError
/*_*******************************************************
* Memory operations
**********************************************************/
-static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); }
-
+static void ZSTD_copy4(void *dst, const void *src) { memcpy(dst, src, 4); }
/*-*************************************************************
* Context management
***************************************************************/
-typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader,
- ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock,
- ZSTDds_decompressLastBlock, ZSTDds_checkChecksum,
- ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage;
+typedef enum {
+ ZSTDds_getFrameHeaderSize,
+ ZSTDds_decodeFrameHeader,
+ ZSTDds_decodeBlockHeader,
+ ZSTDds_decompressBlock,
+ ZSTDds_decompressLastBlock,
+ ZSTDds_checkChecksum,
+ ZSTDds_decodeSkippableHeader,
+ ZSTDds_skipFrame
+} ZSTD_dStage;
typedef struct {
FSE_DTable LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)];
FSE_DTable OFTable[FSE_DTABLE_SIZE_U32(OffFSELog)];
FSE_DTable MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)];
- HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
+ HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */
+ U64 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32 / 2];
U32 rep[ZSTD_REP_NUM];
} ZSTD_entropyTables_t;
-struct ZSTD_DCtx_s
-{
- const FSE_DTable* LLTptr;
- const FSE_DTable* MLTptr;
- const FSE_DTable* OFTptr;
- const HUF_DTable* HUFptr;
+struct ZSTD_DCtx_s {
+ const FSE_DTable *LLTptr;
+ const FSE_DTable *MLTptr;
+ const FSE_DTable *OFTptr;
+ const HUF_DTable *HUFptr;
ZSTD_entropyTables_t entropy;
- const void* previousDstEnd; /* detect continuity */
- const void* base; /* start of current segment */
- const void* vBase; /* virtual start of previous segment if it was just before current one */
- const void* dictEnd; /* end of previous segment */
+ const void *previousDstEnd; /* detect continuity */
+ const void *base; /* start of curr segment */
+ const void *vBase; /* virtual start of previous segment if it was just before curr one */
+ const void *dictEnd; /* end of previous segment */
size_t expected;
ZSTD_frameParams fParams;
- blockType_e bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */
+ blockType_e bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */
ZSTD_dStage stage;
U32 litEntropy;
U32 fseEntropy;
- XXH64_state_t xxhState;
+ struct xxh64_state xxhState;
size_t headerSize;
U32 dictID;
- const BYTE* litPtr;
+ const BYTE *litPtr;
ZSTD_customMem customMem;
size_t litSize;
size_t rleSize;
BYTE litBuffer[ZSTD_BLOCKSIZE_ABSOLUTEMAX + WILDCOPY_OVERLENGTH];
BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
-}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
+}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
-size_t ZSTD_DCtxWorkspaceBound(void)
-{
- return ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_DCtx));
-}
+size_t ZSTD_DCtxWorkspaceBound(void) { return ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_DCtx)); }
-size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
+size_t ZSTD_decompressBegin(ZSTD_DCtx *dctx)
{
dctx->expected = ZSTD_frameHeaderSize_prefix;
dctx->stage = ZSTDds_getFrameHeaderSize;
@@ -105,11 +111,11 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
dctx->base = NULL;
dctx->vBase = NULL;
dctx->dictEnd = NULL;
- dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
+ dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
dctx->litEntropy = dctx->fseEntropy = 0;
dctx->dictID = 0;
- MEM_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
- memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
+ ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
+ memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
dctx->LLTptr = dctx->entropy.LLTable;
dctx->MLTptr = dctx->entropy.MLTable;
dctx->OFTptr = dctx->entropy.OFTable;
@@ -117,64 +123,42 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
return 0;
}
-ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
+ZSTD_DCtx *ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
{
- ZSTD_DCtx* dctx;
+ ZSTD_DCtx *dctx;
- if (!customMem.customAlloc || !customMem.customFree) return NULL;
+ if (!customMem.customAlloc || !customMem.customFree)
+ return NULL;
- dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(ZSTD_DCtx), customMem);
- if (!dctx) return NULL;
+ dctx = (ZSTD_DCtx *)ZSTD_malloc(sizeof(ZSTD_DCtx), customMem);
+ if (!dctx)
+ return NULL;
memcpy(&dctx->customMem, &customMem, sizeof(customMem));
ZSTD_decompressBegin(dctx);
return dctx;
}
-ZSTD_DCtx* ZSTD_initDCtx(void* workspace, size_t workspaceSize)
+ZSTD_DCtx *ZSTD_initDCtx(void *workspace, size_t workspaceSize)
{
ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
return ZSTD_createDCtx_advanced(stackMem);
}
-size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
+size_t ZSTD_freeDCtx(ZSTD_DCtx *dctx)
{
- if (dctx==NULL) return 0; /* support free on NULL */
+ if (dctx == NULL)
+ return 0; /* support free on NULL */
ZSTD_free(dctx, dctx->customMem);
- return 0; /* reserved as a potential error code in the future */
+ return 0; /* reserved as a potential error code in the future */
}
-void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
+void ZSTD_copyDCtx(ZSTD_DCtx *dstDCtx, const ZSTD_DCtx *srcDCtx)
{
- size_t const workSpaceSize = (ZSTD_BLOCKSIZE_ABSOLUTEMAX+WILDCOPY_OVERLENGTH) + ZSTD_frameHeaderSize_max;
- memcpy(dstDCtx, srcDCtx, sizeof(ZSTD_DCtx) - workSpaceSize); /* no need to copy workspace */
+ size_t const workSpaceSize = (ZSTD_BLOCKSIZE_ABSOLUTEMAX + WILDCOPY_OVERLENGTH) + ZSTD_frameHeaderSize_max;
+ memcpy(dstDCtx, srcDCtx, sizeof(ZSTD_DCtx) - workSpaceSize); /* no need to copy workspace */
}
-#if 0
-/* deprecated */
-static void ZSTD_refDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
-{
- ZSTD_decompressBegin(dstDCtx); /* init */
- if (srcDCtx) { /* support refDCtx on NULL */
- dstDCtx->dictEnd = srcDCtx->dictEnd;
- dstDCtx->vBase = srcDCtx->vBase;
- dstDCtx->base = srcDCtx->base;
- dstDCtx->previousDstEnd = srcDCtx->previousDstEnd;
- dstDCtx->dictID = srcDCtx->dictID;
- dstDCtx->litEntropy = srcDCtx->litEntropy;
- dstDCtx->fseEntropy = srcDCtx->fseEntropy;
- dstDCtx->LLTptr = srcDCtx->entropy.LLTable;
- dstDCtx->MLTptr = srcDCtx->entropy.MLTable;
- dstDCtx->OFTptr = srcDCtx->entropy.OFTable;
- dstDCtx->HUFptr = srcDCtx->entropy.hufTable;
- dstDCtx->entropy.rep[0] = srcDCtx->entropy.rep[0];
- dstDCtx->entropy.rep[1] = srcDCtx->entropy.rep[1];
- dstDCtx->entropy.rep[2] = srcDCtx->entropy.rep[2];
- }
-}
-#endif
-
-static void ZSTD_refDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddict);
-
+static void ZSTD_refDDict(ZSTD_DCtx *dstDCtx, const ZSTD_DDict *ddict);
/*-*************************************************************
* Decompression section
@@ -185,48 +169,53 @@ static void ZSTD_refDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddict);
* Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
* Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
* Note 3 : Skippable Frame Identifiers are considered valid. */
-unsigned ZSTD_isFrame(const void* buffer, size_t size)
+unsigned ZSTD_isFrame(const void *buffer, size_t size)
{
- if (size < 4) return 0;
- { U32 const magic = MEM_readLE32(buffer);
- if (magic == ZSTD_MAGICNUMBER) return 1;
- if ((magic & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
+ if (size < 4)
+ return 0;
+ {
+ U32 const magic = ZSTD_readLE32(buffer);
+ if (magic == ZSTD_MAGICNUMBER)
+ return 1;
+ if ((magic & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START)
+ return 1;
}
return 0;
}
-
/** ZSTD_frameHeaderSize() :
* srcSize must be >= ZSTD_frameHeaderSize_prefix.
* @return : size of the Frame Header */
-static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
+static size_t ZSTD_frameHeaderSize(const void *src, size_t srcSize)
{
- if (srcSize < ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong);
- { BYTE const fhd = ((const BYTE*)src)[4];
- U32 const dictID= fhd & 3;
+ if (srcSize < ZSTD_frameHeaderSize_prefix)
+ return ERROR(srcSize_wrong);
+ {
+ BYTE const fhd = ((const BYTE *)src)[4];
+ U32 const dictID = fhd & 3;
U32 const singleSegment = (fhd >> 5) & 1;
U32 const fcsId = fhd >> 6;
- return ZSTD_frameHeaderSize_prefix + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
- + (singleSegment && !fcsId);
+ return ZSTD_frameHeaderSize_prefix + !singleSegment + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + (singleSegment && !fcsId);
}
}
-
/** ZSTD_getFrameParams() :
* decode Frame Header, or require larger `srcSize`.
* @return : 0, `fparamsPtr` is correctly filled,
* >0, `srcSize` is too small, result is expected `srcSize`,
* or an error code, which can be tested using ZSTD_isError() */
-size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize)
+size_t ZSTD_getFrameParams(ZSTD_frameParams *fparamsPtr, const void *src, size_t srcSize)
{
- const BYTE* ip = (const BYTE*)src;
+ const BYTE *ip = (const BYTE *)src;
- if (srcSize < ZSTD_frameHeaderSize_prefix) return ZSTD_frameHeaderSize_prefix;
- if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) {
- if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
- if (srcSize < ZSTD_skippableHeaderSize) return ZSTD_skippableHeaderSize; /* magic number + skippable frame length */
+ if (srcSize < ZSTD_frameHeaderSize_prefix)
+ return ZSTD_frameHeaderSize_prefix;
+ if (ZSTD_readLE32(src) != ZSTD_MAGICNUMBER) {
+ if ((ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
+ if (srcSize < ZSTD_skippableHeaderSize)
+ return ZSTD_skippableHeaderSize; /* magic number + skippable frame length */
memset(fparamsPtr, 0, sizeof(*fparamsPtr));
- fparamsPtr->frameContentSize = MEM_readLE32((const char *)src + 4);
+ fparamsPtr->frameContentSize = ZSTD_readLE32((const char *)src + 4);
fparamsPtr->windowSize = 0; /* windowSize==0 means a frame is skippable */
return 0;
}
@@ -234,46 +223,64 @@ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t
}
/* ensure there is enough `srcSize` to fully read/decode frame header */
- { size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize);
- if (srcSize < fhsize) return fhsize; }
+ {
+ size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize);
+ if (srcSize < fhsize)
+ return fhsize;
+ }
- { BYTE const fhdByte = ip[4];
+ {
+ BYTE const fhdByte = ip[4];
size_t pos = 5;
- U32 const dictIDSizeCode = fhdByte&3;
- U32 const checksumFlag = (fhdByte>>2)&1;
- U32 const singleSegment = (fhdByte>>5)&1;
- U32 const fcsID = fhdByte>>6;
+ U32 const dictIDSizeCode = fhdByte & 3;
+ U32 const checksumFlag = (fhdByte >> 2) & 1;
+ U32 const singleSegment = (fhdByte >> 5) & 1;
+ U32 const fcsID = fhdByte >> 6;
U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX;
U32 windowSize = 0;
U32 dictID = 0;
U64 frameContentSize = 0;
- if ((fhdByte & 0x08) != 0) return ERROR(frameParameter_unsupported); /* reserved bits, which must be zero */
+ if ((fhdByte & 0x08) != 0)
+ return ERROR(frameParameter_unsupported); /* reserved bits, which must be zero */
if (!singleSegment) {
BYTE const wlByte = ip[pos++];
U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
- if (windowLog > ZSTD_WINDOWLOG_MAX) return ERROR(frameParameter_windowTooLarge); /* avoids issue with 1 << windowLog */
+ if (windowLog > ZSTD_WINDOWLOG_MAX)
+ return ERROR(frameParameter_windowTooLarge); /* avoids issue with 1 << windowLog */
windowSize = (1U << windowLog);
- windowSize += (windowSize >> 3) * (wlByte&7);
+ windowSize += (windowSize >> 3) * (wlByte & 7);
}
- switch(dictIDSizeCode)
- {
- default: /* impossible */
- case 0 : break;
- case 1 : dictID = ip[pos]; pos++; break;
- case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
- case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;
+ switch (dictIDSizeCode) {
+ default: /* impossible */
+ case 0: break;
+ case 1:
+ dictID = ip[pos];
+ pos++;
+ break;
+ case 2:
+ dictID = ZSTD_readLE16(ip + pos);
+ pos += 2;
+ break;
+ case 3:
+ dictID = ZSTD_readLE32(ip + pos);
+ pos += 4;
+ break;
}
- switch(fcsID)
- {
- default: /* impossible */
- case 0 : if (singleSegment) frameContentSize = ip[pos]; break;
- case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
- case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
- case 3 : frameContentSize = MEM_readLE64(ip+pos); break;
+ switch (fcsID) {
+ default: /* impossible */
+ case 0:
+ if (singleSegment)
+ frameContentSize = ip[pos];
+ break;
+ case 1: frameContentSize = ZSTD_readLE16(ip + pos) + 256; break;
+ case 2: frameContentSize = ZSTD_readLE32(ip + pos); break;
+ case 3: frameContentSize = ZSTD_readLE64(ip + pos); break;
}
- if (!windowSize) windowSize = (U32)frameContentSize;
- if (windowSize > windowSizeMax) return ERROR(frameParameter_windowTooLarge);
+ if (!windowSize)
+ windowSize = (U32)frameContentSize;
+ if (windowSize > windowSizeMax)
+ return ERROR(frameParameter_windowTooLarge);
fparamsPtr->frameContentSize = frameContentSize;
fparamsPtr->windowSize = windowSize;
fparamsPtr->dictID = dictID;
@@ -291,7 +298,8 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
{
{
ZSTD_frameParams fParams;
- if (ZSTD_getFrameParams(&fParams, src, srcSize) != 0) return ZSTD_CONTENTSIZE_ERROR;
+ if (ZSTD_getFrameParams(&fParams, src, srcSize) != 0)
+ return ZSTD_CONTENTSIZE_ERROR;
if (fParams.windowSize == 0) {
/* Either skippable or empty frame, size == 0 either way */
return 0;
@@ -308,19 +316,18 @@ unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
* `srcSize` must be the exact length of some number of ZSTD compressed and/or
* skippable frames
* @return : decompressed size of the frames contained */
-unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
+unsigned long long ZSTD_findDecompressedSize(const void *src, size_t srcSize)
{
{
unsigned long long totalDstSize = 0;
while (srcSize >= ZSTD_frameHeaderSize_prefix) {
- const U32 magicNumber = MEM_readLE32(src);
+ const U32 magicNumber = ZSTD_readLE32(src);
if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
size_t skippableSize;
if (srcSize < ZSTD_skippableHeaderSize)
return ERROR(srcSize_wrong);
- skippableSize = MEM_readLE32((const BYTE *)src + 4) +
- ZSTD_skippableHeaderSize;
+ skippableSize = ZSTD_readLE32((const BYTE *)src + 4) + ZSTD_skippableHeaderSize;
if (srcSize < skippableSize) {
return ZSTD_CONTENTSIZE_ERROR;
}
@@ -332,10 +339,12 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
{
unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
- if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
+ if (ret >= ZSTD_CONTENTSIZE_ERROR)
+ return ret;
/* check for overflow */
- if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
+ if (totalDstSize + ret < totalDstSize)
+ return ZSTD_CONTENTSIZE_ERROR;
totalDstSize += ret;
}
{
@@ -360,19 +369,21 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
/** ZSTD_decodeFrameHeader() :
* `headerSize` must be the size provided by ZSTD_frameHeaderSize().
* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
-static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
+static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx *dctx, const void *src, size_t headerSize)
{
size_t const result = ZSTD_getFrameParams(&(dctx->fParams), src, headerSize);
- if (ZSTD_isError(result)) return result; /* invalid header */
- if (result>0) return ERROR(srcSize_wrong); /* headerSize too small */
- if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID)) return ERROR(dictionary_wrong);
- if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
+ if (ZSTD_isError(result))
+ return result; /* invalid header */
+ if (result > 0)
+ return ERROR(srcSize_wrong); /* headerSize too small */
+ if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
+ return ERROR(dictionary_wrong);
+ if (dctx->fParams.checksumFlag)
+ xxh64_reset(&dctx->xxhState, 0);
return 0;
}
-
-typedef struct
-{
+typedef struct {
blockType_e blockType;
U32 lastBlock;
U32 origSize;
@@ -380,441 +391,478 @@ typedef struct
/*! ZSTD_getcBlockSize() :
* Provides the size of compressed block from block header `src` */
-size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr)
+size_t ZSTD_getcBlockSize(const void *src, size_t srcSize, blockProperties_t *bpPtr)
{
- if (srcSize < ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
- { U32 const cBlockHeader = MEM_readLE24(src);
+ if (srcSize < ZSTD_blockHeaderSize)
+ return ERROR(srcSize_wrong);
+ {
+ U32 const cBlockHeader = ZSTD_readLE24(src);
U32 const cSize = cBlockHeader >> 3;
bpPtr->lastBlock = cBlockHeader & 1;
bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3);
- bpPtr->origSize = cSize; /* only useful for RLE */
- if (bpPtr->blockType == bt_rle) return 1;
- if (bpPtr->blockType == bt_reserved) return ERROR(corruption_detected);
+ bpPtr->origSize = cSize; /* only useful for RLE */
+ if (bpPtr->blockType == bt_rle)
+ return 1;
+ if (bpPtr->blockType == bt_reserved)
+ return ERROR(corruption_detected);
return cSize;
}
}
-
-static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+static size_t ZSTD_copyRawBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
- if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall);
+ if (srcSize > dstCapacity)
+ return ERROR(dstSize_tooSmall);
memcpy(dst, src, srcSize);
return srcSize;
}
-
-static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize, size_t regenSize)
+static size_t ZSTD_setRleBlock(void *dst, size_t dstCapacity, const void *src, size_t srcSize, size_t regenSize)
{
- if (srcSize != 1) return ERROR(srcSize_wrong);
- if (regenSize > dstCapacity) return ERROR(dstSize_tooSmall);
- memset(dst, *(const BYTE*)src, regenSize);
+ if (srcSize != 1)
+ return ERROR(srcSize_wrong);
+ if (regenSize > dstCapacity)
+ return ERROR(dstSize_tooSmall);
+ memset(dst, *(const BYTE *)src, regenSize);
return regenSize;
}
/*! ZSTD_decodeLiteralsBlock() :
@return : nb of bytes read from src (< srcSize ) */
-size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
- const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
+size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx *dctx, const void *src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
{
- if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected);
+ if (srcSize < MIN_CBLOCK_SIZE)
+ return ERROR(corruption_detected);
- { const BYTE* const istart = (const BYTE*) src;
+ {
+ const BYTE *const istart = (const BYTE *)src;
symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3);
- switch(litEncType)
- {
+ switch (litEncType) {
case set_repeat:
- if (dctx->litEntropy==0) return ERROR(dictionary_corrupted);
- /* fall-through */
+ if (dctx->litEntropy == 0)
+ return ERROR(dictionary_corrupted);
+ /* fall-through */
case set_compressed:
- if (srcSize < 5) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
- { size_t lhSize, litSize, litCSize;
- U32 singleStream=0;
+ if (srcSize < 5)
+ return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
+ {
+ size_t lhSize, litSize, litCSize;
+ U32 singleStream = 0;
U32 const lhlCode = (istart[0] >> 2) & 3;
- U32 const lhc = MEM_readLE32(istart);
- switch(lhlCode)
- {
- case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */
+ U32 const lhc = ZSTD_readLE32(istart);
+ switch (lhlCode) {
+ case 0:
+ case 1:
+ default: /* note : default is impossible, since lhlCode into [0..3] */
/* 2 - 2 - 10 - 10 */
singleStream = !lhlCode;
lhSize = 3;
- litSize = (lhc >> 4) & 0x3FF;
+ litSize = (lhc >> 4) & 0x3FF;
litCSize = (lhc >> 14) & 0x3FF;
break;
case 2:
/* 2 - 2 - 14 - 14 */
lhSize = 4;
- litSize = (lhc >> 4) & 0x3FFF;
+ litSize = (lhc >> 4) & 0x3FFF;
litCSize = lhc >> 18;
break;
case 3:
/* 2 - 2 - 18 - 18 */
lhSize = 5;
- litSize = (lhc >> 4) & 0x3FFFF;
+ litSize = (lhc >> 4) & 0x3FFFF;
litCSize = (lhc >> 22) + (istart[4] << 10);
break;
}
- if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected);
- if (litCSize + lhSize > srcSize) return ERROR(corruption_detected);
+ if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX)
+ return ERROR(corruption_detected);
+ if (litCSize + lhSize > srcSize)
+ return ERROR(corruption_detected);
- if (HUF_isError((litEncType==set_repeat) ?
- ( singleStream ?
- HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr) :
- HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->HUFptr) ) :
- ( singleStream ?
- HUF_decompress1X2_DCtx(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize) :
- HUF_decompress4X_hufOnly (dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize)) ))
+ if (HUF_isError(
+ (litEncType == set_repeat)
+ ? (singleStream ? HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart + lhSize, litCSize, dctx->HUFptr)
+ : HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart + lhSize, litCSize, dctx->HUFptr))
+ : (singleStream
+ ? HUF_decompress1X2_DCtx_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart + lhSize, litCSize,
+ dctx->entropy.workspace, sizeof(dctx->entropy.workspace))
+ : HUF_decompress4X_hufOnly_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, istart + lhSize, litCSize,
+ dctx->entropy.workspace, sizeof(dctx->entropy.workspace)))))
return ERROR(corruption_detected);
dctx->litPtr = dctx->litBuffer;
dctx->litSize = litSize;
dctx->litEntropy = 1;
- if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable;
+ if (litEncType == set_compressed)
+ dctx->HUFptr = dctx->entropy.hufTable;
memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
return litCSize + lhSize;
}
- case set_basic:
- { size_t litSize, lhSize;
- U32 const lhlCode = ((istart[0]) >> 2) & 3;
- switch(lhlCode)
- {
- case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */
- lhSize = 1;
- litSize = istart[0] >> 3;
- break;
- case 1:
- lhSize = 2;
- litSize = MEM_readLE16(istart) >> 4;
- break;
- case 3:
- lhSize = 3;
- litSize = MEM_readLE24(istart) >> 4;
- break;
- }
-
- if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */
- if (litSize+lhSize > srcSize) return ERROR(corruption_detected);
- memcpy(dctx->litBuffer, istart+lhSize, litSize);
- dctx->litPtr = dctx->litBuffer;
- dctx->litSize = litSize;
- memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
- return lhSize+litSize;
- }
- /* direct reference into compressed stream */
- dctx->litPtr = istart+lhSize;
- dctx->litSize = litSize;
- return lhSize+litSize;
+ case set_basic: {
+ size_t litSize, lhSize;
+ U32 const lhlCode = ((istart[0]) >> 2) & 3;
+ switch (lhlCode) {
+ case 0:
+ case 2:
+ default: /* note : default is impossible, since lhlCode into [0..3] */
+ lhSize = 1;
+ litSize = istart[0] >> 3;
+ break;
+ case 1:
+ lhSize = 2;
+ litSize = ZSTD_readLE16(istart) >> 4;
+ break;
+ case 3:
+ lhSize = 3;
+ litSize = ZSTD_readLE24(istart) >> 4;
+ break;
}
- case set_rle:
- { U32 const lhlCode = ((istart[0]) >> 2) & 3;
- size_t litSize, lhSize;
- switch(lhlCode)
- {
- case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */
- lhSize = 1;
- litSize = istart[0] >> 3;
- break;
- case 1:
- lhSize = 2;
- litSize = MEM_readLE16(istart) >> 4;
- break;
- case 3:
- lhSize = 3;
- litSize = MEM_readLE24(istart) >> 4;
- if (srcSize<4) return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */
- break;
- }
- if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected);
- memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
+ if (lhSize + litSize + WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */
+ if (litSize + lhSize > srcSize)
+ return ERROR(corruption_detected);
+ memcpy(dctx->litBuffer, istart + lhSize, litSize);
dctx->litPtr = dctx->litBuffer;
dctx->litSize = litSize;
- return lhSize+1;
+ memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);
+ return lhSize + litSize;
}
+ /* direct reference into compressed stream */
+ dctx->litPtr = istart + lhSize;
+ dctx->litSize = litSize;
+ return lhSize + litSize;
+ }
+
+ case set_rle: {
+ U32 const lhlCode = ((istart[0]) >> 2) & 3;
+ size_t litSize, lhSize;
+ switch (lhlCode) {
+ case 0:
+ case 2:
+ default: /* note : default is impossible, since lhlCode into [0..3] */
+ lhSize = 1;
+ litSize = istart[0] >> 3;
+ break;
+ case 1:
+ lhSize = 2;
+ litSize = ZSTD_readLE16(istart) >> 4;
+ break;
+ case 3:
+ lhSize = 3;
+ litSize = ZSTD_readLE24(istart) >> 4;
+ if (srcSize < 4)
+ return ERROR(corruption_detected); /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */
+ break;
+ }
+ if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX)
+ return ERROR(corruption_detected);
+ memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);
+ dctx->litPtr = dctx->litBuffer;
+ dctx->litSize = litSize;
+ return lhSize + 1;
+ }
default:
- return ERROR(corruption_detected); /* impossible */
+ return ERROR(corruption_detected); /* impossible */
}
}
}
-
typedef union {
FSE_decode_t realData;
U32 alignedBy4;
} FSE_decode_t4;
-static const FSE_decode_t4 LL_defaultDTable[(1< max) return ERROR(corruption_detected);
- FSE_buildDTable_rle(DTableSpace, *(const BYTE*)src);
+ const void *const tmpPtr = defaultTable; /* bypass strict aliasing */
+ switch (type) {
+ case set_rle:
+ if (!srcSize)
+ return ERROR(srcSize_wrong);
+ if ((*(const BYTE *)src) > max)
+ return ERROR(corruption_detected);
+ FSE_buildDTable_rle(DTableSpace, *(const BYTE *)src);
*DTablePtr = DTableSpace;
return 1;
- case set_basic :
- *DTablePtr = (const FSE_DTable*)tmpPtr;
- return 0;
+ case set_basic: *DTablePtr = (const FSE_DTable *)tmpPtr; return 0;
case set_repeat:
- if (!flagRepeatTable) return ERROR(corruption_detected);
+ if (!flagRepeatTable)
+ return ERROR(corruption_detected);
return 0;
- default : /* impossible */
- case set_compressed :
- { U32 tableLog;
- S16 norm[MaxSeq+1];
+ default: /* impossible */
+ case set_compressed: {
+ U32 tableLog;
+ S16 *norm = (S16 *)workspace;
+ size_t const spaceUsed32 = ALIGN(sizeof(S16) * (MaxSeq + 1), sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > workspaceSize)
+ return ERROR(GENERIC);
+ workspace = (U32 *)workspace + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
+ {
size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);
- if (FSE_isError(headerSize)) return ERROR(corruption_detected);
- if (tableLog > maxLog) return ERROR(corruption_detected);
- FSE_buildDTable(DTableSpace, norm, max, tableLog);
+ if (FSE_isError(headerSize))
+ return ERROR(corruption_detected);
+ if (tableLog > maxLog)
+ return ERROR(corruption_detected);
+ FSE_buildDTable_wksp(DTableSpace, norm, max, tableLog, workspace, workspaceSize);
*DTablePtr = DTableSpace;
return headerSize;
- } }
+ }
+ }
+ }
}
-size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr,
- const void* src, size_t srcSize)
+size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx *dctx, int *nbSeqPtr, const void *src, size_t srcSize)
{
- const BYTE* const istart = (const BYTE* const)src;
- const BYTE* const iend = istart + srcSize;
- const BYTE* ip = istart;
+ const BYTE *const istart = (const BYTE *const)src;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *ip = istart;
/* check */
- if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong);
+ if (srcSize < MIN_SEQUENCES_SIZE)
+ return ERROR(srcSize_wrong);
/* SeqHead */
- { int nbSeq = *ip++;
- if (!nbSeq) { *nbSeqPtr=0; return 1; }
+ {
+ int nbSeq = *ip++;
+ if (!nbSeq) {
+ *nbSeqPtr = 0;
+ return 1;
+ }
if (nbSeq > 0x7F) {
if (nbSeq == 0xFF) {
- if (ip+2 > iend) return ERROR(srcSize_wrong);
- nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2;
+ if (ip + 2 > iend)
+ return ERROR(srcSize_wrong);
+ nbSeq = ZSTD_readLE16(ip) + LONGNBSEQ, ip += 2;
} else {
- if (ip >= iend) return ERROR(srcSize_wrong);
- nbSeq = ((nbSeq-0x80)<<8) + *ip++;
+ if (ip >= iend)
+ return ERROR(srcSize_wrong);
+ nbSeq = ((nbSeq - 0x80) << 8) + *ip++;
}
}
*nbSeqPtr = nbSeq;
}
/* FSE table descriptors */
- if (ip+4 > iend) return ERROR(srcSize_wrong); /* minimum possible size */
- { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6);
+ if (ip + 4 > iend)
+ return ERROR(srcSize_wrong); /* minimum possible size */
+ {
+ symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6);
symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3);
symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3);
ip++;
/* Build DTables */
- { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr,
- LLtype, MaxLL, LLFSELog,
- ip, iend-ip, LL_defaultDTable, dctx->fseEntropy);
- if (ZSTD_isError(llhSize)) return ERROR(corruption_detected);
+ {
+ size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, LLtype, MaxLL, LLFSELog, ip, iend - ip,
+ LL_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace));
+ if (ZSTD_isError(llhSize))
+ return ERROR(corruption_detected);
ip += llhSize;
}
- { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr,
- OFtype, MaxOff, OffFSELog,
- ip, iend-ip, OF_defaultDTable, dctx->fseEntropy);
- if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected);
+ {
+ size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, OFtype, MaxOff, OffFSELog, ip, iend - ip,
+ OF_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace));
+ if (ZSTD_isError(ofhSize))
+ return ERROR(corruption_detected);
ip += ofhSize;
}
- { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr,
- MLtype, MaxML, MLFSELog,
- ip, iend-ip, ML_defaultDTable, dctx->fseEntropy);
- if (ZSTD_isError(mlhSize)) return ERROR(corruption_detected);
+ {
+ size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, MLtype, MaxML, MLFSELog, ip, iend - ip,
+ ML_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, sizeof(dctx->entropy.workspace));
+ if (ZSTD_isError(mlhSize))
+ return ERROR(corruption_detected);
ip += mlhSize;
}
}
- return ip-istart;
+ return ip - istart;
}
-
typedef struct {
size_t litLength;
size_t matchLength;
size_t offset;
- const BYTE* match;
+ const BYTE *match;
} seq_t;
typedef struct {
@@ -823,29 +871,29 @@ typedef struct {
FSE_DState_t stateOffb;
FSE_DState_t stateML;
size_t prevOffset[ZSTD_REP_NUM];
- const BYTE* base;
+ const BYTE *base;
size_t pos;
uPtrDiff gotoDict;
} seqState_t;
-
FORCE_NOINLINE
-size_t ZSTD_execSequenceLast7(BYTE* op,
- BYTE* const oend, seq_t sequence,
- const BYTE** litPtr, const BYTE* const litLimit,
- const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
+size_t ZSTD_execSequenceLast7(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
+ const BYTE *const vBase, const BYTE *const dictEnd)
{
- BYTE* const oLitEnd = op + sequence.litLength;
+ BYTE *const oLitEnd = op + sequence.litLength;
size_t const sequenceLength = sequence.litLength + sequence.matchLength;
- BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
- BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
- const BYTE* const iLitEnd = *litPtr + sequence.litLength;
- const BYTE* match = oLitEnd - sequence.offset;
+ BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
+ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
+ const BYTE *const iLitEnd = *litPtr + sequence.litLength;
+ const BYTE *match = oLitEnd - sequence.offset;
/* check */
- if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
- if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */
- if (oLitEnd <= oend_w) return ERROR(GENERIC); /* Precondition */
+ if (oMatchEnd > oend)
+ return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
+ if (iLitEnd > litLimit)
+ return ERROR(corruption_detected); /* over-read beyond lit buffer */
+ if (oLitEnd <= oend_w)
+ return ERROR(GENERIC); /* Precondition */
/* copy literals */
if (op < oend_w) {
@@ -853,76 +901,75 @@ size_t ZSTD_execSequenceLast7(BYTE* op,
*litPtr += oend_w - op;
op = oend_w;
}
- while (op < oLitEnd) *op++ = *(*litPtr)++;
+ while (op < oLitEnd)
+ *op++ = *(*litPtr)++;
/* copy Match */
if (sequence.offset > (size_t)(oLitEnd - base)) {
/* offset beyond prefix */
- if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
- match = dictEnd - (base-match);
+ if (sequence.offset > (size_t)(oLitEnd - vBase))
+ return ERROR(corruption_detected);
+ match = dictEnd - (base - match);
if (match + sequence.matchLength <= dictEnd) {
memmove(oLitEnd, match, sequence.matchLength);
return sequenceLength;
}
- /* span extDict & currentPrefixSegment */
- { size_t const length1 = dictEnd - match;
+ /* span extDict & currPrefixSegment */
+ {
+ size_t const length1 = dictEnd - match;
memmove(oLitEnd, match, length1);
op = oLitEnd + length1;
sequence.matchLength -= length1;
match = base;
- } }
- while (op < oMatchEnd) *op++ = *match++;
+ }
+ }
+ while (op < oMatchEnd)
+ *op++ = *match++;
return sequenceLength;
}
-
-
-
-static seq_t ZSTD_decodeSequence(seqState_t* seqState)
+static seq_t ZSTD_decodeSequence(seqState_t *seqState)
{
seq_t seq;
U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
- U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */
+ U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */
U32 const llBits = LL_bits[llCode];
U32 const mlBits = ML_bits[mlCode];
U32 const ofBits = ofCode;
- U32 const totalBits = llBits+mlBits+ofBits;
+ U32 const totalBits = llBits + mlBits + ofBits;
- static const U32 LL_base[MaxLL+1] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
- 0x2000, 0x4000, 0x8000, 0x10000 };
+ static const U32 LL_base[MaxLL + 1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18,
+ 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000};
- static const U32 ML_base[MaxML+1] = {
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
- 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
+ static const U32 ML_base[MaxML + 1] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41,
+ 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003};
- static const U32 OF_base[MaxOff+1] = {
- 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
- 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
- 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
- 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD };
+ static const U32 OF_base[MaxOff + 1] = {0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD,
+ 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD,
+ 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD};
/* sequence */
- { size_t offset;
+ {
+ size_t offset;
if (!ofCode)
offset = 0;
else {
- offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
- if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
+ offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
+ if (ZSTD_32bits())
+ BIT_reloadDStream(&seqState->DStream);
}
if (ofCode <= 1) {
- offset += (llCode==0);
+ offset += (llCode == 0);
if (offset) {
- size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
- temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
- if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
+ size_t temp = (offset == 3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
+ temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
+ if (offset != 1)
+ seqState->prevOffset[2] = seqState->prevOffset[1];
seqState->prevOffset[1] = seqState->prevOffset[0];
seqState->prevOffset[0] = offset = temp;
} else {
@@ -936,123 +983,130 @@ static seq_t ZSTD_decodeSequence(seqState_t* seqState)
seq.offset = offset;
}
- seq.matchLength = ML_base[mlCode] + ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
- if (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream);
+ seq.matchLength = ML_base[mlCode] + ((mlCode > 31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
+ if (ZSTD_32bits() && (mlBits + llBits > 24))
+ BIT_reloadDStream(&seqState->DStream);
- seq.litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
- if (MEM_32bits() ||
- (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BIT_reloadDStream(&seqState->DStream);
+ seq.litLength = LL_base[llCode] + ((llCode > 15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
+ if (ZSTD_32bits() || (totalBits > 64 - 7 - (LLFSELog + MLFSELog + OffFSELog)))
+ BIT_reloadDStream(&seqState->DStream);
/* ANS state update */
- FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
- FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
- if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
- FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
+ FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
+ FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
+ if (ZSTD_32bits())
+ BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
+ FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
return seq;
}
-
FORCE_INLINE
-size_t ZSTD_execSequence(BYTE* op,
- BYTE* const oend, seq_t sequence,
- const BYTE** litPtr, const BYTE* const litLimit,
- const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
+size_t ZSTD_execSequence(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
+ const BYTE *const vBase, const BYTE *const dictEnd)
{
- BYTE* const oLitEnd = op + sequence.litLength;
+ BYTE *const oLitEnd = op + sequence.litLength;
size_t const sequenceLength = sequence.litLength + sequence.matchLength;
- BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
- BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
- const BYTE* const iLitEnd = *litPtr + sequence.litLength;
- const BYTE* match = oLitEnd - sequence.offset;
+ BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
+ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
+ const BYTE *const iLitEnd = *litPtr + sequence.litLength;
+ const BYTE *match = oLitEnd - sequence.offset;
/* check */
- if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
- if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */
- if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
+ if (oMatchEnd > oend)
+ return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
+ if (iLitEnd > litLimit)
+ return ERROR(corruption_detected); /* over-read beyond lit buffer */
+ if (oLitEnd > oend_w)
+ return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
/* copy Literals */
ZSTD_copy8(op, *litPtr);
if (sequence.litLength > 8)
- ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
+ ZSTD_wildcopy(op + 8, (*litPtr) + 8,
+ sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
op = oLitEnd;
- *litPtr = iLitEnd; /* update for next sequence */
+ *litPtr = iLitEnd; /* update for next sequence */
/* copy Match */
if (sequence.offset > (size_t)(oLitEnd - base)) {
/* offset beyond prefix */
- if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
+ if (sequence.offset > (size_t)(oLitEnd - vBase))
+ return ERROR(corruption_detected);
match = dictEnd + (match - base);
if (match + sequence.matchLength <= dictEnd) {
memmove(oLitEnd, match, sequence.matchLength);
return sequenceLength;
}
- /* span extDict & currentPrefixSegment */
- { size_t const length1 = dictEnd - match;
+ /* span extDict & currPrefixSegment */
+ {
+ size_t const length1 = dictEnd - match;
memmove(oLitEnd, match, length1);
op = oLitEnd + length1;
sequence.matchLength -= length1;
match = base;
if (op > oend_w || sequence.matchLength < MINMATCH) {
- U32 i;
- for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i];
- return sequenceLength;
+ U32 i;
+ for (i = 0; i < sequence.matchLength; ++i)
+ op[i] = match[i];
+ return sequenceLength;
}
- } }
+ }
+ }
/* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
/* match within prefix */
if (sequence.offset < 8) {
/* close range match, overlap */
- static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */
- static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */
+ static const U32 dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; /* added */
+ static const int dec64table[] = {8, 8, 8, 7, 8, 9, 10, 11}; /* subtracted */
int const sub2 = dec64table[sequence.offset];
op[0] = match[0];
op[1] = match[1];
op[2] = match[2];
op[3] = match[3];
match += dec32table[sequence.offset];
- ZSTD_copy4(op+4, match);
+ ZSTD_copy4(op + 4, match);
match -= sub2;
} else {
ZSTD_copy8(op, match);
}
- op += 8; match += 8;
+ op += 8;
+ match += 8;
- if (oMatchEnd > oend-(16-MINMATCH)) {
+ if (oMatchEnd > oend - (16 - MINMATCH)) {
if (op < oend_w) {
ZSTD_wildcopy(op, match, oend_w - op);
match += oend_w - op;
op = oend_w;
}
- while (op < oMatchEnd) *op++ = *match++;
+ while (op < oMatchEnd)
+ *op++ = *match++;
} else {
- ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */
+ ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8); /* works even if matchLength < 8 */
}
return sequenceLength;
}
-
-static size_t ZSTD_decompressSequences(
- ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize)
+static size_t ZSTD_decompressSequences(ZSTD_DCtx *dctx, void *dst, size_t maxDstSize, const void *seqStart, size_t seqSize)
{
- const BYTE* ip = (const BYTE*)seqStart;
- const BYTE* const iend = ip + seqSize;
- BYTE* const ostart = (BYTE* const)dst;
- BYTE* const oend = ostart + maxDstSize;
- BYTE* op = ostart;
- const BYTE* litPtr = dctx->litPtr;
- const BYTE* const litEnd = litPtr + dctx->litSize;
- const BYTE* const base = (const BYTE*) (dctx->base);
- const BYTE* const vBase = (const BYTE*) (dctx->vBase);
- const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
+ const BYTE *ip = (const BYTE *)seqStart;
+ const BYTE *const iend = ip + seqSize;
+ BYTE *const ostart = (BYTE * const)dst;
+ BYTE *const oend = ostart + maxDstSize;
+ BYTE *op = ostart;
+ const BYTE *litPtr = dctx->litPtr;
+ const BYTE *const litEnd = litPtr + dctx->litSize;
+ const BYTE *const base = (const BYTE *)(dctx->base);
+ const BYTE *const vBase = (const BYTE *)(dctx->vBase);
+ const BYTE *const dictEnd = (const BYTE *)(dctx->dictEnd);
int nbSeq;
/* Build Decoding Tables */
- { size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
- if (ZSTD_isError(seqHSize)) return seqHSize;
+ {
+ size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
+ if (ZSTD_isError(seqHSize))
+ return seqHSize;
ip += seqHSize;
}
@@ -1060,89 +1114,101 @@ static size_t ZSTD_decompressSequences(
if (nbSeq) {
seqState_t seqState;
dctx->fseEntropy = 1;
- { U32 i; for (i=0; ientropy.rep[i]; }
- CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
+ {
+ U32 i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ seqState.prevOffset[i] = dctx->entropy.rep[i];
+ }
+ CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend - ip), corruption_detected);
FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
- for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) {
+ for (; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq;) {
nbSeq--;
- { seq_t const sequence = ZSTD_decodeSequence(&seqState);
+ {
+ seq_t const sequence = ZSTD_decodeSequence(&seqState);
size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
- if (ZSTD_isError(oneSeqSize)) return oneSeqSize;
+ if (ZSTD_isError(oneSeqSize))
+ return oneSeqSize;
op += oneSeqSize;
- } }
+ }
+ }
/* check if reached exact end */
- if (nbSeq) return ERROR(corruption_detected);
+ if (nbSeq)
+ return ERROR(corruption_detected);
/* save reps for next block */
- { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); }
+ {
+ U32 i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]);
+ }
}
/* last literal segment */
- { size_t const lastLLSize = litEnd - litPtr;
- if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
+ {
+ size_t const lastLLSize = litEnd - litPtr;
+ if (lastLLSize > (size_t)(oend - op))
+ return ERROR(dstSize_tooSmall);
memcpy(op, litPtr, lastLLSize);
op += lastLLSize;
}
- return op-ostart;
+ return op - ostart;
}
-
-FORCE_INLINE seq_t ZSTD_decodeSequenceLong_generic(seqState_t* seqState, int const longOffsets)
+FORCE_INLINE seq_t ZSTD_decodeSequenceLong_generic(seqState_t *seqState, int const longOffsets)
{
seq_t seq;
U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
- U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */
+ U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= maxOff, by table construction */
U32 const llBits = LL_bits[llCode];
U32 const mlBits = ML_bits[mlCode];
U32 const ofBits = ofCode;
- U32 const totalBits = llBits+mlBits+ofBits;
+ U32 const totalBits = llBits + mlBits + ofBits;
- static const U32 LL_base[MaxLL+1] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000,
- 0x2000, 0x4000, 0x8000, 0x10000 };
+ static const U32 LL_base[MaxLL + 1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18,
+ 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000};
- static const U32 ML_base[MaxML+1] = {
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803,
- 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 };
+ static const U32 ML_base[MaxML + 1] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 39, 41,
+ 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003};
- static const U32 OF_base[MaxOff+1] = {
- 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D,
- 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD,
- 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD,
- 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD };
+ static const U32 OF_base[MaxOff + 1] = {0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 0xFD, 0x1FD,
+ 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD,
+ 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD};
/* sequence */
- { size_t offset;
+ {
+ size_t offset;
if (!ofCode)
offset = 0;
else {
if (longOffsets) {
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN);
offset = OF_base[ofCode] + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
- if (MEM_32bits() || extraBits) BIT_reloadDStream(&seqState->DStream);
- if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits);
+ if (ZSTD_32bits() || extraBits)
+ BIT_reloadDStream(&seqState->DStream);
+ if (extraBits)
+ offset += BIT_readBitsFast(&seqState->DStream, extraBits);
} else {
- offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
- if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);
+ offset = OF_base[ofCode] + BIT_readBitsFast(&seqState->DStream, ofBits); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */
+ if (ZSTD_32bits())
+ BIT_reloadDStream(&seqState->DStream);
}
}
if (ofCode <= 1) {
- offset += (llCode==0);
+ offset += (llCode == 0);
if (offset) {
- size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
- temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
- if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1];
+ size_t temp = (offset == 3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
+ temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */
+ if (offset != 1)
+ seqState->prevOffset[2] = seqState->prevOffset[1];
seqState->prevOffset[1] = seqState->prevOffset[0];
seqState->prevOffset[0] = offset = temp;
} else {
@@ -1156,29 +1222,34 @@ FORCE_INLINE seq_t ZSTD_decodeSequenceLong_generic(seqState_t* seqState, int con
seq.offset = offset;
}
- seq.matchLength = ML_base[mlCode] + ((mlCode>31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
- if (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream);
+ seq.matchLength = ML_base[mlCode] + ((mlCode > 31) ? BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <= 16 bits */
+ if (ZSTD_32bits() && (mlBits + llBits > 24))
+ BIT_reloadDStream(&seqState->DStream);
- seq.litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
- if (MEM_32bits() ||
- (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BIT_reloadDStream(&seqState->DStream);
+ seq.litLength = LL_base[llCode] + ((llCode > 15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <= 16 bits */
+ if (ZSTD_32bits() || (totalBits > 64 - 7 - (LLFSELog + MLFSELog + OffFSELog)))
+ BIT_reloadDStream(&seqState->DStream);
- { size_t const pos = seqState->pos + seq.litLength;
- seq.match = seqState->base + pos - seq.offset; /* single memory segment */
- if (seq.offset > pos) seq.match += seqState->gotoDict; /* separate memory segment */
+ {
+ size_t const pos = seqState->pos + seq.litLength;
+ seq.match = seqState->base + pos - seq.offset; /* single memory segment */
+ if (seq.offset > pos)
+ seq.match += seqState->gotoDict; /* separate memory segment */
seqState->pos = pos + seq.matchLength;
}
/* ANS state update */
- FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
- FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
- if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
- FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
+ FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */
+ FSE_updateState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */
+ if (ZSTD_32bits())
+ BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */
+ FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */
return seq;
}
-static seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, unsigned const windowSize) {
+static seq_t ZSTD_decodeSequenceLong(seqState_t *seqState, unsigned const windowSize)
+{
if (ZSTD_highbit32(windowSize) > STREAM_ACCUMULATOR_MIN) {
return ZSTD_decodeSequenceLong_generic(seqState, 1);
} else {
@@ -1187,229 +1258,244 @@ static seq_t ZSTD_decodeSequenceLong(seqState_t* seqState, unsigned const window
}
FORCE_INLINE
-size_t ZSTD_execSequenceLong(BYTE* op,
- BYTE* const oend, seq_t sequence,
- const BYTE** litPtr, const BYTE* const litLimit,
- const BYTE* const base, const BYTE* const vBase, const BYTE* const dictEnd)
+size_t ZSTD_execSequenceLong(BYTE *op, BYTE *const oend, seq_t sequence, const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
+ const BYTE *const vBase, const BYTE *const dictEnd)
{
- BYTE* const oLitEnd = op + sequence.litLength;
+ BYTE *const oLitEnd = op + sequence.litLength;
size_t const sequenceLength = sequence.litLength + sequence.matchLength;
- BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
- BYTE* const oend_w = oend - WILDCOPY_OVERLENGTH;
- const BYTE* const iLitEnd = *litPtr + sequence.litLength;
- const BYTE* match = sequence.match;
+ BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */
+ BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
+ const BYTE *const iLitEnd = *litPtr + sequence.litLength;
+ const BYTE *match = sequence.match;
/* check */
-#if 1
- if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
- if (iLitEnd > litLimit) return ERROR(corruption_detected); /* over-read beyond lit buffer */
- if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
-#endif
+ if (oMatchEnd > oend)
+ return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */
+ if (iLitEnd > litLimit)
+ return ERROR(corruption_detected); /* over-read beyond lit buffer */
+ if (oLitEnd > oend_w)
+ return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);
/* copy Literals */
ZSTD_copy8(op, *litPtr);
if (sequence.litLength > 8)
- ZSTD_wildcopy(op+8, (*litPtr)+8, sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
+ ZSTD_wildcopy(op + 8, (*litPtr) + 8,
+ sequence.litLength - 8); /* note : since oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
op = oLitEnd;
- *litPtr = iLitEnd; /* update for next sequence */
+ *litPtr = iLitEnd; /* update for next sequence */
/* copy Match */
-#if 1
if (sequence.offset > (size_t)(oLitEnd - base)) {
/* offset beyond prefix */
- if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected);
+ if (sequence.offset > (size_t)(oLitEnd - vBase))
+ return ERROR(corruption_detected);
if (match + sequence.matchLength <= dictEnd) {
memmove(oLitEnd, match, sequence.matchLength);
return sequenceLength;
}
- /* span extDict & currentPrefixSegment */
- { size_t const length1 = dictEnd - match;
+ /* span extDict & currPrefixSegment */
+ {
+ size_t const length1 = dictEnd - match;
memmove(oLitEnd, match, length1);
op = oLitEnd + length1;
sequence.matchLength -= length1;
match = base;
if (op > oend_w || sequence.matchLength < MINMATCH) {
- U32 i;
- for (i = 0; i < sequence.matchLength; ++i) op[i] = match[i];
- return sequenceLength;
+ U32 i;
+ for (i = 0; i < sequence.matchLength; ++i)
+ op[i] = match[i];
+ return sequenceLength;
}
- } }
+ }
+ }
/* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
-#endif
/* match within prefix */
if (sequence.offset < 8) {
/* close range match, overlap */
- static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; /* added */
- static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 }; /* subtracted */
+ static const U32 dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; /* added */
+ static const int dec64table[] = {8, 8, 8, 7, 8, 9, 10, 11}; /* subtracted */
int const sub2 = dec64table[sequence.offset];
op[0] = match[0];
op[1] = match[1];
op[2] = match[2];
op[3] = match[3];
match += dec32table[sequence.offset];
- ZSTD_copy4(op+4, match);
+ ZSTD_copy4(op + 4, match);
match -= sub2;
} else {
ZSTD_copy8(op, match);
}
- op += 8; match += 8;
+ op += 8;
+ match += 8;
- if (oMatchEnd > oend-(16-MINMATCH)) {
+ if (oMatchEnd > oend - (16 - MINMATCH)) {
if (op < oend_w) {
ZSTD_wildcopy(op, match, oend_w - op);
match += oend_w - op;
op = oend_w;
}
- while (op < oMatchEnd) *op++ = *match++;
+ while (op < oMatchEnd)
+ *op++ = *match++;
} else {
- ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength-8); /* works even if matchLength < 8 */
+ ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8); /* works even if matchLength < 8 */
}
return sequenceLength;
}
-static size_t ZSTD_decompressSequencesLong(
- ZSTD_DCtx* dctx,
- void* dst, size_t maxDstSize,
- const void* seqStart, size_t seqSize)
+static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx *dctx, void *dst, size_t maxDstSize, const void *seqStart, size_t seqSize)
{
- const BYTE* ip = (const BYTE*)seqStart;
- const BYTE* const iend = ip + seqSize;
- BYTE* const ostart = (BYTE* const)dst;
- BYTE* const oend = ostart + maxDstSize;
- BYTE* op = ostart;
- const BYTE* litPtr = dctx->litPtr;
- const BYTE* const litEnd = litPtr + dctx->litSize;
- const BYTE* const base = (const BYTE*) (dctx->base);
- const BYTE* const vBase = (const BYTE*) (dctx->vBase);
- const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd);
+ const BYTE *ip = (const BYTE *)seqStart;
+ const BYTE *const iend = ip + seqSize;
+ BYTE *const ostart = (BYTE * const)dst;
+ BYTE *const oend = ostart + maxDstSize;
+ BYTE *op = ostart;
+ const BYTE *litPtr = dctx->litPtr;
+ const BYTE *const litEnd = litPtr + dctx->litSize;
+ const BYTE *const base = (const BYTE *)(dctx->base);
+ const BYTE *const vBase = (const BYTE *)(dctx->vBase);
+ const BYTE *const dictEnd = (const BYTE *)(dctx->dictEnd);
unsigned const windowSize = dctx->fParams.windowSize;
int nbSeq;
/* Build Decoding Tables */
- { size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
- if (ZSTD_isError(seqHSize)) return seqHSize;
+ {
+ size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, seqSize);
+ if (ZSTD_isError(seqHSize))
+ return seqHSize;
ip += seqHSize;
}
/* Regen sequences */
if (nbSeq) {
#define STORED_SEQS 4
-#define STOSEQ_MASK (STORED_SEQS-1)
+#define STOSEQ_MASK (STORED_SEQS - 1)
#define ADVANCED_SEQS 4
- seq_t sequences[STORED_SEQS];
+ seq_t *sequences = (seq_t *)dctx->entropy.workspace;
int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
seqState_t seqState;
int seqNb;
+ ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.workspace) >= sizeof(seq_t) * STORED_SEQS);
dctx->fseEntropy = 1;
- { U32 i; for (i=0; ientropy.rep[i]; }
+ {
+ U32 i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ seqState.prevOffset[i] = dctx->entropy.rep[i];
+ }
seqState.base = base;
- seqState.pos = (size_t)(op-base);
+ seqState.pos = (size_t)(op - base);
seqState.gotoDict = (uPtrDiff)dictEnd - (uPtrDiff)base; /* cast to avoid undefined behaviour */
- CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend-ip), corruption_detected);
+ CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend - ip), corruption_detected);
FSE_initDState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr);
FSE_initDState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr);
FSE_initDState(&seqState.stateML, &seqState.DStream, dctx->MLTptr);
/* prepare in advance */
- for (seqNb=0; (BIT_reloadDStream(&seqState.DStream) <= BIT_DStream_completed) && seqNbentropy.rep[i] = (U32)(seqState.prevOffset[i]); }
+ {
+ U32 i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ dctx->entropy.rep[i] = (U32)(seqState.prevOffset[i]);
+ }
}
/* last literal segment */
- { size_t const lastLLSize = litEnd - litPtr;
- if (lastLLSize > (size_t)(oend-op)) return ERROR(dstSize_tooSmall);
+ {
+ size_t const lastLLSize = litEnd - litPtr;
+ if (lastLLSize > (size_t)(oend - op))
+ return ERROR(dstSize_tooSmall);
memcpy(op, litPtr, lastLLSize);
op += lastLLSize;
}
- return op-ostart;
+ return op - ostart;
}
+static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
+{ /* blockType == blockCompressed */
+ const BYTE *ip = (const BYTE *)src;
-static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
-{ /* blockType == blockCompressed */
- const BYTE* ip = (const BYTE*)src;
-
- if (srcSize >= ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(srcSize_wrong);
+ if (srcSize >= ZSTD_BLOCKSIZE_ABSOLUTEMAX)
+ return ERROR(srcSize_wrong);
/* Decode literals section */
- { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
- if (ZSTD_isError(litCSize)) return litCSize;
+ {
+ size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);
+ if (ZSTD_isError(litCSize))
+ return litCSize;
ip += litCSize;
srcSize -= litCSize;
}
- if (sizeof(size_t) > 4) /* do not enable prefetching on 32-bits x86, as it's performance detrimental */
- /* likely because of register pressure */
- /* if that's the correct cause, then 32-bits ARM should be affected differently */
- /* it would be good to test this on ARM real hardware, to see if prefetch version improves speed */
- if (dctx->fParams.windowSize > (1<<23))
+ if (sizeof(size_t) > 4) /* do not enable prefetching on 32-bits x86, as it's performance detrimental */
+ /* likely because of register pressure */
+ /* if that's the correct cause, then 32-bits ARM should be affected differently */
+ /* it would be good to test this on ARM real hardware, to see if prefetch version improves speed */
+ if (dctx->fParams.windowSize > (1 << 23))
return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize);
return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize);
}
-
-static void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
+static void ZSTD_checkContinuity(ZSTD_DCtx *dctx, const void *dst)
{
- if (dst != dctx->previousDstEnd) { /* not contiguous */
+ if (dst != dctx->previousDstEnd) { /* not contiguous */
dctx->dictEnd = dctx->previousDstEnd;
- dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
+ dctx->vBase = (const char *)dst - ((const char *)(dctx->previousDstEnd) - (const char *)(dctx->base));
dctx->base = dst;
dctx->previousDstEnd = dst;
}
}
-size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize)
+size_t ZSTD_decompressBlock(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
size_t dSize;
ZSTD_checkContinuity(dctx, dst);
dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize);
- dctx->previousDstEnd = (char*)dst + dSize;
+ dctx->previousDstEnd = (char *)dst + dSize;
return dSize;
}
-
/** ZSTD_insertBlock() :
insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
-size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
+size_t ZSTD_insertBlock(ZSTD_DCtx *dctx, const void *blockStart, size_t blockSize)
{
ZSTD_checkContinuity(dctx, blockStart);
- dctx->previousDstEnd = (const char*)blockStart + blockSize;
+ dctx->previousDstEnd = (const char *)blockStart + blockSize;
return blockSize;
}
-
-size_t ZSTD_generateNxBytes(void* dst, size_t dstCapacity, BYTE byte, size_t length)
+size_t ZSTD_generateNxBytes(void *dst, size_t dstCapacity, BYTE byte, size_t length)
{
- if (length > dstCapacity) return ERROR(dstSize_tooSmall);
+ if (length > dstCapacity)
+ return ERROR(dstSize_tooSmall);
memset(dst, byte, length);
return length;
}
@@ -1421,22 +1507,25 @@ size_t ZSTD_generateNxBytes(void* dst, size_t dstCapacity, BYTE byte, size_t len
* @return : the compressed size of the frame starting at `src` */
size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
{
- if (srcSize >= ZSTD_skippableHeaderSize &&
- (MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
- return ZSTD_skippableHeaderSize + MEM_readLE32((const BYTE*)src + 4);
+ if (srcSize >= ZSTD_skippableHeaderSize && (ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
+ return ZSTD_skippableHeaderSize + ZSTD_readLE32((const BYTE *)src + 4);
} else {
- const BYTE* ip = (const BYTE*)src;
- const BYTE* const ipstart = ip;
+ const BYTE *ip = (const BYTE *)src;
+ const BYTE *const ipstart = ip;
size_t remainingSize = srcSize;
ZSTD_frameParams fParams;
size_t const headerSize = ZSTD_frameHeaderSize(ip, remainingSize);
- if (ZSTD_isError(headerSize)) return headerSize;
+ if (ZSTD_isError(headerSize))
+ return headerSize;
/* Frame Header */
- { size_t const ret = ZSTD_getFrameParams(&fParams, ip, remainingSize);
- if (ZSTD_isError(ret)) return ret;
- if (ret > 0) return ERROR(srcSize_wrong);
+ {
+ size_t const ret = ZSTD_getFrameParams(&fParams, ip, remainingSize);
+ if (ZSTD_isError(ret))
+ return ret;
+ if (ret > 0)
+ return ERROR(srcSize_wrong);
}
ip += headerSize;
@@ -1446,18 +1535,22 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
while (1) {
blockProperties_t blockProperties;
size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
- if (ZSTD_isError(cBlockSize)) return cBlockSize;
+ if (ZSTD_isError(cBlockSize))
+ return cBlockSize;
- if (ZSTD_blockHeaderSize + cBlockSize > remainingSize) return ERROR(srcSize_wrong);
+ if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
+ return ERROR(srcSize_wrong);
ip += ZSTD_blockHeaderSize + cBlockSize;
remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
- if (blockProperties.lastBlock) break;
+ if (blockProperties.lastBlock)
+ break;
}
- if (fParams.checksumFlag) { /* Frame content checksum */
- if (remainingSize < 4) return ERROR(srcSize_wrong);
+ if (fParams.checksumFlag) { /* Frame content checksum */
+ if (remainingSize < 4)
+ return ERROR(srcSize_wrong);
ip += 4;
remainingSize -= 4;
}
@@ -1468,25 +1561,28 @@ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
/*! ZSTD_decompressFrame() :
* @dctx must be properly initialized */
-static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void** srcPtr, size_t *srcSizePtr)
+static size_t ZSTD_decompressFrame(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void **srcPtr, size_t *srcSizePtr)
{
- const BYTE* ip = (const BYTE*)(*srcPtr);
- BYTE* const ostart = (BYTE* const)dst;
- BYTE* const oend = ostart + dstCapacity;
- BYTE* op = ostart;
+ const BYTE *ip = (const BYTE *)(*srcPtr);
+ BYTE *const ostart = (BYTE * const)dst;
+ BYTE *const oend = ostart + dstCapacity;
+ BYTE *op = ostart;
size_t remainingSize = *srcSizePtr;
/* check */
- if (remainingSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
+ if (remainingSize < ZSTD_frameHeaderSize_min + ZSTD_blockHeaderSize)
+ return ERROR(srcSize_wrong);
/* Frame Header */
- { size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_frameHeaderSize_prefix);
- if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
- if (remainingSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);
+ {
+ size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_frameHeaderSize_prefix);
+ if (ZSTD_isError(frameHeaderSize))
+ return frameHeaderSize;
+ if (remainingSize < frameHeaderSize + ZSTD_blockHeaderSize)
+ return ERROR(srcSize_wrong);
CHECK_F(ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize));
- ip += frameHeaderSize; remainingSize -= frameHeaderSize;
+ ip += frameHeaderSize;
+ remainingSize -= frameHeaderSize;
}
/* Loop on each block */
@@ -1494,42 +1590,41 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
size_t decodedSize;
blockProperties_t blockProperties;
size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
- if (ZSTD_isError(cBlockSize)) return cBlockSize;
+ if (ZSTD_isError(cBlockSize))
+ return cBlockSize;
ip += ZSTD_blockHeaderSize;
remainingSize -= ZSTD_blockHeaderSize;
- if (cBlockSize > remainingSize) return ERROR(srcSize_wrong);
+ if (cBlockSize > remainingSize)
+ return ERROR(srcSize_wrong);
- switch(blockProperties.blockType)
- {
- case bt_compressed:
- decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize);
- break;
- case bt_raw :
- decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
- break;
- case bt_rle :
- decodedSize = ZSTD_generateNxBytes(op, oend-op, *ip, blockProperties.origSize);
- break;
- case bt_reserved :
- default:
- return ERROR(corruption_detected);
+ switch (blockProperties.blockType) {
+ case bt_compressed: decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend - op, ip, cBlockSize); break;
+ case bt_raw: decodedSize = ZSTD_copyRawBlock(op, oend - op, ip, cBlockSize); break;
+ case bt_rle: decodedSize = ZSTD_generateNxBytes(op, oend - op, *ip, blockProperties.origSize); break;
+ case bt_reserved:
+ default: return ERROR(corruption_detected);
}
- if (ZSTD_isError(decodedSize)) return decodedSize;
- if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, op, decodedSize);
+ if (ZSTD_isError(decodedSize))
+ return decodedSize;
+ if (dctx->fParams.checksumFlag)
+ xxh64_update(&dctx->xxhState, op, decodedSize);
op += decodedSize;
ip += cBlockSize;
remainingSize -= cBlockSize;
- if (blockProperties.lastBlock) break;
+ if (blockProperties.lastBlock)
+ break;
}
- if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
- U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
+ if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
+ U32 const checkCalc = (U32)xxh64_digest(&dctx->xxhState);
U32 checkRead;
- if (remainingSize<4) return ERROR(checksum_wrong);
- checkRead = MEM_readLE32(ip);
- if (checkRead != checkCalc) return ERROR(checksum_wrong);
+ if (remainingSize < 4)
+ return ERROR(checksum_wrong);
+ checkRead = ZSTD_readLE32(ip);
+ if (checkRead != checkCalc)
+ return ERROR(checksum_wrong);
ip += 4;
remainingSize -= 4;
}
@@ -1537,19 +1632,16 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
/* Allow caller to get size read */
*srcPtr = ip;
*srcSizePtr = remainingSize;
- return op-ostart;
+ return op - ostart;
}
-static const void* ZSTD_DDictDictContent(const ZSTD_DDict* ddict);
-static size_t ZSTD_DDictDictSize(const ZSTD_DDict* ddict);
+static const void *ZSTD_DDictDictContent(const ZSTD_DDict *ddict);
+static size_t ZSTD_DDictDictSize(const ZSTD_DDict *ddict);
-static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const void *dict, size_t dictSize,
- const ZSTD_DDict* ddict)
+static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize,
+ const ZSTD_DDict *ddict)
{
- void* const dststart = dst;
+ void *const dststart = dst;
if (ddict) {
if (dict) {
@@ -1564,14 +1656,13 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
while (srcSize >= ZSTD_frameHeaderSize_prefix) {
U32 magicNumber;
- magicNumber = MEM_readLE32(src);
+ magicNumber = ZSTD_readLE32(src);
if (magicNumber != ZSTD_MAGICNUMBER) {
if ((magicNumber & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
size_t skippableSize;
if (srcSize < ZSTD_skippableHeaderSize)
return ERROR(srcSize_wrong);
- skippableSize = MEM_readLE32((const BYTE *)src + 4) +
- ZSTD_skippableHeaderSize;
+ skippableSize = ZSTD_readLE32((const BYTE *)src + 4) + ZSTD_skippableHeaderSize;
if (srcSize < skippableSize) {
return ERROR(srcSize_wrong);
}
@@ -1594,90 +1685,87 @@ static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
}
ZSTD_checkContinuity(dctx, dst);
- { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
- &src, &srcSize);
- if (ZSTD_isError(res)) return res;
+ {
+ const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, &src, &srcSize);
+ if (ZSTD_isError(res))
+ return res;
/* don't need to bounds check this, ZSTD_decompressFrame will have
* already */
- dst = (BYTE*)dst + res;
+ dst = (BYTE *)dst + res;
dstCapacity -= res;
}
}
- if (srcSize) return ERROR(srcSize_wrong); /* input not entirely consumed */
+ if (srcSize)
+ return ERROR(srcSize_wrong); /* input not entirely consumed */
- return (BYTE*)dst - (BYTE*)dststart;
+ return (BYTE *)dst - (BYTE *)dststart;
}
-size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void *dict, size_t dictSize)
+size_t ZSTD_decompress_usingDict(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const void *dict, size_t dictSize)
{
return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);
}
-
-size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+size_t ZSTD_decompressDCtx(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
return ZSTD_decompress_usingDict(dctx, dst, dstCapacity, src, srcSize, NULL, 0);
}
-
/*-**************************************
* Advanced Streaming Decompression API
* Bufferless and synchronous
****************************************/
-size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
+size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx *dctx) { return dctx->expected; }
-ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
- switch(dctx->stage)
- {
- default: /* should not happen */
+ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx *dctx)
+{
+ switch (dctx->stage) {
+ default: /* should not happen */
case ZSTDds_getFrameHeaderSize:
- case ZSTDds_decodeFrameHeader:
- return ZSTDnit_frameHeader;
- case ZSTDds_decodeBlockHeader:
- return ZSTDnit_blockHeader;
- case ZSTDds_decompressBlock:
- return ZSTDnit_block;
- case ZSTDds_decompressLastBlock:
- return ZSTDnit_lastBlock;
- case ZSTDds_checkChecksum:
- return ZSTDnit_checksum;
+ case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader;
+ case ZSTDds_decodeBlockHeader: return ZSTDnit_blockHeader;
+ case ZSTDds_decompressBlock: return ZSTDnit_block;
+ case ZSTDds_decompressLastBlock: return ZSTDnit_lastBlock;
+ case ZSTDds_checkChecksum: return ZSTDnit_checksum;
case ZSTDds_decodeSkippableHeader:
- case ZSTDds_skipFrame:
- return ZSTDnit_skippableFrame;
+ case ZSTDds_skipFrame: return ZSTDnit_skippableFrame;
}
}
-int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; } /* for zbuff */
+int ZSTD_isSkipFrame(ZSTD_DCtx *dctx) { return dctx->stage == ZSTDds_skipFrame; } /* for zbuff */
/** ZSTD_decompressContinue() :
* @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
* or an error code, which can be tested using ZSTD_isError() */
-size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+size_t ZSTD_decompressContinue(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
/* Sanity check */
- if (srcSize != dctx->expected) return ERROR(srcSize_wrong);
- if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
+ if (srcSize != dctx->expected)
+ return ERROR(srcSize_wrong);
+ if (dstCapacity)
+ ZSTD_checkContinuity(dctx, dst);
- switch (dctx->stage)
- {
- case ZSTDds_getFrameHeaderSize :
- if (srcSize != ZSTD_frameHeaderSize_prefix) return ERROR(srcSize_wrong); /* impossible */
- if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
+ switch (dctx->stage) {
+ case ZSTDds_getFrameHeaderSize:
+ if (srcSize != ZSTD_frameHeaderSize_prefix)
+ return ERROR(srcSize_wrong); /* impossible */
+ if ((ZSTD_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
- dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix; /* magic number + skippable frame length */
+ dctx->expected = ZSTD_skippableHeaderSize - ZSTD_frameHeaderSize_prefix; /* magic number + skippable frame length */
dctx->stage = ZSTDds_decodeSkippableHeader;
return 0;
}
dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix);
- if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
+ if (ZSTD_isError(dctx->headerSize))
+ return dctx->headerSize;
memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
if (dctx->headerSize > ZSTD_frameHeaderSize_prefix) {
dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_prefix;
dctx->stage = ZSTDds_decodeFrameHeader;
return 0;
}
- dctx->expected = 0; /* not necessary to copy more */
+ dctx->expected = 0; /* not necessary to copy more */
case ZSTDds_decodeFrameHeader:
memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
@@ -1686,171 +1774,187 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
dctx->stage = ZSTDds_decodeBlockHeader;
return 0;
- case ZSTDds_decodeBlockHeader:
- { blockProperties_t bp;
- size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
- if (ZSTD_isError(cBlockSize)) return cBlockSize;
- dctx->expected = cBlockSize;
- dctx->bType = bp.blockType;
- dctx->rleSize = bp.origSize;
- if (cBlockSize) {
- dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
- return 0;
- }
- /* empty block */
- if (bp.lastBlock) {
- if (dctx->fParams.checksumFlag) {
- dctx->expected = 4;
- dctx->stage = ZSTDds_checkChecksum;
- } else {
- dctx->expected = 0; /* end of frame */
- dctx->stage = ZSTDds_getFrameHeaderSize;
- }
- } else {
- dctx->expected = 3; /* go directly to next header */
- dctx->stage = ZSTDds_decodeBlockHeader;
- }
+ case ZSTDds_decodeBlockHeader: {
+ blockProperties_t bp;
+ size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
+ if (ZSTD_isError(cBlockSize))
+ return cBlockSize;
+ dctx->expected = cBlockSize;
+ dctx->bType = bp.blockType;
+ dctx->rleSize = bp.origSize;
+ if (cBlockSize) {
+ dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
return 0;
}
+ /* empty block */
+ if (bp.lastBlock) {
+ if (dctx->fParams.checksumFlag) {
+ dctx->expected = 4;
+ dctx->stage = ZSTDds_checkChecksum;
+ } else {
+ dctx->expected = 0; /* end of frame */
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ }
+ } else {
+ dctx->expected = 3; /* go directly to next header */
+ dctx->stage = ZSTDds_decodeBlockHeader;
+ }
+ return 0;
+ }
case ZSTDds_decompressLastBlock:
- case ZSTDds_decompressBlock:
- { size_t rSize;
- switch(dctx->bType)
- {
- case bt_compressed:
- rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize);
- break;
- case bt_raw :
- rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
- break;
- case bt_rle :
- rSize = ZSTD_setRleBlock(dst, dstCapacity, src, srcSize, dctx->rleSize);
- break;
- case bt_reserved : /* should never happen */
- default:
- return ERROR(corruption_detected);
- }
- if (ZSTD_isError(rSize)) return rSize;
- if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
-
- if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
- if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
- dctx->expected = 4;
- dctx->stage = ZSTDds_checkChecksum;
- } else {
- dctx->expected = 0; /* ends here */
- dctx->stage = ZSTDds_getFrameHeaderSize;
- }
- } else {
- dctx->stage = ZSTDds_decodeBlockHeader;
- dctx->expected = ZSTD_blockHeaderSize;
- dctx->previousDstEnd = (char*)dst + rSize;
- }
+ case ZSTDds_decompressBlock: {
+ size_t rSize;
+ switch (dctx->bType) {
+ case bt_compressed: rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); break;
+ case bt_raw: rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize); break;
+ case bt_rle: rSize = ZSTD_setRleBlock(dst, dstCapacity, src, srcSize, dctx->rleSize); break;
+ case bt_reserved: /* should never happen */
+ default: return ERROR(corruption_detected);
+ }
+ if (ZSTD_isError(rSize))
return rSize;
+ if (dctx->fParams.checksumFlag)
+ xxh64_update(&dctx->xxhState, dst, rSize);
+
+ if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
+ if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
+ dctx->expected = 4;
+ dctx->stage = ZSTDds_checkChecksum;
+ } else {
+ dctx->expected = 0; /* ends here */
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ }
+ } else {
+ dctx->stage = ZSTDds_decodeBlockHeader;
+ dctx->expected = ZSTD_blockHeaderSize;
+ dctx->previousDstEnd = (char *)dst + rSize;
}
- case ZSTDds_checkChecksum:
- { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
- U32 const check32 = MEM_readLE32(src); /* srcSize == 4, guaranteed by dctx->expected */
- if (check32 != h32) return ERROR(checksum_wrong);
- dctx->expected = 0;
- dctx->stage = ZSTDds_getFrameHeaderSize;
- return 0;
- }
- case ZSTDds_decodeSkippableHeader:
- { memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
- dctx->expected = MEM_readLE32(dctx->headerBuffer + 4);
- dctx->stage = ZSTDds_skipFrame;
- return 0;
- }
- case ZSTDds_skipFrame:
- { dctx->expected = 0;
- dctx->stage = ZSTDds_getFrameHeaderSize;
- return 0;
- }
+ return rSize;
+ }
+ case ZSTDds_checkChecksum: {
+ U32 const h32 = (U32)xxh64_digest(&dctx->xxhState);
+ U32 const check32 = ZSTD_readLE32(src); /* srcSize == 4, guaranteed by dctx->expected */
+ if (check32 != h32)
+ return ERROR(checksum_wrong);
+ dctx->expected = 0;
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ return 0;
+ }
+ case ZSTDds_decodeSkippableHeader: {
+ memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);
+ dctx->expected = ZSTD_readLE32(dctx->headerBuffer + 4);
+ dctx->stage = ZSTDds_skipFrame;
+ return 0;
+ }
+ case ZSTDds_skipFrame: {
+ dctx->expected = 0;
+ dctx->stage = ZSTDds_getFrameHeaderSize;
+ return 0;
+ }
default:
- return ERROR(GENERIC); /* impossible */
+ return ERROR(GENERIC); /* impossible */
}
}
-
-static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+static size_t ZSTD_refDictContent(ZSTD_DCtx *dctx, const void *dict, size_t dictSize)
{
dctx->dictEnd = dctx->previousDstEnd;
- dctx->vBase = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base));
+ dctx->vBase = (const char *)dict - ((const char *)(dctx->previousDstEnd) - (const char *)(dctx->base));
dctx->base = dict;
- dctx->previousDstEnd = (const char*)dict + dictSize;
+ dctx->previousDstEnd = (const char *)dict + dictSize;
return 0;
}
/* ZSTD_loadEntropy() :
* dict : must point at beginning of a valid zstd dictionary
* @return : size of entropy tables read */
-static size_t ZSTD_loadEntropy(ZSTD_entropyTables_t* entropy, const void* const dict, size_t const dictSize)
+static size_t ZSTD_loadEntropy(ZSTD_entropyTables_t *entropy, const void *const dict, size_t const dictSize)
{
- const BYTE* dictPtr = (const BYTE*)dict;
- const BYTE* const dictEnd = dictPtr + dictSize;
+ const BYTE *dictPtr = (const BYTE *)dict;
+ const BYTE *const dictEnd = dictPtr + dictSize;
- if (dictSize <= 8) return ERROR(dictionary_corrupted);
- dictPtr += 8; /* skip header = magic + dictID */
+ if (dictSize <= 8)
+ return ERROR(dictionary_corrupted);
+ dictPtr += 8; /* skip header = magic + dictID */
-
- { size_t const hSize = HUF_readDTableX4(entropy->hufTable, dictPtr, dictEnd-dictPtr);
- if (HUF_isError(hSize)) return ERROR(dictionary_corrupted);
+ {
+ size_t const hSize = HUF_readDTableX4_wksp(entropy->hufTable, dictPtr, dictEnd - dictPtr, entropy->workspace, sizeof(entropy->workspace));
+ if (HUF_isError(hSize))
+ return ERROR(dictionary_corrupted);
dictPtr += hSize;
}
- { short offcodeNCount[MaxOff+1];
+ {
+ short offcodeNCount[MaxOff + 1];
U32 offcodeMaxValue = MaxOff, offcodeLog;
- size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
- if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
- if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
- CHECK_E(FSE_buildDTable(entropy->OFTable, offcodeNCount, offcodeMaxValue, offcodeLog), dictionary_corrupted);
+ size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd - dictPtr);
+ if (FSE_isError(offcodeHeaderSize))
+ return ERROR(dictionary_corrupted);
+ if (offcodeLog > OffFSELog)
+ return ERROR(dictionary_corrupted);
+ CHECK_E(FSE_buildDTable_wksp(entropy->OFTable, offcodeNCount, offcodeMaxValue, offcodeLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted);
dictPtr += offcodeHeaderSize;
}
- { short matchlengthNCount[MaxML+1];
+ {
+ short matchlengthNCount[MaxML + 1];
unsigned matchlengthMaxValue = MaxML, matchlengthLog;
- size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
- if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
- if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
- CHECK_E(FSE_buildDTable(entropy->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog), dictionary_corrupted);
+ size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd - dictPtr);
+ if (FSE_isError(matchlengthHeaderSize))
+ return ERROR(dictionary_corrupted);
+ if (matchlengthLog > MLFSELog)
+ return ERROR(dictionary_corrupted);
+ CHECK_E(FSE_buildDTable_wksp(entropy->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted);
dictPtr += matchlengthHeaderSize;
}
- { short litlengthNCount[MaxLL+1];
+ {
+ short litlengthNCount[MaxLL + 1];
unsigned litlengthMaxValue = MaxLL, litlengthLog;
- size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
- if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
- if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
- CHECK_E(FSE_buildDTable(entropy->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog), dictionary_corrupted);
+ size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd - dictPtr);
+ if (FSE_isError(litlengthHeaderSize))
+ return ERROR(dictionary_corrupted);
+ if (litlengthLog > LLFSELog)
+ return ERROR(dictionary_corrupted);
+ CHECK_E(FSE_buildDTable_wksp(entropy->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog, entropy->workspace, sizeof(entropy->workspace)), dictionary_corrupted);
dictPtr += litlengthHeaderSize;
}
- if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
- { int i;
- size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));
- for (i=0; i<3; i++) {
- U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;
- if (rep==0 || rep >= dictContentSize) return ERROR(dictionary_corrupted);
+ if (dictPtr + 12 > dictEnd)
+ return ERROR(dictionary_corrupted);
+ {
+ int i;
+ size_t const dictContentSize = (size_t)(dictEnd - (dictPtr + 12));
+ for (i = 0; i < 3; i++) {
+ U32 const rep = ZSTD_readLE32(dictPtr);
+ dictPtr += 4;
+ if (rep == 0 || rep >= dictContentSize)
+ return ERROR(dictionary_corrupted);
entropy->rep[i] = rep;
- } }
+ }
+ }
- return dictPtr - (const BYTE*)dict;
+ return dictPtr - (const BYTE *)dict;
}
-static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx *dctx, const void *dict, size_t dictSize)
{
- if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);
- { U32 const magic = MEM_readLE32(dict);
+ if (dictSize < 8)
+ return ZSTD_refDictContent(dctx, dict, dictSize);
+ {
+ U32 const magic = ZSTD_readLE32(dict);
if (magic != ZSTD_DICT_MAGIC) {
- return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */
- } }
- dctx->dictID = MEM_readLE32((const char*)dict + 4);
+ return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */
+ }
+ }
+ dctx->dictID = ZSTD_readLE32((const char *)dict + 4);
/* load entropy tables */
- { size_t const eSize = ZSTD_loadEntropy(&dctx->entropy, dict, dictSize);
- if (ZSTD_isError(eSize)) return ERROR(dictionary_corrupted);
- dict = (const char*)dict + eSize;
+ {
+ size_t const eSize = ZSTD_loadEntropy(&dctx->entropy, dict, dictSize);
+ if (ZSTD_isError(eSize))
+ return ERROR(dictionary_corrupted);
+ dict = (const char *)dict + eSize;
dictSize -= eSize;
}
dctx->litEntropy = dctx->fseEntropy = 1;
@@ -1859,49 +1963,40 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict
return ZSTD_refDictContent(dctx, dict, dictSize);
}
-size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
+size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx *dctx, const void *dict, size_t dictSize)
{
CHECK_F(ZSTD_decompressBegin(dctx));
- if (dict && dictSize) CHECK_E(ZSTD_decompress_insertDictionary(dctx, dict, dictSize), dictionary_corrupted);
+ if (dict && dictSize)
+ CHECK_E(ZSTD_decompress_insertDictionary(dctx, dict, dictSize), dictionary_corrupted);
return 0;
}
-
/* ====== ZSTD_DDict ====== */
struct ZSTD_DDict_s {
- void* dictBuffer;
- const void* dictContent;
+ void *dictBuffer;
+ const void *dictContent;
size_t dictSize;
ZSTD_entropyTables_t entropy;
U32 dictID;
U32 entropyPresent;
ZSTD_customMem cMem;
-}; /* typedef'd to ZSTD_DDict within "zstd.h" */
+}; /* typedef'd to ZSTD_DDict within "zstd.h" */
-size_t ZSTD_DDictWorkspaceBound(void)
-{
- return ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_DDict));
-}
+size_t ZSTD_DDictWorkspaceBound(void) { return ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_DDict)); }
-static const void* ZSTD_DDictDictContent(const ZSTD_DDict* ddict)
-{
- return ddict->dictContent;
-}
+static const void *ZSTD_DDictDictContent(const ZSTD_DDict *ddict) { return ddict->dictContent; }
-static size_t ZSTD_DDictDictSize(const ZSTD_DDict* ddict)
-{
- return ddict->dictSize;
-}
+static size_t ZSTD_DDictDictSize(const ZSTD_DDict *ddict) { return ddict->dictSize; }
-static void ZSTD_refDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddict)
+static void ZSTD_refDDict(ZSTD_DCtx *dstDCtx, const ZSTD_DDict *ddict)
{
- ZSTD_decompressBegin(dstDCtx); /* init */
- if (ddict) { /* support refDDict on NULL */
+ ZSTD_decompressBegin(dstDCtx); /* init */
+ if (ddict) { /* support refDDict on NULL */
dstDCtx->dictID = ddict->dictID;
dstDCtx->base = ddict->dictContent;
dstDCtx->vBase = ddict->dictContent;
- dstDCtx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize;
+ dstDCtx->dictEnd = (const BYTE *)ddict->dictContent + ddict->dictSize;
dstDCtx->previousDstEnd = dstDCtx->dictEnd;
if (ddict->entropyPresent) {
dstDCtx->litEntropy = 1;
@@ -1920,49 +2015,59 @@ static void ZSTD_refDDict(ZSTD_DCtx* dstDCtx, const ZSTD_DDict* ddict)
}
}
-static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict* ddict)
+static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict *ddict)
{
ddict->dictID = 0;
ddict->entropyPresent = 0;
- if (ddict->dictSize < 8) return 0;
- { U32 const magic = MEM_readLE32(ddict->dictContent);
- if (magic != ZSTD_DICT_MAGIC) return 0; /* pure content mode */
+ if (ddict->dictSize < 8)
+ return 0;
+ {
+ U32 const magic = ZSTD_readLE32(ddict->dictContent);
+ if (magic != ZSTD_DICT_MAGIC)
+ return 0; /* pure content mode */
}
- ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + 4);
+ ddict->dictID = ZSTD_readLE32((const char *)ddict->dictContent + 4);
/* load entropy tables */
- CHECK_E( ZSTD_loadEntropy(&ddict->entropy, ddict->dictContent, ddict->dictSize), dictionary_corrupted );
+ CHECK_E(ZSTD_loadEntropy(&ddict->entropy, ddict->dictContent, ddict->dictSize), dictionary_corrupted);
ddict->entropyPresent = 1;
return 0;
}
-
-static ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, unsigned byReference, ZSTD_customMem customMem)
+static ZSTD_DDict *ZSTD_createDDict_advanced(const void *dict, size_t dictSize, unsigned byReference, ZSTD_customMem customMem)
{
- if (!customMem.customAlloc || !customMem.customFree) return NULL;
+ if (!customMem.customAlloc || !customMem.customFree)
+ return NULL;
- { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
- if (!ddict) return NULL;
+ {
+ ZSTD_DDict *const ddict = (ZSTD_DDict *)ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
+ if (!ddict)
+ return NULL;
ddict->cMem = customMem;
if ((byReference) || (!dict) || (!dictSize)) {
ddict->dictBuffer = NULL;
ddict->dictContent = dict;
} else {
- void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
- if (!internalBuffer) { ZSTD_freeDDict(ddict); return NULL; }
+ void *const internalBuffer = ZSTD_malloc(dictSize, customMem);
+ if (!internalBuffer) {
+ ZSTD_freeDDict(ddict);
+ return NULL;
+ }
memcpy(internalBuffer, dict, dictSize);
ddict->dictBuffer = internalBuffer;
ddict->dictContent = internalBuffer;
}
ddict->dictSize = dictSize;
- ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
+ ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
/* parse dictionary content */
- { size_t const errorCode = ZSTD_loadEntropy_inDDict(ddict);
+ {
+ size_t const errorCode = ZSTD_loadEntropy_inDDict(ddict);
if (ZSTD_isError(errorCode)) {
ZSTD_freeDDict(ddict);
return NULL;
- } }
+ }
+ }
return ddict;
}
@@ -1972,17 +2077,18 @@ static ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,
* Create a digested dictionary, to start decompression without startup delay.
* `dict` content is copied inside DDict.
* Consequently, `dict` can be released after `ZSTD_DDict` creation */
-ZSTD_DDict* ZSTD_initDDict(const void* dict, size_t dictSize, void* workspace, size_t workspaceSize)
+ZSTD_DDict *ZSTD_initDDict(const void *dict, size_t dictSize, void *workspace, size_t workspaceSize)
{
ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
return ZSTD_createDDict_advanced(dict, dictSize, 1, stackMem);
}
-
-size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
+size_t ZSTD_freeDDict(ZSTD_DDict *ddict)
{
- if (ddict==NULL) return 0; /* support free on NULL */
- { ZSTD_customMem const cMem = ddict->cMem;
+ if (ddict == NULL)
+ return 0; /* support free on NULL */
+ {
+ ZSTD_customMem const cMem = ddict->cMem;
ZSTD_free(ddict->dictBuffer, cMem);
ZSTD_free(ddict, cMem);
return 0;
@@ -1993,20 +2099,23 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict)
* Provides the dictID stored within dictionary.
* if @return == 0, the dictionary is not conformant with Zstandard specification.
* It can still be loaded, but as a content-only dictionary. */
-unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
+unsigned ZSTD_getDictID_fromDict(const void *dict, size_t dictSize)
{
- if (dictSize < 8) return 0;
- if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return 0;
- return MEM_readLE32((const char*)dict + 4);
+ if (dictSize < 8)
+ return 0;
+ if (ZSTD_readLE32(dict) != ZSTD_DICT_MAGIC)
+ return 0;
+ return ZSTD_readLE32((const char *)dict + 4);
}
/*! ZSTD_getDictID_fromDDict() :
* Provides the dictID of the dictionary loaded into `ddict`.
* If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
* Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
-unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
+unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict *ddict)
{
- if (ddict==NULL) return 0;
+ if (ddict == NULL)
+ return 0;
return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
}
@@ -2020,91 +2129,92 @@ unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict)
* - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`).
* - This is not a Zstandard frame.
* When identifying the exact failure cause, it's possible to used ZSTD_getFrameParams(), which will provide a more precise error code. */
-unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
+unsigned ZSTD_getDictID_fromFrame(const void *src, size_t srcSize)
{
- ZSTD_frameParams zfp = { 0 , 0 , 0 , 0 };
+ ZSTD_frameParams zfp = {0, 0, 0, 0};
size_t const hError = ZSTD_getFrameParams(&zfp, src, srcSize);
- if (ZSTD_isError(hError)) return 0;
+ if (ZSTD_isError(hError))
+ return 0;
return zfp.dictID;
}
-
/*! ZSTD_decompress_usingDDict() :
* Decompression using a pre-digested Dictionary
* Use dictionary without significant overhead. */
-size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_DDict* ddict)
+size_t ZSTD_decompress_usingDDict(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, const void *src, size_t srcSize, const ZSTD_DDict *ddict)
{
/* pass content and size in case legacy frames are encountered */
- return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,
- NULL, 0,
- ddict);
+ return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, NULL, 0, ddict);
}
-
/*=====================================
* Streaming decompression
*====================================*/
-typedef enum { zdss_init, zdss_loadHeader,
- zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
+typedef enum { zdss_init, zdss_loadHeader, zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage;
/* *** Resource management *** */
struct ZSTD_DStream_s {
- ZSTD_DCtx* dctx;
- ZSTD_DDict* ddictLocal;
- const ZSTD_DDict* ddict;
+ ZSTD_DCtx *dctx;
+ ZSTD_DDict *ddictLocal;
+ const ZSTD_DDict *ddict;
ZSTD_frameParams fParams;
ZSTD_dStreamStage stage;
- char* inBuff;
+ char *inBuff;
size_t inBuffSize;
size_t inPos;
size_t maxWindowSize;
- char* outBuff;
+ char *outBuff;
size_t outBuffSize;
size_t outStart;
size_t outEnd;
size_t blockSize;
- BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store frame header */
+ BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store frame header */
size_t lhSize;
ZSTD_customMem customMem;
- void* legacyContext;
+ void *legacyContext;
U32 previousLegacyVersion;
U32 legacyVersion;
U32 hostageByte;
-}; /* typedef'd to ZSTD_DStream within "zstd.h" */
+}; /* typedef'd to ZSTD_DStream within "zstd.h" */
-size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize) {
+size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize)
+{
size_t const blockSize = MIN(maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
size_t const inBuffSize = blockSize;
size_t const outBuffSize = maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
return ZSTD_DCtxWorkspaceBound() + ZSTD_ALIGN(sizeof(ZSTD_DStream)) + ZSTD_ALIGN(inBuffSize) + ZSTD_ALIGN(outBuffSize);
}
-static ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)
+static ZSTD_DStream *ZSTD_createDStream_advanced(ZSTD_customMem customMem)
{
- ZSTD_DStream* zds;
+ ZSTD_DStream *zds;
- if (!customMem.customAlloc || !customMem.customFree) return NULL;
+ if (!customMem.customAlloc || !customMem.customFree)
+ return NULL;
- zds = (ZSTD_DStream*) ZSTD_malloc(sizeof(ZSTD_DStream), customMem);
- if (zds==NULL) return NULL;
+ zds = (ZSTD_DStream *)ZSTD_malloc(sizeof(ZSTD_DStream), customMem);
+ if (zds == NULL)
+ return NULL;
memset(zds, 0, sizeof(ZSTD_DStream));
memcpy(&zds->customMem, &customMem, sizeof(ZSTD_customMem));
zds->dctx = ZSTD_createDCtx_advanced(customMem);
- if (zds->dctx == NULL) { ZSTD_freeDStream(zds); return NULL; }
+ if (zds->dctx == NULL) {
+ ZSTD_freeDStream(zds);
+ return NULL;
+ }
zds->stage = zdss_init;
zds->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
return zds;
}
-ZSTD_DStream* ZSTD_initDStream(size_t maxWindowSize, void* workspace, size_t workspaceSize)
+ZSTD_DStream *ZSTD_initDStream(size_t maxWindowSize, void *workspace, size_t workspaceSize)
{
ZSTD_customMem const stackMem = ZSTD_initStack(workspace, workspaceSize);
- ZSTD_DStream* zds = ZSTD_createDStream_advanced(stackMem);
- if (!zds) { return NULL; }
+ ZSTD_DStream *zds = ZSTD_createDStream_advanced(stackMem);
+ if (!zds) {
+ return NULL;
+ }
zds->maxWindowSize = maxWindowSize;
zds->stage = zdss_loadHeader;
@@ -2114,22 +2224,38 @@ ZSTD_DStream* ZSTD_initDStream(size_t maxWindowSize, void* workspace, size_t wor
zds->ddict = zds->ddictLocal;
zds->legacyVersion = 0;
zds->hostageByte = 0;
+
+ {
+ size_t const blockSize = MIN(zds->maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
+ size_t const neededOutSize = zds->maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
+
+ zds->inBuff = (char *)ZSTD_malloc(blockSize, zds->customMem);
+ zds->inBuffSize = blockSize;
+ zds->outBuff = (char *)ZSTD_malloc(neededOutSize, zds->customMem);
+ zds->outBuffSize = neededOutSize;
+ if (zds->inBuff == NULL || zds->outBuff == NULL) {
+ ZSTD_freeDStream(zds);
+ return NULL;
+ }
+ }
return zds;
}
-ZSTD_DStream* ZSTD_initDStream_usingDDict(size_t maxWindowSize, const ZSTD_DDict* ddict, void* workspace, size_t workspaceSize)
+ZSTD_DStream *ZSTD_initDStream_usingDDict(size_t maxWindowSize, const ZSTD_DDict *ddict, void *workspace, size_t workspaceSize)
{
- ZSTD_DStream* zds = ZSTD_initDStream(maxWindowSize, workspace, workspaceSize);
+ ZSTD_DStream *zds = ZSTD_initDStream(maxWindowSize, workspace, workspaceSize);
if (zds) {
zds->ddict = ddict;
}
return zds;
}
-size_t ZSTD_freeDStream(ZSTD_DStream* zds)
+size_t ZSTD_freeDStream(ZSTD_DStream *zds)
{
- if (zds==NULL) return 0; /* support free on null */
- { ZSTD_customMem const cMem = zds->customMem;
+ if (zds == NULL)
+ return 0; /* support free on null */
+ {
+ ZSTD_customMem const cMem = zds->customMem;
ZSTD_freeDCtx(zds->dctx);
zds->dctx = NULL;
ZSTD_freeDDict(zds->ddictLocal);
@@ -2143,13 +2269,12 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds)
}
}
-
/* *** Initialization *** */
-size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX + ZSTD_blockHeaderSize; }
+size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX + ZSTD_blockHeaderSize; }
size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
-size_t ZSTD_resetDStream(ZSTD_DStream* zds)
+size_t ZSTD_resetDStream(ZSTD_DStream *zds)
{
zds->stage = zdss_loadHeader;
zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
@@ -2160,178 +2285,202 @@ size_t ZSTD_resetDStream(ZSTD_DStream* zds)
/* ***** Decompression ***** */
-MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
+ZSTD_STATIC size_t ZSTD_limitCopy(void *dst, size_t dstCapacity, const void *src, size_t srcSize)
{
size_t const length = MIN(dstCapacity, srcSize);
memcpy(dst, src, length);
return length;
}
-
-size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, ZSTD_inBuffer *input)
{
- const char* const istart = (const char*)(input->src) + input->pos;
- const char* const iend = (const char*)(input->src) + input->size;
- const char* ip = istart;
- char* const ostart = (char*)(output->dst) + output->pos;
- char* const oend = (char*)(output->dst) + output->size;
- char* op = ostart;
+ const char *const istart = (const char *)(input->src) + input->pos;
+ const char *const iend = (const char *)(input->src) + input->size;
+ const char *ip = istart;
+ char *const ostart = (char *)(output->dst) + output->pos;
+ char *const oend = (char *)(output->dst) + output->size;
+ char *op = ostart;
U32 someMoreWork = 1;
while (someMoreWork) {
- switch(zds->stage)
- {
- case zdss_init :
- ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */
- /* fall-through */
+ switch (zds->stage) {
+ case zdss_init:
+ ZSTD_resetDStream(zds); /* transparent reset on starting decoding a new frame */
+ /* fall-through */
- case zdss_loadHeader :
- { size_t const hSize = ZSTD_getFrameParams(&zds->fParams, zds->headerBuffer, zds->lhSize);
- if (ZSTD_isError(hSize))
+ case zdss_loadHeader: {
+ size_t const hSize = ZSTD_getFrameParams(&zds->fParams, zds->headerBuffer, zds->lhSize);
+ if (ZSTD_isError(hSize))
return hSize;
- if (hSize != 0) { /* need more input */
- size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */
- if (toLoad > (size_t)(iend-ip)) { /* not enough input to load full header */
- memcpy(zds->headerBuffer + zds->lhSize, ip, iend-ip);
- zds->lhSize += iend-ip;
- input->pos = input->size;
- return (MAX(ZSTD_frameHeaderSize_min, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
- }
- memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
- break;
- } }
+ if (hSize != 0) { /* need more input */
+ size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */
+ if (toLoad > (size_t)(iend - ip)) { /* not enough input to load full header */
+ memcpy(zds->headerBuffer + zds->lhSize, ip, iend - ip);
+ zds->lhSize += iend - ip;
+ input->pos = input->size;
+ return (MAX(ZSTD_frameHeaderSize_min, hSize) - zds->lhSize) +
+ ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
+ }
+ memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad);
+ zds->lhSize = hSize;
+ ip += toLoad;
+ break;
+ }
/* check for single-pass mode opportunity */
if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */
- && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
- size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
- if (cSize <= (size_t)(iend-istart)) {
- size_t const decompressedSize = ZSTD_decompress_usingDDict(zds->dctx, op, oend-op, istart, cSize, zds->ddict);
- if (ZSTD_isError(decompressedSize)) return decompressedSize;
+ && (U64)(size_t)(oend - op) >= zds->fParams.frameContentSize) {
+ size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend - istart);
+ if (cSize <= (size_t)(iend - istart)) {
+ size_t const decompressedSize = ZSTD_decompress_usingDDict(zds->dctx, op, oend - op, istart, cSize, zds->ddict);
+ if (ZSTD_isError(decompressedSize))
+ return decompressedSize;
ip = istart + cSize;
op += decompressedSize;
zds->dctx->expected = 0;
zds->stage = zdss_init;
someMoreWork = 0;
break;
- } }
+ }
+ }
/* Consume header */
ZSTD_refDDict(zds->dctx, zds->ddict);
- { size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */
+ {
+ size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */
CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer, h1Size));
- { size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx);
- CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer+h1Size, h2Size));
- } }
-
- zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
- if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);
-
- /* Adapt buffer sizes to frame header instructions */
- { size_t const blockSize = MIN(zds->fParams.windowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
- size_t const neededOutSize = zds->fParams.windowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
- zds->blockSize = blockSize;
- if (zds->inBuffSize < blockSize) {
- ZSTD_free(zds->inBuff, zds->customMem);
- zds->inBuffSize = blockSize;
- zds->inBuff = (char*)ZSTD_malloc(blockSize, zds->customMem);
- if (zds->inBuff == NULL) return ERROR(memory_allocation);
+ {
+ size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx);
+ CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer + h1Size, h2Size));
}
- if (zds->outBuffSize < neededOutSize) {
- ZSTD_free(zds->outBuff, zds->customMem);
- zds->outBuffSize = neededOutSize;
- zds->outBuff = (char*)ZSTD_malloc(neededOutSize, zds->customMem);
- if (zds->outBuff == NULL) return ERROR(memory_allocation);
- } }
- zds->stage = zdss_read;
- /* pass-through */
-
- case zdss_read:
- { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
- if (neededInSize==0) { /* end of frame */
- zds->stage = zdss_init;
- someMoreWork = 0;
- break;
- }
- if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
- const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);
- size_t const decodedSize = ZSTD_decompressContinue(zds->dctx,
- zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart),
- ip, neededInSize);
- if (ZSTD_isError(decodedSize)) return decodedSize;
- ip += neededInSize;
- if (!decodedSize && !isSkipFrame) break; /* this was just a header */
- zds->outEnd = zds->outStart + decodedSize;
- zds->stage = zdss_flush;
- break;
- }
- if (ip==iend) { someMoreWork = 0; break; } /* no more input */
- zds->stage = zdss_load;
- /* pass-through */
}
- case zdss_load:
- { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
- size_t const toLoad = neededInSize - zds->inPos; /* should always be <= remaining space within inBuff */
- size_t loadedSize;
- if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected); /* should never happen */
- loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
- ip += loadedSize;
- zds->inPos += loadedSize;
- if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
+ zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
+ if (zds->fParams.windowSize > zds->maxWindowSize)
+ return ERROR(frameParameter_windowTooLarge);
- /* decode loaded input */
- { const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);
- size_t const decodedSize = ZSTD_decompressContinue(zds->dctx,
- zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
- zds->inBuff, neededInSize);
- if (ZSTD_isError(decodedSize)) return decodedSize;
- zds->inPos = 0; /* input is consumed */
- if (!decodedSize && !isSkipFrame) { zds->stage = zdss_read; break; } /* this was just a header */
- zds->outEnd = zds->outStart + decodedSize;
- zds->stage = zdss_flush;
- /* pass-through */
- } }
-
- case zdss_flush:
- { size_t const toFlushSize = zds->outEnd - zds->outStart;
- size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
- op += flushedSize;
- zds->outStart += flushedSize;
- if (flushedSize == toFlushSize) { /* flush completed */
- zds->stage = zdss_read;
- if (zds->outStart + zds->blockSize > zds->outBuffSize)
- zds->outStart = zds->outEnd = 0;
- break;
+ /* Buffers are preallocated, but double check */
+ {
+ size_t const blockSize = MIN(zds->maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
+ size_t const neededOutSize = zds->maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
+ if (zds->inBuffSize < blockSize) {
+ return ERROR(GENERIC);
}
- /* cannot complete flush */
+ if (zds->outBuffSize < neededOutSize) {
+ return ERROR(GENERIC);
+ }
+ zds->blockSize = blockSize;
+ }
+ zds->stage = zdss_read;
+ }
+ /* pass-through */
+
+ case zdss_read: {
+ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
+ if (neededInSize == 0) { /* end of frame */
+ zds->stage = zdss_init;
someMoreWork = 0;
break;
}
- default: return ERROR(GENERIC); /* impossible */
- } }
+ if ((size_t)(iend - ip) >= neededInSize) { /* decode directly from src */
+ const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);
+ size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart,
+ (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), ip, neededInSize);
+ if (ZSTD_isError(decodedSize))
+ return decodedSize;
+ ip += neededInSize;
+ if (!decodedSize && !isSkipFrame)
+ break; /* this was just a header */
+ zds->outEnd = zds->outStart + decodedSize;
+ zds->stage = zdss_flush;
+ break;
+ }
+ if (ip == iend) {
+ someMoreWork = 0;
+ break;
+ } /* no more input */
+ zds->stage = zdss_load;
+ /* pass-through */
+ }
+
+ case zdss_load: {
+ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);
+ size_t const toLoad = neededInSize - zds->inPos; /* should always be <= remaining space within inBuff */
+ size_t loadedSize;
+ if (toLoad > zds->inBuffSize - zds->inPos)
+ return ERROR(corruption_detected); /* should never happen */
+ loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend - ip);
+ ip += loadedSize;
+ zds->inPos += loadedSize;
+ if (loadedSize < toLoad) {
+ someMoreWork = 0;
+ break;
+ } /* not enough input, wait for more */
+
+ /* decode loaded input */
+ {
+ const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);
+ size_t const decodedSize = ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
+ zds->inBuff, neededInSize);
+ if (ZSTD_isError(decodedSize))
+ return decodedSize;
+ zds->inPos = 0; /* input is consumed */
+ if (!decodedSize && !isSkipFrame) {
+ zds->stage = zdss_read;
+ break;
+ } /* this was just a header */
+ zds->outEnd = zds->outStart + decodedSize;
+ zds->stage = zdss_flush;
+ /* pass-through */
+ }
+ }
+
+ case zdss_flush: {
+ size_t const toFlushSize = zds->outEnd - zds->outStart;
+ size_t const flushedSize = ZSTD_limitCopy(op, oend - op, zds->outBuff + zds->outStart, toFlushSize);
+ op += flushedSize;
+ zds->outStart += flushedSize;
+ if (flushedSize == toFlushSize) { /* flush completed */
+ zds->stage = zdss_read;
+ if (zds->outStart + zds->blockSize > zds->outBuffSize)
+ zds->outStart = zds->outEnd = 0;
+ break;
+ }
+ /* cannot complete flush */
+ someMoreWork = 0;
+ break;
+ }
+ default:
+ return ERROR(GENERIC); /* impossible */
+ }
+ }
/* result */
- input->pos += (size_t)(ip-istart);
- output->pos += (size_t)(op-ostart);
- { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->dctx);
- if (!nextSrcSizeHint) { /* frame fully decoded */
- if (zds->outEnd == zds->outStart) { /* output fully flushed */
+ input->pos += (size_t)(ip - istart);
+ output->pos += (size_t)(op - ostart);
+ {
+ size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds->dctx);
+ if (!nextSrcSizeHint) { /* frame fully decoded */
+ if (zds->outEnd == zds->outStart) { /* output fully flushed */
if (zds->hostageByte) {
- if (input->pos >= input->size) { zds->stage = zdss_read; return 1; } /* can't release hostage (not present) */
- input->pos++; /* release hostage */
+ if (input->pos >= input->size) {
+ zds->stage = zdss_read;
+ return 1;
+ } /* can't release hostage (not present) */
+ input->pos++; /* release hostage */
}
return 0;
}
if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
- input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */
- zds->hostageByte=1;
+ input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */
+ zds->hostageByte = 1;
}
return 1;
}
- nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->dctx) == ZSTDnit_block); /* preload header of next block */
- if (zds->inPos > nextSrcSizeHint) return ERROR(GENERIC); /* should never happen */
- nextSrcSizeHint -= zds->inPos; /* already loaded*/
+ nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds->dctx) == ZSTDnit_block); /* preload header of next block */
+ if (zds->inPos > nextSrcSizeHint)
+ return ERROR(GENERIC); /* should never happen */
+ nextSrcSizeHint -= zds->inPos; /* already loaded*/
return nextSrcSizeHint;
}
}
@@ -2373,5 +2522,5 @@ EXPORT_SYMBOL(ZSTD_nextInputType);
EXPORT_SYMBOL(ZSTD_decompressBlock);
EXPORT_SYMBOL(ZSTD_insertBlock);
-MODULE_LICENSE("BSD");
+MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Zstd Decompressor");
diff --git a/contrib/linux-kernel/lib/zstd/entropy_common.c b/contrib/linux-kernel/lib/zstd/entropy_common.c
index 68d880827..2b0a643c3 100644
--- a/contrib/linux-kernel/lib/zstd/entropy_common.c
+++ b/contrib/linux-kernel/lib/zstd/entropy_common.c
@@ -1,65 +1,66 @@
/*
- Common functions of New Generation Entropy library
- Copyright (C) 2016, 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 :
- - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
- - Public forum : https://groups.google.com/forum/#!forum/lz4c
-*************************************************************************** */
+ * Common functions of New Generation Entropy library
+ * Copyright (C) 2016, 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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ */
/* *************************************
* Dependencies
***************************************/
-#include "mem.h"
-#include "error_private.h" /* ERR_*, ERROR */
+#include "error_private.h" /* ERR_*, ERROR */
#include "fse.h"
#include "huf.h"
-
+#include "mem.h"
/*=== Version ===*/
unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
-
/*=== Error Management ===*/
unsigned FSE_isError(size_t code) { return ERR_isError(code); }
unsigned HUF_isError(size_t code) { return ERR_isError(code); }
-
/*-**************************************************************
* FSE NCount encoding-decoding
****************************************************************/
-size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
- const void* headerBuffer, size_t hbSize)
+size_t FSE_readNCount(short *normalizedCounter, unsigned *maxSVPtr, unsigned *tableLogPtr, const void *headerBuffer, size_t hbSize)
{
- const BYTE* const istart = (const BYTE*) headerBuffer;
- const BYTE* const iend = istart + hbSize;
- const BYTE* ip = istart;
+ const BYTE *const istart = (const BYTE *)headerBuffer;
+ const BYTE *const iend = istart + hbSize;
+ const BYTE *ip = istart;
int nbBits;
int remaining;
int threshold;
@@ -68,29 +69,32 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
unsigned charnum = 0;
int previous0 = 0;
- if (hbSize < 4) return ERROR(srcSize_wrong);
- bitStream = MEM_readLE32(ip);
- nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
- if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
+ if (hbSize < 4)
+ return ERROR(srcSize_wrong);
+ bitStream = ZSTD_readLE32(ip);
+ nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
+ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX)
+ return ERROR(tableLog_tooLarge);
bitStream >>= 4;
bitCount = 4;
*tableLogPtr = nbBits;
- remaining = (1<1) & (charnum<=*maxSVPtr)) {
+ while ((remaining > 1) & (charnum <= *maxSVPtr)) {
if (previous0) {
unsigned n0 = charnum;
while ((bitStream & 0xFFFF) == 0xFFFF) {
n0 += 24;
- if (ip < iend-5) {
+ if (ip < iend - 5) {
ip += 2;
- bitStream = MEM_readLE32(ip) >> bitCount;
+ bitStream = ZSTD_readLE32(ip) >> bitCount;
} else {
bitStream >>= 16;
- bitCount += 16;
- } }
+ bitCount += 16;
+ }
+ }
while ((bitStream & 3) == 3) {
n0 += 3;
bitStream >>= 2;
@@ -98,29 +102,34 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
}
n0 += bitStream & 3;
bitCount += 2;
- if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
- while (charnum < n0) normalizedCounter[charnum++] = 0;
- if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
- ip += bitCount>>3;
+ if (n0 > *maxSVPtr)
+ return ERROR(maxSymbolValue_tooSmall);
+ while (charnum < n0)
+ normalizedCounter[charnum++] = 0;
+ if ((ip <= iend - 7) || (ip + (bitCount >> 3) <= iend - 4)) {
+ ip += bitCount >> 3;
bitCount &= 7;
- bitStream = MEM_readLE32(ip) >> bitCount;
+ bitStream = ZSTD_readLE32(ip) >> bitCount;
} else {
bitStream >>= 2;
- } }
- { int const max = (2*threshold-1) - remaining;
+ }
+ }
+ {
+ int const max = (2 * threshold - 1) - remaining;
int count;
- if ((bitStream & (threshold-1)) < (U32)max) {
- count = bitStream & (threshold-1);
- bitCount += nbBits-1;
+ if ((bitStream & (threshold - 1)) < (U32)max) {
+ count = bitStream & (threshold - 1);
+ bitCount += nbBits - 1;
} else {
- count = bitStream & (2*threshold-1);
- if (count >= threshold) count -= max;
+ count = bitStream & (2 * threshold - 1);
+ if (count >= threshold)
+ count -= max;
bitCount += nbBits;
}
- count--; /* extra accuracy */
- remaining -= count < 0 ? -count : count; /* -1 means +1 */
+ count--; /* extra accuracy */
+ remaining -= count < 0 ? -count : count; /* -1 means +1 */
normalizedCounter[charnum++] = (short)count;
previous0 = !count;
while (remaining < threshold) {
@@ -128,24 +137,26 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
threshold >>= 1;
}
- if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
- ip += bitCount>>3;
+ if ((ip <= iend - 7) || (ip + (bitCount >> 3) <= iend - 4)) {
+ ip += bitCount >> 3;
bitCount &= 7;
} else {
bitCount -= (int)(8 * (iend - 4 - ip));
ip = iend - 4;
}
- bitStream = MEM_readLE32(ip) >> (bitCount & 31);
- } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
- if (remaining != 1) return ERROR(corruption_detected);
- if (bitCount > 32) return ERROR(corruption_detected);
- *maxSVPtr = charnum-1;
+ bitStream = ZSTD_readLE32(ip) >> (bitCount & 31);
+ }
+ } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
+ if (remaining != 1)
+ return ERROR(corruption_detected);
+ if (bitCount > 32)
+ return ERROR(corruption_detected);
+ *maxSVPtr = charnum - 1;
- ip += (bitCount+7)>>3;
- return ip-istart;
+ ip += (bitCount + 7) >> 3;
+ return ip - istart;
}
-
/*! HUF_readStats() :
Read compact Huffman tree, saved by HUF_writeCTable().
`huffWeight` is destination buffer.
@@ -153,65 +164,80 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t
@return : size read from `src` , or an error Code .
Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
*/
-size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
- U32* nbSymbolsPtr, U32* tableLogPtr,
- const void* src, size_t srcSize)
+size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
{
U32 weightTotal;
- const BYTE* ip = (const BYTE*) src;
+ const BYTE *ip = (const BYTE *)src;
size_t iSize;
size_t oSize;
- if (!srcSize) return ERROR(srcSize_wrong);
+ if (!srcSize)
+ return ERROR(srcSize_wrong);
iSize = ip[0];
- /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
+ /* memset(huffWeight, 0, hwSize); */ /* is not necessary, even though some analyzer complain ... */
- if (iSize >= 128) { /* special header */
+ if (iSize >= 128) { /* special header */
oSize = iSize - 127;
- iSize = ((oSize+1)/2);
- if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
- if (oSize >= hwSize) return ERROR(corruption_detected);
+ iSize = ((oSize + 1) / 2);
+ if (iSize + 1 > srcSize)
+ return ERROR(srcSize_wrong);
+ if (oSize >= hwSize)
+ return ERROR(corruption_detected);
ip += 1;
- { U32 n;
- for (n=0; n> 4;
- huffWeight[n+1] = ip[n/2] & 15;
- } } }
- else { /* header compressed with FSE (normal case) */
- FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
- if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
- oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */
- if (FSE_isError(oSize)) return oSize;
+ {
+ U32 n;
+ for (n = 0; n < oSize; n += 2) {
+ huffWeight[n] = ip[n / 2] >> 4;
+ huffWeight[n + 1] = ip[n / 2] & 15;
+ }
+ }
+ } else { /* header compressed with FSE (normal case) */
+ if (iSize + 1 > srcSize)
+ return ERROR(srcSize_wrong);
+ oSize = FSE_decompress_wksp(huffWeight, hwSize - 1, ip + 1, iSize, 6, workspace, workspaceSize); /* max (hwSize-1) values decoded, as last one is implied */
+ if (FSE_isError(oSize))
+ return oSize;
}
/* collect weight stats */
memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
weightTotal = 0;
- { U32 n; for (n=0; n= HUF_TABLELOG_MAX) return ERROR(corruption_detected);
+ {
+ U32 n;
+ for (n = 0; n < oSize; n++) {
+ if (huffWeight[n] >= HUF_TABLELOG_MAX)
+ return ERROR(corruption_detected);
rankStats[huffWeight[n]]++;
weightTotal += (1 << huffWeight[n]) >> 1;
- } }
- if (weightTotal == 0) return ERROR(corruption_detected);
+ }
+ }
+ if (weightTotal == 0)
+ return ERROR(corruption_detected);
/* get last non-null symbol weight (implied, total must be 2^n) */
- { U32 const tableLog = BIT_highbit32(weightTotal) + 1;
- if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
+ {
+ U32 const tableLog = BIT_highbit32(weightTotal) + 1;
+ if (tableLog > HUF_TABLELOG_MAX)
+ return ERROR(corruption_detected);
*tableLogPtr = tableLog;
/* determine last weight */
- { U32 const total = 1 << tableLog;
+ {
+ U32 const total = 1 << tableLog;
U32 const rest = total - weightTotal;
U32 const verif = 1 << BIT_highbit32(rest);
U32 const lastWeight = BIT_highbit32(rest) + 1;
- if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
+ if (verif != rest)
+ return ERROR(corruption_detected); /* last value must be a clean power of 2 */
huffWeight[oSize] = (BYTE)lastWeight;
rankStats[lastWeight]++;
- } }
+ }
+ }
/* check tree construction validity */
- if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
+ if ((rankStats[1] < 2) || (rankStats[1] & 1))
+ return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
/* results */
- *nbSymbolsPtr = (U32)(oSize+1);
- return iSize+1;
+ *nbSymbolsPtr = (U32)(oSize + 1);
+ return iSize + 1;
}
diff --git a/contrib/linux-kernel/lib/zstd/error_private.h b/contrib/linux-kernel/lib/zstd/error_private.h
index 8cf148bc4..1a60b31f7 100644
--- a/contrib/linux-kernel/lib/zstd/error_private.h
+++ b/contrib/linux-kernel/lib/zstd/error_private.h
@@ -3,8 +3,15 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
+ * LICENSE file in the root directory of https://github.com/facebook/zstd.
+ * An additional grant of patent rights can be found in the PATENTS file in the
+ * same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
*/
/* Note : this module is expected to remain private, do not expose it */
@@ -15,23 +22,20 @@
/* ****************************************
* Dependencies
******************************************/
-#include /* size_t */
+#include /* size_t */
#include /* enum list */
-
/* ****************************************
* Compiler-specific
******************************************/
#define ERR_STATIC static __attribute__((unused))
-
/*-****************************************
* Customization (error_public.h)
******************************************/
typedef ZSTD_ErrorCode ERR_enum;
#define PREFIX(name) ZSTD_error_##name
-
/*-****************************************
* Error codes handling
******************************************/
@@ -39,6 +43,11 @@ typedef ZSTD_ErrorCode ERR_enum;
ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
-ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
+ERR_STATIC ERR_enum ERR_getErrorCode(size_t code)
+{
+ if (!ERR_isError(code))
+ return (ERR_enum)0;
+ return (ERR_enum)(0 - code);
+}
#endif /* ERROR_H_MODULE */
diff --git a/contrib/linux-kernel/lib/zstd/fse.h b/contrib/linux-kernel/lib/zstd/fse.h
index 14fa439ee..7460ab04b 100644
--- a/contrib/linux-kernel/lib/zstd/fse.h
+++ b/contrib/linux-kernel/lib/zstd/fse.h
@@ -1,45 +1,49 @@
-/* ******************************************************************
- FSE : Finite State Entropy codec
- Public Prototypes declaration
- Copyright (C) 2013-2016, 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 :
- - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
-****************************************************************** */
+/*
+ * FSE : Finite State Entropy codec
+ * Public Prototypes declaration
+ * Copyright (C) 2013-2016, 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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ */
#ifndef FSE_H
#define FSE_H
-
/*-*****************************************
* Dependencies
******************************************/
-#include /* size_t, ptrdiff_t */
-
+#include /* size_t, ptrdiff_t */
/*-*****************************************
* FSE_PUBLIC_API : control library symbols visibility
@@ -47,26 +51,25 @@
#define FSE_PUBLIC_API
/*------ Version ------*/
-#define FSE_VERSION_MAJOR 0
-#define FSE_VERSION_MINOR 9
-#define FSE_VERSION_RELEASE 0
+#define FSE_VERSION_MAJOR 0
+#define FSE_VERSION_MINOR 9
+#define FSE_VERSION_RELEASE 0
#define FSE_LIB_VERSION FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
#define FSE_QUOTE(str) #str
#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
-#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR *100*100 + FSE_VERSION_MINOR *100 + FSE_VERSION_RELEASE)
-FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
+#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR * 100 * 100 + FSE_VERSION_MINOR * 100 + FSE_VERSION_RELEASE)
+FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */
/*-*****************************************
* Tool functions
******************************************/
-FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
+FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed size */
/* Error Management */
-FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
-
+FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
/*-*****************************************
* FSE detailed API
@@ -101,7 +104,7 @@ FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize
'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
@return : tableLog,
or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
+FSE_PUBLIC_API size_t FSE_normalizeCount(short *normalizedCounter, unsigned tableLog, const unsigned *count, size_t srcSize, unsigned maxSymbolValue);
/*! FSE_NCountWriteBound():
Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
@@ -112,19 +115,18 @@ FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tab
Compactly save 'normalizedCounter' into 'buffer'.
@return : size of the compressed table,
or an errorCode, which can be tested using FSE_isError(). */
-FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
-
+FSE_PUBLIC_API size_t FSE_writeNCount(void *buffer, size_t bufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
/*! Constructor and Destructor of FSE_CTable.
Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
-typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
+typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
/*! FSE_compress_usingCTable():
Compress `src` using `ct` into `dst` which must be already allocated.
@return : size of compressed data (<= `dstCapacity`),
or 0 if compressed data could not fit into `dst`,
or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
+FSE_PUBLIC_API size_t FSE_compress_usingCTable(void *dst, size_t dstCapacity, const void *src, size_t srcSize, const FSE_CTable *ct);
/*!
Tutorial :
@@ -169,7 +171,6 @@ If it returns '0', compressed data could not fit into 'dst'.
If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
*/
-
/* *** DECOMPRESSION *** */
/*! FSE_readNCount():
@@ -177,23 +178,23 @@ If there is an error, the function will return an ErrorCode (which can be tested
@return : size read from 'rBuffer',
or an errorCode, which can be tested using FSE_isError().
maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
-FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize);
+FSE_PUBLIC_API size_t FSE_readNCount(short *normalizedCounter, unsigned *maxSymbolValuePtr, unsigned *tableLogPtr, const void *rBuffer, size_t rBuffSize);
/*! Constructor and Destructor of FSE_DTable.
Note that its size depends on 'tableLog' */
-typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
+typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
/*! FSE_buildDTable():
Builds 'dt', which must be already allocated, using FSE_createDTable().
return : 0, or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
+FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize);
/*! FSE_decompress_usingDTable():
Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
into `dst` which must be already allocated.
@return : size of regenerated data (necessarily <= `dstCapacity`),
or an errorCode, which can be tested using FSE_isError() */
-FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
+FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt);
/*!
Tutorial :
@@ -223,23 +224,20 @@ FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<
If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
*/
-
/* *** Dependency *** */
#include "bitstream.h"
-
/* *****************************************
* Static allocation
*******************************************/
/* FSE buffer bounds */
#define FSE_NCOUNTBOUND 512
-#define FSE_BLOCKBOUND(size) (size + (size>>7))
-#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
+#define FSE_BLOCKBOUND(size) (size + (size >> 7))
+#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
-#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
-#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<= `1024` unsigned
*/
-size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* source, size_t sourceSize, unsigned* workSpace);
+size_t FSE_count_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace);
/* FSE_countFast_wksp() :
* Same as FSE_countFast(), but using an externally provided scratch buffer.
* `workSpace` must be a table of minimum `1024` unsigned
*/
-size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* workSpace);
+size_t FSE_countFast_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize, unsigned *workSpace);
/*! FSE_count_simple
* Same as FSE_countFast(), but does not use any additional memory (not even on stack).
* This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`).
*/
-size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
-
-
+size_t FSE_count_simple(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize);
unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
/**< same as FSE_optimalTableLog(), which used `minus==2` */
-/* FSE_compress_wksp() :
- * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
- * FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
- */
-#define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + ((maxTableLog > 12) ? (1 << (maxTableLog - 2)) : 1024) )
-size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
-
-size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
+size_t FSE_buildCTable_raw(FSE_CTable *ct, unsigned nbBits);
/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
-size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
+size_t FSE_buildCTable_rle(FSE_CTable *ct, unsigned char symbolValue);
/**< build a fake FSE_CTable, designed to compress always the same symbolValue */
/* FSE_buildCTable_wksp() :
* Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
* `wkspSize` must be >= `(1<= 1 (otherwise, result will be corrupted) */
-
/* *****************************************
* Implementation of inlined functions
*******************************************/
@@ -441,88 +424,86 @@ typedef struct {
U32 deltaNbBits;
} FSE_symbolCompressionTransform; /* total 8 bytes */
-MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
+ZSTD_STATIC void FSE_initCState(FSE_CState_t *statePtr, const FSE_CTable *ct)
{
- const void* ptr = ct;
- const U16* u16ptr = (const U16*) ptr;
- const U32 tableLog = MEM_read16(ptr);
- statePtr->value = (ptrdiff_t)1<stateTable = u16ptr+2;
- statePtr->symbolTT = ((const U32*)ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1));
+ const void *ptr = ct;
+ const U16 *u16ptr = (const U16 *)ptr;
+ const U32 tableLog = ZSTD_read16(ptr);
+ statePtr->value = (ptrdiff_t)1 << tableLog;
+ statePtr->stateTable = u16ptr + 2;
+ statePtr->symbolTT = ((const U32 *)ct + 1 + (tableLog ? (1 << (tableLog - 1)) : 1));
statePtr->stateLog = tableLog;
}
-
/*! FSE_initCState2() :
* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
* uses the smallest state value possible, saving the cost of this symbol */
-MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
+ZSTD_STATIC void FSE_initCState2(FSE_CState_t *statePtr, const FSE_CTable *ct, U32 symbol)
{
FSE_initCState(statePtr, ct);
- { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
- const U16* stateTable = (const U16*)(statePtr->stateTable);
- U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
+ {
+ const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform *)(statePtr->symbolTT))[symbol];
+ const U16 *stateTable = (const U16 *)(statePtr->stateTable);
+ U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1 << 15)) >> 16);
statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
}
}
-MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, U32 symbol)
+ZSTD_STATIC void FSE_encodeSymbol(BIT_CStream_t *bitC, FSE_CState_t *statePtr, U32 symbol)
{
- const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
- const U16* const stateTable = (const U16*)(statePtr->stateTable);
- U32 nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
+ const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform *)(statePtr->symbolTT))[symbol];
+ const U16 *const stateTable = (const U16 *)(statePtr->stateTable);
+ U32 nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
BIT_addBits(bitC, statePtr->value, nbBitsOut);
- statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
+ statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
}
-MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
+ZSTD_STATIC void FSE_flushCState(BIT_CStream_t *bitC, const FSE_CState_t *statePtr)
{
BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
BIT_flushBits(bitC);
}
-
/* ====== Decompression ====== */
typedef struct {
U16 tableLog;
U16 fastMode;
-} FSE_DTableHeader; /* sizeof U32 */
+} FSE_DTableHeader; /* sizeof U32 */
-typedef struct
-{
+typedef struct {
unsigned short newState;
- unsigned char symbol;
- unsigned char nbBits;
-} FSE_decode_t; /* size == U32 */
+ unsigned char symbol;
+ unsigned char nbBits;
+} FSE_decode_t; /* size == U32 */
-MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
+ZSTD_STATIC void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, const FSE_DTable *dt)
{
- const void* ptr = dt;
- const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
+ const void *ptr = dt;
+ const FSE_DTableHeader *const DTableH = (const FSE_DTableHeader *)ptr;
DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
BIT_reloadDStream(bitD);
DStatePtr->table = dt + 1;
}
-MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
+ZSTD_STATIC BYTE FSE_peekSymbol(const FSE_DState_t *DStatePtr)
{
- FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
return DInfo.symbol;
}
-MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+ZSTD_STATIC void FSE_updateState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
{
- FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
U32 const nbBits = DInfo.nbBits;
size_t const lowBits = BIT_readBits(bitD, nbBits);
DStatePtr->state = DInfo.newState + lowBits;
}
-MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+ZSTD_STATIC BYTE FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
{
- FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
U32 const nbBits = DInfo.nbBits;
BYTE const symbol = DInfo.symbol;
size_t const lowBits = BIT_readBits(bitD, nbBits);
@@ -533,9 +514,9 @@ MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
/*! FSE_decodeSymbolFast() :
unsafe, only works if no symbol has a probability > 50% */
-MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
+ZSTD_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD)
{
- FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
+ FSE_decode_t const DInfo = ((const FSE_decode_t *)(DStatePtr->table))[DStatePtr->state];
U32 const nbBits = DInfo.nbBits;
BYTE const symbol = DInfo.symbol;
size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
@@ -544,14 +525,7 @@ MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bit
return symbol;
}
-MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
-{
- return DStatePtr->state == 0;
-}
-
-
-
-#ifndef FSE_COMMONDEFS_ONLY
+ZSTD_STATIC unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr) { return DStatePtr->state == 0; }
/* **************************************************************
* Tuning parameters
@@ -562,17 +536,17 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
* Reduced memory usage can improve speed, due to cache effect
* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
#ifndef FSE_MAX_MEMORY_USAGE
-# define FSE_MAX_MEMORY_USAGE 14
+#define FSE_MAX_MEMORY_USAGE 14
#endif
#ifndef FSE_DEFAULT_MEMORY_USAGE
-# define FSE_DEFAULT_MEMORY_USAGE 13
+#define FSE_DEFAULT_MEMORY_USAGE 13
#endif
/*!FSE_MAX_SYMBOL_VALUE :
* Maximum symbol value authorized.
* Required for proper stack allocation */
#ifndef FSE_MAX_SYMBOL_VALUE
-# define FSE_MAX_SYMBOL_VALUE 255
+#define FSE_MAX_SYMBOL_VALUE 255
#endif
/* **************************************************************
@@ -582,25 +556,20 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
#define FSE_FUNCTION_EXTENSION
#define FSE_DECODE_TYPE FSE_decode_t
-
-#endif /* !FSE_COMMONDEFS_ONLY */
-
-
/* ***************************************************************
* Constants
*****************************************************************/
-#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
-#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX
-# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
+#error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
#endif
-#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
+#define FSE_TABLESTEP(tableSize) ((tableSize >> 1) + (tableSize >> 3) + 3)
-
-#endif /* FSE_H */
+#endif /* FSE_H */
diff --git a/contrib/linux-kernel/lib/zstd/fse_compress.c b/contrib/linux-kernel/lib/zstd/fse_compress.c
index b6a6d4693..ef3d1741d 100644
--- a/contrib/linux-kernel/lib/zstd/fse_compress.c
+++ b/contrib/linux-kernel/lib/zstd/fse_compress.c
@@ -1,57 +1,64 @@
-/* ******************************************************************
- FSE : Finite State Entropy encoder
- Copyright (C) 2013-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 :
- - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
- - Public forum : https://groups.google.com/forum/#!forum/lz4c
-****************************************************************** */
+/*
+ * FSE : Finite State Entropy encoder
+ * Copyright (C) 2013-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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ */
/* **************************************************************
* Compiler specifics
****************************************************************/
#define FORCE_INLINE static __always_inline
-
/* **************************************************************
* Includes
****************************************************************/
-#include
-#include /* memcpy, memset */
#include "bitstream.h"
#include "fse.h"
-
+#include
+#include
+#include
+#include /* memcpy, memset */
/* **************************************************************
* Error Management
****************************************************************/
-#define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
-
+#define FSE_STATIC_ASSERT(c) \
+ { \
+ enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
+ } /* use only *after* variable declarations */
/* **************************************************************
* Templates
@@ -64,17 +71,16 @@
/* safety checks */
#ifndef FSE_FUNCTION_EXTENSION
-# error "FSE_FUNCTION_EXTENSION must be defined"
+#error "FSE_FUNCTION_EXTENSION must be defined"
#endif
#ifndef FSE_FUNCTION_TYPE
-# error "FSE_FUNCTION_TYPE must be defined"
+#error "FSE_FUNCTION_TYPE must be defined"
#endif
/* Function names */
-#define FSE_CAT(X,Y) X##Y
-#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
-#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
-
+#define FSE_CAT(X, Y) X##Y
+#define FSE_FUNCTION_NAME(X, Y) FSE_CAT(X, Y)
+#define FSE_TYPE_NAME(X, Y) FSE_CAT(X, Y)
/* Function templates */
@@ -83,106 +89,123 @@
* wkspSize should be sized to handle worst case situation, which is `1<>1 : 1) ;
- FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
+ void *const ptr = ct;
+ U16 *const tableU16 = ((U16 *)ptr) + 2;
+ void *const FSCT = ((U32 *)ptr) + 1 /* header */ + (tableLog ? tableSize >> 1 : 1);
+ FSE_symbolCompressionTransform *const symbolTT = (FSE_symbolCompressionTransform *)(FSCT);
U32 const step = FSE_TABLESTEP(tableSize);
- U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
+ U32 highThreshold = tableSize - 1;
- FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
- U32 highThreshold = tableSize-1;
+ U32 *cumul;
+ FSE_FUNCTION_TYPE *tableSymbol;
+ size_t spaceUsed32 = 0;
+
+ cumul = (U32 *)workspace + spaceUsed32;
+ spaceUsed32 += FSE_MAX_SYMBOL_VALUE + 2;
+ tableSymbol = (FSE_FUNCTION_TYPE *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += ALIGN(sizeof(FSE_FUNCTION_TYPE) * ((size_t)1 << tableLog), sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > workspaceSize)
+ return ERROR(tableLog_tooLarge);
+ workspace = (U32 *)workspace + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
/* CTable header */
- if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
- tableU16[-2] = (U16) tableLog;
- tableU16[-1] = (U16) maxSymbolValue;
+ tableU16[-2] = (U16)tableLog;
+ tableU16[-1] = (U16)maxSymbolValue;
/* For explanations on how to distribute symbol values over the table :
* http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
/* symbol start positions */
- { U32 u;
+ {
+ U32 u;
cumul[0] = 0;
- for (u=1; u<=maxSymbolValue+1; u++) {
- if (normalizedCounter[u-1]==-1) { /* Low proba symbol */
- cumul[u] = cumul[u-1] + 1;
- tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);
+ for (u = 1; u <= maxSymbolValue + 1; u++) {
+ if (normalizedCounter[u - 1] == -1) { /* Low proba symbol */
+ cumul[u] = cumul[u - 1] + 1;
+ tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u - 1);
} else {
- cumul[u] = cumul[u-1] + normalizedCounter[u-1];
- } }
- cumul[maxSymbolValue+1] = tableSize+1;
+ cumul[u] = cumul[u - 1] + normalizedCounter[u - 1];
+ }
+ }
+ cumul[maxSymbolValue + 1] = tableSize + 1;
}
/* Spread symbols */
- { U32 position = 0;
+ {
+ U32 position = 0;
U32 symbol;
- for (symbol=0; symbol<=maxSymbolValue; symbol++) {
+ for (symbol = 0; symbol <= maxSymbolValue; symbol++) {
int nbOccurences;
- for (nbOccurences=0; nbOccurences highThreshold) position = (position + step) & tableMask; /* Low proba area */
- } }
+ while (position > highThreshold)
+ position = (position + step) & tableMask; /* Low proba area */
+ }
+ }
- if (position!=0) return ERROR(GENERIC); /* Must have gone through all positions */
+ if (position != 0)
+ return ERROR(GENERIC); /* Must have gone through all positions */
}
/* Build table */
- { U32 u; for (u=0; u> 3) + 3;
- return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
+ size_t const maxHeaderSize = (((maxSymbolValue + 1) * tableLog) >> 3) + 3;
+ return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
}
-static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize,
- const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
- unsigned writeIsSafe)
+static size_t FSE_writeNCount_generic(void *header, size_t headerBufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
+ unsigned writeIsSafe)
{
- BYTE* const ostart = (BYTE*) header;
- BYTE* out = ostart;
- BYTE* const oend = ostart + headerBufferSize;
+ BYTE *const ostart = (BYTE *)header;
+ BYTE *out = ostart;
+ BYTE *const oend = ostart + headerBufferSize;
int nbBits;
const int tableSize = 1 << tableLog;
int remaining;
@@ -193,81 +216,94 @@ static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize,
int previous0 = 0;
bitStream = 0;
- bitCount = 0;
+ bitCount = 0;
/* Table Size */
- bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;
- bitCount += 4;
+ bitStream += (tableLog - FSE_MIN_TABLELOG) << bitCount;
+ bitCount += 4;
/* Init */
- remaining = tableSize+1; /* +1 for extra accuracy */
+ remaining = tableSize + 1; /* +1 for extra accuracy */
threshold = tableSize;
- nbBits = tableLog+1;
+ nbBits = tableLog + 1;
- while (remaining>1) { /* stops at 1 */
+ while (remaining > 1) { /* stops at 1 */
if (previous0) {
unsigned start = charnum;
- while (!normalizedCounter[charnum]) charnum++;
- while (charnum >= start+24) {
- start+=24;
+ while (!normalizedCounter[charnum])
+ charnum++;
+ while (charnum >= start + 24) {
+ start += 24;
bitStream += 0xFFFFU << bitCount;
- if ((!writeIsSafe) && (out > oend-2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
- out[0] = (BYTE) bitStream;
- out[1] = (BYTE)(bitStream>>8);
- out+=2;
- bitStream>>=16;
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ out[0] = (BYTE)bitStream;
+ out[1] = (BYTE)(bitStream >> 8);
+ out += 2;
+ bitStream >>= 16;
}
- while (charnum >= start+3) {
- start+=3;
+ while (charnum >= start + 3) {
+ start += 3;
bitStream += 3 << bitCount;
bitCount += 2;
}
- bitStream += (charnum-start) << bitCount;
+ bitStream += (charnum - start) << bitCount;
bitCount += 2;
- if (bitCount>16) {
- if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ if (bitCount > 16) {
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
out[0] = (BYTE)bitStream;
- out[1] = (BYTE)(bitStream>>8);
+ out[1] = (BYTE)(bitStream >> 8);
out += 2;
bitStream >>= 16;
bitCount -= 16;
- } }
- { int count = normalizedCounter[charnum++];
- int const max = (2*threshold-1)-remaining;
- remaining -= count < 0 ? -count : count;
- count++; /* +1 for extra accuracy */
- if (count>=threshold) count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
- bitStream += count << bitCount;
- bitCount += nbBits;
- bitCount -= (count>=1;
+ }
}
- if (bitCount>16) {
- if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ {
+ int count = normalizedCounter[charnum++];
+ int const max = (2 * threshold - 1) - remaining;
+ remaining -= count < 0 ? -count : count;
+ count++; /* +1 for extra accuracy */
+ if (count >= threshold)
+ count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
+ bitStream += count << bitCount;
+ bitCount += nbBits;
+ bitCount -= (count < max);
+ previous0 = (count == 1);
+ if (remaining < 1)
+ return ERROR(GENERIC);
+ while (remaining < threshold)
+ nbBits--, threshold >>= 1;
+ }
+ if (bitCount > 16) {
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
out[0] = (BYTE)bitStream;
- out[1] = (BYTE)(bitStream>>8);
+ out[1] = (BYTE)(bitStream >> 8);
out += 2;
bitStream >>= 16;
bitCount -= 16;
- } }
+ }
+ }
/* flush remaining bitStream */
- if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
+ if ((!writeIsSafe) && (out > oend - 2))
+ return ERROR(dstSize_tooSmall); /* Buffer overflow */
out[0] = (BYTE)bitStream;
- out[1] = (BYTE)(bitStream>>8);
- out+= (bitCount+7) /8;
+ out[1] = (BYTE)(bitStream >> 8);
+ out += (bitCount + 7) / 8;
- if (charnum > maxSymbolValue + 1) return ERROR(GENERIC);
+ if (charnum > maxSymbolValue + 1)
+ return ERROR(GENERIC);
- return (out-ostart);
+ return (out - ostart);
}
-
-size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+size_t FSE_writeNCount(void *buffer, size_t bufferSize, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
{
- if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported */
- if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported */
+ if (tableLog > FSE_MAX_TABLELOG)
+ return ERROR(tableLog_tooLarge); /* Unsupported */
+ if (tableLog < FSE_MIN_TABLELOG)
+ return ERROR(GENERIC); /* Unsupported */
if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
@@ -275,8 +311,6 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalized
return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1);
}
-
-
/*-**************************************************************
* Counting histogram
****************************************************************/
@@ -287,46 +321,52 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalized
For this reason, prefer using a table `count` with 256 elements.
@return : count of most numerous element
*/
-size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* src, size_t srcSize)
+size_t FSE_count_simple(unsigned *count, unsigned *maxSymbolValuePtr, const void *src, size_t srcSize)
{
- const BYTE* ip = (const BYTE*)src;
- const BYTE* const end = ip + srcSize;
+ const BYTE *ip = (const BYTE *)src;
+ const BYTE *const end = ip + srcSize;
unsigned maxSymbolValue = *maxSymbolValuePtr;
- unsigned max=0;
+ unsigned max = 0;
- memset(count, 0, (maxSymbolValue+1)*sizeof(*count));
- if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
+ memset(count, 0, (maxSymbolValue + 1) * sizeof(*count));
+ if (srcSize == 0) {
+ *maxSymbolValuePtr = 0;
+ return 0;
+ }
- while (ip max) max = count[s]; }
+ {
+ U32 s;
+ for (s = 0; s <= maxSymbolValue; s++)
+ if (count[s] > max)
+ max = count[s];
+ }
return (size_t)max;
}
-
/* FSE_count_parallel_wksp() :
* Same as FSE_count_parallel(), but using an externally provided scratch buffer.
* `workSpace` size must be a minimum of `1024 * sizeof(unsigned)`` */
-static size_t FSE_count_parallel_wksp(
- unsigned* count, unsigned* maxSymbolValuePtr,
- const void* source, size_t sourceSize,
- unsigned checkMax, unsigned* const workSpace)
+static size_t FSE_count_parallel_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned checkMax,
+ unsigned *const workSpace)
{
- const BYTE* ip = (const BYTE*)source;
- const BYTE* const iend = ip+sourceSize;
+ const BYTE *ip = (const BYTE *)source;
+ const BYTE *const iend = ip + sourceSize;
unsigned maxSymbolValue = *maxSymbolValuePtr;
- unsigned max=0;
- U32* const Counting1 = workSpace;
- U32* const Counting2 = Counting1 + 256;
- U32* const Counting3 = Counting2 + 256;
- U32* const Counting4 = Counting3 + 256;
+ unsigned max = 0;
+ U32 *const Counting1 = workSpace;
+ U32 *const Counting2 = Counting1 + 256;
+ U32 *const Counting3 = Counting2 + 256;
+ U32 *const Counting4 = Counting3 + 256;
- memset(Counting1, 0, 4*256*sizeof(unsigned));
+ memset(Counting1, 0, 4 * 256 * sizeof(unsigned));
/* safety checks */
if (!sourceSize) {
@@ -334,50 +374,70 @@ static size_t FSE_count_parallel_wksp(
*maxSymbolValuePtr = 0;
return 0;
}
- if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */
+ if (!maxSymbolValue)
+ maxSymbolValue = 255; /* 0 == default */
/* by stripes of 16 bytes */
- { U32 cached = MEM_read32(ip); ip += 4;
- while (ip < iend-15) {
- U32 c = cached; cached = MEM_read32(ip); ip += 4;
- Counting1[(BYTE) c ]++;
- Counting2[(BYTE)(c>>8) ]++;
- Counting3[(BYTE)(c>>16)]++;
- Counting4[ c>>24 ]++;
- c = cached; cached = MEM_read32(ip); ip += 4;
- Counting1[(BYTE) c ]++;
- Counting2[(BYTE)(c>>8) ]++;
- Counting3[(BYTE)(c>>16)]++;
- Counting4[ c>>24 ]++;
- c = cached; cached = MEM_read32(ip); ip += 4;
- Counting1[(BYTE) c ]++;
- Counting2[(BYTE)(c>>8) ]++;
- Counting3[(BYTE)(c>>16)]++;
- Counting4[ c>>24 ]++;
- c = cached; cached = MEM_read32(ip); ip += 4;
- Counting1[(BYTE) c ]++;
- Counting2[(BYTE)(c>>8) ]++;
- Counting3[(BYTE)(c>>16)]++;
- Counting4[ c>>24 ]++;
+ {
+ U32 cached = ZSTD_read32(ip);
+ ip += 4;
+ while (ip < iend - 15) {
+ U32 c = cached;
+ cached = ZSTD_read32(ip);
+ ip += 4;
+ Counting1[(BYTE)c]++;
+ Counting2[(BYTE)(c >> 8)]++;
+ Counting3[(BYTE)(c >> 16)]++;
+ Counting4[c >> 24]++;
+ c = cached;
+ cached = ZSTD_read32(ip);
+ ip += 4;
+ Counting1[(BYTE)c]++;
+ Counting2[(BYTE)(c >> 8)]++;
+ Counting3[(BYTE)(c >> 16)]++;
+ Counting4[c >> 24]++;
+ c = cached;
+ cached = ZSTD_read32(ip);
+ ip += 4;
+ Counting1[(BYTE)c]++;
+ Counting2[(BYTE)(c >> 8)]++;
+ Counting3[(BYTE)(c >> 16)]++;
+ Counting4[c >> 24]++;
+ c = cached;
+ cached = ZSTD_read32(ip);
+ ip += 4;
+ Counting1[(BYTE)c]++;
+ Counting2[(BYTE)(c >> 8)]++;
+ Counting3[(BYTE)(c >> 16)]++;
+ Counting4[c >> 24]++;
}
- ip-=4;
+ ip -= 4;
}
/* finish last symbols */
- while (ipmaxSymbolValue; s--) {
+ if (checkMax) { /* verify stats will fit into destination table */
+ U32 s;
+ for (s = 255; s > maxSymbolValue; s--) {
Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
- if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
- } }
+ if (Counting1[s])
+ return ERROR(maxSymbolValue_tooSmall);
+ }
+ }
- { U32 s; for (s=0; s<=maxSymbolValue; s++) {
+ {
+ U32 s;
+ for (s = 0; s <= maxSymbolValue; s++) {
count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
- if (count[s] > max) max = count[s];
- } }
+ if (count[s] > max)
+ max = count[s];
+ }
+ }
- while (!count[maxSymbolValue]) maxSymbolValue--;
+ while (!count[maxSymbolValue])
+ maxSymbolValue--;
*maxSymbolValuePtr = maxSymbolValue;
return (size_t)max;
}
@@ -385,18 +445,17 @@ static size_t FSE_count_parallel_wksp(
/* FSE_countFast_wksp() :
* Same as FSE_countFast(), but using an externally provided scratch buffer.
* `workSpace` size must be table of >= `1024` unsigned */
-size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* source, size_t sourceSize, unsigned* workSpace)
+size_t FSE_countFast_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace)
{
- if (sourceSize < 1500) return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
+ if (sourceSize < 1500)
+ return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
}
/* FSE_count_wksp() :
* Same as FSE_count(), but using an externally provided scratch buffer.
* `workSpace` size must be table of >= `1024` unsigned */
-size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
- const void* source, size_t sourceSize, unsigned* workSpace)
+size_t FSE_count_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const void *source, size_t sourceSize, unsigned *workSpace)
{
if (*maxSymbolValuePtr < 255)
return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace);
@@ -404,7 +463,6 @@ size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace);
}
-
/*-**************************************************************
* FSE Compression Code
****************************************************************/
@@ -416,10 +474,11 @@ size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
`FSE_symbolCompressionTransform symbolTT[maxSymbolValue+1];` // This size is variable
Allocation is manual (C standard does not support variable-size structures).
*/
-size_t FSE_sizeof_CTable (unsigned maxSymbolValue, unsigned tableLog)
+size_t FSE_sizeof_CTable(unsigned maxSymbolValue, unsigned tableLog)
{
- if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
- return FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
+ if (tableLog > FSE_MAX_TABLELOG)
+ return ERROR(tableLog_tooLarge);
+ return FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue) * sizeof(U32);
}
/* provides the minimum logSize to safely represent a distribution */
@@ -436,11 +495,16 @@ unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsi
U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
U32 tableLog = maxTableLog;
U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
- if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
- if (maxBitsSrc < tableLog) tableLog = maxBitsSrc; /* Accuracy can be reduced */
- if (minBits > tableLog) tableLog = minBits; /* Need a minimum to safely represent all symbol values */
- if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;
- if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;
+ if (tableLog == 0)
+ tableLog = FSE_DEFAULT_TABLELOG;
+ if (maxBitsSrc < tableLog)
+ tableLog = maxBitsSrc; /* Accuracy can be reduced */
+ if (minBits > tableLog)
+ tableLog = minBits; /* Need a minimum to safely represent all symbol values */
+ if (tableLog < FSE_MIN_TABLELOG)
+ tableLog = FSE_MIN_TABLELOG;
+ if (tableLog > FSE_MAX_TABLELOG)
+ tableLog = FSE_MAX_TABLELOG;
return tableLog;
}
@@ -449,11 +513,10 @@ unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS
return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
}
-
/* Secondary normalization method.
To be used when primary method fails. */
-static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
+static size_t FSE_normalizeM2(short *norm, U32 tableLog, const unsigned *count, size_t total, U32 maxSymbolValue)
{
short const NOT_YET_ASSIGNED = -2;
U32 s;
@@ -464,9 +527,9 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count,
U32 const lowThreshold = (U32)(total >> tableLog);
U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
- for (s=0; s<=maxSymbolValue; s++) {
+ for (s = 0; s <= maxSymbolValue; s++) {
if (count[s] == 0) {
- norm[s]=0;
+ norm[s] = 0;
continue;
}
if (count[s] <= lowThreshold) {
@@ -482,47 +545,51 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count,
continue;
}
- norm[s]=NOT_YET_ASSIGNED;
+ norm[s] = NOT_YET_ASSIGNED;
}
ToDistribute = (1 << tableLog) - distributed;
if ((total / ToDistribute) > lowOne) {
/* risk of rounding to zero */
lowOne = (U32)((total * 3) / (ToDistribute * 2));
- for (s=0; s<=maxSymbolValue; s++) {
+ for (s = 0; s <= maxSymbolValue; s++) {
if ((norm[s] == NOT_YET_ASSIGNED) && (count[s] <= lowOne)) {
norm[s] = 1;
distributed++;
total -= count[s];
continue;
- } }
+ }
+ }
ToDistribute = (1 << tableLog) - distributed;
}
- if (distributed == maxSymbolValue+1) {
+ if (distributed == maxSymbolValue + 1) {
/* all values are pretty poor;
probably incompressible data (should have already been detected);
find max, then give all remaining points to max */
U32 maxV = 0, maxC = 0;
- for (s=0; s<=maxSymbolValue; s++)
- if (count[s] > maxC) maxV=s, maxC=count[s];
+ for (s = 0; s <= maxSymbolValue; s++)
+ if (count[s] > maxC)
+ maxV = s, maxC = count[s];
norm[maxV] += (short)ToDistribute;
return 0;
}
if (total == 0) {
/* all of the symbols were low enough for the lowOne or lowThreshold */
- for (s=0; ToDistribute > 0; s = (s+1)%(maxSymbolValue+1))
- if (norm[s] > 0) ToDistribute--, norm[s]++;
+ for (s = 0; ToDistribute > 0; s = (s + 1) % (maxSymbolValue + 1))
+ if (norm[s] > 0)
+ ToDistribute--, norm[s]++;
return 0;
}
- { U64 const vStepLog = 62 - tableLog;
- U64 const mid = (1ULL << (vStepLog-1)) - 1;
- U64 const rStep = ((((U64)1<> vStepLog);
U32 const sEnd = (U32)(end >> vStepLog);
@@ -531,122 +598,121 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count,
return ERROR(GENERIC);
norm[s] = (short)weight;
tmpTotal = end;
- } } }
+ }
+ }
+ }
return 0;
}
-
-size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
- const unsigned* count, size_t total,
- unsigned maxSymbolValue)
+size_t FSE_normalizeCount(short *normalizedCounter, unsigned tableLog, const unsigned *count, size_t total, unsigned maxSymbolValue)
{
/* Sanity checks */
- if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
- if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported size */
- if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */
- if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
+ if (tableLog == 0)
+ tableLog = FSE_DEFAULT_TABLELOG;
+ if (tableLog < FSE_MIN_TABLELOG)
+ return ERROR(GENERIC); /* Unsupported size */
+ if (tableLog > FSE_MAX_TABLELOG)
+ return ERROR(tableLog_tooLarge); /* Unsupported size */
+ if (tableLog < FSE_minTableLog(total, maxSymbolValue))
+ return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
- { U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
+ {
+ U32 const rtbTable[] = {0, 473195, 504333, 520860, 550000, 700000, 750000, 830000};
U64 const scale = 62 - tableLog;
- U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */
- U64 const vStep = 1ULL<<(scale-20);
- int stillToDistribute = 1<> tableLog);
- for (s=0; s<=maxSymbolValue; s++) {
- if (count[s] == total) return 0; /* rle special case */
- if (count[s] == 0) { normalizedCounter[s]=0; continue; }
+ for (s = 0; s <= maxSymbolValue; s++) {
+ if (count[s] == total)
+ return 0; /* rle special case */
+ if (count[s] == 0) {
+ normalizedCounter[s] = 0;
+ continue;
+ }
if (count[s] <= lowThreshold) {
normalizedCounter[s] = -1;
stillToDistribute--;
} else {
- short proba = (short)((count[s]*step) >> scale);
- if (proba<8) {
+ short proba = (short)((count[s] * step) >> scale);
+ if (proba < 8) {
U64 restToBeat = vStep * rtbTable[proba];
- proba += (count[s]*step) - ((U64)proba< restToBeat;
+ proba += (count[s] * step) - ((U64)proba << scale) > restToBeat;
}
- if (proba > largestP) largestP=proba, largest=s;
+ if (proba > largestP)
+ largestP = proba, largest = s;
normalizedCounter[s] = proba;
stillToDistribute -= proba;
- } }
+ }
+ }
if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
/* corner case, need another normalization method */
size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
- if (FSE_isError(errorCode)) return errorCode;
- }
- else normalizedCounter[largest] += (short)stillToDistribute;
+ if (FSE_isError(errorCode))
+ return errorCode;
+ } else
+ normalizedCounter[largest] += (short)stillToDistribute;
}
-#if 0
- { /* Print Table (debug) */
- U32 s;
- U32 nTotal = 0;
- for (s=0; s<=maxSymbolValue; s++)
- printf("%3i: %4i \n", s, normalizedCounter[s]);
- for (s=0; s<=maxSymbolValue; s++)
- nTotal += abs(normalizedCounter[s]);
- if (nTotal != (1U<>1); /* assumption : tableLog >= 1 */
- FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
+ void *const ptr = ct;
+ U16 *const tableU16 = ((U16 *)ptr) + 2;
+ void *const FSCT = ((U32 *)ptr) + 1 /* header */ + (tableSize >> 1); /* assumption : tableLog >= 1 */
+ FSE_symbolCompressionTransform *const symbolTT = (FSE_symbolCompressionTransform *)(FSCT);
unsigned s;
/* Sanity checks */
- if (nbBits < 1) return ERROR(GENERIC); /* min size */
+ if (nbBits < 1)
+ return ERROR(GENERIC); /* min size */
/* header */
- tableU16[-2] = (U16) nbBits;
- tableU16[-1] = (U16) maxSymbolValue;
+ tableU16[-2] = (U16)nbBits;
+ tableU16[-1] = (U16)maxSymbolValue;
/* Build table */
- for (s=0; s FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) { /* test bit 2 */
+ if ((sizeof(bitC.bitContainer) * 8 > FSE_MAX_TABLELOG * 4 + 7) && (srcSize & 2)) { /* test bit 2 */
FSE_encodeSymbol(&bitC, &CState2, *--ip);
FSE_encodeSymbol(&bitC, &CState1, *--ip);
FSE_FLUSHBITS(&bitC);
}
/* 2 or 4 encoding per loop */
- while ( ip>istart ) {
+ while (ip > istart) {
FSE_encodeSymbol(&bitC, &CState2, *--ip);
- if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 ) /* this test must be static */
+ if (sizeof(bitC.bitContainer) * 8 < FSE_MAX_TABLELOG * 2 + 7) /* this test must be static */
FSE_FLUSHBITS(&bitC);
FSE_encodeSymbol(&bitC, &CState1, *--ip);
- if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) { /* this test must be static */
+ if (sizeof(bitC.bitContainer) * 8 > FSE_MAX_TABLELOG * 4 + 7) { /* this test must be static */
FSE_encodeSymbol(&bitC, &CState2, *--ip);
FSE_encodeSymbol(&bitC, &CState1, *--ip);
}
@@ -715,9 +782,7 @@ static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,
return BIT_closeCStream(&bitC);
}
-size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- const FSE_CTable* ct)
+size_t FSE_compress_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const FSE_CTable *ct)
{
unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
@@ -727,62 +792,4 @@ size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
}
-
size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
-
-#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return f
-#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
-
-/* FSE_compress_wksp() :
- * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
- * `wkspSize` size must be `(1< not compressible */
- if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */
- }
-
- tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
- CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
-
- /* Write table description header */
- { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
- op += nc_err;
- }
-
- /* Compress */
- CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );
- { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );
- if (cSize == 0) return 0; /* not enough space for compressed data */
- op += cSize;
- }
-
- /* check compressibility */
- if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;
-
- return op-ostart;
-}
-
-
-#endif /* FSE_COMMONDEFS_ONLY */
diff --git a/contrib/linux-kernel/lib/zstd/fse_decompress.c b/contrib/linux-kernel/lib/zstd/fse_decompress.c
index 2a35f1703..a84300e5a 100644
--- a/contrib/linux-kernel/lib/zstd/fse_decompress.c
+++ b/contrib/linux-kernel/lib/zstd/fse_decompress.c
@@ -1,62 +1,72 @@
-/* ******************************************************************
- FSE : Finite State Entropy decoder
- Copyright (C) 2013-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 :
- - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
- - Public forum : https://groups.google.com/forum/#!forum/lz4c
-****************************************************************** */
-
+/*
+ * FSE : Finite State Entropy decoder
+ * Copyright (C) 2013-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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ */
/* **************************************************************
* Compiler specifics
****************************************************************/
#define FORCE_INLINE static __always_inline
-
/* **************************************************************
* Includes
****************************************************************/
-#include
-#include /* memcpy, memset */
#include "bitstream.h"
#include "fse.h"
-
+#include
+#include
+#include /* memcpy, memset */
/* **************************************************************
* Error Management
****************************************************************/
#define FSE_isError ERR_isError
-#define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
+#define FSE_STATIC_ASSERT(c) \
+ { \
+ enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
+ } /* use only *after* variable declarations */
/* check and forward error code */
-#define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; }
-
+#define CHECK_F(f) \
+ { \
+ size_t const e = f; \
+ if (FSE_isError(e)) \
+ return e; \
+ }
/* **************************************************************
* Templates
@@ -69,89 +79,100 @@
/* safety checks */
#ifndef FSE_FUNCTION_EXTENSION
-# error "FSE_FUNCTION_EXTENSION must be defined"
+#error "FSE_FUNCTION_EXTENSION must be defined"
#endif
#ifndef FSE_FUNCTION_TYPE
-# error "FSE_FUNCTION_TYPE must be defined"
+#error "FSE_FUNCTION_TYPE must be defined"
#endif
/* Function names */
-#define FSE_CAT(X,Y) X##Y
-#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
-#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
-
+#define FSE_CAT(X, Y) X##Y
+#define FSE_FUNCTION_NAME(X, Y) FSE_CAT(X, Y)
+#define FSE_TYPE_NAME(X, Y) FSE_CAT(X, Y)
/* Function templates */
-size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
+size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize)
{
- void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
- FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
- U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
+ void *const tdPtr = dt + 1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
+ FSE_DECODE_TYPE *const tableDecode = (FSE_DECODE_TYPE *)(tdPtr);
+ U16 *symbolNext = (U16 *)workspace;
U32 const maxSV1 = maxSymbolValue + 1;
U32 const tableSize = 1 << tableLog;
- U32 highThreshold = tableSize-1;
+ U32 highThreshold = tableSize - 1;
/* Sanity Checks */
- if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
- if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
+ if (workspaceSize < sizeof(U16) * (FSE_MAX_SYMBOL_VALUE + 1))
+ return ERROR(tableLog_tooLarge);
+ if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE)
+ return ERROR(maxSymbolValue_tooLarge);
+ if (tableLog > FSE_MAX_TABLELOG)
+ return ERROR(tableLog_tooLarge);
/* Init, lay down lowprob symbols */
- { FSE_DTableHeader DTableH;
+ {
+ FSE_DTableHeader DTableH;
DTableH.tableLog = (U16)tableLog;
DTableH.fastMode = 1;
- { S16 const largeLimit= (S16)(1 << (tableLog-1));
+ {
+ S16 const largeLimit = (S16)(1 << (tableLog - 1));
U32 s;
- for (s=0; s= largeLimit) DTableH.fastMode=0;
+ if (normalizedCounter[s] >= largeLimit)
+ DTableH.fastMode = 0;
symbolNext[s] = normalizedCounter[s];
- } } }
+ }
+ }
+ }
memcpy(dt, &DTableH, sizeof(DTableH));
}
/* Spread symbols */
- { U32 const tableMask = tableSize-1;
+ {
+ U32 const tableMask = tableSize - 1;
U32 const step = FSE_TABLESTEP(tableSize);
U32 s, position = 0;
- for (s=0; s highThreshold) position = (position + step) & tableMask; /* lowprob area */
- } }
- if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
+ while (position > highThreshold)
+ position = (position + step) & tableMask; /* lowprob area */
+ }
+ }
+ if (position != 0)
+ return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
}
/* Build Decoding table */
- { U32 u;
- for (u=0; utableLog = 0;
DTableH->fastMode = 0;
@@ -163,25 +184,25 @@ size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
return 0;
}
-
-size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
+size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits)
{
- void* ptr = dt;
- FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
- void* dPtr = dt + 1;
- FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
+ void *ptr = dt;
+ FSE_DTableHeader *const DTableH = (FSE_DTableHeader *)ptr;
+ void *dPtr = dt + 1;
+ FSE_decode_t *const dinfo = (FSE_decode_t *)dPtr;
const unsigned tableSize = 1 << nbBits;
const unsigned tableMask = tableSize - 1;
- const unsigned maxSV1 = tableMask+1;
+ const unsigned maxSV1 = tableMask + 1;
unsigned s;
/* Sanity checks */
- if (nbBits < 1) return ERROR(GENERIC); /* min size */
+ if (nbBits < 1)
+ return ERROR(GENERIC); /* min size */
/* Build Decoding Table */
DTableH->tableLog = (U16)nbBits;
DTableH->fastMode = 1;
- for (s=0; s sizeof(bitD.bitContainer)*8) /* This test must be static */
+ if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
BIT_reloadDStream(&bitD);
op[1] = FSE_GETSYMBOL(&state2);
- if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
- { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
+ if (FSE_MAX_TABLELOG * 4 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
+ {
+ if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) {
+ op += 2;
+ break;
+ }
+ }
op[2] = FSE_GETSYMBOL(&state1);
- if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
+ if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) /* This test must be static */
BIT_reloadDStream(&bitD);
op[3] = FSE_GETSYMBOL(&state2);
@@ -235,58 +259,74 @@ FORCE_INLINE size_t FSE_decompress_usingDTable_generic(
/* tail */
/* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
while (1) {
- if (op>(omax-2)) return ERROR(dstSize_tooSmall);
+ if (op > (omax - 2))
+ return ERROR(dstSize_tooSmall);
*op++ = FSE_GETSYMBOL(&state1);
- if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
+ if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) {
*op++ = FSE_GETSYMBOL(&state2);
break;
}
- if (op>(omax-2)) return ERROR(dstSize_tooSmall);
+ if (op > (omax - 2))
+ return ERROR(dstSize_tooSmall);
*op++ = FSE_GETSYMBOL(&state2);
- if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
+ if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) {
*op++ = FSE_GETSYMBOL(&state1);
break;
- } }
+ }
+ }
- return op-ostart;
+ return op - ostart;
}
-
-size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
- const void* cSrc, size_t cSrcSize,
- const FSE_DTable* dt)
+size_t FSE_decompress_usingDTable(void *dst, size_t originalSize, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt)
{
- const void* ptr = dt;
- const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
+ const void *ptr = dt;
+ const FSE_DTableHeader *DTableH = (const FSE_DTableHeader *)ptr;
const U32 fastMode = DTableH->fastMode;
/* select fast mode (static) */
- if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
+ if (fastMode)
+ return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
}
-
-size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog)
+size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize)
{
- const BYTE* const istart = (const BYTE*)cSrc;
- const BYTE* ip = istart;
- short counting[FSE_MAX_SYMBOL_VALUE+1];
+ const BYTE *const istart = (const BYTE *)cSrc;
+ const BYTE *ip = istart;
unsigned tableLog;
unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
+ size_t NCountLength;
+
+ FSE_DTable *dt;
+ short *counting;
+ size_t spaceUsed32 = 0;
+
+ FSE_STATIC_ASSERT(sizeof(FSE_DTable) == sizeof(U32));
+
+ dt = (FSE_DTable *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += FSE_DTABLE_SIZE_U32(maxLog);
+ counting = (short *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += ALIGN(sizeof(short) * (FSE_MAX_SYMBOL_VALUE + 1), sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > workspaceSize)
+ return ERROR(tableLog_tooLarge);
+ workspace = (U32 *)workspace + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
/* normal FSE decoding mode */
- size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
- if (FSE_isError(NCountLength)) return NCountLength;
- //if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */
- if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
+ NCountLength = FSE_readNCount(counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
+ if (FSE_isError(NCountLength))
+ return NCountLength;
+ // if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining
+ // case : NCountLength==cSrcSize */
+ if (tableLog > maxLog)
+ return ERROR(tableLog_tooLarge);
ip += NCountLength;
cSrcSize -= NCountLength;
- CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );
+ CHECK_F(FSE_buildDTable_wksp(dt, counting, maxSymbolValue, tableLog, workspace, workspaceSize));
- return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */
+ return FSE_decompress_usingDTable(dst, dstCapacity, ip, cSrcSize, dt); /* always return, even if it is an error code */
}
-
-
-#endif /* FSE_COMMONDEFS_ONLY */
diff --git a/contrib/linux-kernel/lib/zstd/huf.h b/contrib/linux-kernel/lib/zstd/huf.h
index f36aded00..2143da28d 100644
--- a/contrib/linux-kernel/lib/zstd/huf.h
+++ b/contrib/linux-kernel/lib/zstd/huf.h
@@ -1,110 +1,113 @@
-/* ******************************************************************
- Huffman coder, part of New Generation Entropy library
- header file
- Copyright (C) 2013-2016, 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 :
- - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
-****************************************************************** */
+/*
+ * Huffman coder, part of New Generation Entropy library
+ * header file
+ * Copyright (C) 2013-2016, 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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ */
#ifndef HUF_H_298734234
#define HUF_H_298734234
-
/* *** Dependencies *** */
-#include /* size_t */
-
+#include /* size_t */
/* *** Tool functions *** */
-#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
-size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
+#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
+size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
/* Error Management */
-unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
-
+unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
/* *** Advanced function *** */
/** HUF_compress4X_wksp() :
* Same as HUF_compress2(), but uses externally allocated `workSpace`, which must be a table of >= 1024 unsigned */
-size_t HUF_compress4X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
-
-
+size_t HUF_compress4X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
+ size_t wkspSize); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
/* *** Dependencies *** */
-#include "mem.h" /* U32 */
-
+#include "mem.h" /* U32 */
/* *** Constants *** */
-#define HUF_TABLELOG_MAX 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
-#define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */
-#define HUF_SYMBOLVALUE_MAX 255
+#define HUF_TABLELOG_MAX 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
+#define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */
+#define HUF_SYMBOLVALUE_MAX 255
-#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
+#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
-# error "HUF_TABLELOG_MAX is too large !"
+#error "HUF_TABLELOG_MAX is too large !"
#endif
-
/* ****************************************
* Static allocation
******************************************/
/* HUF buffer bounds */
#define HUF_CTABLEBOUND 129
-#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true if incompressible pre-filtered with fast heuristic */
-#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
+#define HUF_BLOCKBOUND(size) (size + (size >> 8) + 8) /* only true if incompressible pre-filtered with fast heuristic */
+#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
/* static allocation of HUF's Compression Table */
#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
- U32 name##hb[maxSymbolValue+1]; \
- void* name##hv = &(name##hb); \
- HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */
+ U32 name##hb[maxSymbolValue + 1]; \
+ void *name##hv = &(name##hb); \
+ HUF_CElt *name = (HUF_CElt *)(name##hv) /* no final ; */
/* static allocation of HUF's DTable */
typedef U32 HUF_DTable;
-#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
-#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
- HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
-#define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) \
- HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
+#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1 << (maxTableLog)))
+#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = {((U32)((maxTableLog)-1) * 0x01000001)}
+#define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = {((U32)(maxTableLog)*0x01000001)}
/* The workspace must have alignment at least 4 and be at least this large */
-#define HUF_WORKSPACE_SIZE (6 << 10)
-#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32))
+#define HUF_COMPRESS_WORKSPACE_SIZE (6 << 10)
+#define HUF_COMPRESS_WORKSPACE_SIZE_U32 (HUF_COMPRESS_WORKSPACE_SIZE / sizeof(U32))
+/* The workspace must have alignment at least 4 and be at least this large */
+#define HUF_DECOMPRESS_WORKSPACE_SIZE (3 << 10)
+#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32))
/* ****************************************
* Advanced decompression functions
******************************************/
-size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */
-size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
-size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
-size_t HUF_decompress4X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
-
+size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize); /**< decodes RLE and uncompressed */
+size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
+ size_t workspaceSize); /**< considers RLE and uncompressed as errors */
+size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
+ size_t workspaceSize); /**< single-symbol decoder */
+size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
+ size_t workspaceSize); /**< double-symbols decoder */
/* ****************************************
* HUF detailed API
@@ -114,7 +117,7 @@ HUF_compress() does the following:
1. count symbol occurrence from source[] into table count[] using FSE_count()
2. (optional) refine tableLog using HUF_optimalTableLog()
3. build Huffman table from count using HUF_buildCTable()
-4. save Huffman table to memory buffer using HUF_writeCTable()
+4. save Huffman table to memory buffer using HUF_writeCTable_wksp()
5. encode the data stream using HUF_compress4X_usingCTable()
The following API allows targeting specific sub-functions for advanced tasks.
@@ -123,41 +126,42 @@ or to save and regenerate 'CTable' using external methods.
*/
/* FSE_count() : find it within "fse.h" */
unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
-typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
-size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
-size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
+typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
+size_t HUF_writeCTable_wksp(void *dst, size_t maxDstSize, const HUF_CElt *CTable, unsigned maxSymbolValue, unsigned huffLog, void *workspace, size_t workspaceSize);
+size_t HUF_compress4X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable);
typedef enum {
- HUF_repeat_none, /**< Cannot use the previous table */
- HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */
- HUF_repeat_valid /**< Can use the previous table and it is asumed to be valid */
- } HUF_repeat;
+ HUF_repeat_none, /**< Cannot use the previous table */
+ HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1,
+ 4}X_repeat */
+ HUF_repeat_valid /**< Can use the previous table and it is asumed to be valid */
+} HUF_repeat;
/** HUF_compress4X_repeat() :
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
* If it uses hufTable it does not modify hufTable or repeat.
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
* If preferRepeat then the old table will always be used if valid. */
-size_t HUF_compress4X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+size_t HUF_compress4X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
+ size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat,
+ int preferRepeat); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
/** HUF_buildCTable_wksp() :
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
*/
-size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize);
+size_t HUF_buildCTable_wksp(HUF_CElt *tree, const U32 *count, U32 maxSymbolValue, U32 maxNbBits, void *workSpace, size_t wkspSize);
/*! HUF_readStats() :
Read compact Huffman tree, saved by HUF_writeCTable().
`huffWeight` is destination buffer.
@return : size read from `src` , or an error Code .
Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
-size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
- U32* nbSymbolsPtr, U32* tableLogPtr,
- const void* src, size_t srcSize);
+size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize,
+ void *workspace, size_t workspaceSize);
/** HUF_readCTable() :
* Loading a CTable saved with HUF_writeCTable() */
-size_t HUF_readCTable (HUF_CElt* CTable, unsigned maxSymbolValue, const void* src, size_t srcSize);
-
+size_t HUF_readCTable_wksp(HUF_CElt *CTable, unsigned maxSymbolValue, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
/*
HUF_decompress() does the following:
@@ -171,33 +175,38 @@ HUF_decompress() does the following:
* based on a set of pre-determined metrics.
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
-U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
+U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize);
-size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
-size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize);
-
-size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
-size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
-size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
+size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize);
+size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
+size_t HUF_decompress4X2_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
+size_t HUF_decompress4X4_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
/* single stream variants */
-size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
-size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
+size_t HUF_compress1X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
+ size_t wkspSize); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
+size_t HUF_compress1X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable);
/** HUF_compress1X_repeat() :
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
* If it uses hufTable it does not modify hufTable or repeat.
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
* If preferRepeat then the old table will always be used if valid. */
-size_t HUF_compress1X_repeat(void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize, HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */
+size_t HUF_compress1X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
+ size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat,
+ int preferRepeat); /**< `workSpace` must be a table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
-size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
-size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
-size_t HUF_decompress1X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
+size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize);
+size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
+ size_t workspaceSize); /**< single-symbol decoder */
+size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
+ size_t workspaceSize); /**< double-symbols decoder */
-size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
-size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
-size_t HUF_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
+size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize,
+ const HUF_DTable *DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
+size_t HUF_decompress1X2_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
+size_t HUF_decompress1X4_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
-#endif /* HUF_H_298734234 */
+#endif /* HUF_H_298734234 */
diff --git a/contrib/linux-kernel/lib/zstd/huf_compress.c b/contrib/linux-kernel/lib/zstd/huf_compress.c
index a1a1d454a..0361f387f 100644
--- a/contrib/linux-kernel/lib/zstd/huf_compress.c
+++ b/contrib/linux-kernel/lib/zstd/huf_compress.c
@@ -1,54 +1,66 @@
-/* ******************************************************************
- Huffman encoder, part of New Generation Entropy library
- Copyright (C) 2013-2016, 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 :
- - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
- - Public forum : https://groups.google.com/forum/#!forum/lz4c
-****************************************************************** */
-
+/*
+ * Huffman encoder, part of New Generation Entropy library
+ * Copyright (C) 2013-2016, 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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ */
/* **************************************************************
* Includes
****************************************************************/
-#include /* memcpy, memset */
#include "bitstream.h"
-#include "fse.h" /* header compression */
+#include "fse.h" /* header compression */
#include "huf.h"
-
+#include
+#include /* memcpy, memset */
/* **************************************************************
* Error Management
****************************************************************/
-#define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
-#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return f
-#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
-
+#define HUF_STATIC_ASSERT(c) \
+ { \
+ enum { HUF_static_assert = 1 / (int)(!!(c)) }; \
+ } /* use only *after* variable declarations */
+#define CHECK_V_F(e, f) \
+ size_t const e = f; \
+ if (ERR_isError(e)) \
+ return f
+#define CHECK_F(f) \
+ { \
+ CHECK_V_F(_var_err__, f); \
+ }
/* **************************************************************
* Utils
@@ -58,7 +70,6 @@ unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS
return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
}
-
/* *******************************************************
* HUF : Huffman block compression
*********************************************************/
@@ -68,141 +79,207 @@ unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS
* Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
*/
#define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
-size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
+size_t HUF_compressWeights_wksp(void *dst, size_t dstSize, const void *weightTable, size_t wtSize, void *workspace, size_t workspaceSize)
{
- BYTE* const ostart = (BYTE*) dst;
- BYTE* op = ostart;
- BYTE* const oend = ostart + dstSize;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *op = ostart;
+ BYTE *const oend = ostart + dstSize;
U32 maxSymbolValue = HUF_TABLELOG_MAX;
U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
- FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
- BYTE scratchBuffer[1<> 2;
+
+ if ((spaceUsed32 << 2) > workspaceSize)
+ return ERROR(tableLog_tooLarge);
+ workspace = (U32 *)workspace + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
/* init conditions */
- if (wtSize <= 1) return 0; /* Not compressible */
+ if (wtSize <= 1)
+ return 0; /* Not compressible */
/* Scan input and build symbol stats */
- { CHECK_V_F(maxCount, FSE_count_simple(count, &maxSymbolValue, weightTable, wtSize) );
- if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
- if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
+ {
+ CHECK_V_F(maxCount, FSE_count_simple(count, &maxSymbolValue, weightTable, wtSize));
+ if (maxCount == wtSize)
+ return 1; /* only a single symbol in src : rle */
+ if (maxCount == 1)
+ return 0; /* each symbol present maximum once => not compressible */
}
tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
- CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) );
+ CHECK_F(FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue));
/* Write table description header */
- { CHECK_V_F(hSize, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
+ {
+ CHECK_V_F(hSize, FSE_writeNCount(op, oend - op, norm, maxSymbolValue, tableLog));
op += hSize;
}
/* Compress */
- CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
- { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) );
- if (cSize == 0) return 0; /* not enough space for compressed data */
+ CHECK_F(FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, workspace, workspaceSize));
+ {
+ CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable));
+ if (cSize == 0)
+ return 0; /* not enough space for compressed data */
op += cSize;
}
- return op-ostart;
+ return op - ostart;
}
-
struct HUF_CElt_s {
- U16 val;
- BYTE nbBits;
-}; /* typedef'd to HUF_CElt within "huf.h" */
+ U16 val;
+ BYTE nbBits;
+}; /* typedef'd to HUF_CElt within "huf.h" */
-/*! HUF_writeCTable() :
+/*! HUF_writeCTable_wksp() :
`CTable` : Huffman tree to save, using huf representation.
@return : size of saved CTable */
-size_t HUF_writeCTable (void* dst, size_t maxDstSize,
- const HUF_CElt* CTable, U32 maxSymbolValue, U32 huffLog)
+size_t HUF_writeCTable_wksp(void *dst, size_t maxDstSize, const HUF_CElt *CTable, U32 maxSymbolValue, U32 huffLog, void *workspace, size_t workspaceSize)
{
- BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
- BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
- BYTE* op = (BYTE*)dst;
+ BYTE *op = (BYTE *)dst;
U32 n;
- /* check conditions */
- if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
+ BYTE *bitsToWeight;
+ BYTE *huffWeight;
+ size_t spaceUsed32 = 0;
+
+ bitsToWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += ALIGN(HUF_TABLELOG_MAX + 1, sizeof(U32)) >> 2;
+ huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX, sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > workspaceSize)
+ return ERROR(tableLog_tooLarge);
+ workspace = (U32 *)workspace + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
+
+ /* check conditions */
+ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX)
+ return ERROR(maxSymbolValue_tooLarge);
/* convert to weight */
bitsToWeight[0] = 0;
- for (n=1; n1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
+ {
+ CHECK_V_F(hSize, HUF_compressWeights_wksp(op + 1, maxDstSize - 1, huffWeight, maxSymbolValue, workspace, workspaceSize));
+ if ((hSize > 1) & (hSize < maxSymbolValue / 2)) { /* FSE compressed */
op[0] = (BYTE)hSize;
- return hSize+1;
- } }
+ return hSize + 1;
+ }
+ }
/* write raw values as 4-bits (max : 15) */
- if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
- if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
- op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
- huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
- for (n=0; n (256 - 128))
+ return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
+ if (((maxSymbolValue + 1) / 2) + 1 > maxDstSize)
+ return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
+ op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue - 1));
+ huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
+ for (n = 0; n < maxSymbolValue; n += 2)
+ op[(n / 2) + 1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n + 1]);
+ return ((maxSymbolValue + 1) / 2) + 1;
}
-
-size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, size_t srcSize)
+size_t HUF_readCTable_wksp(HUF_CElt *CTable, U32 maxSymbolValue, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
{
- BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */
- U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
+ U32 *rankVal;
+ BYTE *huffWeight;
U32 tableLog = 0;
U32 nbSymbols = 0;
+ size_t readSize;
+ size_t spaceUsed32 = 0;
+
+ rankVal = (U32 *)workspace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
+ huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > workspaceSize)
+ return ERROR(tableLog_tooLarge);
+ workspace = (U32 *)workspace + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
/* get symbol weights */
- CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));
+ readSize = HUF_readStats_wksp(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
+ if (ERR_isError(readSize))
+ return readSize;
/* check result */
- if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
- if (nbSymbols > maxSymbolValue+1) return ERROR(maxSymbolValue_tooSmall);
+ if (tableLog > HUF_TABLELOG_MAX)
+ return ERROR(tableLog_tooLarge);
+ if (nbSymbols > maxSymbolValue + 1)
+ return ERROR(maxSymbolValue_tooSmall);
/* Prepare base value per rank */
- { U32 n, nextRankStart = 0;
- for (n=1; n<=tableLog; n++) {
- U32 current = nextRankStart;
- nextRankStart += (rankVal[n] << (n-1));
- rankVal[n] = current;
- } }
+ {
+ U32 n, nextRankStart = 0;
+ for (n = 1; n <= tableLog; n++) {
+ U32 curr = nextRankStart;
+ nextRankStart += (rankVal[n] << (n - 1));
+ rankVal[n] = curr;
+ }
+ }
/* fill nbBits */
- { U32 n; for (n=0; nn=tableLog+1 */
- U16 valPerRank[HUF_TABLELOG_MAX+2] = {0};
- { U32 n; for (n=0; nn=tableLog+1 */
+ U16 valPerRank[HUF_TABLELOG_MAX + 2] = {0};
+ {
+ U32 n;
+ for (n = 0; n < nbSymbols; n++)
+ nbPerRank[CTable[n].nbBits]++;
+ }
/* determine stating value per rank */
- valPerRank[tableLog+1] = 0; /* for w==0 */
- { U16 min = 0;
- U32 n; for (n=tableLog; n>0; n--) { /* start at n=tablelog <-> w=1 */
+ valPerRank[tableLog + 1] = 0; /* for w==0 */
+ {
+ U16 min = 0;
+ U32 n;
+ for (n = tableLog; n > 0; n--) { /* start at n=tablelog <-> w=1 */
valPerRank[n] = min; /* get starting value within each rank */
min += nbPerRank[n];
min >>= 1;
- } }
+ }
+ }
/* assign value within rank, symbol order */
- { U32 n; for (n=0; n<=maxSymbolValue; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
+ {
+ U32 n;
+ for (n = 0; n <= maxSymbolValue; n++)
+ CTable[n].val = valPerRank[CTable[n].nbBits]++;
+ }
}
return readSize;
}
-
typedef struct nodeElt_s {
U32 count;
U16 parent;
@@ -210,130 +287,152 @@ typedef struct nodeElt_s {
BYTE nbBits;
} nodeElt;
-static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
+static U32 HUF_setMaxHeight(nodeElt *huffNode, U32 lastNonNull, U32 maxNbBits)
{
const U32 largestBits = huffNode[lastNonNull].nbBits;
- if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */
+ if (largestBits <= maxNbBits)
+ return largestBits; /* early exit : no elt > maxNbBits */
/* there are several too large elements (at least >= 2) */
- { int totalCost = 0;
+ {
+ int totalCost = 0;
const U32 baseCost = 1 << (largestBits - maxNbBits);
U32 n = lastNonNull;
while (huffNode[n].nbBits > maxNbBits) {
totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
huffNode[n].nbBits = (BYTE)maxNbBits;
- n --;
- } /* n stops at huffNode[n].nbBits <= maxNbBits */
- while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */
+ n--;
+ } /* n stops at huffNode[n].nbBits <= maxNbBits */
+ while (huffNode[n].nbBits == maxNbBits)
+ n--; /* n end at index of smallest symbol using < maxNbBits */
/* renorm totalCost */
- totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */
+ totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */
/* repay normalized cost */
- { U32 const noSymbol = 0xF0F0F0F0;
- U32 rankLast[HUF_TABLELOG_MAX+2];
+ {
+ U32 const noSymbol = 0xF0F0F0F0;
+ U32 rankLast[HUF_TABLELOG_MAX + 2];
int pos;
/* Get pos of last (smallest) symbol per rank */
memset(rankLast, 0xF0, sizeof(rankLast));
- { U32 currentNbBits = maxNbBits;
- for (pos=n ; pos >= 0; pos--) {
- if (huffNode[pos].nbBits >= currentNbBits) continue;
- currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */
- rankLast[maxNbBits-currentNbBits] = pos;
- } }
+ {
+ U32 currNbBits = maxNbBits;
+ for (pos = n; pos >= 0; pos--) {
+ if (huffNode[pos].nbBits >= currNbBits)
+ continue;
+ currNbBits = huffNode[pos].nbBits; /* < maxNbBits */
+ rankLast[maxNbBits - currNbBits] = pos;
+ }
+ }
while (totalCost > 0) {
U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1;
- for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
+ for (; nBitsToDecrease > 1; nBitsToDecrease--) {
U32 highPos = rankLast[nBitsToDecrease];
- U32 lowPos = rankLast[nBitsToDecrease-1];
- if (highPos == noSymbol) continue;
- if (lowPos == noSymbol) break;
- { U32 const highTotal = huffNode[highPos].count;
+ U32 lowPos = rankLast[nBitsToDecrease - 1];
+ if (highPos == noSymbol)
+ continue;
+ if (lowPos == noSymbol)
+ break;
+ {
+ U32 const highTotal = huffNode[highPos].count;
U32 const lowTotal = 2 * huffNode[lowPos].count;
- if (highTotal <= lowTotal) break;
- } }
+ if (highTotal <= lowTotal)
+ break;
+ }
+ }
/* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
- while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
- nBitsToDecrease ++;
- totalCost -= 1 << (nBitsToDecrease-1);
- if (rankLast[nBitsToDecrease-1] == noSymbol)
- rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */
- huffNode[rankLast[nBitsToDecrease]].nbBits ++;
- if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */
+ /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
+ while ((nBitsToDecrease <= HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol))
+ nBitsToDecrease++;
+ totalCost -= 1 << (nBitsToDecrease - 1);
+ if (rankLast[nBitsToDecrease - 1] == noSymbol)
+ rankLast[nBitsToDecrease - 1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */
+ huffNode[rankLast[nBitsToDecrease]].nbBits++;
+ if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */
rankLast[nBitsToDecrease] = noSymbol;
else {
rankLast[nBitsToDecrease]--;
- if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
- rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
- } } /* while (totalCost > 0) */
+ if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits - nBitsToDecrease)
+ rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
+ }
+ } /* while (totalCost > 0) */
- while (totalCost < 0) { /* Sometimes, cost correction overshoot */
- if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
- while (huffNode[n].nbBits == maxNbBits) n--;
- huffNode[n+1].nbBits--;
- rankLast[1] = n+1;
+ while (totalCost < 0) { /* Sometimes, cost correction overshoot */
+ if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0
+ (using maxNbBits) */
+ while (huffNode[n].nbBits == maxNbBits)
+ n--;
+ huffNode[n + 1].nbBits--;
+ rankLast[1] = n + 1;
totalCost++;
continue;
}
- huffNode[ rankLast[1] + 1 ].nbBits--;
+ huffNode[rankLast[1] + 1].nbBits--;
rankLast[1]++;
- totalCost ++;
- } } } /* there are several too large elements (at least >= 2) */
+ totalCost++;
+ }
+ }
+ } /* there are several too large elements (at least >= 2) */
return maxNbBits;
}
-
typedef struct {
U32 base;
- U32 current;
+ U32 curr;
} rankPos;
-static void HUF_sort(nodeElt* huffNode, const U32* count, U32 maxSymbolValue)
+static void HUF_sort(nodeElt *huffNode, const U32 *count, U32 maxSymbolValue)
{
rankPos rank[32];
U32 n;
memset(rank, 0, sizeof(rank));
- for (n=0; n<=maxSymbolValue; n++) {
+ for (n = 0; n <= maxSymbolValue; n++) {
U32 r = BIT_highbit32(count[n] + 1);
- rank[r].base ++;
+ rank[r].base++;
}
- for (n=30; n>0; n--) rank[n-1].base += rank[n].base;
- for (n=0; n<32; n++) rank[n].current = rank[n].base;
- for (n=0; n<=maxSymbolValue; n++) {
+ for (n = 30; n > 0; n--)
+ rank[n - 1].base += rank[n].base;
+ for (n = 0; n < 32; n++)
+ rank[n].curr = rank[n].base;
+ for (n = 0; n <= maxSymbolValue; n++) {
U32 const c = count[n];
- U32 const r = BIT_highbit32(c+1) + 1;
- U32 pos = rank[r].current++;
- while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) huffNode[pos]=huffNode[pos-1], pos--;
+ U32 const r = BIT_highbit32(c + 1) + 1;
+ U32 pos = rank[r].curr++;
+ while ((pos > rank[r].base) && (c > huffNode[pos - 1].count))
+ huffNode[pos] = huffNode[pos - 1], pos--;
huffNode[pos].count = c;
- huffNode[pos].byte = (BYTE)n;
+ huffNode[pos].byte = (BYTE)n;
}
}
-
/** HUF_buildCTable_wksp() :
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
* `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
*/
-#define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
-typedef nodeElt huffNodeTable[2*HUF_SYMBOLVALUE_MAX+1 +1];
-size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
+#define STARTNODE (HUF_SYMBOLVALUE_MAX + 1)
+typedef nodeElt huffNodeTable[2 * HUF_SYMBOLVALUE_MAX + 1 + 1];
+size_t HUF_buildCTable_wksp(HUF_CElt *tree, const U32 *count, U32 maxSymbolValue, U32 maxNbBits, void *workSpace, size_t wkspSize)
{
- nodeElt* const huffNode0 = (nodeElt*)workSpace;
- nodeElt* const huffNode = huffNode0+1;
+ nodeElt *const huffNode0 = (nodeElt *)workSpace;
+ nodeElt *const huffNode = huffNode0 + 1;
U32 n, nonNullRank;
int lowS, lowN;
U16 nodeNb = STARTNODE;
U32 nodeRoot;
/* safety checks */
- if (wkspSize < sizeof(huffNodeTable)) return ERROR(GENERIC); /* workSpace is not large enough */
- if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
- if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(GENERIC);
+ if (wkspSize < sizeof(huffNodeTable))
+ return ERROR(GENERIC); /* workSpace is not large enough */
+ if (maxNbBits == 0)
+ maxNbBits = HUF_TABLELOG_DEFAULT;
+ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX)
+ return ERROR(GENERIC);
memset(huffNode0, 0, sizeof(huffNodeTable));
/* sort, decreasing order */
@@ -341,13 +440,18 @@ size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValu
/* init for parents */
nonNullRank = maxSymbolValue;
- while(huffNode[nonNullRank].count == 0) nonNullRank--;
- lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb;
- huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count;
- huffNode[lowS].parent = huffNode[lowS-1].parent = nodeNb;
- nodeNb++; lowS-=2;
- for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30);
- huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */
+ while (huffNode[nonNullRank].count == 0)
+ nonNullRank--;
+ lowS = nonNullRank;
+ nodeRoot = nodeNb + lowS - 1;
+ lowN = nodeNb;
+ huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS - 1].count;
+ huffNode[lowS].parent = huffNode[lowS - 1].parent = nodeNb;
+ nodeNb++;
+ lowS -= 2;
+ for (n = nodeNb; n <= nodeRoot; n++)
+ huffNode[n].count = (U32)(1U << 30);
+ huffNode0[0].count = (U32)(1U << 31); /* fake entry, strong barrier */
/* create parents */
while (nodeNb <= nodeRoot) {
@@ -360,37 +464,41 @@ size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValu
/* distribute weights (unlimited tree height) */
huffNode[nodeRoot].nbBits = 0;
- for (n=nodeRoot-1; n>=STARTNODE; n--)
- huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
- for (n=0; n<=nonNullRank; n++)
- huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
+ for (n = nodeRoot - 1; n >= STARTNODE; n--)
+ huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1;
+ for (n = 0; n <= nonNullRank; n++)
+ huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1;
/* enforce maxTableLog */
maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits);
/* fill result into tree (val, nbBits) */
- { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
- U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
- if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */
- for (n=0; n<=nonNullRank; n++)
+ {
+ U16 nbPerRank[HUF_TABLELOG_MAX + 1] = {0};
+ U16 valPerRank[HUF_TABLELOG_MAX + 1] = {0};
+ if (maxNbBits > HUF_TABLELOG_MAX)
+ return ERROR(GENERIC); /* check fit into table */
+ for (n = 0; n <= nonNullRank; n++)
nbPerRank[huffNode[n].nbBits]++;
/* determine stating value per rank */
- { U16 min = 0;
- for (n=maxNbBits; n>0; n--) {
- valPerRank[n] = min; /* get starting value within each rank */
+ {
+ U16 min = 0;
+ for (n = maxNbBits; n > 0; n--) {
+ valPerRank[n] = min; /* get starting value within each rank */
min += nbPerRank[n];
min >>= 1;
- } }
- for (n=0; n<=maxSymbolValue; n++)
- tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */
- for (n=0; n<=maxSymbolValue; n++)
- tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */
+ }
+ }
+ for (n = 0; n <= maxSymbolValue; n++)
+ tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */
+ for (n = 0; n <= maxSymbolValue; n++)
+ tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */
}
return maxNbBits;
}
-static size_t HUF_estimateCompressedSize(HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue)
+static size_t HUF_estimateCompressedSize(HUF_CElt *CTable, const unsigned *count, unsigned maxSymbolValue)
{
size_t nbBits = 0;
int s;
@@ -400,165 +508,180 @@ static size_t HUF_estimateCompressedSize(HUF_CElt* CTable, const unsigned* count
return nbBits >> 3;
}
-static int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) {
- int bad = 0;
- int s;
- for (s = 0; s <= (int)maxSymbolValue; ++s) {
- bad |= (count[s] != 0) & (CTable[s].nbBits == 0);
- }
- return !bad;
+static int HUF_validateCTable(const HUF_CElt *CTable, const unsigned *count, unsigned maxSymbolValue)
+{
+ int bad = 0;
+ int s;
+ for (s = 0; s <= (int)maxSymbolValue; ++s) {
+ bad |= (count[s] != 0) & (CTable[s].nbBits == 0);
+ }
+ return !bad;
}
-static void HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
+static void HUF_encodeSymbol(BIT_CStream_t *bitCPtr, U32 symbol, const HUF_CElt *CTable)
{
BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
}
size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
-#define HUF_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
+#define HUF_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
-#define HUF_FLUSHBITS_1(stream) \
- if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream)
+#define HUF_FLUSHBITS_1(stream) \
+ if (sizeof((stream)->bitContainer) * 8 < HUF_TABLELOG_MAX * 2 + 7) \
+ HUF_FLUSHBITS(stream)
-#define HUF_FLUSHBITS_2(stream) \
- if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
+#define HUF_FLUSHBITS_2(stream) \
+ if (sizeof((stream)->bitContainer) * 8 < HUF_TABLELOG_MAX * 4 + 7) \
+ HUF_FLUSHBITS(stream)
-size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
+size_t HUF_compress1X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable)
{
- const BYTE* ip = (const BYTE*) src;
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* op = ostart;
+ const BYTE *ip = (const BYTE *)src;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *const oend = ostart + dstSize;
+ BYTE *op = ostart;
size_t n;
const unsigned fast = (dstSize >= HUF_BLOCKBOUND(srcSize));
BIT_CStream_t bitC;
/* init */
- if (dstSize < 8) return 0; /* not enough space to compress */
- { size_t const initErr = BIT_initCStream(&bitC, op, oend-op);
- if (HUF_isError(initErr)) return 0; }
-
- n = srcSize & ~3; /* join to mod 4 */
- switch (srcSize & 3)
+ if (dstSize < 8)
+ return 0; /* not enough space to compress */
{
- case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable);
- HUF_FLUSHBITS_2(&bitC);
- case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable);
- HUF_FLUSHBITS_1(&bitC);
- case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable);
- HUF_FLUSHBITS(&bitC);
- case 0 :
- default: ;
+ size_t const initErr = BIT_initCStream(&bitC, op, oend - op);
+ if (HUF_isError(initErr))
+ return 0;
}
- for (; n>0; n-=4) { /* note : n&3==0 at this stage */
- HUF_encodeSymbol(&bitC, ip[n- 1], CTable);
+ n = srcSize & ~3; /* join to mod 4 */
+ switch (srcSize & 3) {
+ case 3: HUF_encodeSymbol(&bitC, ip[n + 2], CTable); HUF_FLUSHBITS_2(&bitC);
+ case 2: HUF_encodeSymbol(&bitC, ip[n + 1], CTable); HUF_FLUSHBITS_1(&bitC);
+ case 1: HUF_encodeSymbol(&bitC, ip[n + 0], CTable); HUF_FLUSHBITS(&bitC);
+ case 0:
+ default:;
+ }
+
+ for (; n > 0; n -= 4) { /* note : n&3==0 at this stage */
+ HUF_encodeSymbol(&bitC, ip[n - 1], CTable);
HUF_FLUSHBITS_1(&bitC);
- HUF_encodeSymbol(&bitC, ip[n- 2], CTable);
+ HUF_encodeSymbol(&bitC, ip[n - 2], CTable);
HUF_FLUSHBITS_2(&bitC);
- HUF_encodeSymbol(&bitC, ip[n- 3], CTable);
+ HUF_encodeSymbol(&bitC, ip[n - 3], CTable);
HUF_FLUSHBITS_1(&bitC);
- HUF_encodeSymbol(&bitC, ip[n- 4], CTable);
+ HUF_encodeSymbol(&bitC, ip[n - 4], CTable);
HUF_FLUSHBITS(&bitC);
}
return BIT_closeCStream(&bitC);
}
-
-size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
+size_t HUF_compress4X_usingCTable(void *dst, size_t dstSize, const void *src, size_t srcSize, const HUF_CElt *CTable)
{
- size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
- const BYTE* ip = (const BYTE*) src;
- const BYTE* const iend = ip + srcSize;
- BYTE* const ostart = (BYTE*) dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* op = ostart;
+ size_t const segmentSize = (srcSize + 3) / 4; /* first 3 segments */
+ const BYTE *ip = (const BYTE *)src;
+ const BYTE *const iend = ip + srcSize;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *const oend = ostart + dstSize;
+ BYTE *op = ostart;
- if (dstSize < 6 + 1 + 1 + 1 + 8) return 0; /* minimum space to compress successfully */
- if (srcSize < 12) return 0; /* no saving possible : too small input */
- op += 6; /* jumpTable */
+ if (dstSize < 6 + 1 + 1 + 1 + 8)
+ return 0; /* minimum space to compress successfully */
+ if (srcSize < 12)
+ return 0; /* no saving possible : too small input */
+ op += 6; /* jumpTable */
- { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
- if (cSize==0) return 0;
- MEM_writeLE16(ostart, (U16)cSize);
+ {
+ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend - op, ip, segmentSize, CTable));
+ if (cSize == 0)
+ return 0;
+ ZSTD_writeLE16(ostart, (U16)cSize);
op += cSize;
}
ip += segmentSize;
- { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
- if (cSize==0) return 0;
- MEM_writeLE16(ostart+2, (U16)cSize);
+ {
+ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend - op, ip, segmentSize, CTable));
+ if (cSize == 0)
+ return 0;
+ ZSTD_writeLE16(ostart + 2, (U16)cSize);
op += cSize;
}
ip += segmentSize;
- { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
- if (cSize==0) return 0;
- MEM_writeLE16(ostart+4, (U16)cSize);
+ {
+ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend - op, ip, segmentSize, CTable));
+ if (cSize == 0)
+ return 0;
+ ZSTD_writeLE16(ostart + 4, (U16)cSize);
op += cSize;
}
ip += segmentSize;
- { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, iend-ip, CTable) );
- if (cSize==0) return 0;
+ {
+ CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend - op, ip, iend - ip, CTable));
+ if (cSize == 0)
+ return 0;
op += cSize;
}
- return op-ostart;
+ return op - ostart;
}
-
-static size_t HUF_compressCTable_internal(
- BYTE* const ostart, BYTE* op, BYTE* const oend,
- const void* src, size_t srcSize,
- unsigned singleStream, const HUF_CElt* CTable)
+static size_t HUF_compressCTable_internal(BYTE *const ostart, BYTE *op, BYTE *const oend, const void *src, size_t srcSize, unsigned singleStream,
+ const HUF_CElt *CTable)
{
- size_t const cSize = singleStream ?
- HUF_compress1X_usingCTable(op, oend - op, src, srcSize, CTable) :
- HUF_compress4X_usingCTable(op, oend - op, src, srcSize, CTable);
- if (HUF_isError(cSize)) { return cSize; }
- if (cSize==0) { return 0; } /* uncompressible */
+ size_t const cSize =
+ singleStream ? HUF_compress1X_usingCTable(op, oend - op, src, srcSize, CTable) : HUF_compress4X_usingCTable(op, oend - op, src, srcSize, CTable);
+ if (HUF_isError(cSize)) {
+ return cSize;
+ }
+ if (cSize == 0) {
+ return 0;
+ } /* uncompressible */
op += cSize;
/* check compressibility */
- if ((size_t)(op-ostart) >= srcSize-1) { return 0; }
- return op-ostart;
+ if ((size_t)(op - ostart) >= srcSize - 1) {
+ return 0;
+ }
+ return op - ostart;
}
-
/* `workSpace` must a table of at least 1024 unsigned */
-static size_t HUF_compress_internal (
- void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- unsigned singleStream,
- void* workSpace, size_t wkspSize,
- HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat)
+static size_t HUF_compress_internal(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog,
+ unsigned singleStream, void *workSpace, size_t wkspSize, HUF_CElt *oldHufTable, HUF_repeat *repeat, int preferRepeat)
{
- BYTE* const ostart = (BYTE*)dst;
- BYTE* const oend = ostart + dstSize;
- BYTE* op = ostart;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *const oend = ostart + dstSize;
+ BYTE *op = ostart;
- U32* count;
+ U32 *count;
size_t const countSize = sizeof(U32) * (HUF_SYMBOLVALUE_MAX + 1);
- HUF_CElt* CTable;
+ HUF_CElt *CTable;
size_t const CTableSize = sizeof(HUF_CElt) * (HUF_SYMBOLVALUE_MAX + 1);
/* checks & inits */
- if (wkspSize < sizeof(huffNodeTable) + countSize + CTableSize) return ERROR(GENERIC);
- if (!srcSize) return 0; /* Uncompressed (note : 1 means rle, so first byte must be correct) */
- if (!dstSize) return 0; /* cannot fit within dst budget */
- if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */
- if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
- if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
- if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
+ if (wkspSize < sizeof(huffNodeTable) + countSize + CTableSize)
+ return ERROR(GENERIC);
+ if (!srcSize)
+ return 0; /* Uncompressed (note : 1 means rle, so first byte must be correct) */
+ if (!dstSize)
+ return 0; /* cannot fit within dst budget */
+ if (srcSize > HUF_BLOCKSIZE_MAX)
+ return ERROR(srcSize_wrong); /* curr block size limit */
+ if (huffLog > HUF_TABLELOG_MAX)
+ return ERROR(tableLog_tooLarge);
+ if (!maxSymbolValue)
+ maxSymbolValue = HUF_SYMBOLVALUE_MAX;
+ if (!huffLog)
+ huffLog = HUF_TABLELOG_DEFAULT;
- count = (U32*)workSpace;
- workSpace = (BYTE*)workSpace + countSize;
+ count = (U32 *)workSpace;
+ workSpace = (BYTE *)workSpace + countSize;
wkspSize -= countSize;
- CTable = (HUF_CElt*)workSpace;
- workSpace = (BYTE*)workSpace + CTableSize;
+ CTable = (HUF_CElt *)workSpace;
+ workSpace = (BYTE *)workSpace + CTableSize;
wkspSize -= CTableSize;
/* Heuristic : If we don't need to check the validity of the old table use the old table for small inputs */
@@ -567,9 +690,14 @@ static size_t HUF_compress_internal (
}
/* Scan input and build symbol stats */
- { CHECK_V_F(largest, FSE_count_wksp (count, &maxSymbolValue, (const BYTE*)src, srcSize, (U32*)workSpace) );
- if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
- if (largest <= (srcSize >> 7)+1) return 0; /* Fast heuristic : not compressible enough */
+ {
+ CHECK_V_F(largest, FSE_count_wksp(count, &maxSymbolValue, (const BYTE *)src, srcSize, (U32 *)workSpace));
+ if (largest == srcSize) {
+ *ostart = ((const BYTE *)src)[0];
+ return 1;
+ } /* single symbol, rle */
+ if (largest <= (srcSize >> 7) + 1)
+ return 0; /* Fast heuristic : not compressible enough */
}
/* Check validity of previous table */
@@ -583,14 +711,16 @@ static size_t HUF_compress_internal (
/* Build Huffman Tree */
huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
- { CHECK_V_F(maxBits, HUF_buildCTable_wksp (CTable, count, maxSymbolValue, huffLog, workSpace, wkspSize) );
+ {
+ CHECK_V_F(maxBits, HUF_buildCTable_wksp(CTable, count, maxSymbolValue, huffLog, workSpace, wkspSize));
huffLog = (U32)maxBits;
/* Zero the unused symbols so we can check it for validity */
memset(CTable + maxSymbolValue + 1, 0, CTableSize - (maxSymbolValue + 1) * sizeof(HUF_CElt));
}
/* Write table description header */
- { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, CTable, maxSymbolValue, huffLog) );
+ {
+ CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, CTable, maxSymbolValue, huffLog, workSpace, wkspSize));
/* Check if using the previous table will be beneficial */
if (repeat && *repeat != HUF_repeat_none) {
size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, count, maxSymbolValue);
@@ -600,45 +730,42 @@ static size_t HUF_compress_internal (
}
}
/* Use the new table */
- if (hSize + 12ul >= srcSize) { return 0; }
+ if (hSize + 12ul >= srcSize) {
+ return 0;
+ }
op += hSize;
- if (repeat) { *repeat = HUF_repeat_none; }
- if (oldHufTable) { memcpy(oldHufTable, CTable, CTableSize); } /* Save the new table */
+ if (repeat) {
+ *repeat = HUF_repeat_none;
+ }
+ if (oldHufTable) {
+ memcpy(oldHufTable, CTable, CTableSize);
+ } /* Save the new table */
}
return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, CTable);
}
-
-size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- void* workSpace, size_t wkspSize)
+size_t HUF_compress1X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void *workSpace,
+ size_t wkspSize)
{
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, NULL, NULL, 0);
}
-size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- void* workSpace, size_t wkspSize,
- HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat)
+size_t HUF_compress1X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void *workSpace,
+ size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat, int preferRepeat)
{
- return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, hufTable, repeat, preferRepeat);
+ return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, hufTable, repeat,
+ preferRepeat);
}
-size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- void* workSpace, size_t wkspSize)
+size_t HUF_compress4X_wksp(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void *workSpace,
+ size_t wkspSize)
{
return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, NULL, NULL, 0);
}
-size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
- const void* src, size_t srcSize,
- unsigned maxSymbolValue, unsigned huffLog,
- void* workSpace, size_t wkspSize,
- HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat)
+size_t HUF_compress4X_repeat(void *dst, size_t dstSize, const void *src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void *workSpace,
+ size_t wkspSize, HUF_CElt *hufTable, HUF_repeat *repeat, int preferRepeat)
{
- return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, hufTable, repeat, preferRepeat);
+ return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, hufTable, repeat,
+ preferRepeat);
}
diff --git a/contrib/linux-kernel/lib/zstd/huf_decompress.c b/contrib/linux-kernel/lib/zstd/huf_decompress.c
index f73223c4e..652648204 100644
--- a/contrib/linux-kernel/lib/zstd/huf_decompress.c
+++ b/contrib/linux-kernel/lib/zstd/huf_decompress.c
@@ -1,129 +1,161 @@
-/* ******************************************************************
- Huffman decoder, part of New Generation Entropy library
- Copyright (C) 2013-2016, 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 :
- - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
- - Public forum : https://groups.google.com/forum/#!forum/lz4c
-****************************************************************** */
+/*
+ * Huffman decoder, part of New Generation Entropy library
+ * Copyright (C) 2013-2016, 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.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ *
+ * You can contact the author at :
+ * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
+ */
/* **************************************************************
* Compiler specifics
****************************************************************/
#define FORCE_INLINE static __always_inline
-
/* **************************************************************
* Dependencies
****************************************************************/
-#include
-#include /* memcpy, memset */
-#include "bitstream.h" /* BIT_* */
-#include "fse.h" /* header compression */
+#include "bitstream.h" /* BIT_* */
+#include "fse.h" /* header compression */
#include "huf.h"
-
+#include
+#include
+#include /* memcpy, memset */
/* **************************************************************
* Error Management
****************************************************************/
-#define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
-
+#define HUF_STATIC_ASSERT(c) \
+ { \
+ enum { HUF_static_assert = 1 / (int)(!!(c)) }; \
+ } /* use only *after* variable declarations */
/*-***************************/
/* generic DTableDesc */
/*-***************************/
-typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; } DTableDesc;
+typedef struct {
+ BYTE maxTableLog;
+ BYTE tableType;
+ BYTE tableLog;
+ BYTE reserved;
+} DTableDesc;
-static DTableDesc HUF_getDTableDesc(const HUF_DTable* table)
+static DTableDesc HUF_getDTableDesc(const HUF_DTable *table)
{
DTableDesc dtd;
memcpy(&dtd, table, sizeof(dtd));
return dtd;
}
-
/*-***************************/
/* single-symbol decoding */
/*-***************************/
-typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */
+typedef struct {
+ BYTE byte;
+ BYTE nbBits;
+} HUF_DEltX2; /* single-symbol decoding */
-size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize)
+size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
{
- BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1];
- U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
U32 tableLog = 0;
U32 nbSymbols = 0;
size_t iSize;
- void* const dtPtr = DTable + 1;
- HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;
+ void *const dtPtr = DTable + 1;
+ HUF_DEltX2 *const dt = (HUF_DEltX2 *)dtPtr;
+
+ U32 *rankVal;
+ BYTE *huffWeight;
+ size_t spaceUsed32 = 0;
+
+ rankVal = (U32 *)workspace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
+ huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > workspaceSize)
+ return ERROR(tableLog_tooLarge);
+ workspace = (U32 *)workspace + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
- /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
+ /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */
- iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);
- if (HUF_isError(iSize)) return iSize;
+ iSize = HUF_readStats_wksp(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
+ if (HUF_isError(iSize))
+ return iSize;
/* Table header */
- { DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
+ {
+ DTableDesc dtd = HUF_getDTableDesc(DTable);
+ if (tableLog > (U32)(dtd.maxTableLog + 1))
+ return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */
dtd.tableType = 0;
dtd.tableLog = (BYTE)tableLog;
memcpy(DTable, &dtd, sizeof(dtd));
}
/* Calculate starting value for each rank */
- { U32 n, nextRankStart = 0;
- for (n=1; n> 1;
U32 u;
HUF_DEltX2 D;
- D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);
+ D.byte = (BYTE)n;
+ D.nbBits = (BYTE)(tableLog + 1 - w);
for (u = rankVal[w]; u < rankVal[w] + length; u++)
dt[u] = D;
rankVal[w] += length;
- } }
+ }
+ }
return iSize;
}
-
-static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog)
+static BYTE HUF_decodeSymbolX2(BIT_DStream_t *Dstream, const HUF_DEltX2 *dt, const U32 dtLog)
{
size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */
BYTE const c = dt[val].byte;
@@ -131,23 +163,22 @@ static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, con
return c;
}
-#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
- *ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
+#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) *ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
-#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
- if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
- HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
+#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
+ if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
+ HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
- if (MEM_64bits()) \
- HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
+ if (ZSTD_64bits()) \
+ HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
-FORCE_INLINE size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX2* const dt, const U32 dtLog)
+FORCE_INLINE size_t HUF_decodeStreamX2(BYTE *p, BIT_DStream_t *const bitDPtr, BYTE *const pEnd, const HUF_DEltX2 *const dt, const U32 dtLog)
{
- BYTE* const pStart = p;
+ BYTE *const pStart = p;
/* up to 4 symbols at a time */
- while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-4)) {
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd - 4)) {
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
@@ -162,108 +193,121 @@ FORCE_INLINE size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* const bitDPtr, BY
while (p < pEnd)
HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
- return pEnd-pStart;
+ return pEnd - pStart;
}
-static size_t HUF_decompress1X2_usingDTable_internal(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+static size_t HUF_decompress1X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
- BYTE* op = (BYTE*)dst;
- BYTE* const oend = op + dstSize;
- const void* dtPtr = DTable + 1;
- const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
+ BYTE *op = (BYTE *)dst;
+ BYTE *const oend = op + dstSize;
+ const void *dtPtr = DTable + 1;
+ const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
BIT_DStream_t bitD;
DTableDesc const dtd = HUF_getDTableDesc(DTable);
U32 const dtLog = dtd.tableLog;
- { size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
- if (HUF_isError(errorCode)) return errorCode; }
+ {
+ size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
/* check */
- if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
+ if (!BIT_endOfDStream(&bitD))
+ return ERROR(corruption_detected);
return dstSize;
}
-size_t HUF_decompress1X2_usingDTable(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+size_t HUF_decompress1X2_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (dtd.tableType != 0) return ERROR(GENERIC);
+ if (dtd.tableType != 0)
+ return ERROR(GENERIC);
return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
}
-size_t HUF_decompress1X2_DCtx (HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
{
- const BYTE* ip = (const BYTE*) cSrc;
+ const BYTE *ip = (const BYTE *)cSrc;
- size_t const hSize = HUF_readDTableX2 (DCtx, cSrc, cSrcSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
+ size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize);
+ if (HUF_isError(hSize))
+ return hSize;
+ if (hSize >= cSrcSize)
+ return ERROR(srcSize_wrong);
+ ip += hSize;
+ cSrcSize -= hSize;
- return HUF_decompress1X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);
+ return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx);
}
-
-static size_t HUF_decompress4X2_usingDTable_internal(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+static size_t HUF_decompress4X2_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
/* Check */
- if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
+ if (cSrcSize < 10)
+ return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
- { const BYTE* const istart = (const BYTE*) cSrc;
- BYTE* const ostart = (BYTE*) dst;
- BYTE* const oend = ostart + dstSize;
- const void* const dtPtr = DTable + 1;
- const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr;
+ {
+ const BYTE *const istart = (const BYTE *)cSrc;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *const oend = ostart + dstSize;
+ const void *const dtPtr = DTable + 1;
+ const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
/* Init */
BIT_DStream_t bitD1;
BIT_DStream_t bitD2;
BIT_DStream_t bitD3;
BIT_DStream_t bitD4;
- size_t const length1 = MEM_readLE16(istart);
- size_t const length2 = MEM_readLE16(istart+2);
- size_t const length3 = MEM_readLE16(istart+4);
+ size_t const length1 = ZSTD_readLE16(istart);
+ size_t const length2 = ZSTD_readLE16(istart + 2);
+ size_t const length3 = ZSTD_readLE16(istart + 4);
size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
- const BYTE* const istart1 = istart + 6; /* jumpTable */
- const BYTE* const istart2 = istart1 + length1;
- const BYTE* const istart3 = istart2 + length2;
- const BYTE* const istart4 = istart3 + length3;
- const size_t segmentSize = (dstSize+3) / 4;
- BYTE* const opStart2 = ostart + segmentSize;
- BYTE* const opStart3 = opStart2 + segmentSize;
- BYTE* const opStart4 = opStart3 + segmentSize;
- BYTE* op1 = ostart;
- BYTE* op2 = opStart2;
- BYTE* op3 = opStart3;
- BYTE* op4 = opStart4;
+ const BYTE *const istart1 = istart + 6; /* jumpTable */
+ const BYTE *const istart2 = istart1 + length1;
+ const BYTE *const istart3 = istart2 + length2;
+ const BYTE *const istart4 = istart3 + length3;
+ const size_t segmentSize = (dstSize + 3) / 4;
+ BYTE *const opStart2 = ostart + segmentSize;
+ BYTE *const opStart3 = opStart2 + segmentSize;
+ BYTE *const opStart4 = opStart3 + segmentSize;
+ BYTE *op1 = ostart;
+ BYTE *op2 = opStart2;
+ BYTE *op3 = opStart3;
+ BYTE *op4 = opStart4;
U32 endSignal;
DTableDesc const dtd = HUF_getDTableDesc(DTable);
U32 const dtLog = dtd.tableLog;
- if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
- { size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
- if (HUF_isError(errorCode)) return errorCode; }
- { size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
- if (HUF_isError(errorCode)) return errorCode; }
- { size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
- if (HUF_isError(errorCode)) return errorCode; }
- { size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
- if (HUF_isError(errorCode)) return errorCode; }
+ if (length4 > cSrcSize)
+ return ERROR(corruption_detected); /* overflow */
+ {
+ size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
+ {
+ size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
+ {
+ size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
+ {
+ size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
/* 16-32 symbols per loop (4-8 symbols per stream) */
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
- for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) {
+ for (; (endSignal == BIT_DStream_unfinished) && (op4 < (oend - 7));) {
HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
@@ -284,63 +328,71 @@ static size_t HUF_decompress4X2_usingDTable_internal(
}
/* check corruption */
- if (op1 > opStart2) return ERROR(corruption_detected);
- if (op2 > opStart3) return ERROR(corruption_detected);
- if (op3 > opStart4) return ERROR(corruption_detected);
+ if (op1 > opStart2)
+ return ERROR(corruption_detected);
+ if (op2 > opStart3)
+ return ERROR(corruption_detected);
+ if (op3 > opStart4)
+ return ERROR(corruption_detected);
/* note : op4 supposed already verified within main loop */
/* finish bitStreams one by one */
HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
- HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
+ HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
/* check */
endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
- if (!endSignal) return ERROR(corruption_detected);
+ if (!endSignal)
+ return ERROR(corruption_detected);
/* decoded size */
return dstSize;
}
}
-
-size_t HUF_decompress4X2_usingDTable(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+size_t HUF_decompress4X2_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (dtd.tableType != 0) return ERROR(GENERIC);
+ if (dtd.tableType != 0)
+ return ERROR(GENERIC);
return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
}
-
-size_t HUF_decompress4X2_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
{
- const BYTE* ip = (const BYTE*) cSrc;
+ const BYTE *ip = (const BYTE *)cSrc;
- size_t const hSize = HUF_readDTableX2 (dctx, cSrc, cSrcSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
+ size_t const hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize);
+ if (HUF_isError(hSize))
+ return hSize;
+ if (hSize >= cSrcSize)
+ return ERROR(srcSize_wrong);
+ ip += hSize;
+ cSrcSize -= hSize;
- return HUF_decompress4X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, dctx);
+ return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
}
/* *************************/
/* double-symbols decoding */
/* *************************/
-typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4; /* double-symbols decoding */
+typedef struct {
+ U16 sequence;
+ BYTE nbBits;
+ BYTE length;
+} HUF_DEltX4; /* double-symbols decoding */
-typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t;
+typedef struct {
+ BYTE symbol;
+ BYTE weight;
+} sortedSymbol_t;
/* HUF_fillDTableX4Level2() :
* `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
-static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 consumed,
- const U32* rankValOrigin, const int minWeight,
- const sortedSymbol_t* sortedSymbols, const U32 sortedListSize,
- U32 nbBitsBaseline, U16 baseSeq)
+static void HUF_fillDTableX4Level2(HUF_DEltX4 *DTable, U32 sizeLog, const U32 consumed, const U32 *rankValOrigin, const int minWeight,
+ const sortedSymbol_t *sortedSymbols, const U32 sortedListSize, U32 nbBitsBaseline, U16 baseSeq)
{
HUF_DEltX4 DElt;
U32 rankVal[HUF_TABLELOG_MAX + 1];
@@ -349,151 +401,190 @@ static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 co
memcpy(rankVal, rankValOrigin, sizeof(rankVal));
/* fill skipped values */
- if (minWeight>1) {
+ if (minWeight > 1) {
U32 i, skipSize = rankVal[minWeight];
- MEM_writeLE16(&(DElt.sequence), baseSeq);
- DElt.nbBits = (BYTE)(consumed);
- DElt.length = 1;
+ ZSTD_writeLE16(&(DElt.sequence), baseSeq);
+ DElt.nbBits = (BYTE)(consumed);
+ DElt.length = 1;
for (i = 0; i < skipSize; i++)
DTable[i] = DElt;
}
/* fill DTable */
- { U32 s; for (s=0; s= 1 */
+ do {
+ DTable[i++] = DElt;
+ } while (i < end); /* since length >= 1 */
rankVal[weight] += length;
- } }
+ }
+ }
}
typedef U32 rankVal_t[HUF_TABLELOG_MAX][HUF_TABLELOG_MAX + 1];
+typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
-static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog,
- const sortedSymbol_t* sortedList, const U32 sortedListSize,
- const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight,
- const U32 nbBitsBaseline)
+static void HUF_fillDTableX4(HUF_DEltX4 *DTable, const U32 targetLog, const sortedSymbol_t *sortedList, const U32 sortedListSize, const U32 *rankStart,
+ rankVal_t rankValOrigin, const U32 maxWeight, const U32 nbBitsBaseline)
{
U32 rankVal[HUF_TABLELOG_MAX + 1];
- const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
- const U32 minBits = nbBitsBaseline - maxWeight;
+ const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */
+ const U32 minBits = nbBitsBaseline - maxWeight;
U32 s;
memcpy(rankVal, rankValOrigin, sizeof(rankVal));
/* fill DTable */
- for (s=0; s= minBits) { /* enough room for a second symbol */
+ if (targetLog - nbBits >= minBits) { /* enough room for a second symbol */
U32 sortedRank;
int minWeight = nbBits + scaleLog;
- if (minWeight < 1) minWeight = 1;
+ if (minWeight < 1)
+ minWeight = 1;
sortedRank = rankStart[minWeight];
- HUF_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits,
- rankValOrigin[nbBits], minWeight,
- sortedList+sortedRank, sortedListSize-sortedRank,
- nbBitsBaseline, symbol);
+ HUF_fillDTableX4Level2(DTable + start, targetLog - nbBits, nbBits, rankValOrigin[nbBits], minWeight, sortedList + sortedRank,
+ sortedListSize - sortedRank, nbBitsBaseline, symbol);
} else {
HUF_DEltX4 DElt;
- MEM_writeLE16(&(DElt.sequence), symbol);
+ ZSTD_writeLE16(&(DElt.sequence), symbol);
DElt.nbBits = (BYTE)(nbBits);
DElt.length = 1;
- { U32 const end = start + length;
+ {
+ U32 const end = start + length;
U32 u;
- for (u = start; u < end; u++) DTable[u] = DElt;
- } }
+ for (u = start; u < end; u++)
+ DTable[u] = DElt;
+ }
+ }
rankVal[weight] += length;
}
}
-size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize)
+size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t srcSize, void *workspace, size_t workspaceSize)
{
- BYTE weightList[HUF_SYMBOLVALUE_MAX + 1];
- sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1];
- U32 rankStats[HUF_TABLELOG_MAX + 1] = { 0 };
- U32 rankStart0[HUF_TABLELOG_MAX + 2] = { 0 };
- U32* const rankStart = rankStart0+1;
- rankVal_t rankVal;
U32 tableLog, maxW, sizeOfSort, nbSymbols;
DTableDesc dtd = HUF_getDTableDesc(DTable);
U32 const maxTableLog = dtd.maxTableLog;
size_t iSize;
- void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */
- HUF_DEltX4* const dt = (HUF_DEltX4*)dtPtr;
+ void *dtPtr = DTable + 1; /* force compiler to avoid strict-aliasing */
+ HUF_DEltX4 *const dt = (HUF_DEltX4 *)dtPtr;
+ U32 *rankStart;
- HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
- if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
- /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
+ rankValCol_t *rankVal;
+ U32 *rankStats;
+ U32 *rankStart0;
+ sortedSymbol_t *sortedSymbol;
+ BYTE *weightList;
+ size_t spaceUsed32 = 0;
- iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);
- if (HUF_isError(iSize)) return iSize;
+ HUF_STATIC_ASSERT((sizeof(rankValCol_t) & 3) == 0);
+
+ rankVal = (rankValCol_t *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
+ rankStats = (U32 *)workspace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_MAX + 1;
+ rankStart0 = (U32 *)workspace + spaceUsed32;
+ spaceUsed32 += HUF_TABLELOG_MAX + 2;
+ sortedSymbol = (sortedSymbol_t *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2;
+ weightList = (BYTE *)((U32 *)workspace + spaceUsed32);
+ spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
+
+ if ((spaceUsed32 << 2) > workspaceSize)
+ return ERROR(tableLog_tooLarge);
+ workspace = (U32 *)workspace + spaceUsed32;
+ workspaceSize -= (spaceUsed32 << 2);
+
+ rankStart = rankStart0 + 1;
+ memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
+
+ HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */
+ if (maxTableLog > HUF_TABLELOG_MAX)
+ return ERROR(tableLog_tooLarge);
+ /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */
+
+ iSize = HUF_readStats_wksp(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
+ if (HUF_isError(iSize))
+ return iSize;
/* check result */
- if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
+ if (tableLog > maxTableLog)
+ return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */
/* find maxWeight */
- for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */
+ for (maxW = tableLog; rankStats[maxW] == 0; maxW--) {
+ } /* necessarily finds a solution before 0 */
/* Get start index of each weight */
- { U32 w, nextRankStart = 0;
- for (w=1; w> consumed;
- } } } }
+ }
+ }
+ }
+ }
- HUF_fillDTableX4(dt, maxTableLog,
- sortedSymbol, sizeOfSort,
- rankStart0, rankVal, maxW,
- tableLog+1);
+ HUF_fillDTableX4(dt, maxTableLog, sortedSymbol, sizeOfSort, rankStart0, rankVal, maxW, tableLog + 1);
dtd.tableLog = (BYTE)maxTableLog;
dtd.tableType = 1;
@@ -501,47 +592,47 @@ size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize)
return iSize;
}
-
-static U32 HUF_decodeSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
+static U32 HUF_decodeSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog)
{
- size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
- memcpy(op, dt+val, 2);
+ size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
+ memcpy(op, dt + val, 2);
BIT_skipBits(DStream, dt[val].nbBits);
return dt[val].length;
}
-static U32 HUF_decodeLastSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog)
+static U32 HUF_decodeLastSymbolX4(void *op, BIT_DStream_t *DStream, const HUF_DEltX4 *dt, const U32 dtLog)
{
- size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
- memcpy(op, dt+val, 1);
- if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits);
+ size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */
+ memcpy(op, dt + val, 1);
+ if (dt[val].length == 1)
+ BIT_skipBits(DStream, dt[val].nbBits);
else {
- if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) {
+ if (DStream->bitsConsumed < (sizeof(DStream->bitContainer) * 8)) {
BIT_skipBits(DStream, dt[val].nbBits);
- if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8))
- DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
- } }
+ if (DStream->bitsConsumed > (sizeof(DStream->bitContainer) * 8))
+ /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */
+ DStream->bitsConsumed = (sizeof(DStream->bitContainer) * 8);
+ }
+ }
return 1;
}
+#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
-#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \
+#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
+ if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
-#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \
- if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
- ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
-
#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
- if (MEM_64bits()) \
- ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
+ if (ZSTD_64bits()) \
+ ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
-FORCE_INLINE size_t HUF_decodeStreamX4(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, const HUF_DEltX4* const dt, const U32 dtLog)
+FORCE_INLINE size_t HUF_decodeStreamX4(BYTE *p, BIT_DStream_t *bitDPtr, BYTE *const pEnd, const HUF_DEltX4 *const dt, const U32 dtLog)
{
- BYTE* const pStart = p;
+ BYTE *const pStart = p;
/* up to 8 symbols at a time */
- while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) {
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd - (sizeof(bitDPtr->bitContainer) - 1))) {
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
@@ -549,120 +640,133 @@ FORCE_INLINE size_t HUF_decodeStreamX4(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* co
}
/* closer to end : up to 2 symbols at a time */
- while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2))
+ while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd - 2))
HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
- while (p <= pEnd-2)
- HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
+ while (p <= pEnd - 2)
+ HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */
if (p < pEnd)
p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
- return p-pStart;
+ return p - pStart;
}
-
-static size_t HUF_decompress1X4_usingDTable_internal(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+static size_t HUF_decompress1X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
BIT_DStream_t bitD;
/* Init */
- { size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
- if (HUF_isError(errorCode)) return errorCode;
+ {
+ size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize);
+ if (HUF_isError(errorCode))
+ return errorCode;
}
/* decode */
- { BYTE* const ostart = (BYTE*) dst;
- BYTE* const oend = ostart + dstSize;
- const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */
- const HUF_DEltX4* const dt = (const HUF_DEltX4*)dtPtr;
+ {
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *const oend = ostart + dstSize;
+ const void *const dtPtr = DTable + 1; /* force compiler to not use strict-aliasing */
+ const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
DTableDesc const dtd = HUF_getDTableDesc(DTable);
HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
}
/* check */
- if (!BIT_endOfDStream(&bitD)) return ERROR(corruption_detected);
+ if (!BIT_endOfDStream(&bitD))
+ return ERROR(corruption_detected);
/* decoded size */
return dstSize;
}
-size_t HUF_decompress1X4_usingDTable(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+size_t HUF_decompress1X4_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (dtd.tableType != 1) return ERROR(GENERIC);
+ if (dtd.tableType != 1)
+ return ERROR(GENERIC);
return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
}
-size_t HUF_decompress1X4_DCtx (HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
{
- const BYTE* ip = (const BYTE*) cSrc;
+ const BYTE *ip = (const BYTE *)cSrc;
- size_t const hSize = HUF_readDTableX4 (DCtx, cSrc, cSrcSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
+ size_t const hSize = HUF_readDTableX4_wksp(DCtx, cSrc, cSrcSize, workspace, workspaceSize);
+ if (HUF_isError(hSize))
+ return hSize;
+ if (hSize >= cSrcSize)
+ return ERROR(srcSize_wrong);
+ ip += hSize;
+ cSrcSize -= hSize;
- return HUF_decompress1X4_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);
+ return HUF_decompress1X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx);
}
-static size_t HUF_decompress4X4_usingDTable_internal(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+static size_t HUF_decompress4X4_usingDTable_internal(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
- if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
+ if (cSrcSize < 10)
+ return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */
- { const BYTE* const istart = (const BYTE*) cSrc;
- BYTE* const ostart = (BYTE*) dst;
- BYTE* const oend = ostart + dstSize;
- const void* const dtPtr = DTable+1;
- const HUF_DEltX4* const dt = (const HUF_DEltX4*)dtPtr;
+ {
+ const BYTE *const istart = (const BYTE *)cSrc;
+ BYTE *const ostart = (BYTE *)dst;
+ BYTE *const oend = ostart + dstSize;
+ const void *const dtPtr = DTable + 1;
+ const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
/* Init */
BIT_DStream_t bitD1;
BIT_DStream_t bitD2;
BIT_DStream_t bitD3;
BIT_DStream_t bitD4;
- size_t const length1 = MEM_readLE16(istart);
- size_t const length2 = MEM_readLE16(istart+2);
- size_t const length3 = MEM_readLE16(istart+4);
+ size_t const length1 = ZSTD_readLE16(istart);
+ size_t const length2 = ZSTD_readLE16(istart + 2);
+ size_t const length3 = ZSTD_readLE16(istart + 4);
size_t const length4 = cSrcSize - (length1 + length2 + length3 + 6);
- const BYTE* const istart1 = istart + 6; /* jumpTable */
- const BYTE* const istart2 = istart1 + length1;
- const BYTE* const istart3 = istart2 + length2;
- const BYTE* const istart4 = istart3 + length3;
- size_t const segmentSize = (dstSize+3) / 4;
- BYTE* const opStart2 = ostart + segmentSize;
- BYTE* const opStart3 = opStart2 + segmentSize;
- BYTE* const opStart4 = opStart3 + segmentSize;
- BYTE* op1 = ostart;
- BYTE* op2 = opStart2;
- BYTE* op3 = opStart3;
- BYTE* op4 = opStart4;
+ const BYTE *const istart1 = istart + 6; /* jumpTable */
+ const BYTE *const istart2 = istart1 + length1;
+ const BYTE *const istart3 = istart2 + length2;
+ const BYTE *const istart4 = istart3 + length3;
+ size_t const segmentSize = (dstSize + 3) / 4;
+ BYTE *const opStart2 = ostart + segmentSize;
+ BYTE *const opStart3 = opStart2 + segmentSize;
+ BYTE *const opStart4 = opStart3 + segmentSize;
+ BYTE *op1 = ostart;
+ BYTE *op2 = opStart2;
+ BYTE *op3 = opStart3;
+ BYTE *op4 = opStart4;
U32 endSignal;
DTableDesc const dtd = HUF_getDTableDesc(DTable);
U32 const dtLog = dtd.tableLog;
- if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */
- { size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
- if (HUF_isError(errorCode)) return errorCode; }
- { size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
- if (HUF_isError(errorCode)) return errorCode; }
- { size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
- if (HUF_isError(errorCode)) return errorCode; }
- { size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
- if (HUF_isError(errorCode)) return errorCode; }
+ if (length4 > cSrcSize)
+ return ERROR(corruption_detected); /* overflow */
+ {
+ size_t const errorCode = BIT_initDStream(&bitD1, istart1, length1);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
+ {
+ size_t const errorCode = BIT_initDStream(&bitD2, istart2, length2);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
+ {
+ size_t const errorCode = BIT_initDStream(&bitD3, istart3, length3);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
+ {
+ size_t const errorCode = BIT_initDStream(&bitD4, istart4, length4);
+ if (HUF_isError(errorCode))
+ return errorCode;
+ }
/* 16-32 symbols per loop (4-8 symbols per stream) */
endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4);
- for ( ; (endSignal==BIT_DStream_unfinished) & (op4<(oend-(sizeof(bitD4.bitContainer)-1))) ; ) {
+ for (; (endSignal == BIT_DStream_unfinished) & (op4 < (oend - (sizeof(bitD4.bitContainer) - 1)));) {
HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
@@ -684,94 +788,95 @@ static size_t HUF_decompress4X4_usingDTable_internal(
}
/* check corruption */
- if (op1 > opStart2) return ERROR(corruption_detected);
- if (op2 > opStart3) return ERROR(corruption_detected);
- if (op3 > opStart4) return ERROR(corruption_detected);
+ if (op1 > opStart2)
+ return ERROR(corruption_detected);
+ if (op2 > opStart3)
+ return ERROR(corruption_detected);
+ if (op3 > opStart4)
+ return ERROR(corruption_detected);
/* note : op4 already verified within main loop */
/* finish bitStreams one by one */
HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
- HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
+ HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
/* check */
- { U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
- if (!endCheck) return ERROR(corruption_detected); }
+ {
+ U32 const endCheck = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4);
+ if (!endCheck)
+ return ERROR(corruption_detected);
+ }
/* decoded size */
return dstSize;
}
}
-
-size_t HUF_decompress4X4_usingDTable(
- void* dst, size_t dstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+size_t HUF_decompress4X4_usingDTable(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
DTableDesc dtd = HUF_getDTableDesc(DTable);
- if (dtd.tableType != 1) return ERROR(GENERIC);
+ if (dtd.tableType != 1)
+ return ERROR(GENERIC);
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable);
}
-
-size_t HUF_decompress4X4_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
{
- const BYTE* ip = (const BYTE*) cSrc;
+ const BYTE *ip = (const BYTE *)cSrc;
- size_t hSize = HUF_readDTableX4 (dctx, cSrc, cSrcSize);
- if (HUF_isError(hSize)) return hSize;
- if (hSize >= cSrcSize) return ERROR(srcSize_wrong);
- ip += hSize; cSrcSize -= hSize;
+ size_t hSize = HUF_readDTableX4_wksp(dctx, cSrc, cSrcSize, workspace, workspaceSize);
+ if (HUF_isError(hSize))
+ return hSize;
+ if (hSize >= cSrcSize)
+ return ERROR(srcSize_wrong);
+ ip += hSize;
+ cSrcSize -= hSize;
return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);
}
-
/* ********************************/
/* Generic decompression selector */
/* ********************************/
-size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
DTableDesc const dtd = HUF_getDTableDesc(DTable);
- return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) :
- HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
+ return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable)
+ : HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
}
-size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize,
- const void* cSrc, size_t cSrcSize,
- const HUF_DTable* DTable)
+size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
{
DTableDesc const dtd = HUF_getDTableDesc(DTable);
- return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable) :
- HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
+ return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable)
+ : HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable);
}
-
-typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t;
-static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] =
-{
- /* single, double, quad */
- {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */
- {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */
- {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */
- {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */
- {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */
- {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */
- {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */
- {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */
- {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */
- {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */
- {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */
- {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */
- {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */
- {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */
- {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */
- {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */
+typedef struct {
+ U32 tableTime;
+ U32 decode256Time;
+} algo_time_t;
+static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = {
+ /* single, double, quad */
+ {{0, 0}, {1, 1}, {2, 2}}, /* Q==0 : impossible */
+ {{0, 0}, {1, 1}, {2, 2}}, /* Q==1 : impossible */
+ {{38, 130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */
+ {{448, 128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */
+ {{556, 128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */
+ {{714, 128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */
+ {{883, 128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */
+ {{897, 128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */
+ {{926, 128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */
+ {{947, 128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */
+ {{1107, 128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */
+ {{1177, 128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */
+ {{1242, 128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */
+ {{1349, 128}, {2644, 106}, {5260, 106}}, /* Q ==13 : 81-87% */
+ {{1455, 128}, {2422, 124}, {4174, 124}}, /* Q ==14 : 87-93% */
+ {{722, 128}, {1891, 145}, {1936, 146}}, /* Q ==15 : 93-99% */
};
/** HUF_selectDecoder() :
@@ -779,57 +884,77 @@ static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, qu
* based on a set of pre-determined metrics.
* @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
* Assumption : 0 < cSrcSize < dstSize <= 128 KB */
-U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize)
+U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize)
{
/* decoder timing evaluation */
- U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */
+ U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize > cSrcSize */
U32 const D256 = (U32)(dstSize >> 8);
U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256);
U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256);
- DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, for cache eviction */
+ DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, for cache eviction */
return DTime1 < DTime0;
}
+typedef size_t (*decompressionAlgo)(void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize);
-typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
-
-size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
{
/* validation checks */
- if (dstSize == 0) return ERROR(dstSize_tooSmall);
- if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
- if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
- if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
+ if (dstSize == 0)
+ return ERROR(dstSize_tooSmall);
+ if (cSrcSize > dstSize)
+ return ERROR(corruption_detected); /* invalid */
+ if (cSrcSize == dstSize) {
+ memcpy(dst, cSrc, dstSize);
+ return dstSize;
+ } /* not compressed */
+ if (cSrcSize == 1) {
+ memset(dst, *(const BYTE *)cSrc, dstSize);
+ return dstSize;
+ } /* RLE */
- { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
- return algoNb ? HUF_decompress4X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
- HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
+ {
+ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+ return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
+ : HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
}
}
-size_t HUF_decompress4X_hufOnly (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
{
/* validation checks */
- if (dstSize == 0) return ERROR(dstSize_tooSmall);
- if ((cSrcSize >= dstSize) || (cSrcSize <= 1)) return ERROR(corruption_detected); /* invalid */
+ if (dstSize == 0)
+ return ERROR(dstSize_tooSmall);
+ if ((cSrcSize >= dstSize) || (cSrcSize <= 1))
+ return ERROR(corruption_detected); /* invalid */
- { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
- return algoNb ? HUF_decompress4X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
- HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
+ {
+ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+ return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
+ : HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
}
}
-size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)
+size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t workspaceSize)
{
/* validation checks */
- if (dstSize == 0) return ERROR(dstSize_tooSmall);
- if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */
- if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */
- if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */
+ if (dstSize == 0)
+ return ERROR(dstSize_tooSmall);
+ if (cSrcSize > dstSize)
+ return ERROR(corruption_detected); /* invalid */
+ if (cSrcSize == dstSize) {
+ memcpy(dst, cSrc, dstSize);
+ return dstSize;
+ } /* not compressed */
+ if (cSrcSize == 1) {
+ memset(dst, *(const BYTE *)cSrc, dstSize);
+ return dstSize;
+ } /* RLE */
- { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
- return algoNb ? HUF_decompress1X4_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) :
- HUF_decompress1X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;
+ {
+ U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
+ return algoNb ? HUF_decompress1X4_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize)
+ : HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workspace, workspaceSize);
}
}
diff --git a/contrib/linux-kernel/lib/zstd/mem.h b/contrib/linux-kernel/lib/zstd/mem.h
index 76cae04fa..3a0f34c87 100644
--- a/contrib/linux-kernel/lib/zstd/mem.h
+++ b/contrib/linux-kernel/lib/zstd/mem.h
@@ -3,8 +3,15 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
+ * LICENSE file in the root directory of https://github.com/facebook/zstd.
+ * An additional grant of patent rights can be found in the PATENTS file in the
+ * same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
*/
#ifndef MEM_H_MODULE
@@ -14,195 +21,130 @@
* Dependencies
******************************************/
#include
-#include /* size_t, ptrdiff_t */
-#include /* memcpy */
-
+#include /* memcpy */
+#include /* size_t, ptrdiff_t */
/*-****************************************
* Compiler specifics
******************************************/
-#define MEM_STATIC static __inline __attribute__((unused))
-
-/* code only tested on 32 and 64 bits systems */
-#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; }
-MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
-
+#define ZSTD_STATIC static __inline __attribute__((unused))
/*-**************************************************************
* Basic Types
*****************************************************************/
-typedef uint8_t BYTE;
-typedef uint16_t U16;
-typedef int16_t S16;
-typedef uint32_t U32;
-typedef int32_t S32;
-typedef uint64_t U64;
-typedef int64_t S64;
+typedef uint8_t BYTE;
+typedef uint16_t U16;
+typedef int16_t S16;
+typedef uint32_t U32;
+typedef int32_t S32;
+typedef uint64_t U64;
+typedef int64_t S64;
typedef ptrdiff_t iPtrDiff;
typedef uintptr_t uPtrDiff;
-
/*-**************************************************************
* Memory I/O
*****************************************************************/
-MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
-MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
+ZSTD_STATIC unsigned ZSTD_32bits(void) { return sizeof(size_t) == 4; }
+ZSTD_STATIC unsigned ZSTD_64bits(void) { return sizeof(size_t) == 8; }
#if defined(__LITTLE_ENDIAN)
-# define MEM_LITTLE_ENDIAN 1
+#define ZSTD_LITTLE_ENDIAN 1
#else
-# define MEM_LITTLE_ENDIAN 0
+#define ZSTD_LITTLE_ENDIAN 0
#endif
-MEM_STATIC unsigned MEM_isLittleEndian(void)
-{
- return MEM_LITTLE_ENDIAN;
-}
+ZSTD_STATIC unsigned ZSTD_isLittleEndian(void) { return ZSTD_LITTLE_ENDIAN; }
-MEM_STATIC U16 MEM_read16(const void* memPtr)
-{
- return get_unaligned((const U16*)memPtr);
-}
+ZSTD_STATIC U16 ZSTD_read16(const void *memPtr) { return get_unaligned((const U16 *)memPtr); }
-MEM_STATIC U32 MEM_read32(const void* memPtr)
-{
- return get_unaligned((const U32*)memPtr);
-}
+ZSTD_STATIC U32 ZSTD_read32(const void *memPtr) { return get_unaligned((const U32 *)memPtr); }
-MEM_STATIC U64 MEM_read64(const void* memPtr)
-{
- return get_unaligned((const U64*)memPtr);
-}
+ZSTD_STATIC U64 ZSTD_read64(const void *memPtr) { return get_unaligned((const U64 *)memPtr); }
-MEM_STATIC size_t MEM_readST(const void* memPtr)
-{
- return get_unaligned((const size_t*)memPtr);
-}
+ZSTD_STATIC size_t ZSTD_readST(const void *memPtr) { return get_unaligned((const size_t *)memPtr); }
-MEM_STATIC void MEM_write16(void* memPtr, U16 value)
-{
- put_unaligned(value, (U16*)memPtr);
-}
+ZSTD_STATIC void ZSTD_write16(void *memPtr, U16 value) { put_unaligned(value, (U16 *)memPtr); }
-MEM_STATIC void MEM_write32(void* memPtr, U32 value)
-{
- put_unaligned(value, (U32*)memPtr);
-}
+ZSTD_STATIC void ZSTD_write32(void *memPtr, U32 value) { put_unaligned(value, (U32 *)memPtr); }
-MEM_STATIC void MEM_write64(void* memPtr, U64 value)
-{
- put_unaligned(value, (U64*)memPtr);
-}
+ZSTD_STATIC void ZSTD_write64(void *memPtr, U64 value) { put_unaligned(value, (U64 *)memPtr); }
/*=== Little endian r/w ===*/
-MEM_STATIC U16 MEM_readLE16(const void* memPtr)
+ZSTD_STATIC U16 ZSTD_readLE16(const void *memPtr) { return get_unaligned_le16(memPtr); }
+
+ZSTD_STATIC void ZSTD_writeLE16(void *memPtr, U16 val) { put_unaligned_le16(val, memPtr); }
+
+ZSTD_STATIC U32 ZSTD_readLE24(const void *memPtr) { return ZSTD_readLE16(memPtr) + (((const BYTE *)memPtr)[2] << 16); }
+
+ZSTD_STATIC void ZSTD_writeLE24(void *memPtr, U32 val)
{
- return get_unaligned_le16(memPtr);
+ ZSTD_writeLE16(memPtr, (U16)val);
+ ((BYTE *)memPtr)[2] = (BYTE)(val >> 16);
}
-MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
-{
- put_unaligned_le16(val, memPtr);
-}
+ZSTD_STATIC U32 ZSTD_readLE32(const void *memPtr) { return get_unaligned_le32(memPtr); }
-MEM_STATIC U32 MEM_readLE24(const void* memPtr)
-{
- return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
-}
+ZSTD_STATIC void ZSTD_writeLE32(void *memPtr, U32 val32) { put_unaligned_le32(val32, memPtr); }
-MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
-{
- MEM_writeLE16(memPtr, (U16)val);
- ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
-}
+ZSTD_STATIC U64 ZSTD_readLE64(const void *memPtr) { return get_unaligned_le64(memPtr); }
-MEM_STATIC U32 MEM_readLE32(const void* memPtr)
-{
- return get_unaligned_le32(memPtr);
-}
+ZSTD_STATIC void ZSTD_writeLE64(void *memPtr, U64 val64) { put_unaligned_le64(val64, memPtr); }
-MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
+ZSTD_STATIC size_t ZSTD_readLEST(const void *memPtr)
{
- put_unaligned_le32(val32, memPtr);
-}
-
-MEM_STATIC U64 MEM_readLE64(const void* memPtr)
-{
- return get_unaligned_le64(memPtr);
-}
-
-MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
-{
- put_unaligned_le64(val64, memPtr);
-}
-
-MEM_STATIC size_t MEM_readLEST(const void* memPtr)
-{
- if (MEM_32bits())
- return (size_t)MEM_readLE32(memPtr);
+ if (ZSTD_32bits())
+ return (size_t)ZSTD_readLE32(memPtr);
else
- return (size_t)MEM_readLE64(memPtr);
+ return (size_t)ZSTD_readLE64(memPtr);
}
-MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
+ZSTD_STATIC void ZSTD_writeLEST(void *memPtr, size_t val)
{
- if (MEM_32bits())
- MEM_writeLE32(memPtr, (U32)val);
+ if (ZSTD_32bits())
+ ZSTD_writeLE32(memPtr, (U32)val);
else
- MEM_writeLE64(memPtr, (U64)val);
+ ZSTD_writeLE64(memPtr, (U64)val);
}
/*=== Big endian r/w ===*/
-MEM_STATIC U32 MEM_readBE32(const void* memPtr)
-{
- return get_unaligned_be32(memPtr);
-}
+ZSTD_STATIC U32 ZSTD_readBE32(const void *memPtr) { return get_unaligned_be32(memPtr); }
-MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
-{
- put_unaligned_be32(val32, memPtr);
-}
+ZSTD_STATIC void ZSTD_writeBE32(void *memPtr, U32 val32) { put_unaligned_be32(val32, memPtr); }
-MEM_STATIC U64 MEM_readBE64(const void* memPtr)
-{
- return get_unaligned_be64(memPtr);
-}
+ZSTD_STATIC U64 ZSTD_readBE64(const void *memPtr) { return get_unaligned_be64(memPtr); }
-MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
-{
- put_unaligned_be64(val64, memPtr);
-}
+ZSTD_STATIC void ZSTD_writeBE64(void *memPtr, U64 val64) { put_unaligned_be64(val64, memPtr); }
-MEM_STATIC size_t MEM_readBEST(const void* memPtr)
+ZSTD_STATIC size_t ZSTD_readBEST(const void *memPtr)
{
- if (MEM_32bits())
- return (size_t)MEM_readBE32(memPtr);
+ if (ZSTD_32bits())
+ return (size_t)ZSTD_readBE32(memPtr);
else
- return (size_t)MEM_readBE64(memPtr);
+ return (size_t)ZSTD_readBE64(memPtr);
}
-MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
+ZSTD_STATIC void ZSTD_writeBEST(void *memPtr, size_t val)
{
- if (MEM_32bits())
- MEM_writeBE32(memPtr, (U32)val);
+ if (ZSTD_32bits())
+ ZSTD_writeBE32(memPtr, (U32)val);
else
- MEM_writeBE64(memPtr, (U64)val);
+ ZSTD_writeBE64(memPtr, (U64)val);
}
-
/* function safe only for comparisons */
-MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length)
+ZSTD_STATIC U32 ZSTD_readMINMATCH(const void *memPtr, U32 length)
{
- switch (length)
- {
- default :
- case 4 : return MEM_read32(memPtr);
- case 3 : if (MEM_isLittleEndian())
- return MEM_read32(memPtr)<<8;
- else
- return MEM_read32(memPtr)>>8;
+ switch (length) {
+ default:
+ case 4: return ZSTD_read32(memPtr);
+ case 3:
+ if (ZSTD_isLittleEndian())
+ return ZSTD_read32(memPtr) << 8;
+ else
+ return ZSTD_read32(memPtr) >> 8;
}
}
diff --git a/contrib/linux-kernel/lib/zstd/xxhash.c b/contrib/linux-kernel/lib/zstd/xxhash.c
deleted file mode 100644
index 0d301ad86..000000000
--- a/contrib/linux-kernel/lib/zstd/xxhash.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
-* xxHash - Fast Hash algorithm
-* Copyright (C) 2012-2016, 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 homepage: http://www.xxhash.com
-* - xxHash source repository : https://github.com/Cyan4973/xxHash
-*/
-
-
-/* *************************************
-* Tuning parameters
-***************************************/
-/*!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,
- * to improve speed for Big-endian CPU.
- * This option has no impact on Little_Endian CPU.
- */
-#define XXH_FORCE_NATIVE_FORMAT 0
-
-/*!XXH_FORCE_ALIGN_CHECK :
- * This is a minor performance trick, only useful with lots of very small keys.
- * It means : check for aligned/unaligned input.
- * The check costs one initial branch per hash; set to 0 when the input data
- * is guaranteed to be aligned.
- */
-#define XXH_FORCE_ALIGN_CHECK 0
-
-
-/* *************************************
-* Includes & Memory related functions
-***************************************/
-/* Modify the local functions below should you wish to use some other memory routines */
-/* for memcpy() */
-#include
-static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
-
-#include "xxhash.h"
-#include "mem.h"
-
-
-/* *************************************
-* Compiler Specific Options
-***************************************/
-#include
-#define FORCE_INLINE static __always_inline
-
-
-/* ****************************************
-* Compiler-specific Functions and Macros
-******************************************/
-#define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
-#define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
-
-/* *************************************
-* Architecture Macros
-***************************************/
-typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
-
-/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
-#ifndef XXH_CPU_LITTLE_ENDIAN
-# define XXH_CPU_LITTLE_ENDIAN MEM_LITTLE_ENDIAN
-#endif
-
-
-/* ***************************
-* 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)
-{
- (void)endian;
- (void)align;
- return MEM_readLE32(ptr);
-}
-
-FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
-{
- return XXH_readLE32_align(ptr, endian, XXH_unaligned);
-}
-
-static U32 XXH_readBE32(const void* ptr)
-{
- return MEM_readBE32(ptr);
-}
-
-FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
-{
- (void)endian;
- (void)align;
- return MEM_readLE64(ptr);
-}
-
-FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
-{
- return XXH_readLE64_align(ptr, endian, XXH_unaligned);
-}
-
-static U64 XXH_readBE64(const void* ptr)
-{
- return MEM_readBE64(ptr);
-}
-
-
-/* *************************************
-* Macros
-***************************************/
-#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
-
-
-/* *************************************
-* Constants
-***************************************/
-static const U32 PRIME32_1 = 2654435761U;
-static const U32 PRIME32_2 = 2246822519U;
-static const U32 PRIME32_3 = 3266489917U;
-static const U32 PRIME32_4 = 668265263U;
-static const U32 PRIME32_5 = 374761393U;
-
-static const U64 PRIME64_1 = 11400714785074694791ULL;
-static const U64 PRIME64_2 = 14029467366897019727ULL;
-static const U64 PRIME64_3 = 1609587929392839161ULL;
-static const U64 PRIME64_4 = 9650029242287828579ULL;
-static const U64 PRIME64_5 = 2870177450012600261ULL;
-
-XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
-
-
-/* **************************
-* Utils
-****************************/
-XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
-{
- memcpy(dstState, srcState, sizeof(*dstState));
-}
-
-XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
-{
- memcpy(dstState, srcState, sizeof(*dstState));
-}
-
-
-/* ***************************
-* Simple Hash Functions
-*****************************/
-
-static U32 XXH32_round(U32 seed, U32 input)
-{
- seed += input * PRIME32_2;
- seed = XXH_rotl32(seed, 13);
- seed *= PRIME32_1;
- return seed;
-}
-
-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 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
- v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
- v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
- v4 = XXH32_round(v4, XXH_get32bits(p)); 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> 15;
- h32 *= PRIME32_2;
- h32 ^= h32 >> 13;
- h32 *= PRIME32_3;
- h32 ^= h32 >> 16;
-
- return h32;
-}
-
-
-XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
-{
-#if 0
- /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
- XXH32_CREATESTATE_STATIC(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 (XXH_FORCE_ALIGN_CHECK) {
- if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
- 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);
- } }
-
- 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
-}
-
-
-static U64 XXH64_round(U64 acc, U64 input)
-{
- acc += input * PRIME64_2;
- acc = XXH_rotl64(acc, 31);
- acc *= PRIME64_1;
- return acc;
-}
-
-static U64 XXH64_mergeRound(U64 acc, U64 val)
-{
- val = XXH64_round(0, val);
- acc ^= val;
- acc = acc * PRIME64_1 + PRIME64_4;
- return acc;
-}
-
-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* const 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 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
- v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
- v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
- v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
- } while (p<=limit);
-
- h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
- h64 = XXH64_mergeRound(h64, v1);
- h64 = XXH64_mergeRound(h64, v2);
- h64 = XXH64_mergeRound(h64, v3);
- h64 = XXH64_mergeRound(h64, v4);
-
- } else {
- h64 = seed + PRIME64_5;
- }
-
- h64 += (U64) len;
-
- while (p+8<=bEnd) {
- U64 const k1 = XXH64_round(0, XXH_get64bits(p));
- 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> 33;
- h64 *= PRIME64_2;
- h64 ^= h64 >> 29;
- h64 *= PRIME64_3;
- h64 ^= h64 >> 32;
-
- return h64;
-}
-
-
-XXH_PUBLIC_API 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_CREATESTATE_STATIC(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 (XXH_FORCE_ALIGN_CHECK) {
- 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);
- } }
-
- 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
-****************************************************/
-
-
-/*** Hash feed ***/
-
-XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
-{
- XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
- memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */
- state.v1 = seed + PRIME32_1 + PRIME32_2;
- state.v2 = seed + PRIME32_2;
- state.v3 = seed + 0;
- state.v4 = seed - PRIME32_1;
- memcpy(statePtr, &state, sizeof(state));
- return XXH_OK;
-}
-
-
-XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
-{
- XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
- memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */
- state.v1 = seed + PRIME64_1 + PRIME64_2;
- state.v2 = seed + PRIME64_2;
- state.v3 = seed + 0;
- state.v4 = seed - PRIME64_1;
- memcpy(statePtr, &state, sizeof(state));
- return XXH_OK;
-}
-
-
-FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
-{
- 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_32 += (unsigned)len;
- state->large_len |= (len>=16) | (state->total_len_32>=16);
-
- if (state->memsize + len < 16) { /* fill in tmp buffer */
- XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
- state->memsize += (unsigned)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 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
- state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
- state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
- state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); 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 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
- v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
- v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
- v4 = XXH32_round(v4, XXH_readLE32(p, endian)); 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, (size_t)(bEnd-p));
- state->memsize = (unsigned)(bEnd-p);
- }
-
- return XXH_OK;
-}
-
-XXH_PUBLIC_API 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, XXH_endianess endian)
-{
- const BYTE * p = (const BYTE*)state->mem32;
- const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
- U32 h32;
-
- if (state->large_len) {
- h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
- } else {
- h32 = state->v3 /* == seed */ + PRIME32_5;
- }
-
- h32 += state->total_len_32;
-
- while (p+4<=bEnd) {
- h32 += XXH_readLE32(p, endian) * PRIME32_3;
- h32 = XXH_rotl32(h32, 17) * PRIME32_4;
- p+=4;
- }
-
- while (p> 15;
- h32 *= PRIME32_2;
- h32 ^= h32 >> 13;
- h32 *= PRIME32_3;
- h32 ^= h32 >> 16;
-
- return h32;
-}
-
-
-XXH_PUBLIC_API unsigned int 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);
-}
-
-
-
-/* **** XXH64 **** */
-
-FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
-{
- 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) { /* tmp buffer is full */
- XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
- state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
- state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
- state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
- state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
- 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 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
- v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
- v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
- v4 = XXH64_round(v4, XXH_readLE64(p, endian)); 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, (size_t)(bEnd-p));
- state->memsize = (unsigned)(bEnd-p);
- }
-
- return XXH_OK;
-}
-
-XXH_PUBLIC_API 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, XXH_endianess endian)
-{
- const BYTE * p = (const BYTE*)state->mem64;
- const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
- U64 h64;
-
- if (state->total_len >= 32) {
- U64 const v1 = state->v1;
- U64 const v2 = state->v2;
- U64 const v3 = state->v3;
- U64 const v4 = state->v4;
-
- h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
- h64 = XXH64_mergeRound(h64, v1);
- h64 = XXH64_mergeRound(h64, v2);
- h64 = XXH64_mergeRound(h64, v3);
- h64 = XXH64_mergeRound(h64, v4);
- } else {
- h64 = state->v3 + PRIME64_5;
- }
-
- h64 += (U64) state->total_len;
-
- while (p+8<=bEnd) {
- U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
- 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> 33;
- h64 *= PRIME64_2;
- h64 ^= h64 >> 29;
- h64 *= PRIME64_3;
- h64 ^= h64 >> 32;
-
- return h64;
-}
-
-
-XXH_PUBLIC_API 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);
-}
-
-
-/* **************************
-* Canonical representation
-****************************/
-
-/*! Default XXH result types are basic unsigned 32 and 64 bits.
-* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
-* These functions allow transformation of hash result into and from its canonical format.
-* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
-*/
-
-XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
-{
- XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
- MEM_writeBE32(dst, hash);
-}
-
-XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
-{
- XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
- MEM_writeBE64(dst, hash);
-}
-
-XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
-{
- return XXH_readBE32(src);
-}
-
-XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
-{
- return XXH_readBE64(src);
-}
diff --git a/contrib/linux-kernel/lib/zstd/xxhash.h b/contrib/linux-kernel/lib/zstd/xxhash.h
deleted file mode 100644
index 974a81c48..000000000
--- a/contrib/linux-kernel/lib/zstd/xxhash.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- xxHash - Extremely Fast Hash algorithm
- Header File
- Copyright (C) 2012-2016, 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 : https://github.com/Cyan4973/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.
-
-A 64-bits version, named XXH64, is available since r35.
-It offers much better speed, but for 64-bits applications only.
-Name Speed on 64 bits Speed on 32 bits
-XXH64 13.8 GB/s 1.9 GB/s
-XXH32 6.8 GB/s 6.0 GB/s
-*/
-
-#ifndef XXHASH_H_5627135585666179
-#define XXHASH_H_5627135585666179 1
-
-
-/* ****************************
-* Definitions
-******************************/
-#include /* size_t */
-typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
-
-
-/* ****************************
-* API modifier
-******************************/
-/** XXH_PRIVATE_API
-* This is useful if you want to include xxhash functions in `static` mode
-* in order to inline them, and remove their symbol from the public list.
-* Methodology :
-* #define XXH_PRIVATE_API
-* #include "xxhash.h"
-* `xxhash.c` is automatically included.
-* It's not useful to compile and link it as a separate module anymore.
-*/
-#define XXH_PUBLIC_API /* do nothing */
-
-/*!XXH_NAMESPACE, aka Namespace Emulation :
-
-If you want to include _and expose_ xxHash functions from within your own library,
-but also want to avoid symbol collisions with another library which also includes xxHash,
-
-you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
-with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values).
-
-Note that no change is required within the calling program as long as it includes `xxhash.h` :
-regular symbol name will be automatically translated by this header.
-*/
-
-
-/* *************************************
-* Version
-***************************************/
-#define XXH_VERSION_MAJOR 0
-#define XXH_VERSION_MINOR 6
-#define XXH_VERSION_RELEASE 2
-#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
-XXH_PUBLIC_API unsigned XXH_versionNumber (void);
-
-
-/* ****************************
-* Simple Hash Functions
-******************************/
-typedef unsigned int XXH32_hash_t;
-typedef unsigned long long XXH64_hash_t;
-
-XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
-XXH_PUBLIC_API XXH64_hash_t 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.
- 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".
- "seed" can be used to alter the result predictably.
- This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
-*/
-
-
-/* ****************************
-* Streaming Hash Functions
-******************************/
-typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
-typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
-
-
-/* hash streaming */
-
-XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
-XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
-XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
-
-XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
-XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
-XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
-
-/*
-These functions generate the xxHash of an input provided in multiple segments.
-Note that, for small input, they are slower than single-call functions, due to state management.
-For small input, prefer `XXH32()` and `XXH64()` .
-
-XXH state must first be allocated, using XXH*_createState() .
-
-Start a new hash by initializing state with a seed, using XXH*_reset().
-
-Then, feed the hash state by calling XXH*_update() as many times as necessary.
-Obviously, input must be allocated and read accessible.
-The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
-
-Finally, a hash value can be produced anytime, by using XXH*_digest().
-This function returns the nn-bits hash as an int or long long.
-
-It's still possible to continue inserting input into the hash state after a digest,
-and generate some new hashes later on, by calling again XXH*_digest().
-
-When done, free XXH state space if it was allocated dynamically.
-*/
-
-
-/* **************************
-* Utils
-****************************/
-XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
-XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
-
-
-/* **************************
-* Canonical representation
-****************************/
-/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
-* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
-* These functions allow transformation of hash result into and from its canonical format.
-* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
-*/
-typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
-typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
-
-XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
-XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
-
-XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
-XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
-
-
-/* ================================================================================================
- This section contains definitions which are not guaranteed to remain stable.
- They may change in future versions, becoming incompatible with a different version of the library.
- They shall only be used with static linking.
- Never use these definitions in association with dynamic linking !
-=================================================================================================== */
-/* These definitions are only meant to allow allocation of XXH state
- statically, on stack, or in a struct for example.
- Do not use members directly. */
-
-struct XXH32_state_s {
- unsigned total_len_32;
- unsigned large_len;
- unsigned v1;
- unsigned v2;
- unsigned v3;
- unsigned v4;
- unsigned mem32[4]; /* buffer defined as U32 for alignment */
- unsigned memsize;
- unsigned reserved; /* never read nor write, will be removed in a future version */
-}; /* typedef'd to XXH32_state_t */
-
-struct XXH64_state_s {
- unsigned long long total_len;
- unsigned long long v1;
- unsigned long long v2;
- unsigned long long v3;
- unsigned long long v4;
- unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
- unsigned memsize;
- unsigned reserved[2]; /* never read nor write, will be removed in a future version */
-}; /* typedef'd to XXH64_state_t */
-
-#endif /* XXHASH_H_5627135585666179 */
diff --git a/contrib/linux-kernel/lib/zstd/zstd_common.c b/contrib/linux-kernel/lib/zstd/zstd_common.c
index 106f54055..a282624ee 100644
--- a/contrib/linux-kernel/lib/zstd/zstd_common.c
+++ b/contrib/linux-kernel/lib/zstd/zstd_common.c
@@ -3,33 +3,39 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
+ * LICENSE file in the root directory of https://github.com/facebook/zstd.
+ * An additional grant of patent rights can be found in the PATENTS file in the
+ * same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
*/
-
-
/*-*************************************
* Dependencies
***************************************/
#include "error_private.h"
-#include "zstd_internal.h" /* declaration of ZSTD_isError, ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber */
+#include "zstd_internal.h" /* declaration of ZSTD_isError, ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber */
#include
-
/*=**************************************************************
* Custom allocator
****************************************************************/
-#define stack_push(stack, size) ({ \
- void* const ptr = ZSTD_PTR_ALIGN((stack)->ptr); \
- (stack)->ptr = (char*)ptr + (size); \
- (stack)->ptr <= (stack)->end ? ptr : NULL; \
+#define stack_push(stack, size) \
+ ({ \
+ void *const ptr = ZSTD_PTR_ALIGN((stack)->ptr); \
+ (stack)->ptr = (char *)ptr + (size); \
+ (stack)->ptr <= (stack)->end ? ptr : NULL; \
})
-ZSTD_customMem ZSTD_initStack(void* workspace, size_t workspaceSize) {
- ZSTD_customMem stackMem = { ZSTD_stackAlloc, ZSTD_stackFree, workspace };
- ZSTD_stack* stack = (ZSTD_stack*) workspace;
+ZSTD_customMem ZSTD_initStack(void *workspace, size_t workspaceSize)
+{
+ ZSTD_customMem stackMem = {ZSTD_stackAlloc, ZSTD_stackFree, workspace};
+ ZSTD_stack *stack = (ZSTD_stack *)workspace;
/* Verify preconditions */
if (!workspace || workspaceSize < sizeof(ZSTD_stack) || workspace != ZSTD_PTR_ALIGN(workspace)) {
ZSTD_customMem error = {NULL, NULL, NULL};
@@ -37,33 +43,33 @@ ZSTD_customMem ZSTD_initStack(void* workspace, size_t workspaceSize) {
}
/* Initialize the stack */
stack->ptr = workspace;
- stack->end = (char*)workspace + workspaceSize;
+ stack->end = (char *)workspace + workspaceSize;
stack_push(stack, sizeof(ZSTD_stack));
return stackMem;
}
-void* ZSTD_stackAllocAll(void* opaque, size_t* size) {
- ZSTD_stack* stack = (ZSTD_stack*)opaque;
- *size = stack->end - ZSTD_PTR_ALIGN(stack->ptr);
+void *ZSTD_stackAllocAll(void *opaque, size_t *size)
+{
+ ZSTD_stack *stack = (ZSTD_stack *)opaque;
+ *size = (BYTE const *)stack->end - (BYTE *)ZSTD_PTR_ALIGN(stack->ptr);
return stack_push(stack, *size);
}
-void* ZSTD_stackAlloc(void* opaque, size_t size) {
- ZSTD_stack* stack = (ZSTD_stack*)opaque;
+void *ZSTD_stackAlloc(void *opaque, size_t size)
+{
+ ZSTD_stack *stack = (ZSTD_stack *)opaque;
return stack_push(stack, size);
}
-void ZSTD_stackFree(void* opaque, void* address) {
+void ZSTD_stackFree(void *opaque, void *address)
+{
(void)opaque;
(void)address;
}
-void* ZSTD_malloc(size_t size, ZSTD_customMem customMem)
-{
- return customMem.customAlloc(customMem.opaque, size);
-}
+void *ZSTD_malloc(size_t size, ZSTD_customMem customMem) { return customMem.customAlloc(customMem.opaque, size); }
-void ZSTD_free(void* ptr, ZSTD_customMem customMem)
+void ZSTD_free(void *ptr, ZSTD_customMem customMem)
{
- if (ptr!=NULL)
+ if (ptr != NULL)
customMem.customFree(customMem.opaque, ptr);
}
diff --git a/contrib/linux-kernel/lib/zstd/zstd_internal.h b/contrib/linux-kernel/lib/zstd/zstd_internal.h
index 479d6827d..67487199e 100644
--- a/contrib/linux-kernel/lib/zstd/zstd_internal.h
+++ b/contrib/linux-kernel/lib/zstd/zstd_internal.h
@@ -3,8 +3,15 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
+ * LICENSE file in the root directory of https://github.com/facebook/zstd.
+ * An additional grant of patent rights can be found in the PATENTS file in the
+ * same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
*/
#ifndef ZSTD_CCOMMON_H_MODULE
@@ -16,60 +23,71 @@
#define FORCE_INLINE static __always_inline
#define FORCE_NOINLINE static noinline
-
/*-*************************************
* Dependencies
***************************************/
+#include "error_private.h"
+#include "mem.h"
#include
#include
+#include
#include
-#include "mem.h"
-#include "error_private.h"
-#include "xxhash.h" /* XXH_reset, update, digest */
-
/*-*************************************
* shared macros
***************************************/
-#define MIN(a,b) ((a)<(b) ? (a) : (b))
-#define MAX(a,b) ((a)>(b) ? (a) : (b))
-#define CHECK_F(f) { size_t const errcod = f; if (ERR_isError(errcod)) return errcod; } /* check and Forward error code */
-#define CHECK_E(f, e) { size_t const errcod = f; if (ERR_isError(errcod)) return ERROR(e); } /* check and send Error code */
-
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define CHECK_F(f) \
+ { \
+ size_t const errcod = f; \
+ if (ERR_isError(errcod)) \
+ return errcod; \
+ } /* check and Forward error code */
+#define CHECK_E(f, e) \
+ { \
+ size_t const errcod = f; \
+ if (ERR_isError(errcod)) \
+ return ERROR(e); \
+ } /* check and send Error code */
+#define ZSTD_STATIC_ASSERT(c) \
+ { \
+ enum { ZSTD_static_assert = 1 / (int)(!!(c)) }; \
+ }
/*-*************************************
* Common constants
***************************************/
-#define ZSTD_OPT_NUM (1<<12)
-#define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */
+#define ZSTD_OPT_NUM (1 << 12)
+#define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */
-#define ZSTD_REP_NUM 3 /* number of repcodes */
-#define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */
-#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1)
+#define ZSTD_REP_NUM 3 /* number of repcodes */
+#define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */
+#define ZSTD_REP_MOVE (ZSTD_REP_NUM - 1)
#define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM)
-static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
+static const U32 repStartValue[ZSTD_REP_NUM] = {1, 4, 8};
-#define KB *(1 <<10)
-#define MB *(1 <<20)
-#define GB *(1U<<30)
+#define KB *(1 << 10)
+#define MB *(1 << 20)
+#define GB *(1U << 30)
#define BIT7 128
-#define BIT6 64
-#define BIT5 32
-#define BIT4 16
-#define BIT1 2
-#define BIT0 1
+#define BIT6 64
+#define BIT5 32
+#define BIT4 16
+#define BIT1 2
+#define BIT0 1
#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
-static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
-static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
+static const size_t ZSTD_fcs_fieldSize[4] = {0, 2, 4, 8};
+static const size_t ZSTD_did_fieldSize[4] = {0, 1, 2, 4};
-#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
+#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
-#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
-#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
+#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
+#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
#define HufLog 12
typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
@@ -79,72 +97,66 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy
#define MINMATCH 3
#define EQUAL_READ32 4
-#define Litbits 8
-#define MaxLit ((1<= 3) /* GCC Intrinsic */
- return 31 - __builtin_clz(val);
-# else /* Software version */
- static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
- U32 v = val;
- int r;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
- return r;
-# endif
-}
-
+ZSTD_STATIC U32 ZSTD_highbit32(U32 val) { return 31 - __builtin_clz(val); }
/* hidden functions */
@@ -261,14 +257,13 @@ MEM_STATIC U32 ZSTD_highbit32(U32 val)
* ensures next compression will not use repcodes from previous block.
* Note : only works with regular variant;
* do not use with extDict variant ! */
-void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx);
+void ZSTD_invalidateRepCodes(ZSTD_CCtx *cctx);
-size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx);
-size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
-size_t ZSTD_freeCDict(ZSTD_CDict* cdict);
-size_t ZSTD_freeDDict(ZSTD_DDict* cdict);
-size_t ZSTD_freeCStream(ZSTD_CStream* zcs);
-size_t ZSTD_freeDStream(ZSTD_DStream* zds);
+size_t ZSTD_freeCCtx(ZSTD_CCtx *cctx);
+size_t ZSTD_freeDCtx(ZSTD_DCtx *dctx);
+size_t ZSTD_freeCDict(ZSTD_CDict *cdict);
+size_t ZSTD_freeDDict(ZSTD_DDict *cdict);
+size_t ZSTD_freeCStream(ZSTD_CStream *zcs);
+size_t ZSTD_freeDStream(ZSTD_DStream *zds);
-
-#endif /* ZSTD_CCOMMON_H_MODULE */
+#endif /* ZSTD_CCOMMON_H_MODULE */
diff --git a/contrib/linux-kernel/lib/zstd/zstd_opt.h b/contrib/linux-kernel/lib/zstd/zstd_opt.h
index 297a71559..55e1b4cba 100644
--- a/contrib/linux-kernel/lib/zstd/zstd_opt.h
+++ b/contrib/linux-kernel/lib/zstd/zstd_opt.h
@@ -3,36 +3,39 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
+ * LICENSE file in the root directory of https://github.com/facebook/zstd.
+ * An additional grant of patent rights can be found in the PATENTS file in the
+ * same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
*/
-
/* Note : this file is intended to be included within zstd_compress.c */
-
#ifndef ZSTD_OPT_H_91842398743
#define ZSTD_OPT_H_91842398743
-
-#define ZSTD_LITFREQ_ADD 2
-#define ZSTD_FREQ_DIV 4
-#define ZSTD_MAX_PRICE (1<<30)
+#define ZSTD_LITFREQ_ADD 2
+#define ZSTD_FREQ_DIV 4
+#define ZSTD_MAX_PRICE (1 << 30)
/*-*************************************
* Price functions for optimal parser
***************************************/
-FORCE_INLINE void ZSTD_setLog2Prices(seqStore_t* ssPtr)
+FORCE_INLINE void ZSTD_setLog2Prices(seqStore_t *ssPtr)
{
- ssPtr->log2matchLengthSum = ZSTD_highbit32(ssPtr->matchLengthSum+1);
- ssPtr->log2litLengthSum = ZSTD_highbit32(ssPtr->litLengthSum+1);
- ssPtr->log2litSum = ZSTD_highbit32(ssPtr->litSum+1);
- ssPtr->log2offCodeSum = ZSTD_highbit32(ssPtr->offCodeSum+1);
- ssPtr->factor = 1 + ((ssPtr->litSum>>5) / ssPtr->litLengthSum) + ((ssPtr->litSum<<1) / (ssPtr->litSum + ssPtr->matchSum));
+ ssPtr->log2matchLengthSum = ZSTD_highbit32(ssPtr->matchLengthSum + 1);
+ ssPtr->log2litLengthSum = ZSTD_highbit32(ssPtr->litLengthSum + 1);
+ ssPtr->log2litSum = ZSTD_highbit32(ssPtr->litSum + 1);
+ ssPtr->log2offCodeSum = ZSTD_highbit32(ssPtr->offCodeSum + 1);
+ ssPtr->factor = 1 + ((ssPtr->litSum >> 5) / ssPtr->litLengthSum) + ((ssPtr->litSum << 1) / (ssPtr->litSum + ssPtr->matchSum));
}
-
-MEM_STATIC void ZSTD_rescaleFreqs(seqStore_t* ssPtr, const BYTE* src, size_t srcSize)
+ZSTD_STATIC void ZSTD_rescaleFreqs(seqStore_t *ssPtr, const BYTE *src, size_t srcSize)
{
unsigned u;
@@ -41,28 +44,29 @@ MEM_STATIC void ZSTD_rescaleFreqs(seqStore_t* ssPtr, const BYTE* src, size_t src
ssPtr->staticPrices = 0;
if (ssPtr->litLengthSum == 0) {
- if (srcSize <= 1024) ssPtr->staticPrices = 1;
+ if (srcSize <= 1024)
+ ssPtr->staticPrices = 1;
- for (u=0; u<=MaxLit; u++)
+ for (u = 0; u <= MaxLit; u++)
ssPtr->litFreq[u] = 0;
- for (u=0; ulitFreq[src[u]]++;
ssPtr->litSum = 0;
- ssPtr->litLengthSum = MaxLL+1;
- ssPtr->matchLengthSum = MaxML+1;
- ssPtr->offCodeSum = (MaxOff+1);
- ssPtr->matchSum = (ZSTD_LITFREQ_ADD<litLengthSum = MaxLL + 1;
+ ssPtr->matchLengthSum = MaxML + 1;
+ ssPtr->offCodeSum = (MaxOff + 1);
+ ssPtr->matchSum = (ZSTD_LITFREQ_ADD << Litbits);
- for (u=0; u<=MaxLit; u++) {
- ssPtr->litFreq[u] = 1 + (ssPtr->litFreq[u]>>ZSTD_FREQ_DIV);
+ for (u = 0; u <= MaxLit; u++) {
+ ssPtr->litFreq[u] = 1 + (ssPtr->litFreq[u] >> ZSTD_FREQ_DIV);
ssPtr->litSum += ssPtr->litFreq[u];
}
- for (u=0; u<=MaxLL; u++)
+ for (u = 0; u <= MaxLL; u++)
ssPtr->litLengthFreq[u] = 1;
- for (u=0; u<=MaxML; u++)
+ for (u = 0; u <= MaxML; u++)
ssPtr->matchLengthFreq[u] = 1;
- for (u=0; u<=MaxOff; u++)
+ for (u = 0; u <= MaxOff; u++)
ssPtr->offCodeFreq[u] = 1;
} else {
ssPtr->matchLengthSum = 0;
@@ -71,22 +75,22 @@ MEM_STATIC void ZSTD_rescaleFreqs(seqStore_t* ssPtr, const BYTE* src, size_t src
ssPtr->matchSum = 0;
ssPtr->litSum = 0;
- for (u=0; u<=MaxLit; u++) {
- ssPtr->litFreq[u] = 1 + (ssPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1));
+ for (u = 0; u <= MaxLit; u++) {
+ ssPtr->litFreq[u] = 1 + (ssPtr->litFreq[u] >> (ZSTD_FREQ_DIV + 1));
ssPtr->litSum += ssPtr->litFreq[u];
}
- for (u=0; u<=MaxLL; u++) {
- ssPtr->litLengthFreq[u] = 1 + (ssPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
+ for (u = 0; u <= MaxLL; u++) {
+ ssPtr->litLengthFreq[u] = 1 + (ssPtr->litLengthFreq[u] >> (ZSTD_FREQ_DIV + 1));
ssPtr->litLengthSum += ssPtr->litLengthFreq[u];
}
- for (u=0; u<=MaxML; u++) {
- ssPtr->matchLengthFreq[u] = 1 + (ssPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
+ for (u = 0; u <= MaxML; u++) {
+ ssPtr->matchLengthFreq[u] = 1 + (ssPtr->matchLengthFreq[u] >> ZSTD_FREQ_DIV);
ssPtr->matchLengthSum += ssPtr->matchLengthFreq[u];
ssPtr->matchSum += ssPtr->matchLengthFreq[u] * (u + 3);
}
ssPtr->matchSum *= ZSTD_LITFREQ_ADD;
- for (u=0; u<=MaxOff; u++) {
- ssPtr->offCodeFreq[u] = 1 + (ssPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
+ for (u = 0; u <= MaxOff; u++) {
+ ssPtr->offCodeFreq[u] = 1 + (ssPtr->offCodeFreq[u] >> ZSTD_FREQ_DIV);
ssPtr->offCodeSum += ssPtr->offCodeFreq[u];
}
}
@@ -94,30 +98,29 @@ MEM_STATIC void ZSTD_rescaleFreqs(seqStore_t* ssPtr, const BYTE* src, size_t src
ZSTD_setLog2Prices(ssPtr);
}
-
-FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t* ssPtr, U32 litLength, const BYTE* literals)
+FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t *ssPtr, U32 litLength, const BYTE *literals)
{
U32 price, u;
if (ssPtr->staticPrices)
- return ZSTD_highbit32((U32)litLength+1) + (litLength*6);
+ return ZSTD_highbit32((U32)litLength + 1) + (litLength * 6);
if (litLength == 0)
- return ssPtr->log2litLengthSum - ZSTD_highbit32(ssPtr->litLengthFreq[0]+1);
+ return ssPtr->log2litLengthSum - ZSTD_highbit32(ssPtr->litLengthFreq[0] + 1);
/* literals */
if (ssPtr->cachedLiterals == literals) {
U32 const additional = litLength - ssPtr->cachedLitLength;
- const BYTE* literals2 = ssPtr->cachedLiterals + ssPtr->cachedLitLength;
+ const BYTE *literals2 = ssPtr->cachedLiterals + ssPtr->cachedLitLength;
price = ssPtr->cachedPrice + additional * ssPtr->log2litSum;
- for (u=0; u < additional; u++)
- price -= ZSTD_highbit32(ssPtr->litFreq[literals2[u]]+1);
+ for (u = 0; u < additional; u++)
+ price -= ZSTD_highbit32(ssPtr->litFreq[literals2[u]] + 1);
ssPtr->cachedPrice = price;
ssPtr->cachedLitLength = litLength;
} else {
price = litLength * ssPtr->log2litSum;
- for (u=0; u < litLength; u++)
- price -= ZSTD_highbit32(ssPtr->litFreq[literals[u]]+1);
+ for (u = 0; u < litLength; u++)
+ price -= ZSTD_highbit32(ssPtr->litFreq[literals[u]] + 1);
if (litLength >= 12) {
ssPtr->cachedLiterals = literals;
@@ -127,62 +130,66 @@ FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t* ssPtr, U32 litLength, const BY
}
/* literal Length */
- { const BYTE LL_deltaCode = 19;
- const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
- price += LL_bits[llCode] + ssPtr->log2litLengthSum - ZSTD_highbit32(ssPtr->litLengthFreq[llCode]+1);
+ {
+ const BYTE LL_deltaCode = 19;
+ const BYTE llCode = (litLength > 63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
+ price += LL_bits[llCode] + ssPtr->log2litLengthSum - ZSTD_highbit32(ssPtr->litLengthFreq[llCode] + 1);
}
return price;
}
-
-FORCE_INLINE U32 ZSTD_getPrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra)
+FORCE_INLINE U32 ZSTD_getPrice(seqStore_t *seqStorePtr, U32 litLength, const BYTE *literals, U32 offset, U32 matchLength, const int ultra)
{
/* offset */
U32 price;
- BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
+ BYTE const offCode = (BYTE)ZSTD_highbit32(offset + 1);
if (seqStorePtr->staticPrices)
- return ZSTD_getLiteralPrice(seqStorePtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode;
+ return ZSTD_getLiteralPrice(seqStorePtr, litLength, literals) + ZSTD_highbit32((U32)matchLength + 1) + 16 + offCode;
- price = offCode + seqStorePtr->log2offCodeSum - ZSTD_highbit32(seqStorePtr->offCodeFreq[offCode]+1);
- if (!ultra && offCode >= 20) price += (offCode-19)*2;
+ price = offCode + seqStorePtr->log2offCodeSum - ZSTD_highbit32(seqStorePtr->offCodeFreq[offCode] + 1);
+ if (!ultra && offCode >= 20)
+ price += (offCode - 19) * 2;
/* match Length */
- { const BYTE ML_deltaCode = 36;
- const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
- price += ML_bits[mlCode] + seqStorePtr->log2matchLengthSum - ZSTD_highbit32(seqStorePtr->matchLengthFreq[mlCode]+1);
+ {
+ const BYTE ML_deltaCode = 36;
+ const BYTE mlCode = (matchLength > 127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
+ price += ML_bits[mlCode] + seqStorePtr->log2matchLengthSum - ZSTD_highbit32(seqStorePtr->matchLengthFreq[mlCode] + 1);
}
return price + ZSTD_getLiteralPrice(seqStorePtr, litLength, literals) + seqStorePtr->factor;
}
-
-MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength)
+ZSTD_STATIC void ZSTD_updatePrice(seqStore_t *seqStorePtr, U32 litLength, const BYTE *literals, U32 offset, U32 matchLength)
{
U32 u;
/* literals */
- seqStorePtr->litSum += litLength*ZSTD_LITFREQ_ADD;
- for (u=0; u < litLength; u++)
+ seqStorePtr->litSum += litLength * ZSTD_LITFREQ_ADD;
+ for (u = 0; u < litLength; u++)
seqStorePtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
/* literal Length */
- { const BYTE LL_deltaCode = 19;
- const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
+ {
+ const BYTE LL_deltaCode = 19;
+ const BYTE llCode = (litLength > 63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
seqStorePtr->litLengthFreq[llCode]++;
seqStorePtr->litLengthSum++;
}
/* match offset */
- { BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
+ {
+ BYTE const offCode = (BYTE)ZSTD_highbit32(offset + 1);
seqStorePtr->offCodeSum++;
seqStorePtr->offCodeFreq[offCode]++;
}
/* match Length */
- { const BYTE ML_deltaCode = 36;
- const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
+ {
+ const BYTE ML_deltaCode = 36;
+ const BYTE mlCode = (matchLength > 127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
seqStorePtr->matchLengthFreq[mlCode]++;
seqStorePtr->matchLengthSum++;
}
@@ -190,241 +197,243 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B
ZSTD_setLog2Prices(seqStorePtr);
}
-
-#define SET_PRICE(pos, mlen_, offset_, litlen_, price_) \
- { \
- while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \
- opt[pos].mlen = mlen_; \
- opt[pos].off = offset_; \
- opt[pos].litlen = litlen_; \
- opt[pos].price = price_; \
+#define SET_PRICE(pos, mlen_, offset_, litlen_, price_) \
+ { \
+ while (last_pos < pos) { \
+ opt[last_pos + 1].price = ZSTD_MAX_PRICE; \
+ last_pos++; \
+ } \
+ opt[pos].mlen = mlen_; \
+ opt[pos].off = offset_; \
+ opt[pos].litlen = litlen_; \
+ opt[pos].price = price_; \
}
-
-
/* Update hashTable3 up to ip (excluded)
Assumption : always within prefix (i.e. not within extDict) */
FORCE_INLINE
-U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
+U32 ZSTD_insertAndFindFirstIndexHash3(ZSTD_CCtx *zc, const BYTE *ip)
{
- U32* const hashTable3 = zc->hashTable3;
- U32 const hashLog3 = zc->hashLog3;
- const BYTE* const base = zc->base;
+ U32 *const hashTable3 = zc->hashTable3;
+ U32 const hashLog3 = zc->hashLog3;
+ const BYTE *const base = zc->base;
U32 idx = zc->nextToUpdate3;
const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
- while(idx < target) {
- hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
+ while (idx < target) {
+ hashTable3[ZSTD_hash3Ptr(base + idx, hashLog3)] = idx;
idx++;
}
return hashTable3[hash3];
}
-
/*-*************************************
* Binary Tree search
***************************************/
-static U32 ZSTD_insertBtAndGetAllMatches (
- ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iLimit,
- U32 nbCompares, const U32 mls,
- U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen)
+static U32 ZSTD_insertBtAndGetAllMatches(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, U32 nbCompares, const U32 mls, U32 extDict,
+ ZSTD_match_t *matches, const U32 minMatchLen)
{
- const BYTE* const base = zc->base;
- const U32 current = (U32)(ip-base);
+ const BYTE *const base = zc->base;
+ const U32 curr = (U32)(ip - base);
const U32 hashLog = zc->params.cParams.hashLog;
- const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
- U32* const hashTable = zc->hashTable;
- U32 matchIndex = hashTable[h];
- U32* const bt = zc->chainTable;
+ const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
+ U32 *const hashTable = zc->hashTable;
+ U32 matchIndex = hashTable[h];
+ U32 *const bt = zc->chainTable;
const U32 btLog = zc->params.cParams.chainLog - 1;
- const U32 btMask= (1U << btLog) - 1;
- size_t commonLengthSmaller=0, commonLengthLarger=0;
- const BYTE* const dictBase = zc->dictBase;
+ const U32 btMask = (1U << btLog) - 1;
+ size_t commonLengthSmaller = 0, commonLengthLarger = 0;
+ const BYTE *const dictBase = zc->dictBase;
const U32 dictLimit = zc->dictLimit;
- const BYTE* const dictEnd = dictBase + dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const U32 btLow = btMask >= current ? 0 : current - btMask;
+ const BYTE *const dictEnd = dictBase + dictLimit;
+ const BYTE *const prefixStart = base + dictLimit;
+ const U32 btLow = btMask >= curr ? 0 : curr - btMask;
const U32 windowLow = zc->lowLimit;
- U32* smallerPtr = bt + 2*(current&btMask);
- U32* largerPtr = bt + 2*(current&btMask) + 1;
- U32 matchEndIdx = current+8;
- U32 dummy32; /* to be nullified at the end */
+ U32 *smallerPtr = bt + 2 * (curr & btMask);
+ U32 *largerPtr = bt + 2 * (curr & btMask) + 1;
+ U32 matchEndIdx = curr + 8;
+ U32 dummy32; /* to be nullified at the end */
U32 mnum = 0;
const U32 minMatch = (mls == 3) ? 3 : 4;
- size_t bestLength = minMatchLen-1;
+ size_t bestLength = minMatchLen - 1;
if (minMatch == 3) { /* HC3 match finder */
- U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
- if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) {
- const BYTE* match;
- size_t currentMl=0;
+ U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(zc, ip);
+ if (matchIndex3 > windowLow && (curr - matchIndex3 < (1 << 18))) {
+ const BYTE *match;
+ size_t currMl = 0;
if ((!extDict) || matchIndex3 >= dictLimit) {
match = base + matchIndex3;
- if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);
+ if (match[bestLength] == ip[bestLength])
+ currMl = ZSTD_count(ip, match, iLimit);
} else {
match = dictBase + matchIndex3;
- if (MEM_readMINMATCH(match, MINMATCH) == MEM_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
- currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
+ if (ZSTD_readMINMATCH(match, MINMATCH) ==
+ ZSTD_readMINMATCH(ip, MINMATCH)) /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
+ currMl = ZSTD_count_2segments(ip + MINMATCH, match + MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
}
/* save best solution */
- if (currentMl > bestLength) {
- bestLength = currentMl;
- matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;
- matches[mnum].len = (U32)currentMl;
+ if (currMl > bestLength) {
+ bestLength = currMl;
+ matches[mnum].off = ZSTD_REP_MOVE_OPT + curr - matchIndex3;
+ matches[mnum].len = (U32)currMl;
mnum++;
- if (currentMl > ZSTD_OPT_NUM) goto update;
- if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/
+ if (currMl > ZSTD_OPT_NUM)
+ goto update;
+ if (ip + currMl == iLimit)
+ goto update; /* best possible, and avoid read overflow*/
}
}
}
- hashTable[h] = current; /* Update Hash Table */
+ hashTable[h] = curr; /* Update Hash Table */
while (nbCompares-- && (matchIndex > windowLow)) {
- U32* nextPtr = bt + 2*(matchIndex & btMask);
- size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
- const BYTE* match;
+ U32 *nextPtr = bt + 2 * (matchIndex & btMask);
+ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
+ const BYTE *match;
- if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
+ if ((!extDict) || (matchIndex + matchLength >= dictLimit)) {
match = base + matchIndex;
if (match[matchLength] == ip[matchLength]) {
- matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1;
+ matchLength += ZSTD_count(ip + matchLength + 1, match + matchLength + 1, iLimit) + 1;
}
} else {
match = dictBase + matchIndex;
- matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
- if (matchIndex+matchLength >= dictLimit)
- match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
+ matchLength += ZSTD_count_2segments(ip + matchLength, match + matchLength, iLimit, dictEnd, prefixStart);
+ if (matchIndex + matchLength >= dictLimit)
+ match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
}
if (matchLength > bestLength) {
- if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength;
+ if (matchLength > matchEndIdx - matchIndex)
+ matchEndIdx = matchIndex + (U32)matchLength;
bestLength = matchLength;
- matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex;
+ matches[mnum].off = ZSTD_REP_MOVE_OPT + curr - matchIndex;
matches[mnum].len = (U32)matchLength;
mnum++;
- if (matchLength > ZSTD_OPT_NUM) break;
- if (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */
- break; /* drop, to guarantee consistency (miss a little bit of compression) */
+ if (matchLength > ZSTD_OPT_NUM)
+ break;
+ if (ip + matchLength == iLimit) /* equal : no way to know if inf or sup */
+ break; /* drop, to guarantee consistency (miss a little bit of compression) */
}
if (match[matchLength] < ip[matchLength]) {
- /* match is smaller than current */
- *smallerPtr = matchIndex; /* update smaller idx */
- commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
- if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
- smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
- matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
+ /* match is smaller than curr */
+ *smallerPtr = matchIndex; /* update smaller idx */
+ commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
+ if (matchIndex <= btLow) {
+ smallerPtr = &dummy32;
+ break;
+ } /* beyond tree size, stop the search */
+ smallerPtr = nextPtr + 1; /* new "smaller" => larger of match */
+ matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to curr) */
} else {
- /* match is larger than current */
+ /* match is larger than curr */
*largerPtr = matchIndex;
commonLengthLarger = matchLength;
- if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
+ if (matchIndex <= btLow) {
+ largerPtr = &dummy32;
+ break;
+ } /* beyond tree size, stop the search */
largerPtr = nextPtr;
matchIndex = nextPtr[0];
- } }
+ }
+ }
*smallerPtr = *largerPtr = 0;
update:
- zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
+ zc->nextToUpdate = (matchEndIdx > curr + 8) ? matchEndIdx - 8 : curr + 1;
return mnum;
}
-
/** Tree updater, providing best match */
-static U32 ZSTD_BtGetAllMatches (
- ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iLimit,
- const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
+static U32 ZSTD_BtGetAllMatches(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, const U32 maxNbAttempts, const U32 mls, ZSTD_match_t *matches,
+ const U32 minMatchLen)
{
- if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
+ if (ip < zc->base + zc->nextToUpdate)
+ return 0; /* skipped area */
ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
}
-
-static U32 ZSTD_BtGetAllMatches_selectMLS (
- ZSTD_CCtx* zc, /* Index table will be updated */
- const BYTE* ip, const BYTE* const iHighLimit,
- const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
+static U32 ZSTD_BtGetAllMatches_selectMLS(ZSTD_CCtx *zc, /* Index table will be updated */
+ const BYTE *ip, const BYTE *const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch,
+ ZSTD_match_t *matches, const U32 minMatchLen)
{
- switch(matchLengthSearch)
- {
- case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
- default :
- case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
- case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
- case 7 :
- case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
+ switch (matchLengthSearch) {
+ case 3: return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
+ default:
+ case 4: return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
+ case 5: return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
+ case 7:
+ case 6: return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
}
}
/** Tree updater, providing best match */
-static U32 ZSTD_BtGetAllMatches_extDict (
- ZSTD_CCtx* zc,
- const BYTE* const ip, const BYTE* const iLimit,
- const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
+static U32 ZSTD_BtGetAllMatches_extDict(ZSTD_CCtx *zc, const BYTE *const ip, const BYTE *const iLimit, const U32 maxNbAttempts, const U32 mls,
+ ZSTD_match_t *matches, const U32 minMatchLen)
{
- if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
+ if (ip < zc->base + zc->nextToUpdate)
+ return 0; /* skipped area */
ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
}
-
-static U32 ZSTD_BtGetAllMatches_selectMLS_extDict (
- ZSTD_CCtx* zc, /* Index table will be updated */
- const BYTE* ip, const BYTE* const iHighLimit,
- const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
+static U32 ZSTD_BtGetAllMatches_selectMLS_extDict(ZSTD_CCtx *zc, /* Index table will be updated */
+ const BYTE *ip, const BYTE *const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch,
+ ZSTD_match_t *matches, const U32 minMatchLen)
{
- switch(matchLengthSearch)
- {
- case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
- default :
- case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
- case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
- case 7 :
- case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
+ switch (matchLengthSearch) {
+ case 3: return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
+ default:
+ case 4: return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
+ case 5: return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
+ case 7:
+ case 6: return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
}
}
-
/*-*******************************
* Optimal parser
*********************************/
FORCE_INLINE
-void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize, const int ultra)
+void ZSTD_compressBlock_opt_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const int ultra)
{
- seqStore_t* seqStorePtr = &(ctx->seqStore);
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ctx->base;
- const BYTE* const prefixStart = base + ctx->dictLimit;
+ seqStore_t *seqStorePtr = &(ctx->seqStore);
+ const BYTE *const istart = (const BYTE *)src;
+ const BYTE *ip = istart;
+ const BYTE *anchor = istart;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *const ilimit = iend - 8;
+ const BYTE *const base = ctx->base;
+ const BYTE *const prefixStart = base + ctx->dictLimit;
const U32 maxSearches = 1U << ctx->params.cParams.searchLog;
const U32 sufficient_len = ctx->params.cParams.targetLength;
const U32 mls = ctx->params.cParams.searchLength;
const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4;
- ZSTD_optimal_t* opt = seqStorePtr->priceTable;
- ZSTD_match_t* matches = seqStorePtr->matchTable;
- const BYTE* inr;
+ ZSTD_optimal_t *opt = seqStorePtr->priceTable;
+ ZSTD_match_t *matches = seqStorePtr->matchTable;
+ const BYTE *inr;
U32 offset, rep[ZSTD_REP_NUM];
/* init */
ctx->nextToUpdate3 = ctx->nextToUpdate;
- ZSTD_rescaleFreqs(seqStorePtr, (const BYTE*)src, srcSize);
- ip += (ip==prefixStart);
- { U32 i; for (i=0; irep[i]; }
+ ZSTD_rescaleFreqs(seqStorePtr, (const BYTE *)src, srcSize);
+ ip += (ip == prefixStart);
+ {
+ U32 i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ rep[i] = ctx->rep[i];
+ }
/* Match Loop */
while (ip < ilimit) {
@@ -435,32 +444,41 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
litlen = (U32)(ip - anchor);
/* check repCode */
- { U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
- for (i=(ip == anchor); i 0) && (repCur < (S32)(ip-prefixStart))
- && (MEM_readMINMATCH(ip, minMatch) == MEM_readMINMATCH(ip - repCur, minMatch))) {
- mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch;
+ {
+ U32 i, last_i = ZSTD_REP_CHECK + (ip == anchor);
+ for (i = (ip == anchor); i < last_i; i++) {
+ const S32 repCur = (i == ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
+ if ((repCur > 0) && (repCur < (S32)(ip - prefixStart)) &&
+ (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) {
+ mlen = (U32)ZSTD_count(ip + minMatch, ip + minMatch - repCur, iend) + minMatch;
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
- best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
+ best_mlen = mlen;
+ best_off = i;
+ cur = 0;
+ last_pos = 1;
goto _storeSequence;
}
best_off = i - (ip == anchor);
do {
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
if (mlen > last_pos || price < opt[mlen].price)
- SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
+ SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
mlen--;
} while (mlen >= minMatch);
- } } }
+ }
+ }
+ }
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
- if (!last_pos && !match_num) { ip++; continue; }
+ if (!last_pos && !match_num) {
+ ip++;
+ continue;
+ }
- if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
- best_mlen = matches[match_num-1].len;
- best_off = matches[match_num-1].off;
+ if (match_num && (matches[match_num - 1].len > sufficient_len || matches[match_num - 1].len >= ZSTD_OPT_NUM)) {
+ best_mlen = matches[match_num - 1].len;
+ best_off = matches[match_num - 1].off;
cur = 0;
last_pos = 1;
goto _storeSequence;
@@ -469,77 +487,92 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
/* set prices using matches at position = 0 */
best_mlen = (last_pos) ? last_pos : minMatch;
for (u = 0; u < match_num; u++) {
- mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
+ mlen = (u > 0) ? matches[u - 1].len + 1 : best_mlen;
best_mlen = matches[u].len;
while (mlen <= best_mlen) {
- price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
+ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
if (mlen > last_pos || price < opt[mlen].price)
- SET_PRICE(mlen, mlen, matches[u].off, litlen, price); /* note : macro modifies last_pos */
+ SET_PRICE(mlen, mlen, matches[u].off, litlen, price); /* note : macro modifies last_pos */
mlen++;
- } }
+ }
+ }
- if (last_pos < minMatch) { ip++; continue; }
+ if (last_pos < minMatch) {
+ ip++;
+ continue;
+ }
/* initialize opt[0] */
- { U32 i ; for (i=0; i litlen) {
- price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen);
+ price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr - litlen);
} else
price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor);
- } else {
+ } else {
litlen = 1;
- price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1);
- }
+ price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr - 1);
+ }
- if (cur > last_pos || price <= opt[cur].price)
+ if (cur > last_pos || price <= opt[cur].price)
SET_PRICE(cur, 1, 0, litlen, price);
- if (cur == last_pos) break;
+ if (cur == last_pos)
+ break;
- if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
- continue;
+ if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
+ continue;
- mlen = opt[cur].mlen;
- if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
- opt[cur].rep[2] = opt[cur-mlen].rep[1];
- opt[cur].rep[1] = opt[cur-mlen].rep[0];
+ mlen = opt[cur].mlen;
+ if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
+ opt[cur].rep[2] = opt[cur - mlen].rep[1];
+ opt[cur].rep[1] = opt[cur - mlen].rep[0];
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
- } else {
- opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
- opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
- opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
- }
+ } else {
+ opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur - mlen].rep[1] : opt[cur - mlen].rep[2];
+ opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur - mlen].rep[0] : opt[cur - mlen].rep[1];
+ opt[cur].rep[0] =
+ ((opt[cur].off == ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur - mlen].rep[0] - 1) : (opt[cur - mlen].rep[opt[cur].off]);
+ }
best_mlen = minMatch;
- { U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
- for (i=(opt[cur].mlen != 1); i 0) && (repCur < (S32)(inr-prefixStart))
- && (MEM_readMINMATCH(inr, minMatch) == MEM_readMINMATCH(inr - repCur, minMatch))) {
- mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch;
+ {
+ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
+ for (i = (opt[cur].mlen != 1); i < last_i; i++) { /* check rep */
+ const S32 repCur = (i == ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
+ if ((repCur > 0) && (repCur < (S32)(inr - prefixStart)) &&
+ (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) {
+ mlen = (U32)ZSTD_count(inr + minMatch, inr + minMatch - repCur, iend) + minMatch;
- if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
- best_mlen = mlen; best_off = i; last_pos = cur + 1;
+ if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
+ best_mlen = mlen;
+ best_off = i;
+ last_pos = cur + 1;
goto _storeSequence;
- }
+ }
- best_off = i - (opt[cur].mlen != 1);
- if (mlen > best_mlen) best_mlen = mlen;
+ best_off = i - (opt[cur].mlen != 1);
+ if (mlen > best_mlen)
+ best_mlen = mlen;
- do {
- if (opt[cur].mlen == 1) {
+ do {
+ if (opt[cur].mlen == 1) {
litlen = opt[cur].litlen;
if (cur > litlen) {
- price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
+ price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr - litlen,
+ best_off, mlen - MINMATCH, ultra);
} else
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
} else {
@@ -551,46 +584,51 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
SET_PRICE(cur + mlen, mlen, i, litlen, price);
mlen--;
} while (mlen >= minMatch);
- } } }
+ }
+ }
+ }
match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
- if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
- best_mlen = matches[match_num-1].len;
- best_off = matches[match_num-1].off;
+ if (match_num > 0 && (matches[match_num - 1].len > sufficient_len || cur + matches[match_num - 1].len >= ZSTD_OPT_NUM)) {
+ best_mlen = matches[match_num - 1].len;
+ best_off = matches[match_num - 1].off;
last_pos = cur + 1;
goto _storeSequence;
}
/* set prices using matches at position = cur */
for (u = 0; u < match_num; u++) {
- mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
+ mlen = (u > 0) ? matches[u - 1].len + 1 : best_mlen;
best_mlen = matches[u].len;
while (mlen <= best_mlen) {
if (opt[cur].mlen == 1) {
litlen = opt[cur].litlen;
if (cur > litlen)
- price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
+ price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip + cur - litlen,
+ matches[u].off - 1, mlen - MINMATCH, ultra);
else
- price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
+ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
} else {
litlen = 0;
- price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
+ price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off - 1, mlen - MINMATCH, ultra);
}
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
mlen++;
- } } }
+ }
+ }
+ }
best_mlen = opt[last_pos].mlen;
best_off = opt[last_pos].off;
cur = last_pos - best_mlen;
- /* store sequence */
-_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
+ /* store sequence */
+_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
opt[0].mlen = 1;
while (1) {
@@ -600,7 +638,8 @@ _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
opt[cur].off = best_off;
best_mlen = mlen;
best_off = offset;
- if (mlen > cur) break;
+ if (mlen > cur)
+ break;
cur -= mlen;
}
@@ -608,9 +647,13 @@ _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
u += opt[u].mlen;
}
- for (cur=0; cur < last_pos; ) {
+ for (cur = 0; cur < last_pos;) {
mlen = opt[cur].mlen;
- if (mlen == 1) { ip++; cur++; continue; }
+ if (mlen == 1) {
+ ip++;
+ cur++;
+ continue;
+ }
offset = opt[cur].off;
cur += mlen;
litLength = (U32)(ip - anchor);
@@ -622,112 +665,135 @@ _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
offset--;
} else {
if (offset != 0) {
- best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
- if (offset != 1) rep[2] = rep[1];
+ best_off = (offset == ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
+ if (offset != 1)
+ rep[2] = rep[1];
rep[1] = rep[0];
rep[0] = best_off;
}
- if (litLength==0) offset--;
+ if (litLength == 0)
+ offset--;
}
- ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
- ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
+ ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen - MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen - MINMATCH);
anchor = ip = ip + mlen;
- } } /* for (cur=0; cur < last_pos; ) */
+ }
+ } /* for (cur=0; cur < last_pos; ) */
/* Save reps for next block */
- { int i; for (i=0; irepToConfirm[i] = rep[i]; }
+ {
+ int i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ ctx->repToConfirm[i] = rep[i];
+ }
/* Last Literals */
- { size_t const lastLLSize = iend - anchor;
+ {
+ size_t const lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
}
-
FORCE_INLINE
-void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
- const void* src, size_t srcSize, const int ultra)
+void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx *ctx, const void *src, size_t srcSize, const int ultra)
{
- seqStore_t* seqStorePtr = &(ctx->seqStore);
- const BYTE* const istart = (const BYTE*)src;
- const BYTE* ip = istart;
- const BYTE* anchor = istart;
- const BYTE* const iend = istart + srcSize;
- const BYTE* const ilimit = iend - 8;
- const BYTE* const base = ctx->base;
+ seqStore_t *seqStorePtr = &(ctx->seqStore);
+ const BYTE *const istart = (const BYTE *)src;
+ const BYTE *ip = istart;
+ const BYTE *anchor = istart;
+ const BYTE *const iend = istart + srcSize;
+ const BYTE *const ilimit = iend - 8;
+ const BYTE *const base = ctx->base;
const U32 lowestIndex = ctx->lowLimit;
const U32 dictLimit = ctx->dictLimit;
- const BYTE* const prefixStart = base + dictLimit;
- const BYTE* const dictBase = ctx->dictBase;
- const BYTE* const dictEnd = dictBase + dictLimit;
+ const BYTE *const prefixStart = base + dictLimit;
+ const BYTE *const dictBase = ctx->dictBase;
+ const BYTE *const dictEnd = dictBase + dictLimit;
const U32 maxSearches = 1U << ctx->params.cParams.searchLog;
const U32 sufficient_len = ctx->params.cParams.targetLength;
const U32 mls = ctx->params.cParams.searchLength;
const U32 minMatch = (ctx->params.cParams.searchLength == 3) ? 3 : 4;
- ZSTD_optimal_t* opt = seqStorePtr->priceTable;
- ZSTD_match_t* matches = seqStorePtr->matchTable;
- const BYTE* inr;
+ ZSTD_optimal_t *opt = seqStorePtr->priceTable;
+ ZSTD_match_t *matches = seqStorePtr->matchTable;
+ const BYTE *inr;
/* init */
U32 offset, rep[ZSTD_REP_NUM];
- { U32 i; for (i=0; irep[i]; }
+ {
+ U32 i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ rep[i] = ctx->rep[i];
+ }
ctx->nextToUpdate3 = ctx->nextToUpdate;
- ZSTD_rescaleFreqs(seqStorePtr, (const BYTE*)src, srcSize);
- ip += (ip==prefixStart);
+ ZSTD_rescaleFreqs(seqStorePtr, (const BYTE *)src, srcSize);
+ ip += (ip == prefixStart);
/* Match Loop */
while (ip < ilimit) {
U32 cur, match_num, last_pos, litlen, price;
U32 u, mlen, best_mlen, best_off, litLength;
- U32 current = (U32)(ip-base);
+ U32 curr = (U32)(ip - base);
memset(opt, 0, sizeof(ZSTD_optimal_t));
last_pos = 0;
opt[0].litlen = (U32)(ip - anchor);
/* check repCode */
- { U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
- for (i = (ip==anchor); i 0 && repCur <= (S32)current)
- && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
- && (MEM_readMINMATCH(ip, minMatch) == MEM_readMINMATCH(repMatch, minMatch)) ) {
+ {
+ U32 i, last_i = ZSTD_REP_CHECK + (ip == anchor);
+ for (i = (ip == anchor); i < last_i; i++) {
+ const S32 repCur = (i == ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
+ const U32 repIndex = (U32)(curr - repCur);
+ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE *const repMatch = repBase + repIndex;
+ if ((repCur > 0 && repCur <= (S32)curr) &&
+ (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch))) {
/* repcode detected we should take it */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
+ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ mlen = (U32)ZSTD_count_2segments(ip + minMatch, repMatch + minMatch, iend, repEnd, prefixStart) + minMatch;
if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
- best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
+ best_mlen = mlen;
+ best_off = i;
+ cur = 0;
+ last_pos = 1;
goto _storeSequence;
}
- best_off = i - (ip==anchor);
+ best_off = i - (ip == anchor);
litlen = opt[0].litlen;
do {
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
if (mlen > last_pos || price < opt[mlen].price)
- SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
+ SET_PRICE(mlen, mlen, i, litlen, price); /* note : macro modifies last_pos */
mlen--;
} while (mlen >= minMatch);
- } } }
+ }
+ }
+ }
- match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch); /* first search (depth 0) */
+ match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch); /* first search (depth 0) */
- if (!last_pos && !match_num) { ip++; continue; }
+ if (!last_pos && !match_num) {
+ ip++;
+ continue;
+ }
- { U32 i; for (i=0; i sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
- best_mlen = matches[match_num-1].len;
- best_off = matches[match_num-1].off;
+ if (match_num && (matches[match_num - 1].len > sufficient_len || matches[match_num - 1].len >= ZSTD_OPT_NUM)) {
+ best_mlen = matches[match_num - 1].len;
+ best_off = matches[match_num - 1].off;
cur = 0;
last_pos = 1;
goto _storeSequence;
@@ -737,81 +803,90 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
/* set prices using matches at position = 0 */
for (u = 0; u < match_num; u++) {
- mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
+ mlen = (u > 0) ? matches[u - 1].len + 1 : best_mlen;
best_mlen = matches[u].len;
litlen = opt[0].litlen;
while (mlen <= best_mlen) {
- price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
+ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
if (mlen > last_pos || price < opt[mlen].price)
SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
mlen++;
- } }
+ }
+ }
if (last_pos < minMatch) {
- ip++; continue;
+ ip++;
+ continue;
}
/* check further positions */
for (cur = 1; cur <= last_pos; cur++) {
inr = ip + cur;
- if (opt[cur-1].mlen == 1) {
- litlen = opt[cur-1].litlen + 1;
+ if (opt[cur - 1].mlen == 1) {
+ litlen = opt[cur - 1].litlen + 1;
if (cur > litlen) {
- price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen);
+ price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr - litlen);
} else
price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor);
} else {
litlen = 1;
- price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1);
+ price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr - 1);
}
if (cur > last_pos || price <= opt[cur].price)
SET_PRICE(cur, 1, 0, litlen, price);
- if (cur == last_pos) break;
+ if (cur == last_pos)
+ break;
- if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
+ if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */
continue;
mlen = opt[cur].mlen;
if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
- opt[cur].rep[2] = opt[cur-mlen].rep[1];
- opt[cur].rep[1] = opt[cur-mlen].rep[0];
+ opt[cur].rep[2] = opt[cur - mlen].rep[1];
+ opt[cur].rep[1] = opt[cur - mlen].rep[0];
opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
} else {
- opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
- opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
- opt[cur].rep[0] = ((opt[cur].off==ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
+ opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur - mlen].rep[1] : opt[cur - mlen].rep[2];
+ opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur - mlen].rep[0] : opt[cur - mlen].rep[1];
+ opt[cur].rep[0] =
+ ((opt[cur].off == ZSTD_REP_MOVE_OPT) && (mlen != 1)) ? (opt[cur - mlen].rep[0] - 1) : (opt[cur - mlen].rep[opt[cur].off]);
}
best_mlen = minMatch;
- { U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
- for (i = (mlen != 1); i 0 && repCur <= (S32)(current+cur))
- && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex)) /* intentional overflow */
- && (MEM_readMINMATCH(inr, minMatch) == MEM_readMINMATCH(repMatch, minMatch)) ) {
+ {
+ U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
+ for (i = (mlen != 1); i < last_i; i++) {
+ const S32 repCur = (i == ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
+ const U32 repIndex = (U32)(curr + cur - repCur);
+ const BYTE *const repBase = repIndex < dictLimit ? dictBase : base;
+ const BYTE *const repMatch = repBase + repIndex;
+ if ((repCur > 0 && repCur <= (S32)(curr + cur)) &&
+ (((U32)((dictLimit - 1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
+ && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch))) {
/* repcode detected */
- const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
- mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
+ const BYTE *const repEnd = repIndex < dictLimit ? dictEnd : iend;
+ mlen = (U32)ZSTD_count_2segments(inr + minMatch, repMatch + minMatch, iend, repEnd, prefixStart) + minMatch;
if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
- best_mlen = mlen; best_off = i; last_pos = cur + 1;
+ best_mlen = mlen;
+ best_off = i;
+ last_pos = cur + 1;
goto _storeSequence;
}
best_off = i - (opt[cur].mlen != 1);
- if (mlen > best_mlen) best_mlen = mlen;
+ if (mlen > best_mlen)
+ best_mlen = mlen;
do {
if (opt[cur].mlen == 1) {
litlen = opt[cur].litlen;
if (cur > litlen) {
- price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
+ price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr - litlen,
+ best_off, mlen - MINMATCH, ultra);
} else
price = ZSTD_getPrice(seqStorePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
} else {
@@ -823,46 +898,51 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
SET_PRICE(cur + mlen, mlen, i, litlen, price);
mlen--;
} while (mlen >= minMatch);
- } } }
+ }
+ }
+ }
match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
- if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
- best_mlen = matches[match_num-1].len;
- best_off = matches[match_num-1].off;
+ if (match_num > 0 && (matches[match_num - 1].len > sufficient_len || cur + matches[match_num - 1].len >= ZSTD_OPT_NUM)) {
+ best_mlen = matches[match_num - 1].len;
+ best_off = matches[match_num - 1].off;
last_pos = cur + 1;
goto _storeSequence;
}
/* set prices using matches at position = cur */
for (u = 0; u < match_num; u++) {
- mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
+ mlen = (u > 0) ? matches[u - 1].len + 1 : best_mlen;
best_mlen = matches[u].len;
while (mlen <= best_mlen) {
if (opt[cur].mlen == 1) {
litlen = opt[cur].litlen;
if (cur > litlen)
- price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
+ price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip + cur - litlen,
+ matches[u].off - 1, mlen - MINMATCH, ultra);
else
- price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
+ price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off - 1, mlen - MINMATCH, ultra);
} else {
litlen = 0;
- price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
+ price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off - 1, mlen - MINMATCH, ultra);
}
if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
mlen++;
- } } } /* for (cur = 1; cur <= last_pos; cur++) */
+ }
+ }
+ } /* for (cur = 1; cur <= last_pos; cur++) */
best_mlen = opt[last_pos].mlen;
best_off = opt[last_pos].off;
cur = last_pos - best_mlen;
- /* store sequence */
-_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
+ /* store sequence */
+_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
opt[0].mlen = 1;
while (1) {
@@ -872,17 +952,22 @@ _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
opt[cur].off = best_off;
best_mlen = mlen;
best_off = offset;
- if (mlen > cur) break;
+ if (mlen > cur)
+ break;
cur -= mlen;
}
- for (u = 0; u <= last_pos; ) {
+ for (u = 0; u <= last_pos;) {
u += opt[u].mlen;
}
- for (cur=0; cur < last_pos; ) {
+ for (cur = 0; cur < last_pos;) {
mlen = opt[cur].mlen;
- if (mlen == 1) { ip++; cur++; continue; }
+ if (mlen == 1) {
+ ip++;
+ cur++;
+ continue;
+ }
offset = opt[cur].off;
cur += mlen;
litLength = (U32)(ip - anchor);
@@ -894,28 +979,36 @@ _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */
offset--;
} else {
if (offset != 0) {
- best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
- if (offset != 1) rep[2] = rep[1];
+ best_off = (offset == ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
+ if (offset != 1)
+ rep[2] = rep[1];
rep[1] = rep[0];
rep[0] = best_off;
}
- if (litLength==0) offset--;
+ if (litLength == 0)
+ offset--;
}
- ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
- ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
+ ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen - MINMATCH);
+ ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen - MINMATCH);
anchor = ip = ip + mlen;
- } } /* for (cur=0; cur < last_pos; ) */
+ }
+ } /* for (cur=0; cur < last_pos; ) */
/* Save reps for next block */
- { int i; for (i=0; irepToConfirm[i] = rep[i]; }
+ {
+ int i;
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ ctx->repToConfirm[i] = rep[i];
+ }
/* Last Literals */
- { size_t lastLLSize = iend - anchor;
+ {
+ size_t lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
}
-#endif /* ZSTD_OPT_H_91842398743 */
+#endif /* ZSTD_OPT_H_91842398743 */
diff --git a/contrib/linux-kernel/spaces_to_tabs.sh b/contrib/linux-kernel/spaces_to_tabs.sh
deleted file mode 100755
index ebde5fbaa..000000000
--- a/contrib/linux-kernel/spaces_to_tabs.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-set -e
-
-# Constants
-INCLUDE='include/'
-LIB='lib/'
-SPACES=' '
-TAB=$'\t'
-TMP="replacements.tmp"
-
-echo "Files: " $INCLUDE* $LIB*
-
-# Check files for existing tabs
-grep "$TAB" $INCLUDE* $LIB* && exit 1 || true
-# Replace the first tab on every line
-sed -i '' "s/^$SPACES/$TAB/" $INCLUDE* $LIB*
-
-# Execute once and then execute as long as replacements are happening
-more_work="yes"
-while [ ! -z "$more_work" ]
-do
- rm -f $TMP
- # Replaces $SPACES that directly follow a $TAB with a $TAB.
- # $TMP will be non-empty if any replacements took place.
- sed -i '' "s/$TAB$SPACES/$TAB$TAB/w $TMP" $INCLUDE* $LIB*
- more_work=$(cat "$TMP")
-done
-rm -f $TMP
diff --git a/contrib/linux-kernel/test/DecompressCrash.c b/contrib/linux-kernel/test/DecompressCrash.c
new file mode 100644
index 000000000..b5b673aad
--- /dev/null
+++ b/contrib/linux-kernel/test/DecompressCrash.c
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+/*
+ This program takes a file in input,
+ performs a zstd round-trip test (compression - decompress)
+ compares the result with original
+ and generates a crash (double free) on corruption detection.
+*/
+
+/*===========================================
+* Dependencies
+*==========================================*/
+#include /* size_t */
+#include /* malloc, free, exit */
+#include /* fprintf */
+#include
+
+/*===========================================
+* Macros
+*==========================================*/
+#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
+
+static ZSTD_DCtx *dctx = NULL;
+void *dws = NULL;
+static void* rBuff = NULL;
+static size_t buffSize = 0;
+
+static void crash(int errorCode){
+ /* abort if AFL/libfuzzer, exit otherwise */
+ #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */
+ abort();
+ #else
+ exit(errorCode);
+ #endif
+}
+
+static void decompressCheck(const void* srcBuff, size_t srcBuffSize)
+{
+ size_t const neededBuffSize = 20 * srcBuffSize;
+
+ /* Allocate all buffers and contexts if not already allocated */
+ if (neededBuffSize > buffSize) {
+ free(rBuff);
+ buffSize = 0;
+
+ rBuff = malloc(neededBuffSize);
+ if (!rBuff) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ buffSize = neededBuffSize;
+ }
+ if (!dctx) {
+ size_t const workspaceSize = ZSTD_DCtxWorkspaceBound();
+ dws = malloc(workspaceSize);
+ if (!dws) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ dctx = ZSTD_initDCtx(dws, workspaceSize);
+ if (!dctx) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ }
+ ZSTD_decompressDCtx(dctx, rBuff, buffSize, srcBuff, srcBuffSize);
+
+#ifndef SKIP_FREE
+ free(dws); dws = NULL; dctx = NULL;
+ free(rBuff); rBuff = NULL;
+ buffSize = 0;
+#endif
+}
+
+int LLVMFuzzerTestOneInput(const unsigned char *srcBuff, size_t srcBuffSize) {
+ decompressCheck(srcBuff, srcBuffSize);
+ return 0;
+}
diff --git a/contrib/linux-kernel/test/Makefile b/contrib/linux-kernel/test/Makefile
index 01e877b7e..8411462c9 100644
--- a/contrib/linux-kernel/test/Makefile
+++ b/contrib/linux-kernel/test/Makefile
@@ -1,20 +1,35 @@
-IFLAGS := -isystem include/ -I ../include/ -I ../lib/zstd/ -isystem googletest/googletest/include
+IFLAGS := -isystem include/ -I ../include/ -I ../lib/zstd/ -isystem googletest/googletest/include -isystem ../../../lib/common/
SOURCES := $(wildcard ../lib/zstd/*.c)
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
ARFLAGS := rcs
-CXXFLAGS += -std=c++11
-CFLAGS += -g -O0
+CXXFLAGS += -std=c++11 -g -O3 -Wcast-align
+CFLAGS += -g -O3 -Wframe-larger-than=400 -Wcast-align
CPPFLAGS += $(IFLAGS)
../lib/zstd/libzstd.a: $(OBJECTS)
$(AR) $(ARFLAGS) $@ $^
-UserlandTest: UserlandTest.cpp ../lib/zstd/libzstd.a
+DecompressCrash: DecompressCrash.o $(OBJECTS) libFuzzer.a
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
+
+RoundTripCrash: RoundTripCrash.o $(OBJECTS) ../lib/xxhash.o libFuzzer.a
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
+
+UserlandTest: UserlandTest.cpp ../lib/zstd/libzstd.a ../lib/xxhash.o
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ googletest/build/googlemock/gtest/libgtest.a googletest/build/googlemock/gtest/libgtest_main.a -o $@
+
+XXHashUserlandTest: XXHashUserlandTest.cpp ../lib/xxhash.o ../../../lib/common/xxhash.o
$(CXX) $(CXXFLAGS) $(CFLAGS) $(CPPFLAGS) $^ googletest/build/googlemock/gtest/libgtest.a googletest/build/googlemock/gtest/libgtest_main.a -o $@
+# Install libfuzzer
+libFuzzer.a:
+ @$(RM) -rf Fuzzer
+ @git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer
+ @./Fuzzer/build.sh
+
# Install googletest
.PHONY: googletest
googletest:
@@ -24,4 +39,5 @@ googletest:
@cd googletest/build && cmake .. && $(MAKE)
clean:
- $(RM) -f *.{o,a} ../lib/zstd/*.{o,a}
+ $(RM) -f *.{o,a} ../lib/zstd/*.{o,a} ../lib/*.o
+ $(RM) -f DecompressCrash RoundTripCrash UserlandTest XXHashUserlandTest
diff --git a/contrib/linux-kernel/test/RoundTripCrash.c b/contrib/linux-kernel/test/RoundTripCrash.c
new file mode 100644
index 000000000..44c67f3ab
--- /dev/null
+++ b/contrib/linux-kernel/test/RoundTripCrash.c
@@ -0,0 +1,162 @@
+/**
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+/*
+ This program takes a file in input,
+ performs a zstd round-trip test (compression - decompress)
+ compares the result with original
+ and generates a crash (double free) on corruption detection.
+*/
+
+/*===========================================
+* Dependencies
+*==========================================*/
+#include /* size_t */
+#include /* malloc, free, exit */
+#include /* fprintf */
+#include
+#include
+
+/*===========================================
+* Macros
+*==========================================*/
+#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
+
+static const int kMaxClevel = 22;
+
+static ZSTD_CCtx *cctx = NULL;
+void *cws = NULL;
+static ZSTD_DCtx *dctx = NULL;
+void *dws = NULL;
+static void* cBuff = NULL;
+static void* rBuff = NULL;
+static size_t buffSize = 0;
+
+
+/** roundTripTest() :
+* Compresses `srcBuff` into `compressedBuff`,
+* then decompresses `compressedBuff` into `resultBuff`.
+* Compression level used is derived from first content byte.
+* @return : result of decompression, which should be == `srcSize`
+* or an error code if either compression or decompression fails.
+* Note : `compressedBuffCapacity` should be `>= ZSTD_compressBound(srcSize)`
+* for compression to be guaranteed to work */
+static size_t roundTripTest(void* resultBuff, size_t resultBuffCapacity,
+ void* compressedBuff, size_t compressedBuffCapacity,
+ const void* srcBuff, size_t srcBuffSize)
+{
+ size_t const hashLength = MIN(128, srcBuffSize);
+ unsigned const h32 = xxh32(srcBuff, hashLength, 0);
+ int const cLevel = h32 % kMaxClevel;
+ ZSTD_parameters const params = ZSTD_getParams(cLevel, srcBuffSize, 0);
+ size_t const cSize = ZSTD_compressCCtx(cctx, compressedBuff, compressedBuffCapacity, srcBuff, srcBuffSize, params);
+ if (ZSTD_isError(cSize)) {
+ fprintf(stderr, "Compression error : %u \n", ZSTD_getErrorCode(cSize));
+ return cSize;
+ }
+ return ZSTD_decompressDCtx(dctx, resultBuff, resultBuffCapacity, compressedBuff, cSize);
+}
+
+
+static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize)
+{
+ const char* ip1 = (const char*)buff1;
+ const char* ip2 = (const char*)buff2;
+ size_t pos;
+
+ for (pos=0; pos buffSize) {
+ free(cBuff);
+ free(rBuff);
+ buffSize = 0;
+
+ cBuff = malloc(neededBuffSize);
+ rBuff = malloc(neededBuffSize);
+ if (!cBuff || !rBuff) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ buffSize = neededBuffSize;
+ }
+ if (!cctx) {
+ ZSTD_compressionParameters const params = ZSTD_getCParams(kMaxClevel, 0, 0);
+ size_t const workspaceSize = ZSTD_CCtxWorkspaceBound(params);
+ cws = malloc(workspaceSize);
+ if (!cws) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ cctx = ZSTD_initCCtx(cws, workspaceSize);
+ if (!cctx) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ }
+ if (!dctx) {
+ size_t const workspaceSize = ZSTD_DCtxWorkspaceBound();
+ dws = malloc(workspaceSize);
+ if (!dws) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ dctx = ZSTD_initDCtx(dws, workspaceSize);
+ if (!dctx) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ }
+
+ { size_t const result = roundTripTest(rBuff, buffSize, cBuff, buffSize, srcBuff, srcBuffSize);
+ if (ZSTD_isError(result)) {
+ fprintf(stderr, "roundTripTest error : %u \n", ZSTD_getErrorCode(result));
+ crash(1);
+ }
+ if (result != srcBuffSize) {
+ fprintf(stderr, "Incorrect regenerated size : %u != %u\n", (unsigned)result, (unsigned)srcBuffSize);
+ crash(1);
+ }
+ if (checkBuffers(srcBuff, rBuff, srcBuffSize) != srcBuffSize) {
+ fprintf(stderr, "Silent decoding corruption !!!");
+ crash(1);
+ }
+ }
+
+#ifndef SKIP_FREE
+ free(cws); cws = NULL; cctx = NULL;
+ free(dws); dws = NULL; dctx = NULL;
+ free(cBuff); cBuff = NULL;
+ free(rBuff); rBuff = NULL;
+ buffSize = 0;
+#endif
+}
+
+int LLVMFuzzerTestOneInput(const unsigned char *srcBuff, size_t srcBuffSize) {
+ roundTripCheck(srcBuff, srcBuffSize);
+ return 0;
+}
diff --git a/contrib/linux-kernel/test/UserlandTest.cpp b/contrib/linux-kernel/test/UserlandTest.cpp
index 73b30be4c..03058382f 100644
--- a/contrib/linux-kernel/test/UserlandTest.cpp
+++ b/contrib/linux-kernel/test/UserlandTest.cpp
@@ -280,9 +280,9 @@ TEST(Block, ContentSize) {
TEST(Block, CCtxLevelIncrease) {
std::string c;
- auto cctx = createCCtx(6);
+ auto cctx = createCCtx(22);
auto dctx = createDCtx();
- for (int level = 1; level <= 6; ++level) {
+ for (int level = 1; level <= 22; ++level) {
auto compressed = compress(*cctx, kData, level);
auto const decompressed = decompress(*dctx, compressed, kData.size());
EXPECT_EQ(kData, decompressed);
@@ -478,6 +478,17 @@ TEST(Stream, Flush) {
EXPECT_EQ(kData, decompressed);
}
+TEST(Stream, DStreamLevelIncrease) {
+ auto zds = createDStream();
+ for (int level = 1; level <= 22; ++level) {
+ auto zcs = createCStream(level);
+ auto compressed = compress(*zcs, kData);
+ ZSTD_resetDStream(zds.get());
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
#define TEST_SYMBOL(symbol) \
do { \
extern void *__##symbol; \
diff --git a/contrib/linux-kernel/test/XXHashUserlandTest.cpp b/contrib/linux-kernel/test/XXHashUserlandTest.cpp
new file mode 100644
index 000000000..f50401a2e
--- /dev/null
+++ b/contrib/linux-kernel/test/XXHashUserlandTest.cpp
@@ -0,0 +1,166 @@
+extern "C" {
+#include
+#include
+}
+#include
+#include
+#include
+#include
+#include
+#define XXH_STATIC_LINKING_ONLY
+#include
+
+using namespace std;
+
+namespace {
+const std::array kTestInputs = {
+ "",
+ "0",
+ "01234",
+ "0123456789abcde",
+ "0123456789abcdef",
+ "0123456789abcdef0",
+ "0123456789abcdef0123",
+ "0123456789abcdef0123456789abcde",
+ "0123456789abcdef0123456789abcdef",
+ "0123456789abcdef0123456789abcdef0",
+ "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+};
+
+bool testXXH32(const void *input, const size_t length, uint32_t seed) {
+ return XXH32(input, length, seed) == xxh32(input, length, seed);
+}
+
+bool testXXH64(const void *input, const size_t length, uint32_t seed) {
+ return XXH64(input, length, seed) == xxh64(input, length, seed);
+}
+
+class XXH32State {
+ struct xxh32_state kernelState;
+ XXH32_state_t state;
+
+public:
+ explicit XXH32State(const uint32_t seed) { reset(seed); }
+ XXH32State(XXH32State const& other) noexcept {
+ xxh32_copy_state(&kernelState, &other.kernelState);
+ XXH32_copyState(&state, &other.state);
+ }
+ XXH32State& operator=(XXH32State const& other) noexcept {
+ xxh32_copy_state(&kernelState, &other.kernelState);
+ XXH32_copyState(&state, &other.state);
+ return *this;
+ }
+
+ void reset(const uint32_t seed) {
+ xxh32_reset(&kernelState, seed);
+ EXPECT_EQ(0, XXH32_reset(&state, seed));
+ }
+
+ void update(const void *input, const size_t length) {
+ EXPECT_EQ(0, xxh32_update(&kernelState, input, length));
+ EXPECT_EQ(0, (int)XXH32_update(&state, input, length));
+ }
+
+ bool testDigest() const {
+ return xxh32_digest(&kernelState) == XXH32_digest(&state);
+ }
+};
+
+class XXH64State {
+ struct xxh64_state kernelState;
+ XXH64_state_t state;
+
+public:
+ explicit XXH64State(const uint64_t seed) { reset(seed); }
+ XXH64State(XXH64State const& other) noexcept {
+ xxh64_copy_state(&kernelState, &other.kernelState);
+ XXH64_copyState(&state, &other.state);
+ }
+ XXH64State& operator=(XXH64State const& other) noexcept {
+ xxh64_copy_state(&kernelState, &other.kernelState);
+ XXH64_copyState(&state, &other.state);
+ return *this;
+ }
+
+ void reset(const uint64_t seed) {
+ xxh64_reset(&kernelState, seed);
+ EXPECT_EQ(0, XXH64_reset(&state, seed));
+ }
+
+ void update(const void *input, const size_t length) {
+ EXPECT_EQ(0, xxh64_update(&kernelState, input, length));
+ EXPECT_EQ(0, (int)XXH64_update(&state, input, length));
+ }
+
+ bool testDigest() const {
+ return xxh64_digest(&kernelState) == XXH64_digest(&state);
+ }
+};
+}
+
+TEST(Simple, Null) {
+ EXPECT_TRUE(testXXH32(NULL, 0, 0));
+ EXPECT_TRUE(testXXH64(NULL, 0, 0));
+}
+
+TEST(Stream, Null) {
+ struct xxh32_state state32;
+ xxh32_reset(&state32, 0);
+ EXPECT_EQ(-EINVAL, xxh32_update(&state32, NULL, 0));
+
+ struct xxh64_state state64;
+ xxh64_reset(&state64, 0);
+ EXPECT_EQ(-EINVAL, xxh64_update(&state64, NULL, 0));
+}
+
+TEST(Simple, TestInputs) {
+ for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
+ for (auto const input : kTestInputs) {
+ EXPECT_TRUE(testXXH32(input.data(), input.size(), seed));
+ EXPECT_TRUE(testXXH64(input.data(), input.size(), (uint64_t)seed));
+ }
+ }
+}
+
+TEST(Stream, TestInputs) {
+ for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
+ for (auto const input : kTestInputs) {
+ XXH32State s32(seed);
+ XXH64State s64(seed);
+ s32.update(input.data(), input.size());
+ s64.update(input.data(), input.size());
+ EXPECT_TRUE(s32.testDigest());
+ EXPECT_TRUE(s64.testDigest());
+ }
+ }
+}
+
+TEST(Stream, MultipleTestInputs) {
+ for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
+ XXH32State s32(seed);
+ XXH64State s64(seed);
+ for (auto const input : kTestInputs) {
+ s32.update(input.data(), input.size());
+ s64.update(input.data(), input.size());
+ }
+ EXPECT_TRUE(s32.testDigest());
+ EXPECT_TRUE(s64.testDigest());
+ }
+}
+
+TEST(Stream, CopyState) {
+ for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
+ XXH32State s32(seed);
+ XXH64State s64(seed);
+ for (auto const input : kTestInputs) {
+ auto t32(s32);
+ t32.update(input.data(), input.size());
+ s32 = t32;
+ auto t64(s64);
+ t64.update(input.data(), input.size());
+ s64 = t64;
+ }
+ EXPECT_TRUE(s32.testDigest());
+ EXPECT_TRUE(s64.testDigest());
+ }
+}
diff --git a/contrib/linux-kernel/test/include/linux/errno.h b/contrib/linux-kernel/test/include/linux/errno.h
new file mode 100644
index 000000000..b9db08524
--- /dev/null
+++ b/contrib/linux-kernel/test/include/linux/errno.h
@@ -0,0 +1,6 @@
+#ifndef LINUX_ERRNO_H_
+#define LINUX_ERRNO_H_
+
+#define EINVAL 22
+
+#endif // LINUX_ERRNO_H_
diff --git a/contrib/linux-kernel/test/include/linux/kernel.h b/contrib/linux-kernel/test/include/linux/kernel.h
index b208e23ba..3ef2f7fe8 100644
--- a/contrib/linux-kernel/test/include/linux/kernel.h
+++ b/contrib/linux-kernel/test/include/linux/kernel.h
@@ -11,4 +11,6 @@
#define PTR_ALIGN(p, a) (typeof(p))ALIGN((unsigned long long)(p), (a))
+#define current Something that doesn't compile :)
+
#endif // LINUX_KERNEL_H_
diff --git a/contrib/linux-kernel/test/include/linux/math64.h b/contrib/linux-kernel/test/include/linux/math64.h
new file mode 100644
index 000000000..3d0ae72d5
--- /dev/null
+++ b/contrib/linux-kernel/test/include/linux/math64.h
@@ -0,0 +1,11 @@
+#ifndef LINUX_MATH64_H
+#define LINUX_MATH64_H
+
+#include
+
+static uint64_t div_u64(uint64_t n, uint32_t d)
+{
+ return n / d;
+}
+
+#endif
diff --git a/contrib/linux-kernel/xxhash_test.c b/contrib/linux-kernel/xxhash_test.c
new file mode 100644
index 000000000..5c1101b6f
--- /dev/null
+++ b/contrib/linux-kernel/xxhash_test.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ */
+
+/* DO_XXH should be 32 or 64 for xxh32 and xxh64 respectively */
+#define DO_XXH 0
+/* DO_CRC should be 0 or 1 */
+#define DO_CRC 0
+/* Buffer size */
+#define BUFFER_SIZE 4096
+
+#include
+#include
+#include
+#include
+
+#if DO_XXH
+#include
+#endif
+
+#if DO_CRC
+#include
+#endif
+
+/* Device name to pass to register_chrdev(). */
+#define DEVICE_NAME "xxhash_test"
+
+/* Dynamically allocated device major number */
+static int device_major;
+
+/*
+ * We reuse the same hash state, and thus can hash only one
+ * file at a time.
+ */
+static bool device_is_open;
+
+static uint64_t total_length;
+
+
+#if (DO_XXH == 32)
+
+#define xxh_state xxh32_state
+#define xxh_reset xxh32_reset
+#define xxh_update xxh32_update
+#define xxh_digest xxh32_digest
+#define XXH_FORMAT "XXH32 = 0x%x"
+
+#elif (DO_XXH == 64)
+
+#define xxh_state xxh64_state
+#define xxh_reset xxh64_reset
+#define xxh_update xxh64_update
+#define xxh_digest xxh64_digest
+#define XXH_FORMAT "XXH64 = 0x%llx"
+
+#elif DO_XXH
+
+#error "Invalid value of DO_XXH"
+
+#endif
+
+#if DO_XXH
+
+/* XXH state */
+static struct xxh_state state;
+
+#endif /* DO_XXH */
+
+#if DO_CRC
+
+static uint32_t crc;
+
+#endif /* DO_CRC */
+
+/*
+ * Input buffer used to put data coming from userspace.
+ */
+static uint8_t buffer_in[BUFFER_SIZE];
+
+static int xxhash_test_open(struct inode *i, struct file *f)
+{
+ if (device_is_open)
+ return -EBUSY;
+
+ device_is_open = true;
+
+ total_length = 0;
+#if DO_XXH
+ xxh_reset(&state, 0);
+#endif
+#if DO_CRC
+ crc = 0xFFFFFFFF;
+#endif
+
+ printk(KERN_INFO DEVICE_NAME ": opened\n");
+ return 0;
+}
+
+static int xxhash_test_release(struct inode *i, struct file *f)
+{
+ device_is_open = false;
+
+ printk(KERN_INFO DEVICE_NAME ": total_len = %llu\n", total_length);
+#if DO_XXH
+ printk(KERN_INFO DEVICE_NAME ": " XXH_FORMAT "\n", xxh_digest(&state));
+#endif
+#if DO_CRC
+ printk(KERN_INFO DEVICE_NAME ": CRC32 = 0x%08x\n", ~crc);
+#endif
+ printk(KERN_INFO DEVICE_NAME ": closed\n");
+ return 0;
+}
+
+/*
+ * Hash the data given to us from userspace.
+ */
+static ssize_t xxhash_test_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ size_t remaining = size;
+
+ while (remaining > 0) {
+#if DO_XXH
+ int ret;
+#endif
+ size_t const copy_size = min(remaining, sizeof(buffer_in));
+
+ if (copy_from_user(buffer_in, buf, copy_size))
+ return -EFAULT;
+ buf += copy_size;
+ remaining -= copy_size;
+ total_length += copy_size;
+#if DO_XXH
+ if ((ret = xxh_update(&state, buffer_in, copy_size))) {
+ printk(KERN_INFO DEVICE_NAME ": xxh failure.");
+ return ret;
+ }
+#endif
+#if DO_CRC
+ crc = crc32(crc, buffer_in, copy_size);
+#endif
+ }
+ return size;
+}
+/* register the character device. */
+static int __init xxhash_test_init(void)
+{
+ static const struct file_operations fileops = {
+ .owner = THIS_MODULE,
+ .open = &xxhash_test_open,
+ .release = &xxhash_test_release,
+ .write = &xxhash_test_write
+ };
+
+ device_major = register_chrdev(0, DEVICE_NAME, &fileops);
+ if (device_major < 0) {
+ return device_major;
+ }
+
+ printk(KERN_INFO DEVICE_NAME ": module loaded\n");
+ printk(KERN_INFO DEVICE_NAME ": Create a device node with "
+ "'mknod " DEVICE_NAME " c %d 0' and write data "
+ "to it.\n", device_major);
+ return 0;
+}
+
+static void __exit xxhash_test_exit(void)
+{
+ unregister_chrdev(device_major, DEVICE_NAME);
+ printk(KERN_INFO DEVICE_NAME ": module unloaded\n");
+}
+
+module_init(xxhash_test_init);
+module_exit(xxhash_test_exit);
+
+MODULE_DESCRIPTION("XXHash tester");
+MODULE_VERSION("1.0");
+
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/contrib/linux-kernel/zstd_compress_test.c b/contrib/linux-kernel/zstd_compress_test.c
new file mode 100644
index 000000000..bf856b796
--- /dev/null
+++ b/contrib/linux-kernel/zstd_compress_test.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ */
+
+/* Compression level or 0 to disable */
+#define DO_ZLIB 9
+/* Compression level or 0 to disable */
+#define DO_ZSTD 0
+/* Buffer size */
+#define BUFFER_SIZE 4096
+
+#include
+#include
+#include
+#include
+#include
+
+#if DO_ZSTD
+#include
+#endif
+
+#if DO_ZLIB
+#include
+#endif
+
+/* Device name to pass to register_chrdev(). */
+#define DEVICE_NAME "zstd_compress_test"
+
+/* Dynamically allocated device major number */
+static int device_major;
+
+/*
+ * We reuse the same state, and thus can compress only one file at a time.
+ */
+static bool device_is_open;
+
+
+static void *workspace = NULL;
+
+/*
+ * Input buffer used to put data coming from userspace.
+ */
+static uint8_t buffer_in[BUFFER_SIZE];
+static uint8_t buffer_out[BUFFER_SIZE];
+
+static uint64_t uncompressed_len;
+static uint64_t compressed_len;
+
+#if DO_ZSTD
+
+static ZSTD_CStream *state;
+
+static ZSTD_inBuffer input = {
+ .src = buffer_in,
+ .size = sizeof(buffer_in),
+ .pos = sizeof(buffer_in),
+};
+
+static ZSTD_outBuffer output = {
+ .dst = buffer_out,
+ .size = sizeof(buffer_out),
+ .pos = sizeof(buffer_out),
+};
+
+#endif /* DO_ZSTD */
+
+#if DO_ZLIB
+
+static z_stream state = {
+ .next_in = buffer_in,
+ .avail_in = 0,
+ .total_in = 0,
+
+ .next_out = buffer_out,
+ .avail_out = sizeof(buffer_out),
+ .total_out = 0,
+
+ .msg = NULL,
+ .state = NULL,
+ .workspace = NULL,
+};
+
+#endif /* DO_ZLIB */
+
+static int zstd_compress_test_open(struct inode *i, struct file *f)
+{
+ if (device_is_open)
+ return -EBUSY;
+
+ device_is_open = true;
+
+ uncompressed_len = compressed_len = 0;
+
+#if DO_ZSTD
+ if (ZSTD_isError(ZSTD_resetCStream(state, 0)))
+ return -EIO;
+#endif
+
+#if DO_ZLIB
+ if (zlib_deflateReset(&state) != Z_OK)
+ return -EIO;
+#endif
+
+ printk(KERN_INFO DEVICE_NAME ": opened\n");
+ return 0;
+}
+
+static int zstd_compress_test_release(struct inode *i, struct file *f)
+{
+ device_is_open = false;
+
+#if DO_ZSTD
+ do {
+ size_t ret;
+
+ output.pos = 0;
+ ret = ZSTD_endStream(state, &output);
+ if (ZSTD_isError(ret)) {
+ printk(KERN_INFO DEVICE_NAME ": zstd end error %u\n", ZSTD_getErrorCode(ret));
+ return -EIO;
+ }
+ compressed_len += output.pos;
+ } while (output.pos != output.size);
+#endif
+
+#if DO_ZLIB
+ for (;;) {
+ int ret;
+
+ state.next_out = buffer_out;
+ state.avail_out = sizeof(buffer_out);
+ ret = zlib_deflate(&state, Z_FINISH);
+ compressed_len += sizeof(buffer_out) - state.avail_out;
+ if (ret == Z_STREAM_END)
+ break;
+ if (ret != Z_OK) {
+ printk(KERN_INFO DEVICE_NAME ": zlib end error %d: %s\n", ret, state.msg);
+ return -EIO;
+ }
+ }
+#endif
+
+ printk(KERN_INFO DEVICE_NAME ": uncompressed_len = %llu\n", uncompressed_len);
+ printk(KERN_INFO DEVICE_NAME ": compressed_len = %llu\n", compressed_len);
+ printk(KERN_INFO DEVICE_NAME ": closed\n");
+ return 0;
+}
+
+/*
+ * Hash the data given to us from userspace.
+ */
+static ssize_t zstd_compress_test_write(struct file *file,
+ const char __user *buf, size_t size, loff_t *pos)
+{
+ size_t remaining = size;
+
+ while (remaining > 0) {
+ size_t const copy_size = min(remaining, sizeof(buffer_in));
+
+ if (copy_from_user(buffer_in, buf, copy_size))
+ return -EFAULT;
+ buf += copy_size;
+ remaining -= copy_size;
+ uncompressed_len += copy_size;
+
+#if DO_ZSTD
+ input.pos = 0;
+ input.size = copy_size;
+ while (input.pos != input.size) {
+ size_t ret;
+
+ output.pos = 0;
+ ret = ZSTD_compressStream(state, &output, &input);
+ if (ZSTD_isError(ret)) {
+ printk(KERN_INFO DEVICE_NAME ": zstd compress error %u\n", ZSTD_getErrorCode(ret));
+ return -EIO;
+ }
+ compressed_len += output.pos;
+ }
+#endif
+#if DO_ZLIB
+ state.next_in = buffer_in;
+ state.avail_in = copy_size;
+ while (state.avail_in > 0) {
+ int ret;
+
+ state.next_out = buffer_out;
+ state.avail_out = sizeof(buffer_out);
+ ret = zlib_deflate(&state, Z_NO_FLUSH);
+ compressed_len += sizeof(buffer_out) - state.avail_out;
+ if (ret != Z_OK) {
+ printk(KERN_INFO DEVICE_NAME ": zlib end error %d: %s\n", ret, state.msg);
+ return -EIO;
+ }
+ }
+#endif
+ }
+ return size;
+}
+/* register the character device. */
+static int __init zstd_compress_test_init(void)
+{
+ static const struct file_operations fileops = {
+ .owner = THIS_MODULE,
+ .open = &zstd_compress_test_open,
+ .release = &zstd_compress_test_release,
+ .write = &zstd_compress_test_write
+ };
+ size_t workspace_size = 0;
+#if DO_ZSTD
+ ZSTD_parameters params;
+#endif
+
+ device_major = register_chrdev(0, DEVICE_NAME, &fileops);
+ if (device_major < 0) {
+ return device_major;
+ }
+
+#if DO_ZSTD
+ params = ZSTD_getParams(DO_ZSTD, 0, 0);
+ workspace_size = ZSTD_CStreamWorkspaceBound(params.cParams);
+
+ if (!(workspace = vmalloc(workspace_size)))
+ goto fail;
+ if (!(state = ZSTD_initCStream(params, 0, workspace, workspace_size)))
+ goto fail;
+#endif
+
+#if DO_ZLIB
+ workspace_size = zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL);
+
+ if (!(workspace = vmalloc(workspace_size)))
+ goto fail;
+ state.workspace = workspace;
+ if (zlib_deflateInit(&state, DO_ZLIB) != Z_OK)
+ goto fail;
+#endif
+
+ printk(KERN_INFO DEVICE_NAME ": module loaded\n");
+ printk(KERN_INFO DEVICE_NAME ": compression requires %zu bytes of memory\n", workspace_size);
+ printk(KERN_INFO DEVICE_NAME ": Create a device node with "
+ "'mknod " DEVICE_NAME " c %d 0' and write data "
+ "to it.\n", device_major);
+ return 0;
+
+fail:
+ printk(KERN_INFO DEVICE_NAME ": failed to load module\n");
+ if (workspace) {
+ vfree(workspace);
+ workspace = NULL;
+ }
+ return -ENOMEM;
+}
+
+static void __exit zstd_compress_test_exit(void)
+{
+ unregister_chrdev(device_major, DEVICE_NAME);
+#if DO_ZLIB
+ zlib_deflateEnd(&state);
+#endif
+ if (workspace) {
+ vfree(workspace);
+ workspace = NULL;
+ }
+ printk(KERN_INFO DEVICE_NAME ": module unloaded\n");
+}
+
+module_init(zstd_compress_test_init);
+module_exit(zstd_compress_test_exit);
+
+MODULE_DESCRIPTION("Zstd compression tester");
+MODULE_VERSION("1.0");
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/contrib/linux-kernel/zstd_decompress_test.c b/contrib/linux-kernel/zstd_decompress_test.c
new file mode 100644
index 000000000..4905a5ac5
--- /dev/null
+++ b/contrib/linux-kernel/zstd_decompress_test.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation. This program is dual-licensed; you may select
+ * either version 2 of the GNU General Public License ("GPL") or BSD license
+ * ("BSD").
+ */
+
+/* Compression level or 0 to disable */
+#define DO_ZLIB 1
+/* Compression level or 0 to disable */
+#define DO_ZSTD 0
+/* Buffer size */
+#define BUFFER_SIZE 4096
+
+#include
+#include
+#include
+#include
+#include
+
+#if DO_ZSTD
+#include
+#endif
+
+#if DO_ZLIB
+#include
+#endif
+
+/* Device name to pass to register_chrdev(). */
+#define DEVICE_NAME "zstd_decompress_test"
+
+/* Dynamically allocated device major number */
+static int device_major;
+
+/*
+ * We reuse the same state, and thus can compress only one file at a time.
+ */
+static bool device_is_open;
+
+
+static void *workspace = NULL;
+
+/*
+ * Input buffer used to put data coming from userspace.
+ */
+static uint8_t buffer_in[BUFFER_SIZE];
+static uint8_t buffer_out[BUFFER_SIZE];
+
+static uint64_t uncompressed_len;
+static uint64_t compressed_len;
+
+#if DO_ZSTD
+
+static ZSTD_DStream *state;
+
+static ZSTD_inBuffer input = {
+ .src = buffer_in,
+ .size = sizeof(buffer_in),
+ .pos = sizeof(buffer_in),
+};
+
+static ZSTD_outBuffer output = {
+ .dst = buffer_out,
+ .size = sizeof(buffer_out),
+ .pos = sizeof(buffer_out),
+};
+
+#endif /* DO_ZSTD */
+
+#if DO_ZLIB
+
+static z_stream state = {
+ .next_in = buffer_in,
+ .avail_in = 0,
+ .total_in = 0,
+
+ .next_out = buffer_out,
+ .avail_out = sizeof(buffer_out),
+ .total_out = 0,
+
+ .msg = NULL,
+ .state = NULL,
+ .workspace = NULL,
+};
+
+#endif /* DO_ZLIB */
+
+static int zstd_decompress_test_open(struct inode *i, struct file *f)
+{
+ if (device_is_open)
+ return -EBUSY;
+
+ device_is_open = true;
+
+ uncompressed_len = compressed_len = 0;
+
+#if DO_ZSTD
+ if (ZSTD_isError(ZSTD_resetDStream(state)))
+ return -EIO;
+#endif
+
+#if DO_ZLIB
+ if (zlib_inflateReset(&state) != Z_OK)
+ return -EIO;
+#endif
+
+ printk(KERN_INFO DEVICE_NAME ": opened\n");
+ return 0;
+}
+
+static int zstd_decompress_test_release(struct inode *i, struct file *f)
+{
+ device_is_open = false;
+
+ printk(KERN_INFO DEVICE_NAME ": uncompressed_len = %llu\n", uncompressed_len);
+ printk(KERN_INFO DEVICE_NAME ": compressed_len = %llu\n", compressed_len);
+ printk(KERN_INFO DEVICE_NAME ": closed\n");
+ return 0;
+}
+
+/*
+ * Hash the data given to us from userspace.
+ */
+static ssize_t zstd_decompress_test_write(struct file *file,
+ const char __user *buf, size_t size, loff_t *pos)
+{
+ size_t remaining = size;
+
+ while (remaining > 0) {
+ size_t const copy_size = min(remaining, sizeof(buffer_in));
+
+ if (copy_from_user(buffer_in, buf, copy_size))
+ return -EFAULT;
+ buf += copy_size;
+ remaining -= copy_size;
+ compressed_len += copy_size;
+
+#if DO_ZSTD
+ input.pos = 0;
+ input.size = copy_size;
+ while (input.pos != input.size) {
+ size_t ret;
+
+ output.pos = 0;
+ ret = ZSTD_decompressStream(state, &output, &input);
+ if (ZSTD_isError(ret)) {
+ printk(KERN_INFO DEVICE_NAME ": zstd decompress error %u\n", ZSTD_getErrorCode(ret));
+ return -EIO;
+ }
+ uncompressed_len += output.pos;
+ }
+#endif
+#if DO_ZLIB
+ state.next_in = buffer_in;
+ state.avail_in = copy_size;
+ while (state.avail_in > 0) {
+ int ret;
+
+ state.next_out = buffer_out;
+ state.avail_out = sizeof(buffer_out);
+ ret = zlib_inflate(&state, Z_NO_FLUSH);
+ uncompressed_len += sizeof(buffer_out) - state.avail_out;
+ if (ret != Z_OK && ret != Z_STREAM_END) {
+ printk(KERN_INFO DEVICE_NAME ": zlib decompress error %d: %s\n", ret, state.msg);
+ return -EIO;
+ }
+ }
+#endif
+ }
+ return size;
+}
+/* register the character device. */
+static int __init zstd_decompress_test_init(void)
+{
+ static const struct file_operations fileops = {
+ .owner = THIS_MODULE,
+ .open = &zstd_decompress_test_open,
+ .release = &zstd_decompress_test_release,
+ .write = &zstd_decompress_test_write
+ };
+ size_t workspace_size = 0;
+#if DO_ZSTD
+ ZSTD_parameters params;
+ size_t max_window_size;
+#endif
+
+ device_major = register_chrdev(0, DEVICE_NAME, &fileops);
+ if (device_major < 0) {
+ return device_major;
+ }
+
+#if DO_ZSTD
+ params = ZSTD_getParams(DO_ZSTD, 0, 0);
+ max_window_size = (size_t)1 << params.cParams.windowLog;
+ workspace_size = ZSTD_DStreamWorkspaceBound(max_window_size);
+
+ if (!(workspace = vmalloc(workspace_size)))
+ goto fail;
+ if (!(state = ZSTD_initDStream(max_window_size, workspace, workspace_size)))
+ goto fail;
+#endif
+
+#if DO_ZLIB
+ workspace_size = zlib_inflate_workspacesize();
+
+ if (!(workspace = vmalloc(workspace_size)))
+ goto fail;
+ state.workspace = workspace;
+ if (zlib_inflateInit(&state) != Z_OK)
+ goto fail;
+#endif
+
+ printk(KERN_INFO DEVICE_NAME ": module loaded\n");
+ printk(KERN_INFO DEVICE_NAME ": decompression requires %zu bytes of memory\n", workspace_size);
+ printk(KERN_INFO DEVICE_NAME ": Create a device node with "
+ "'mknod " DEVICE_NAME " c %d 0' and write data "
+ "to it.\n", device_major);
+ return 0;
+
+fail:
+ printk(KERN_INFO DEVICE_NAME ": failed to load module\n");
+ if (workspace) {
+ vfree(workspace);
+ workspace = NULL;
+ }
+ return -ENOMEM;
+}
+
+static void __exit zstd_decompress_test_exit(void)
+{
+ unregister_chrdev(device_major, DEVICE_NAME);
+#if DO_ZLIB
+ zlib_deflateEnd(&state);
+#endif
+ if (workspace) {
+ vfree(workspace);
+ workspace = NULL;
+ }
+ printk(KERN_INFO DEVICE_NAME ": module unloaded\n");
+}
+
+module_init(zstd_decompress_test_init);
+module_exit(zstd_decompress_test_exit);
+
+MODULE_DESCRIPTION("Zstd decompression tester");
+MODULE_VERSION("1.0");
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/contrib/pzstd/Pzstd.cpp b/contrib/pzstd/Pzstd.cpp
index 1265b53ef..ae5d73444 100644
--- a/contrib/pzstd/Pzstd.cpp
+++ b/contrib/pzstd/Pzstd.cpp
@@ -585,7 +585,10 @@ std::uint64_t writeFile(
std::uint64_t bytesWritten = 0;
std::shared_ptr out;
// Grab the output queue for each decompression job (in order).
- while (outs.pop(out) && !errorHolder.hasError()) {
+ while (outs.pop(out)) {
+ if (errorHolder.hasError()) {
+ continue;
+ }
if (!decompress) {
// If we are compressing and want to write skippable frames we can't
// start writing before compression is done because we need to know the
diff --git a/contrib/seekable_format/examples/.gitignore b/contrib/seekable_format/examples/.gitignore
new file mode 100644
index 000000000..df2f9ab07
--- /dev/null
+++ b/contrib/seekable_format/examples/.gitignore
@@ -0,0 +1,4 @@
+seekable_compression
+seekable_decompression
+parallel_processing
+parallel_compression
diff --git a/contrib/seekable_format/examples/Makefile b/contrib/seekable_format/examples/Makefile
new file mode 100644
index 000000000..625e1fcc8
--- /dev/null
+++ b/contrib/seekable_format/examples/Makefile
@@ -0,0 +1,42 @@
+# ################################################################
+# Copyright (c) 2017-present, Facebook, Inc.
+# All rights reserved.
+#
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree. An additional grant
+# of patent rights can be found in the PATENTS file in the same directory.
+# ################################################################
+
+# This Makefile presumes libzstd is built, using `make` in / or /lib/
+
+LDFLAGS += ../../../lib/libzstd.a
+CPPFLAGS += -I../ -I../../../lib -I../../../lib/common
+
+CFLAGS ?= -O3
+CFLAGS += -g
+
+SEEKABLE_OBJS = ../zstdseek_compress.c ../zstdseek_decompress.c
+
+.PHONY: default all clean test
+
+default: all
+
+all: seekable_compression seekable_decompression parallel_processing
+
+seekable_compression : seekable_compression.c $(SEEKABLE_OBJS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+seekable_decompression : seekable_decompression.c $(SEEKABLE_OBJS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+parallel_processing : parallel_processing.c $(SEEKABLE_OBJS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ -pthread
+
+parallel_compression : parallel_compression.c $(SEEKABLE_OBJS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@ -pthread
+
+clean:
+ @rm -f core *.o tmp* result* *.zst \
+ seekable_compression seekable_decompression \
+ parallel_processing parallel_compression
+ @echo Cleaning completed
diff --git a/contrib/seekable_format/examples/parallel_compression.c b/contrib/seekable_format/examples/parallel_compression.c
new file mode 100644
index 000000000..89a13185f
--- /dev/null
+++ b/contrib/seekable_format/examples/parallel_compression.c
@@ -0,0 +1,214 @@
+/**
+ * Copyright 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the license found in the
+ * LICENSE-examples file in the root directory of this source tree.
+ */
+
+#include // malloc, free, exit, atoi
+#include // fprintf, perror, feof, fopen, etc.
+#include // strlen, memset, strcat
+#define ZSTD_STATIC_LINKING_ONLY
+#include // presumes zstd library is installed
+#include
+#if defined(WIN32) || defined(_WIN32)
+# include
+# define SLEEP(x) Sleep(x)
+#else
+# include
+# define SLEEP(x) usleep(x * 1000)
+#endif
+
+#define XXH_NAMESPACE ZSTD_
+#include "xxhash.h"
+
+#include "pool.h" // use zstd thread pool for demo
+
+#include "zstd_seekable.h"
+
+static void* malloc_orDie(size_t size)
+{
+ void* const buff = malloc(size);
+ if (buff) return buff;
+ /* error */
+ perror("malloc:");
+ exit(1);
+}
+
+static FILE* fopen_orDie(const char *filename, const char *instruction)
+{
+ FILE* const inFile = fopen(filename, instruction);
+ if (inFile) return inFile;
+ /* error */
+ perror(filename);
+ exit(3);
+}
+
+static size_t fread_orDie(void* buffer, size_t sizeToRead, FILE* file)
+{
+ size_t const readSize = fread(buffer, 1, sizeToRead, file);
+ if (readSize == sizeToRead) return readSize; /* good */
+ if (feof(file)) return readSize; /* good, reached end of file */
+ /* error */
+ perror("fread");
+ exit(4);
+}
+
+static size_t fwrite_orDie(const void* buffer, size_t sizeToWrite, FILE* file)
+{
+ size_t const writtenSize = fwrite(buffer, 1, sizeToWrite, file);
+ if (writtenSize == sizeToWrite) return sizeToWrite; /* good */
+ /* error */
+ perror("fwrite");
+ exit(5);
+}
+
+static size_t fclose_orDie(FILE* file)
+{
+ if (!fclose(file)) return 0;
+ /* error */
+ perror("fclose");
+ exit(6);
+}
+
+static void fseek_orDie(FILE* file, long int offset, int origin)
+{
+ if (!fseek(file, offset, origin)) {
+ if (!fflush(file)) return;
+ }
+ /* error */
+ perror("fseek");
+ exit(7);
+}
+
+static long int ftell_orDie(FILE* file)
+{
+ long int off = ftell(file);
+ if (off != -1) return off;
+ /* error */
+ perror("ftell");
+ exit(8);
+}
+
+struct job {
+ const void* src;
+ size_t srcSize;
+ void* dst;
+ size_t dstSize;
+
+ unsigned checksum;
+
+ int compressionLevel;
+ int done;
+};
+
+static void compressFrame(void* opaque)
+{
+ struct job* job = opaque;
+
+ job->checksum = XXH64(job->src, job->srcSize, 0);
+
+ size_t ret = ZSTD_compress(job->dst, job->dstSize, job->src, job->srcSize, job->compressionLevel);
+ if (ZSTD_isError(ret)) {
+ fprintf(stderr, "ZSTD_compress() error : %s \n", ZSTD_getErrorName(ret));
+ exit(20);
+ }
+
+ job->dstSize = ret;
+ job->done = 1;
+}
+
+static void compressFile_orDie(const char* fname, const char* outName, int cLevel, unsigned frameSize, int nbThreads)
+{
+ POOL_ctx* pool = POOL_create(nbThreads, nbThreads);
+ if (pool == NULL) { fprintf(stderr, "POOL_create() error \n"); exit(9); }
+
+ FILE* const fin = fopen_orDie(fname, "rb");
+ FILE* const fout = fopen_orDie(outName, "wb");
+
+ if (ZSTD_compressBound(frameSize) > 0xFFFFFFFFU) { fprintf(stderr, "Frame size too large \n"); exit(10); }
+ unsigned dstSize = ZSTD_compressBound(frameSize);
+
+
+ fseek_orDie(fin, 0, SEEK_END);
+ long int length = ftell_orDie(fin);
+ fseek_orDie(fin, 0, SEEK_SET);
+
+ size_t numFrames = (length + frameSize - 1) / frameSize;
+
+ struct job* jobs = malloc_orDie(sizeof(struct job) * numFrames);
+
+ size_t i;
+ for(i = 0; i < numFrames; i++) {
+ void* in = malloc_orDie(frameSize);
+ void* out = malloc_orDie(dstSize);
+
+ size_t inSize = fread_orDie(in, frameSize, fin);
+
+ jobs[i].src = in;
+ jobs[i].srcSize = inSize;
+ jobs[i].dst = out;
+ jobs[i].dstSize = dstSize;
+ jobs[i].compressionLevel = cLevel;
+ jobs[i].done = 0;
+ POOL_add(pool, compressFrame, &jobs[i]);
+ }
+
+ ZSTD_frameLog* fl = ZSTD_seekable_createFrameLog(1);
+ if (fl == NULL) { fprintf(stderr, "ZSTD_seekable_createFrameLog() failed \n"); exit(11); }
+ for (i = 0; i < numFrames; i++) {
+ while (!jobs[i].done) SLEEP(5); /* wake up every 5 milliseconds to check */
+ fwrite_orDie(jobs[i].dst, jobs[i].dstSize, fout);
+ free((void*)jobs[i].src);
+ free(jobs[i].dst);
+
+ size_t ret = ZSTD_seekable_logFrame(fl, jobs[i].dstSize, jobs[i].srcSize, jobs[i].checksum);
+ if (ZSTD_isError(ret)) { fprintf(stderr, "ZSTD_seekable_logFrame() error : %s \n", ZSTD_getErrorName(ret)); }
+ }
+
+ { unsigned char seekTableBuff[1024];
+ ZSTD_outBuffer out = {seekTableBuff, 1024, 0};
+ while (ZSTD_seekable_writeSeekTable(fl, &out) != 0) {
+ fwrite_orDie(seekTableBuff, out.pos, fout);
+ out.pos = 0;
+ }
+ fwrite_orDie(seekTableBuff, out.pos, fout);
+ }
+
+ ZSTD_seekable_freeFrameLog(fl);
+ free(jobs);
+ fclose_orDie(fout);
+ fclose_orDie(fin);
+}
+
+static const char* createOutFilename_orDie(const char* filename)
+{
+ size_t const inL = strlen(filename);
+ size_t const outL = inL + 5;
+ void* outSpace = malloc_orDie(outL);
+ memset(outSpace, 0, outL);
+ strcat(outSpace, filename);
+ strcat(outSpace, ".zst");
+ return (const char*)outSpace;
+}
+
+int main(int argc, const char** argv) {
+ const char* const exeName = argv[0];
+ if (argc!=4) {
+ printf("wrong arguments\n");
+ printf("usage:\n");
+ printf("%s FILE FRAME_SIZE NB_THREADS\n", exeName);
+ return 1;
+ }
+
+ { const char* const inFileName = argv[1];
+ unsigned const frameSize = (unsigned)atoi(argv[2]);
+ int const nbThreads = atoi(argv[3]);
+
+ const char* const outFileName = createOutFilename_orDie(inFileName);
+ compressFile_orDie(inFileName, outFileName, 5, frameSize, nbThreads);
+ }
+
+ return 0;
+}
diff --git a/contrib/seekable_format/examples/parallel_processing.c b/contrib/seekable_format/examples/parallel_processing.c
new file mode 100644
index 000000000..cea4d5364
--- /dev/null
+++ b/contrib/seekable_format/examples/parallel_processing.c
@@ -0,0 +1,193 @@
+/**
+ * Copyright 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the license found in the
+ * LICENSE-examples file in the root directory of this source tree.
+ */
+
+/*
+ * A simple demo that sums up all the bytes in the file in parallel using
+ * seekable decompression and the zstd thread pool
+ */
+
+#include // malloc, exit
+#include // fprintf, perror, feof
+#include // strerror
+#include // errno
+#define ZSTD_STATIC_LINKING_ONLY
+#include // presumes zstd library is installed
+#include
+#if defined(WIN32) || defined(_WIN32)
+# include
+# define SLEEP(x) Sleep(x)
+#else
+# include
+# define SLEEP(x) usleep(x * 1000)
+#endif
+
+#include "pool.h" // use zstd thread pool for demo
+
+#include "zstd_seekable.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static void* malloc_orDie(size_t size)
+{
+ void* const buff = malloc(size);
+ if (buff) return buff;
+ /* error */
+ perror("malloc");
+ exit(1);
+}
+
+static void* realloc_orDie(void* ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr) return ptr;
+ /* error */
+ perror("realloc");
+ exit(1);
+}
+
+static FILE* fopen_orDie(const char *filename, const char *instruction)
+{
+ FILE* const inFile = fopen(filename, instruction);
+ if (inFile) return inFile;
+ /* error */
+ perror(filename);
+ exit(3);
+}
+
+static size_t fread_orDie(void* buffer, size_t sizeToRead, FILE* file)
+{
+ size_t const readSize = fread(buffer, 1, sizeToRead, file);
+ if (readSize == sizeToRead) return readSize; /* good */
+ if (feof(file)) return readSize; /* good, reached end of file */
+ /* error */
+ perror("fread");
+ exit(4);
+}
+
+static size_t fwrite_orDie(const void* buffer, size_t sizeToWrite, FILE* file)
+{
+ size_t const writtenSize = fwrite(buffer, 1, sizeToWrite, file);
+ if (writtenSize == sizeToWrite) return sizeToWrite; /* good */
+ /* error */
+ perror("fwrite");
+ exit(5);
+}
+
+static size_t fclose_orDie(FILE* file)
+{
+ if (!fclose(file)) return 0;
+ /* error */
+ perror("fclose");
+ exit(6);
+}
+
+static void fseek_orDie(FILE* file, long int offset, int origin) {
+ if (!fseek(file, offset, origin)) {
+ if (!fflush(file)) return;
+ }
+ /* error */
+ perror("fseek");
+ exit(7);
+}
+
+struct sum_job {
+ const char* fname;
+ unsigned long long sum;
+ unsigned frameNb;
+ int done;
+};
+
+static void sumFrame(void* opaque)
+{
+ struct sum_job* job = (struct sum_job*)opaque;
+ job->done = 0;
+
+ FILE* const fin = fopen_orDie(job->fname, "rb");
+
+ ZSTD_seekable* const seekable = ZSTD_seekable_create();
+ if (seekable==NULL) { fprintf(stderr, "ZSTD_seekable_create() error \n"); exit(10); }
+
+ size_t const initResult = ZSTD_seekable_initFile(seekable, fin);
+ if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_seekable_init() error : %s \n", ZSTD_getErrorName(initResult)); exit(11); }
+
+ size_t const frameSize = ZSTD_seekable_getFrameDecompressedSize(seekable, job->frameNb);
+ unsigned char* data = malloc_orDie(frameSize);
+
+ size_t result = ZSTD_seekable_decompressFrame(seekable, data, frameSize, job->frameNb);
+ if (ZSTD_isError(result)) { fprintf(stderr, "ZSTD_seekable_decompressFrame() error : %s \n", ZSTD_getErrorName(result)); exit(12); }
+
+ unsigned long long sum = 0;
+ size_t i;
+ for (i = 0; i < frameSize; i++) {
+ sum += data[i];
+ }
+ job->sum = sum;
+ job->done = 1;
+
+ fclose(fin);
+ ZSTD_seekable_free(seekable);
+ free(data);
+}
+
+static void sumFile_orDie(const char* fname, int nbThreads)
+{
+ POOL_ctx* pool = POOL_create(nbThreads, nbThreads);
+ if (pool == NULL) { fprintf(stderr, "POOL_create() error \n"); exit(9); }
+
+ FILE* const fin = fopen_orDie(fname, "rb");
+
+ ZSTD_seekable* const seekable = ZSTD_seekable_create();
+ if (seekable==NULL) { fprintf(stderr, "ZSTD_seekable_create() error \n"); exit(10); }
+
+ size_t const initResult = ZSTD_seekable_initFile(seekable, fin);
+ if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_seekable_init() error : %s \n", ZSTD_getErrorName(initResult)); exit(11); }
+
+ size_t const numFrames = ZSTD_seekable_getNumFrames(seekable);
+ struct sum_job* jobs = (struct sum_job*)malloc(numFrames * sizeof(struct sum_job));
+
+ size_t i;
+ for (i = 0; i < numFrames; i++) {
+ jobs[i] = (struct sum_job){ fname, 0, i, 0 };
+ POOL_add(pool, sumFrame, &jobs[i]);
+ }
+
+ unsigned long long total = 0;
+
+ for (i = 0; i < numFrames; i++) {
+ while (!jobs[i].done) SLEEP(5); /* wake up every 5 milliseconds to check */
+ total += jobs[i].sum;
+ }
+
+ printf("Sum: %llu\n", total);
+
+ POOL_free(pool);
+ ZSTD_seekable_free(seekable);
+ fclose(fin);
+ free(jobs);
+}
+
+
+int main(int argc, const char** argv)
+{
+ const char* const exeName = argv[0];
+
+ if (argc!=3) {
+ fprintf(stderr, "wrong arguments\n");
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "%s FILE NB_THREADS\n", exeName);
+ return 1;
+ }
+
+ {
+ const char* const inFilename = argv[1];
+ int const nbThreads = atoi(argv[2]);
+ sumFile_orDie(inFilename, nbThreads);
+ }
+
+ return 0;
+}
diff --git a/contrib/seekable_format/examples/seekable_compression.c b/contrib/seekable_format/examples/seekable_compression.c
new file mode 100644
index 000000000..a33952d93
--- /dev/null
+++ b/contrib/seekable_format/examples/seekable_compression.c
@@ -0,0 +1,131 @@
+/**
+ * Copyright 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the license found in the
+ * LICENSE-examples file in the root directory of this source tree.
+ */
+
+#include // malloc, free, exit, atoi
+#include