summaryrefslogtreecommitdiffstats
path: root/src/zstd/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'src/zstd/contrib')
-rw-r--r--src/zstd/contrib/VS2005/README.md3
-rw-r--r--src/zstd/contrib/VS2005/fullbench/fullbench.vcproj440
-rw-r--r--src/zstd/contrib/VS2005/fuzzer/fuzzer.vcproj488
-rw-r--r--src/zstd/contrib/VS2005/zstd.sln55
-rw-r--r--src/zstd/contrib/VS2005/zstd/zstd.vcproj548
-rw-r--r--src/zstd/contrib/VS2005/zstdlib/zstdlib.vcproj562
-rwxr-xr-xsrc/zstd/contrib/cleanTabs2
-rw-r--r--src/zstd/contrib/diagnose_corruption/.gitignore1
-rw-r--r--src/zstd/contrib/diagnose_corruption/Makefile35
-rw-r--r--src/zstd/contrib/diagnose_corruption/check_flipped_bits.c400
-rw-r--r--src/zstd/contrib/docker/Dockerfile20
-rw-r--r--src/zstd/contrib/docker/README.md20
-rw-r--r--src/zstd/contrib/gen_html/.gitignore3
-rw-r--r--src/zstd/contrib/gen_html/Makefile51
-rw-r--r--src/zstd/contrib/gen_html/README.md31
-rwxr-xr-xsrc/zstd/contrib/gen_html/gen-zstd-manual.sh9
-rw-r--r--src/zstd/contrib/gen_html/gen_html.cpp224
-rw-r--r--src/zstd/contrib/largeNbDicts/.gitignore2
-rw-r--r--src/zstd/contrib/largeNbDicts/Makefile58
-rw-r--r--src/zstd/contrib/largeNbDicts/README.md25
-rw-r--r--src/zstd/contrib/largeNbDicts/largeNbDicts.c979
-rw-r--r--src/zstd/contrib/linux-kernel/.gitignore4
-rw-r--r--src/zstd/contrib/linux-kernel/0000-cover-letter.patch122
-rw-r--r--src/zstd/contrib/linux-kernel/0001-lib-Add-xxhash-module.patch862
-rw-r--r--src/zstd/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch13285
-rw-r--r--src/zstd/contrib/linux-kernel/0003-btrfs-Add-zstd-support.patch740
-rw-r--r--src/zstd/contrib/linux-kernel/0004-squashfs-Add-zstd-support.patch306
-rw-r--r--src/zstd/contrib/linux-kernel/0005-crypto-Add-zstd-support.patch424
-rw-r--r--src/zstd/contrib/linux-kernel/0006-squashfs-tools-Add-zstd-support.patch420
-rw-r--r--src/zstd/contrib/linux-kernel/COPYING339
-rw-r--r--src/zstd/contrib/linux-kernel/README.md101
-rwxr-xr-xsrc/zstd/contrib/linux-kernel/btrfs-benchmark.sh104
-rwxr-xr-xsrc/zstd/contrib/linux-kernel/btrfs-extract-benchmark.sh99
-rw-r--r--src/zstd/contrib/linux-kernel/fs/btrfs/zstd.c432
-rw-r--r--src/zstd/contrib/linux-kernel/fs/squashfs/zstd_wrapper.c151
-rw-r--r--src/zstd/contrib/linux-kernel/include/linux/xxhash.h236
-rw-r--r--src/zstd/contrib/linux-kernel/include/linux/zstd.h1155
-rwxr-xr-xsrc/zstd/contrib/linux-kernel/kernelize.sh110
-rw-r--r--src/zstd/contrib/linux-kernel/lib/Kconfig.diff19
-rw-r--r--src/zstd/contrib/linux-kernel/lib/Makefile.diff13
-rw-r--r--src/zstd/contrib/linux-kernel/lib/xxhash.c500
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/.clang-format11
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/Makefile18
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/bitstream.h374
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/compress.c3482
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/decompress.c2526
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/entropy_common.c243
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/error_private.h51
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/fse.h575
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/fse_compress.c795
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/fse_decompress.c332
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/huf.h212
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/huf_compress.c770
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/huf_decompress.c960
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/mem.h149
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/zstd_common.c73
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/zstd_internal.h261
-rw-r--r--src/zstd/contrib/linux-kernel/lib/zstd/zstd_opt.h1012
-rwxr-xr-xsrc/zstd/contrib/linux-kernel/squashfs-benchmark.sh39
-rw-r--r--src/zstd/contrib/linux-kernel/test/.gitignore1
-rw-r--r--src/zstd/contrib/linux-kernel/test/DecompressCrash.c85
-rw-r--r--src/zstd/contrib/linux-kernel/test/Makefile43
-rw-r--r--src/zstd/contrib/linux-kernel/test/RoundTripCrash.c162
-rw-r--r--src/zstd/contrib/linux-kernel/test/UserlandTest.cpp565
-rw-r--r--src/zstd/contrib/linux-kernel/test/XXHashUserlandTest.cpp166
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/asm/unaligned.h177
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/compiler.h12
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/errno.h6
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/kernel.h16
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/math64.h11
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/module.h10
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/string.h1
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/types.h2
-rw-r--r--src/zstd/contrib/linux-kernel/xxhash_test.c185
-rw-r--r--src/zstd/contrib/linux-kernel/zstd_compress_test.c279
-rw-r--r--src/zstd/contrib/linux-kernel/zstd_decompress_test.c250
-rw-r--r--src/zstd/contrib/match_finders/README.md42
-rw-r--r--src/zstd/contrib/match_finders/zstd_edist.c558
-rw-r--r--src/zstd/contrib/match_finders/zstd_edist.h70
-rw-r--r--src/zstd/contrib/premake/premake4.lua6
-rw-r--r--src/zstd/contrib/premake/zstd.lua80
-rw-r--r--src/zstd/contrib/pzstd/.gitignore2
-rw-r--r--src/zstd/contrib/pzstd/BUCK72
-rw-r--r--src/zstd/contrib/pzstd/ErrorHolder.h54
-rw-r--r--src/zstd/contrib/pzstd/Logging.h72
-rw-r--r--src/zstd/contrib/pzstd/Makefile271
-rw-r--r--src/zstd/contrib/pzstd/Options.cpp424
-rw-r--r--src/zstd/contrib/pzstd/Options.h68
-rw-r--r--src/zstd/contrib/pzstd/Pzstd.cpp611
-rw-r--r--src/zstd/contrib/pzstd/Pzstd.h150
-rw-r--r--src/zstd/contrib/pzstd/README.md56
-rw-r--r--src/zstd/contrib/pzstd/SkippableFrame.cpp30
-rw-r--r--src/zstd/contrib/pzstd/SkippableFrame.h64
-rw-r--r--src/zstd/contrib/pzstd/images/Cspeed.pngbin0 -> 69804 bytes
-rw-r--r--src/zstd/contrib/pzstd/images/Dspeed.pngbin0 -> 26335 bytes
-rw-r--r--src/zstd/contrib/pzstd/main.cpp27
-rw-r--r--src/zstd/contrib/pzstd/test/BUCK37
-rw-r--r--src/zstd/contrib/pzstd/test/OptionsTest.cpp536
-rw-r--r--src/zstd/contrib/pzstd/test/PzstdTest.cpp149
-rw-r--r--src/zstd/contrib/pzstd/test/RoundTrip.h86
-rw-r--r--src/zstd/contrib/pzstd/test/RoundTripTest.cpp86
-rw-r--r--src/zstd/contrib/pzstd/utils/BUCK75
-rw-r--r--src/zstd/contrib/pzstd/utils/Buffer.h99
-rw-r--r--src/zstd/contrib/pzstd/utils/FileSystem.h94
-rw-r--r--src/zstd/contrib/pzstd/utils/Likely.h28
-rw-r--r--src/zstd/contrib/pzstd/utils/Range.h131
-rw-r--r--src/zstd/contrib/pzstd/utils/ResourcePool.h96
-rw-r--r--src/zstd/contrib/pzstd/utils/ScopeGuard.h50
-rw-r--r--src/zstd/contrib/pzstd/utils/ThreadPool.h58
-rw-r--r--src/zstd/contrib/pzstd/utils/WorkQueue.h181
-rw-r--r--src/zstd/contrib/pzstd/utils/test/BUCK35
-rw-r--r--src/zstd/contrib/pzstd/utils/test/BufferTest.cpp89
-rw-r--r--src/zstd/contrib/pzstd/utils/test/RangeTest.cpp82
-rw-r--r--src/zstd/contrib/pzstd/utils/test/ResourcePoolTest.cpp72
-rw-r--r--src/zstd/contrib/pzstd/utils/test/ScopeGuardTest.cpp28
-rw-r--r--src/zstd/contrib/pzstd/utils/test/ThreadPoolTest.cpp71
-rw-r--r--src/zstd/contrib/pzstd/utils/test/WorkQueueTest.cpp282
-rw-r--r--src/zstd/contrib/seekable_format/examples/.gitignore5
-rw-r--r--src/zstd/contrib/seekable_format/examples/Makefile53
-rw-r--r--src/zstd/contrib/seekable_format/examples/parallel_compression.c215
-rw-r--r--src/zstd/contrib/seekable_format/examples/parallel_processing.c194
-rw-r--r--src/zstd/contrib/seekable_format/examples/seekable_compression.c133
-rw-r--r--src/zstd/contrib/seekable_format/examples/seekable_decompression.c138
-rw-r--r--src/zstd/contrib/seekable_format/examples/seekable_decompression_mem.c144
-rw-r--r--src/zstd/contrib/seekable_format/zstd_seekable.h186
-rw-r--r--src/zstd/contrib/seekable_format/zstd_seekable_compression_format.md116
-rw-r--r--src/zstd/contrib/seekable_format/zstdseek_compress.c369
-rw-r--r--src/zstd/contrib/seekable_format/zstdseek_decompress.c467
-rw-r--r--src/zstd/contrib/single_file_libs/.gitignore4
-rw-r--r--src/zstd/contrib/single_file_libs/README.md33
-rwxr-xr-xsrc/zstd/contrib/single_file_libs/build_decoder_test.sh55
-rwxr-xr-xsrc/zstd/contrib/single_file_libs/build_library_test.sh61
-rwxr-xr-xsrc/zstd/contrib/single_file_libs/combine.sh211
-rwxr-xr-xsrc/zstd/contrib/single_file_libs/create_single_file_decoder.sh14
-rwxr-xr-xsrc/zstd/contrib/single_file_libs/create_single_file_library.sh14
-rw-r--r--src/zstd/contrib/single_file_libs/examples/README.md11
-rw-r--r--src/zstd/contrib/single_file_libs/examples/emscripten.c340
-rw-r--r--src/zstd/contrib/single_file_libs/examples/roundtrip.c83
-rw-r--r--src/zstd/contrib/single_file_libs/examples/shell.html31
-rw-r--r--src/zstd/contrib/single_file_libs/examples/simple.c75
-rw-r--r--src/zstd/contrib/single_file_libs/examples/testcard-dxt1.inl2731
-rw-r--r--src/zstd/contrib/single_file_libs/examples/testcard-zstd.inl261
-rwxr-xr-xsrc/zstd/contrib/single_file_libs/examples/testcard.pngbin0 -> 12675 bytes
-rw-r--r--src/zstd/contrib/single_file_libs/zstd-in.c76
-rw-r--r--src/zstd/contrib/single_file_libs/zstddeclib-in.c54
-rw-r--r--src/zstd/contrib/snap/snapcraft.yaml28
146 files changed, 48356 insertions, 0 deletions
diff --git a/src/zstd/contrib/VS2005/README.md b/src/zstd/contrib/VS2005/README.md
new file mode 100644
index 000000000..ec1ef68a0
--- /dev/null
+++ b/src/zstd/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/src/zstd/contrib/VS2005/fullbench/fullbench.vcproj b/src/zstd/contrib/VS2005/fullbench/fullbench.vcproj
new file mode 100644
index 000000000..c67490c6f
--- /dev/null
+++ b/src/zstd/contrib/VS2005/fullbench/fullbench.vcproj
@@ -0,0 +1,440 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="fullbench"
+ ProjectGUID="{CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}"
+ RootNamespace="fullbench"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\programs\datagen.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\entropy_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\error_private.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\fse_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\xxhash.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\tests\fullbench.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\huf_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\decompress\huf_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstd_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\decompress\zstd_decompress.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\lib\common\bitstream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\error_private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_errors.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\huf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\huf_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\xxhash.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\mem.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\zstd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstd_opt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_static.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/zstd/contrib/VS2005/fuzzer/fuzzer.vcproj b/src/zstd/contrib/VS2005/fuzzer/fuzzer.vcproj
new file mode 100644
index 000000000..c64c5037a
--- /dev/null
+++ b/src/zstd/contrib/VS2005/fuzzer/fuzzer.vcproj
@@ -0,0 +1,488 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="fuzzer"
+ ProjectGUID="{A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}"
+ RootNamespace="fuzzer"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\programs"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\programs"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\programs"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\programs"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\programs\datagen.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\cover.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\divsufsort.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\entropy_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\pool.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\threading.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\error_private.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstdmt_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\fse_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\tests\fuzzer.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\huf_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\decompress\huf_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\xxhash.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstd_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\decompress\zstd_decompress.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\lib\common\pool.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\threading.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\bitstream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\divsufsort.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\error_private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_errors.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\huf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\huf_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\mem.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\xxhash.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\zstd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstd_opt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_static.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/zstd/contrib/VS2005/zstd.sln b/src/zstd/contrib/VS2005/zstd.sln
new file mode 100644
index 000000000..0c31ae126
--- /dev/null
+++ b/src/zstd/contrib/VS2005/zstd.sln
@@ -0,0 +1,55 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C++ Express 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zstd", "zstd\zstd.vcproj", "{1A2AB08E-5CE7-4C5B-BE55-458157C14051}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fuzzer", "fuzzer\fuzzer.vcproj", "{A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fullbench", "fullbench\fullbench.vcproj", "{CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zstdlib", "zstdlib\zstdlib.vcproj", "{99DE2A79-7298-4004-A0ED-030D7A3796CA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1A2AB08E-5CE7-4C5B-BE55-458157C14051}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A2AB08E-5CE7-4C5B-BE55-458157C14051}.Debug|Win32.Build.0 = Debug|Win32
+ {1A2AB08E-5CE7-4C5B-BE55-458157C14051}.Debug|x64.ActiveCfg = Debug|x64
+ {1A2AB08E-5CE7-4C5B-BE55-458157C14051}.Debug|x64.Build.0 = Debug|x64
+ {1A2AB08E-5CE7-4C5B-BE55-458157C14051}.Release|Win32.ActiveCfg = Release|Win32
+ {1A2AB08E-5CE7-4C5B-BE55-458157C14051}.Release|Win32.Build.0 = Release|Win32
+ {1A2AB08E-5CE7-4C5B-BE55-458157C14051}.Release|x64.ActiveCfg = Release|x64
+ {1A2AB08E-5CE7-4C5B-BE55-458157C14051}.Release|x64.Build.0 = Release|x64
+ {A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}.Debug|Win32.Build.0 = Debug|Win32
+ {A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}.Debug|x64.ActiveCfg = Debug|x64
+ {A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}.Debug|x64.Build.0 = Debug|x64
+ {A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}.Release|Win32.ActiveCfg = Release|Win32
+ {A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}.Release|Win32.Build.0 = Release|Win32
+ {A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}.Release|x64.ActiveCfg = Release|x64
+ {A62E89D2-9DDE-42BA-8F9B-9DA74889A6B0}.Release|x64.Build.0 = Release|x64
+ {CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}.Debug|Win32.Build.0 = Debug|Win32
+ {CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}.Debug|x64.ActiveCfg = Debug|x64
+ {CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}.Debug|x64.Build.0 = Debug|x64
+ {CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}.Release|Win32.ActiveCfg = Release|Win32
+ {CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}.Release|Win32.Build.0 = Release|Win32
+ {CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}.Release|x64.ActiveCfg = Release|x64
+ {CC8F1D1B-BA2F-43E3-A71F-FA415D81AAD3}.Release|x64.Build.0 = Release|x64
+ {99DE2A79-7298-4004-A0ED-030D7A3796CA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {99DE2A79-7298-4004-A0ED-030D7A3796CA}.Debug|Win32.Build.0 = Debug|Win32
+ {99DE2A79-7298-4004-A0ED-030D7A3796CA}.Debug|x64.ActiveCfg = Debug|x64
+ {99DE2A79-7298-4004-A0ED-030D7A3796CA}.Debug|x64.Build.0 = Debug|x64
+ {99DE2A79-7298-4004-A0ED-030D7A3796CA}.Release|Win32.ActiveCfg = Release|Win32
+ {99DE2A79-7298-4004-A0ED-030D7A3796CA}.Release|Win32.Build.0 = Release|Win32
+ {99DE2A79-7298-4004-A0ED-030D7A3796CA}.Release|x64.ActiveCfg = Release|x64
+ {99DE2A79-7298-4004-A0ED-030D7A3796CA}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/zstd/contrib/VS2005/zstd/zstd.vcproj b/src/zstd/contrib/VS2005/zstd/zstd.vcproj
new file mode 100644
index 000000000..46cabbf6e
--- /dev/null
+++ b/src/zstd/contrib/VS2005/zstd/zstd.vcproj
@@ -0,0 +1,548 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="zstd"
+ ProjectGUID="{1A2AB08E-5CE7-4C5B-BE55-458157C14051}"
+ RootNamespace="zstd"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\lib\compress"
+ PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=4;WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="setargv.obj"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\lib\compress"
+ PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=4;WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="setargv.obj"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\lib\compress"
+ PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=4;WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="setargv.obj"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib\dictBuilder;$(SolutionDir)..\..\lib\compress"
+ PreprocessorDefinitions="ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=4;WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="setargv.obj"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\programs\bench.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\programs\datagen.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\programs\dibio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\cover.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\divsufsort.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\entropy_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\error_private.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\programs\fileio.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\fse_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\huf_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\decompress\huf_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\xxhash.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstd_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstdmt_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\decompress\zstd_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v01.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v02.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v03.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v04.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v05.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v06.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v07.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\programs\zstdcli.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\lib\common\bitstream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\divsufsort.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\error_private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_errors.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\huf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\huf_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\mem.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\xxhash.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\zstd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_legacy.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstd_opt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v01.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v02.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v03.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v04.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v05.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v06.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v07.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/zstd/contrib/VS2005/zstdlib/zstdlib.vcproj b/src/zstd/contrib/VS2005/zstdlib/zstdlib.vcproj
new file mode 100644
index 000000000..f77df786f
--- /dev/null
+++ b/src/zstd/contrib/VS2005/zstdlib/zstdlib.vcproj
@@ -0,0 +1,562 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="zstdlib"
+ ProjectGUID="{99DE2A79-7298-4004-A0ED-030D7A3796CA}"
+ RootNamespace="zstdlib"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder"
+ PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=4;WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder"
+ PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=4;WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder"
+ PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=4;WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ OmitFramePointers="true"
+ AdditionalIncludeDirectories="$(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\common;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\dictBuilder"
+ PreprocessorDefinitions="ZSTD_DLL_EXPORT=1;ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=4;WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\cover.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\divsufsort.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\pool.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\threading.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\entropy_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\error_private.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\fse_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\huf_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\decompress\huf_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\xxhash.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\deprecated\zbuff_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\deprecated\zbuff_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\deprecated\zbuff_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstdmt_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstd_compress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\decompress\zstd_decompress.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v01.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v02.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v03.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v04.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v05.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v06.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v07.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\..\lib\common\bitstream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\divsufsort.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\pool.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\threading.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\error_private.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_errors.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\fse_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\huf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\huf_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\mem.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\xxhash.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zbuff.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\dictBuilder\zdict_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\zstd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_legacy.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstd_opt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\compress\zstdmt_compress.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\zstd_static.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v01.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v02.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v03.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v04.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v05.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v06.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\legacy\zstd_v07.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/zstd/contrib/cleanTabs b/src/zstd/contrib/cleanTabs
new file mode 100755
index 000000000..215913a90
--- /dev/null
+++ b/src/zstd/contrib/cleanTabs
@@ -0,0 +1,2 @@
+#!/bin/sh
+sed -i '' $'s/\t/ /g' ../lib/**/*.{h,c} ../programs/*.{h,c} ../tests/*.c ./**/*.{h,cpp} ../examples/*.c ../zlibWrapper/*.{h,c}
diff --git a/src/zstd/contrib/diagnose_corruption/.gitignore b/src/zstd/contrib/diagnose_corruption/.gitignore
new file mode 100644
index 000000000..a8e92b69b
--- /dev/null
+++ b/src/zstd/contrib/diagnose_corruption/.gitignore
@@ -0,0 +1 @@
+check_flipped_bits
diff --git a/src/zstd/contrib/diagnose_corruption/Makefile b/src/zstd/contrib/diagnose_corruption/Makefile
new file mode 100644
index 000000000..dc6fd2906
--- /dev/null
+++ b/src/zstd/contrib/diagnose_corruption/Makefile
@@ -0,0 +1,35 @@
+# ################################################################
+# Copyright (c) 2019-present, Facebook, Inc.
+# All rights reserved.
+#
+# This source code is licensed under both the BSD-style license (found in the
+# LICENSE file in the root directory of this source tree) and the GPLv2 (found
+# in the COPYING file in the root directory of this source tree).
+# ################################################################
+
+.PHONY: all
+all: check_flipped_bits
+
+ZSTDLIBDIR ?= ../../lib
+
+CFLAGS ?= -O3
+CFLAGS += -I$(ZSTDLIBDIR) -I$(ZSTDLIBDIR)/common -I$(ZSTDLIBDIR)/compress \
+ -I$(ZSTDLIBDIR)/decompress
+CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
+ -Wstrict-aliasing=1 -Wswitch-enum -Wdeclaration-after-statement \
+ -Wstrict-prototypes -Wundef \
+ -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
+ -Wredundant-decls -Wmissing-prototypes
+CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
+FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
+
+.PHONY: $(ZSTDLIBDIR)/libzstd.a
+$(ZSTDLIBDIR)/libzstd.a:
+ $(MAKE) -C $(ZSTDLIBDIR) libzstd.a
+
+check_flipped_bits: check_flipped_bits.c $(ZSTDLIBDIR)/libzstd.a
+ $(CC) $(FLAGS) $< -o $@$(EXT) $(ZSTDLIBDIR)/libzstd.a
+
+.PHONY: clean
+clean:
+ rm -f check_flipped_bits \ No newline at end of file
diff --git a/src/zstd/contrib/diagnose_corruption/check_flipped_bits.c b/src/zstd/contrib/diagnose_corruption/check_flipped_bits.c
new file mode 100644
index 000000000..cc40ab84b
--- /dev/null
+++ b/src/zstd/contrib/diagnose_corruption/check_flipped_bits.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2019-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#define ZSTD_STATIC_LINKING_ONLY
+#include "zstd.h"
+#include "zstd_errors.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+typedef struct {
+ char *input;
+ size_t input_size;
+
+ char *perturbed; /* same size as input */
+
+ char *output;
+ size_t output_size;
+
+ const char *dict_file_name;
+ const char *dict_file_dir_name;
+ int32_t dict_id;
+ char *dict;
+ size_t dict_size;
+ ZSTD_DDict* ddict;
+
+ ZSTD_DCtx* dctx;
+
+ int success_count;
+ int error_counts[ZSTD_error_maxCode];
+} stuff_t;
+
+static void free_stuff(stuff_t* stuff) {
+ free(stuff->input);
+ free(stuff->output);
+ ZSTD_freeDDict(stuff->ddict);
+ free(stuff->dict);
+ ZSTD_freeDCtx(stuff->dctx);
+}
+
+static void usage(void) {
+ fprintf(stderr, "check_flipped_bits input_filename [-d dict] [-D dict_dir]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Arguments:\n");
+ fprintf(stderr, " -d file: path to a dictionary file to use.\n");
+ fprintf(stderr, " -D dir : path to a directory, with files containing dictionaries, of the\n"
+ " form DICTID.zstd-dict, e.g., 12345.zstd-dict.\n");
+ exit(1);
+}
+
+static void print_summary(stuff_t* stuff) {
+ int error_code;
+ fprintf(stderr, "%9d successful decompressions\n", stuff->success_count);
+ for (error_code = 0; error_code < ZSTD_error_maxCode; error_code++) {
+ int count = stuff->error_counts[error_code];
+ if (count) {
+ fprintf(
+ stderr, "%9d failed decompressions with message: %s\n",
+ count, ZSTD_getErrorString(error_code));
+ }
+ }
+}
+
+static char* readFile(const char* filename, size_t* size) {
+ struct stat statbuf;
+ int ret;
+ FILE* f;
+ char *buf;
+ size_t bytes_read;
+
+ ret = stat(filename, &statbuf);
+ if (ret != 0) {
+ fprintf(stderr, "stat failed: %m\n");
+ return NULL;
+ }
+ if ((statbuf.st_mode & S_IFREG) != S_IFREG) {
+ fprintf(stderr, "Input must be regular file\n");
+ return NULL;
+ }
+
+ *size = statbuf.st_size;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ fprintf(stderr, "fopen failed: %m\n");
+ return NULL;
+ }
+
+ buf = malloc(*size);
+ if (buf == NULL) {
+ fprintf(stderr, "malloc failed\n");
+ fclose(f);
+ return NULL;
+ }
+
+ bytes_read = fread(buf, 1, *size, f);
+ if (bytes_read != *size) {
+ fprintf(stderr, "failed to read whole file\n");
+ fclose(f);
+ free(buf);
+ return NULL;
+ }
+
+ ret = fclose(f);
+ if (ret != 0) {
+ fprintf(stderr, "fclose failed: %m\n");
+ free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+static ZSTD_DDict* readDict(const char* filename, char **buf, size_t* size, int32_t* dict_id) {
+ ZSTD_DDict* ddict;
+ *buf = readFile(filename, size);
+ if (*buf == NULL) {
+ fprintf(stderr, "Opening dictionary file '%s' failed\n", filename);
+ return NULL;
+ }
+
+ ddict = ZSTD_createDDict_advanced(*buf, *size, ZSTD_dlm_byRef, ZSTD_dct_auto, ZSTD_defaultCMem);
+ if (ddict == NULL) {
+ fprintf(stderr, "Failed to create ddict.\n");
+ return NULL;
+ }
+ if (dict_id != NULL) {
+ *dict_id = ZSTD_getDictID_fromDDict(ddict);
+ }
+ return ddict;
+}
+
+static ZSTD_DDict* readDictByID(stuff_t *stuff, int32_t dict_id, char **buf, size_t* size) {
+ if (stuff->dict_file_dir_name == NULL) {
+ return NULL;
+ } else {
+ size_t dir_name_len = strlen(stuff->dict_file_dir_name);
+ int dir_needs_separator = 0;
+ size_t dict_file_name_alloc_size = dir_name_len + 1 /* '/' */ + 10 /* max int32_t len */ + strlen(".zstd-dict") + 1 /* '\0' */;
+ char *dict_file_name = malloc(dict_file_name_alloc_size);
+ ZSTD_DDict* ddict;
+ int32_t read_dict_id;
+ if (dict_file_name == NULL) {
+ fprintf(stderr, "malloc failed.\n");
+ return 0;
+ }
+
+ if (dir_name_len > 0 && stuff->dict_file_dir_name[dir_name_len - 1] != '/') {
+ dir_needs_separator = 1;
+ }
+
+ snprintf(
+ dict_file_name,
+ dict_file_name_alloc_size,
+ "%s%s%u.zstd-dict",
+ stuff->dict_file_dir_name,
+ dir_needs_separator ? "/" : "",
+ dict_id);
+
+ /* fprintf(stderr, "Loading dict %u from '%s'.\n", dict_id, dict_file_name); */
+
+ ddict = readDict(dict_file_name, buf, size, &read_dict_id);
+ if (ddict == NULL) {
+ fprintf(stderr, "Failed to create ddict from '%s'.\n", dict_file_name);
+ free(dict_file_name);
+ return 0;
+ }
+ if (read_dict_id != dict_id) {
+ fprintf(stderr, "Read dictID (%u) does not match expected (%u).\n", read_dict_id, dict_id);
+ free(dict_file_name);
+ ZSTD_freeDDict(ddict);
+ return 0;
+ }
+
+ free(dict_file_name);
+ return ddict;
+ }
+}
+
+static int init_stuff(stuff_t* stuff, int argc, char *argv[]) {
+ const char* input_filename;
+
+ if (argc < 2) {
+ usage();
+ }
+
+ input_filename = argv[1];
+ stuff->input_size = 0;
+ stuff->input = readFile(input_filename, &stuff->input_size);
+ if (stuff->input == NULL) {
+ fprintf(stderr, "Failed to read input file.\n");
+ return 0;
+ }
+
+ stuff->perturbed = malloc(stuff->input_size);
+ if (stuff->perturbed == NULL) {
+ fprintf(stderr, "malloc failed.\n");
+ return 0;
+ }
+ memcpy(stuff->perturbed, stuff->input, stuff->input_size);
+
+ stuff->output_size = ZSTD_DStreamOutSize();
+ stuff->output = malloc(stuff->output_size);
+ if (stuff->output == NULL) {
+ fprintf(stderr, "malloc failed.\n");
+ return 0;
+ }
+
+ stuff->dict_file_name = NULL;
+ stuff->dict_file_dir_name = NULL;
+ stuff->dict_id = 0;
+ stuff->dict = NULL;
+ stuff->dict_size = 0;
+ stuff->ddict = NULL;
+
+ if (argc > 2) {
+ if (!strcmp(argv[2], "-d")) {
+ if (argc > 3) {
+ stuff->dict_file_name = argv[3];
+ } else {
+ usage();
+ }
+ } else
+ if (!strcmp(argv[2], "-D")) {
+ if (argc > 3) {
+ stuff->dict_file_dir_name = argv[3];
+ } else {
+ usage();
+ }
+ } else {
+ usage();
+ }
+ }
+
+ if (stuff->dict_file_dir_name) {
+ int32_t dict_id = ZSTD_getDictID_fromFrame(stuff->input, stuff->input_size);
+ if (dict_id != 0) {
+ stuff->ddict = readDictByID(stuff, dict_id, &stuff->dict, &stuff->dict_size);
+ if (stuff->ddict == NULL) {
+ fprintf(stderr, "Failed to create cached ddict.\n");
+ return 0;
+ }
+ stuff->dict_id = dict_id;
+ }
+ } else
+ if (stuff->dict_file_name) {
+ stuff->ddict = readDict(stuff->dict_file_name, &stuff->dict, &stuff->dict_size, &stuff->dict_id);
+ if (stuff->ddict == NULL) {
+ fprintf(stderr, "Failed to create ddict from '%s'.\n", stuff->dict_file_name);
+ return 0;
+ }
+ }
+
+ stuff->dctx = ZSTD_createDCtx();
+ if (stuff->dctx == NULL) {
+ return 0;
+ }
+
+ stuff->success_count = 0;
+ memset(stuff->error_counts, 0, sizeof(stuff->error_counts));
+
+ return 1;
+}
+
+static int test_decompress(stuff_t* stuff) {
+ size_t ret;
+ ZSTD_inBuffer in = {stuff->perturbed, stuff->input_size, 0};
+ ZSTD_outBuffer out = {stuff->output, stuff->output_size, 0};
+ ZSTD_DCtx* dctx = stuff->dctx;
+ int32_t custom_dict_id = ZSTD_getDictID_fromFrame(in.src, in.size);
+ char *custom_dict = NULL;
+ size_t custom_dict_size = 0;
+ ZSTD_DDict* custom_ddict = NULL;
+
+ if (custom_dict_id != 0 && custom_dict_id != stuff->dict_id) {
+ /* fprintf(stderr, "Instead of dict %u, this perturbed blob wants dict %u.\n", stuff->dict_id, custom_dict_id); */
+ custom_ddict = readDictByID(stuff, custom_dict_id, &custom_dict, &custom_dict_size);
+ }
+
+ ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
+
+ if (custom_ddict != NULL) {
+ ZSTD_DCtx_refDDict(dctx, custom_ddict);
+ } else {
+ ZSTD_DCtx_refDDict(dctx, stuff->ddict);
+ }
+
+ while (in.pos != in.size) {
+ out.pos = 0;
+ ret = ZSTD_decompressStream(dctx, &out, &in);
+
+ if (ZSTD_isError(ret)) {
+ unsigned int code = ZSTD_getErrorCode(ret);
+ if (code >= ZSTD_error_maxCode) {
+ fprintf(stderr, "Received unexpected error code!\n");
+ exit(1);
+ }
+ stuff->error_counts[code]++;
+ /*
+ fprintf(
+ stderr, "Decompression failed: %s\n", ZSTD_getErrorName(ret));
+ */
+ if (custom_ddict != NULL) {
+ ZSTD_freeDDict(custom_ddict);
+ free(custom_dict);
+ }
+ return 0;
+ }
+ }
+
+ stuff->success_count++;
+
+ if (custom_ddict != NULL) {
+ ZSTD_freeDDict(custom_ddict);
+ free(custom_dict);
+ }
+ return 1;
+}
+
+static int perturb_bits(stuff_t* stuff) {
+ size_t pos;
+ size_t bit;
+ for (pos = 0; pos < stuff->input_size; pos++) {
+ unsigned char old_val = stuff->input[pos];
+ if (pos % 1000 == 0) {
+ fprintf(stderr, "Perturbing byte %zu / %zu\n", pos, stuff->input_size);
+ }
+ for (bit = 0; bit < 8; bit++) {
+ unsigned char new_val = old_val ^ (1 << bit);
+ stuff->perturbed[pos] = new_val;
+ if (test_decompress(stuff)) {
+ fprintf(
+ stderr,
+ "Flipping byte %zu bit %zu (0x%02x -> 0x%02x) "
+ "produced a successful decompression!\n",
+ pos, bit, old_val, new_val);
+ }
+ }
+ stuff->perturbed[pos] = old_val;
+ }
+ return 1;
+}
+
+static int perturb_bytes(stuff_t* stuff) {
+ size_t pos;
+ size_t new_val;
+ for (pos = 0; pos < stuff->input_size; pos++) {
+ unsigned char old_val = stuff->input[pos];
+ if (pos % 1000 == 0) {
+ fprintf(stderr, "Perturbing byte %zu / %zu\n", pos, stuff->input_size);
+ }
+ for (new_val = 0; new_val < 256; new_val++) {
+ stuff->perturbed[pos] = new_val;
+ if (test_decompress(stuff)) {
+ fprintf(
+ stderr,
+ "Changing byte %zu (0x%02x -> 0x%02x) "
+ "produced a successful decompression!\n",
+ pos, old_val, (unsigned char)new_val);
+ }
+ }
+ stuff->perturbed[pos] = old_val;
+ }
+ return 1;
+}
+
+int main(int argc, char* argv[]) {
+ stuff_t stuff;
+
+ if(!init_stuff(&stuff, argc, argv)) {
+ fprintf(stderr, "Failed to init.\n");
+ return 1;
+ }
+
+ if (test_decompress(&stuff)) {
+ fprintf(stderr, "Blob already decompresses successfully!\n");
+ return 1;
+ }
+
+ perturb_bits(&stuff);
+
+ perturb_bytes(&stuff);
+
+ print_summary(&stuff);
+
+ free_stuff(&stuff);
+
+ return 0;
+}
diff --git a/src/zstd/contrib/docker/Dockerfile b/src/zstd/contrib/docker/Dockerfile
new file mode 100644
index 000000000..e06a32c0d
--- /dev/null
+++ b/src/zstd/contrib/docker/Dockerfile
@@ -0,0 +1,20 @@
+# Dockerfile
+# First image to build the binary
+FROM alpine as builder
+
+RUN apk --no-cache add make gcc libc-dev
+COPY . /src
+RUN mkdir /pkg && cd /src && make && make DESTDIR=/pkg install
+
+# Second minimal image to only keep the built binary
+FROM alpine
+
+# Copy the built files
+COPY --from=builder /pkg /
+
+# Copy the license as well
+RUN mkdir -p /usr/local/share/licenses/zstd
+COPY --from=builder /src/LICENSE /usr/local/share/licences/zstd/
+
+# Just run `zstd` if no other command is given
+CMD ["/usr/local/bin/zstd"]
diff --git a/src/zstd/contrib/docker/README.md b/src/zstd/contrib/docker/README.md
new file mode 100644
index 000000000..43f6d7a1a
--- /dev/null
+++ b/src/zstd/contrib/docker/README.md
@@ -0,0 +1,20 @@
+
+## Requirement
+
+The `Dockerfile` script requires a version of `docker` >= 17.05
+
+## Installing docker
+
+The official docker install docs use a ppa with a modern version available:
+https://docs.docker.com/install/linux/docker-ce/ubuntu/
+
+## How to run
+
+`docker build -t zstd .`
+
+## test
+
+```
+echo foo | docker run -i --rm zstd | docker run -i --rm zstd zstdcat
+foo
+```
diff --git a/src/zstd/contrib/gen_html/.gitignore b/src/zstd/contrib/gen_html/.gitignore
new file mode 100644
index 000000000..344611428
--- /dev/null
+++ b/src/zstd/contrib/gen_html/.gitignore
@@ -0,0 +1,3 @@
+# make artefact
+gen_html
+zstd_manual.html
diff --git a/src/zstd/contrib/gen_html/Makefile b/src/zstd/contrib/gen_html/Makefile
new file mode 100644
index 000000000..425f266c4
--- /dev/null
+++ b/src/zstd/contrib/gen_html/Makefile
@@ -0,0 +1,51 @@
+# ################################################################
+# Copyright (c) 2016-present, Facebook, Inc.
+# All rights reserved.
+#
+# This source code is licensed under both the BSD-style license (found in the
+# LICENSE file in the root directory of this source tree) and the GPLv2 (found
+# in the COPYING file in the root directory of this source tree).
+# ################################################################
+
+CXXFLAGS ?= -O3
+CXXFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wno-comment
+CXXFLAGS += $(MOREFLAGS)
+FLAGS = $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS)
+
+ZSTDAPI = ../../lib/zstd.h
+ZSTDMANUAL = ../../doc/zstd_manual.html
+LIBVER_MAJOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(ZSTDAPI)`
+LIBVER_MINOR_SCRIPT:=`sed -n '/define ZSTD_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(ZSTDAPI)`
+LIBVER_PATCH_SCRIPT:=`sed -n '/define ZSTD_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(ZSTDAPI)`
+LIBVER_SCRIPT:= $(LIBVER_MAJOR_SCRIPT).$(LIBVER_MINOR_SCRIPT).$(LIBVER_PATCH_SCRIPT)
+LIBVER := $(shell echo $(LIBVER_SCRIPT))
+
+
+# Define *.exe as extension for Windows systems
+ifneq (,$(filter Windows%,$(OS)))
+EXT =.exe
+else
+EXT =
+endif
+
+
+.PHONY: default
+default: gen_html
+
+.PHONY: all
+all: manual
+
+gen_html: gen_html.cpp
+ $(CXX) $(FLAGS) $^ -o $@$(EXT)
+
+$(ZSTDMANUAL): gen_html $(ZSTDAPI)
+ echo "Update zstd manual in /doc"
+ ./gen_html $(LIBVER) $(ZSTDAPI) $(ZSTDMANUAL)
+
+.PHONY: manual
+manual: gen_html $(ZSTDMANUAL)
+
+.PHONY: clean
+clean:
+ @$(RM) gen_html$(EXT)
+ @echo Cleaning completed
diff --git a/src/zstd/contrib/gen_html/README.md b/src/zstd/contrib/gen_html/README.md
new file mode 100644
index 000000000..63a4caa25
--- /dev/null
+++ b/src/zstd/contrib/gen_html/README.md
@@ -0,0 +1,31 @@
+gen_html - a program for automatic generation of zstd manual
+============================================================
+
+#### Introduction
+
+This simple C++ program generates a single-page HTML manual from `zstd.h`.
+
+The format of recognized comment blocks is following:
+- comments of type `/*!` mean: this is a function declaration; switch comments with declarations
+- comments of type `/**` and `/*-` mean: this is a comment; use a `<H2>` header for the first line
+- comments of type `/*=` and `/**=` mean: use a `<H3>` header and show also all functions until first empty line
+- comments of type `/*X` where `X` is different from above-mentioned are ignored
+
+Moreover:
+- `ZSTDLIB_API` is removed to improve readability
+- `typedef` are detected and included even if uncommented
+- comments of type `/**<` and `/*!<` are detected and only function declaration is highlighted (bold)
+
+
+#### Usage
+
+The program requires 3 parameters:
+```
+gen_html [zstd_version] [input_file] [output_html]
+```
+
+To compile program and generate zstd manual we have used:
+```
+make
+./gen_html.exe 1.1.1 ../../lib/zstd.h zstd_manual.html
+```
diff --git a/src/zstd/contrib/gen_html/gen-zstd-manual.sh b/src/zstd/contrib/gen_html/gen-zstd-manual.sh
new file mode 100755
index 000000000..57a8b6ea5
--- /dev/null
+++ b/src/zstd/contrib/gen_html/gen-zstd-manual.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+LIBVER_MAJOR_SCRIPT=`sed -n '/define ZSTD_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ../../lib/zstd.h`
+LIBVER_MINOR_SCRIPT=`sed -n '/define ZSTD_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ../../lib/zstd.h`
+LIBVER_PATCH_SCRIPT=`sed -n '/define ZSTD_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ../../lib/zstd.h`
+LIBVER_SCRIPT=$LIBVER_MAJOR_SCRIPT.$LIBVER_MINOR_SCRIPT.$LIBVER_PATCH_SCRIPT
+
+echo ZSTD_VERSION=$LIBVER_SCRIPT
+./gen_html $LIBVER_SCRIPT ../../lib/zstd.h ./zstd_manual.html
diff --git a/src/zstd/contrib/gen_html/gen_html.cpp b/src/zstd/contrib/gen_html/gen_html.cpp
new file mode 100644
index 000000000..90d5b21a3
--- /dev/null
+++ b/src/zstd/contrib/gen_html/gen_html.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2016-present, Przemyslaw Skibinski, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+using namespace std;
+
+
+/* trim string at the beginning and at the end */
+void trim(string& s, string characters)
+{
+ size_t p = s.find_first_not_of(characters);
+ s.erase(0, p);
+
+ p = s.find_last_not_of(characters);
+ if (string::npos != p)
+ s.erase(p+1);
+}
+
+
+/* trim C++ style comments */
+void trim_comments(string &s)
+{
+ size_t spos, epos;
+
+ spos = s.find("/*");
+ epos = s.find("*/");
+ s = s.substr(spos+3, epos-(spos+3));
+}
+
+
+/* get lines until a given terminator */
+vector<string> get_lines(vector<string>& input, int& linenum, string terminator)
+{
+ vector<string> out;
+ string line;
+ size_t epos;
+
+ while ((size_t)linenum < input.size()) {
+ line = input[linenum];
+
+ if (terminator.empty() && line.empty()) { linenum--; break; }
+
+ epos = line.find(terminator);
+ if (!terminator.empty() && epos!=string::npos) {
+ out.push_back(line);
+ break;
+ }
+ out.push_back(line);
+ linenum++;
+ }
+ return out;
+}
+
+
+/* print line with ZSTDLIB_API removed and C++ comments not bold */
+void print_line(stringstream &sout, string line)
+{
+ size_t spos;
+
+ if (line.substr(0,12) == "ZSTDLIB_API ") line = line.substr(12);
+ spos = line.find("/*");
+ if (spos!=string::npos) {
+ sout << line.substr(0, spos);
+ sout << "</b>" << line.substr(spos) << "<b>" << endl;
+ } else {
+ // fprintf(stderr, "lines=%s\n", line.c_str());
+ sout << line << endl;
+ }
+}
+
+
+int main(int argc, char *argv[]) {
+ char exclam;
+ int linenum, chapter = 1;
+ vector<string> input, lines, comments, chapters;
+ string line, version;
+ size_t spos, l;
+ stringstream sout;
+ ifstream istream;
+ ofstream ostream;
+
+ if (argc < 4) {
+ cout << "usage: " << argv[0] << " [zstd_version] [input_file] [output_html]" << endl;
+ return 1;
+ }
+
+ version = "zstd " + string(argv[1]) + " Manual";
+
+ istream.open(argv[2], ifstream::in);
+ if (!istream.is_open()) {
+ cout << "Error opening file " << argv[2] << endl;
+ return 1;
+ }
+
+ ostream.open(argv[3], ifstream::out);
+ if (!ostream.is_open()) {
+ cout << "Error opening file " << argv[3] << endl;
+ return 1;
+ }
+
+ while (getline(istream, line)) {
+ input.push_back(line);
+ }
+
+ for (linenum=0; (size_t)linenum < input.size(); linenum++) {
+ line = input[linenum];
+
+ /* typedefs are detected and included even if uncommented */
+ if (line.substr(0,7) == "typedef" && line.find("{")!=string::npos) {
+ lines = get_lines(input, linenum, "}");
+ sout << "<pre><b>";
+ for (l=0; l<lines.size(); l++) {
+ print_line(sout, lines[l]);
+ }
+ sout << "</b></pre><BR>" << endl;
+ continue;
+ }
+
+ /* comments of type /**< and /*!< are detected and only function declaration is highlighted (bold) */
+ if ((line.find("/**<")!=string::npos || line.find("/*!<")!=string::npos) && line.find("*/")!=string::npos) {
+ sout << "<pre><b>";
+ print_line(sout, line);
+ sout << "</b></pre><BR>" << endl;
+ continue;
+ }
+
+ spos = line.find("/**=");
+ if (spos==string::npos) {
+ spos = line.find("/*!");
+ if (spos==string::npos)
+ spos = line.find("/**");
+ if (spos==string::npos)
+ spos = line.find("/*-");
+ if (spos==string::npos)
+ spos = line.find("/*=");
+ if (spos==string::npos)
+ continue;
+ exclam = line[spos+2];
+ }
+ else exclam = '=';
+
+ comments = get_lines(input, linenum, "*/");
+ if (!comments.empty()) comments[0] = line.substr(spos+3);
+ if (!comments.empty()) comments[comments.size()-1] = comments[comments.size()-1].substr(0, comments[comments.size()-1].find("*/"));
+ for (l=0; l<comments.size(); l++) {
+ if (comments[l].find(" *")==0) comments[l] = comments[l].substr(2);
+ else if (comments[l].find(" *")==0) comments[l] = comments[l].substr(3);
+ trim(comments[l], "*-=");
+ }
+ while (!comments.empty() && comments[comments.size()-1].empty()) comments.pop_back(); // remove empty line at the end
+ while (!comments.empty() && comments[0].empty()) comments.erase(comments.begin()); // remove empty line at the start
+
+ /* comments of type /*! mean: this is a function declaration; switch comments with declarations */
+ if (exclam == '!') {
+ if (!comments.empty()) comments.erase(comments.begin()); /* remove first line like "ZSTD_XXX() :" */
+ linenum++;
+ lines = get_lines(input, linenum, "");
+
+ sout << "<pre><b>";
+ for (l=0; l<lines.size(); l++) {
+ // fprintf(stderr, "line[%d]=%s\n", l, lines[l].c_str());
+ string fline = lines[l];
+ if (fline.substr(0, 12) == "ZSTDLIB_API " ||
+ fline.substr(0, 12) == string(12, ' '))
+ fline = fline.substr(12);
+ print_line(sout, fline);
+ }
+ sout << "</b><p>";
+ for (l=0; l<comments.size(); l++) {
+ print_line(sout, comments[l]);
+ }
+ sout << "</p></pre><BR>" << endl << endl;
+ } else if (exclam == '=') { /* comments of type /*= and /**= mean: use a <H3> header and show also all functions until first empty line */
+ trim(comments[0], " ");
+ sout << "<h3>" << comments[0] << "</h3><pre>";
+ for (l=1; l<comments.size(); l++) {
+ print_line(sout, comments[l]);
+ }
+ sout << "</pre><b><pre>";
+ lines = get_lines(input, ++linenum, "");
+ for (l=0; l<lines.size(); l++) {
+ print_line(sout, lines[l]);
+ }
+ sout << "</pre></b><BR>" << endl;
+ } else { /* comments of type /** and /*- mean: this is a comment; use a <H2> header for the first line */
+ if (comments.empty()) continue;
+
+ trim(comments[0], " ");
+ sout << "<a name=\"Chapter" << chapter << "\"></a><h2>" << comments[0] << "</h2><pre>";
+ chapters.push_back(comments[0]);
+ chapter++;
+
+ for (l=1; l<comments.size(); l++) {
+ print_line(sout, comments[l]);
+ }
+ if (comments.size() > 1)
+ sout << "<BR></pre>" << endl << endl;
+ else
+ sout << "</pre>" << endl << endl;
+ }
+ }
+
+ ostream << "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\n<title>" << version << "</title>\n</head>\n<body>" << endl;
+ ostream << "<h1>" << version << "</h1>\n";
+
+ ostream << "<hr>\n<a name=\"Contents\"></a><h2>Contents</h2>\n<ol>\n";
+ for (size_t i=0; i<chapters.size(); i++)
+ ostream << "<li><a href=\"#Chapter" << i+1 << "\">" << chapters[i].c_str() << "</a></li>\n";
+ ostream << "</ol>\n<hr>\n";
+
+ ostream << sout.str();
+ ostream << "</html>" << endl << "</body>" << endl;
+
+ return 0;
+}
diff --git a/src/zstd/contrib/largeNbDicts/.gitignore b/src/zstd/contrib/largeNbDicts/.gitignore
new file mode 100644
index 000000000..e77c4e496
--- /dev/null
+++ b/src/zstd/contrib/largeNbDicts/.gitignore
@@ -0,0 +1,2 @@
+# build artifacts
+largeNbDicts
diff --git a/src/zstd/contrib/largeNbDicts/Makefile b/src/zstd/contrib/largeNbDicts/Makefile
new file mode 100644
index 000000000..4c055b0ed
--- /dev/null
+++ b/src/zstd/contrib/largeNbDicts/Makefile
@@ -0,0 +1,58 @@
+# ################################################################
+# Copyright (c) 2018-present, Yann Collet, Facebook, Inc.
+# All rights reserved.
+#
+# This source code is licensed under both the BSD-style license (found in the
+# LICENSE file in the root directory of this source tree) and the GPLv2 (found
+# in the COPYING file in the root directory of this source tree).
+# ################################################################
+
+PROGDIR = ../../programs
+LIBDIR = ../../lib
+
+LIBZSTD = $(LIBDIR)/libzstd.a
+
+CPPFLAGS+= -I$(LIBDIR) -I$(LIBDIR)/common -I$(LIBDIR)/dictBuilder -I$(PROGDIR)
+
+CFLAGS ?= -O3
+CFLAGS += -std=gnu99
+DEBUGFLAGS= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
+ -Wstrict-aliasing=1 -Wswitch-enum \
+ -Wstrict-prototypes -Wundef -Wpointer-arith \
+ -Wvla -Wformat=2 -Winit-self -Wfloat-equal -Wwrite-strings \
+ -Wredundant-decls
+CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
+
+
+default: largeNbDicts
+
+all : largeNbDicts
+
+largeNbDicts: util.o timefn.o benchfn.o datagen.o xxhash.o largeNbDicts.c $(LIBZSTD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+.PHONY: $(LIBZSTD)
+$(LIBZSTD):
+ $(MAKE) -C $(LIBDIR) libzstd.a CFLAGS="$(CFLAGS)"
+
+benchfn.o: $(PROGDIR)/benchfn.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ -c
+
+timefn.o: $(PROGDIR)/timefn.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ -c
+
+datagen.o: $(PROGDIR)/datagen.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ -c
+
+util.o: $(PROGDIR)/util.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ -c
+
+
+xxhash.o : $(LIBDIR)/common/xxhash.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ -c
+
+
+clean:
+ $(RM) *.o
+ $(MAKE) -C $(LIBDIR) clean > /dev/null
+ $(RM) largeNbDicts
diff --git a/src/zstd/contrib/largeNbDicts/README.md b/src/zstd/contrib/largeNbDicts/README.md
new file mode 100644
index 000000000..f29bcdfe8
--- /dev/null
+++ b/src/zstd/contrib/largeNbDicts/README.md
@@ -0,0 +1,25 @@
+largeNbDicts
+=====================
+
+`largeNbDicts` is a benchmark test tool
+dedicated to the specific scenario of
+dictionary decompression using a very large number of dictionaries.
+When dictionaries are constantly changing, they are always "cold",
+suffering from increased latency due to cache misses.
+
+The tool is created in a bid to investigate performance for this scenario,
+and experiment mitigation techniques.
+
+Command line :
+```
+largeNbDicts [Options] filename(s)
+
+Options :
+-r : recursively load all files in subdirectories (default: off)
+-B# : split input into blocks of size # (default: no split)
+-# : use compression level # (default: 3)
+-D # : use # as a dictionary (default: create one)
+-i# : nb benchmark rounds (default: 6)
+--nbDicts=# : set nb of dictionaries to # (default: one per block)
+-h : help (this text)
+```
diff --git a/src/zstd/contrib/largeNbDicts/largeNbDicts.c b/src/zstd/contrib/largeNbDicts/largeNbDicts.c
new file mode 100644
index 000000000..c84d48b24
--- /dev/null
+++ b/src/zstd/contrib/largeNbDicts/largeNbDicts.c
@@ -0,0 +1,979 @@
+/*
+ * Copyright (c) 2018-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* largeNbDicts
+ * This is a benchmark test tool
+ * dedicated to the specific case of dictionary decompression
+ * using a very large nb of dictionaries
+ * thus suffering latency from lots of cache misses.
+ * It's created in a bid to investigate performance and find optimizations. */
+
+
+/*--- Dependencies ---*/
+
+#include <stddef.h> /* size_t */
+#include <stdlib.h> /* malloc, free, abort */
+#include <stdio.h> /* fprintf */
+#include <limits.h> /* UINT_MAX */
+#include <assert.h> /* assert */
+
+#include "util.h"
+#include "benchfn.h"
+#define ZSTD_STATIC_LINKING_ONLY
+#include "zstd.h"
+#include "zdict.h"
+
+
+/*--- Constants --- */
+
+#define KB *(1<<10)
+#define MB *(1<<20)
+
+#define BLOCKSIZE_DEFAULT 0 /* no slicing into blocks */
+#define DICTSIZE (4 KB)
+#define CLEVEL_DEFAULT 3
+
+#define BENCH_TIME_DEFAULT_S 6
+#define RUN_TIME_DEFAULT_MS 1000
+#define BENCH_TIME_DEFAULT_MS (BENCH_TIME_DEFAULT_S * RUN_TIME_DEFAULT_MS)
+
+#define DISPLAY_LEVEL_DEFAULT 3
+
+#define BENCH_SIZE_MAX (1200 MB)
+
+
+/*--- Macros ---*/
+
+#define CONTROL(c) { if (!(c)) abort(); }
+#undef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+
+/*--- Display Macros ---*/
+
+#define DISPLAY(...) fprintf(stdout, __VA_ARGS__)
+#define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } }
+static int g_displayLevel = DISPLAY_LEVEL_DEFAULT; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */
+
+
+/*--- buffer_t ---*/
+
+typedef struct {
+ void* ptr;
+ size_t size;
+ size_t capacity;
+} buffer_t;
+
+static const buffer_t kBuffNull = { NULL, 0, 0 };
+
+/* @return : kBuffNull if any error */
+static buffer_t createBuffer(size_t capacity)
+{
+ assert(capacity > 0);
+ void* const ptr = malloc(capacity);
+ if (ptr==NULL) return kBuffNull;
+
+ buffer_t buffer;
+ buffer.ptr = ptr;
+ buffer.capacity = capacity;
+ buffer.size = 0;
+ return buffer;
+}
+
+static void freeBuffer(buffer_t buff)
+{
+ free(buff.ptr);
+}
+
+
+static void fillBuffer_fromHandle(buffer_t* buff, FILE* f)
+{
+ size_t const readSize = fread(buff->ptr, 1, buff->capacity, f);
+ buff->size = readSize;
+}
+
+
+/* @return : kBuffNull if any error */
+static buffer_t createBuffer_fromFile(const char* fileName)
+{
+ U64 const fileSize = UTIL_getFileSize(fileName);
+ size_t const bufferSize = (size_t) fileSize;
+
+ if (fileSize == UTIL_FILESIZE_UNKNOWN) return kBuffNull;
+ assert((U64)bufferSize == fileSize); /* check overflow */
+
+ { FILE* const f = fopen(fileName, "rb");
+ if (f == NULL) return kBuffNull;
+
+ buffer_t buff = createBuffer(bufferSize);
+ CONTROL(buff.ptr != NULL);
+
+ fillBuffer_fromHandle(&buff, f);
+ CONTROL(buff.size == buff.capacity);
+
+ fclose(f); /* do nothing specific if fclose() fails */
+ return buff;
+ }
+}
+
+
+/* @return : kBuffNull if any error */
+static buffer_t
+createDictionaryBuffer(const char* dictionaryName,
+ const void* srcBuffer,
+ const size_t* srcBlockSizes, size_t nbBlocks,
+ size_t requestedDictSize)
+{
+ if (dictionaryName) {
+ DISPLAYLEVEL(3, "loading dictionary %s \n", dictionaryName);
+ return createBuffer_fromFile(dictionaryName); /* note : result might be kBuffNull */
+
+ } else {
+
+ DISPLAYLEVEL(3, "creating dictionary, of target size %u bytes \n",
+ (unsigned)requestedDictSize);
+ void* const dictBuffer = malloc(requestedDictSize);
+ CONTROL(dictBuffer != NULL);
+
+ assert(nbBlocks <= UINT_MAX);
+ size_t const dictSize = ZDICT_trainFromBuffer(dictBuffer, requestedDictSize,
+ srcBuffer,
+ srcBlockSizes, (unsigned)nbBlocks);
+ CONTROL(!ZSTD_isError(dictSize));
+
+ buffer_t result;
+ result.ptr = dictBuffer;
+ result.capacity = requestedDictSize;
+ result.size = dictSize;
+ return result;
+ }
+}
+
+
+/*! BMK_loadFiles() :
+ * Loads `buffer`, with content from files listed within `fileNamesTable`.
+ * Fills `buffer` entirely.
+ * @return : 0 on success, !=0 on error */
+static int loadFiles(void* buffer, size_t bufferSize,
+ size_t* fileSizes,
+ const char* const * fileNamesTable, unsigned nbFiles)
+{
+ size_t pos = 0, totalSize = 0;
+
+ for (unsigned n=0; n<nbFiles; n++) {
+ U64 fileSize = UTIL_getFileSize(fileNamesTable[n]);
+ if (UTIL_isDirectory(fileNamesTable[n])) {
+ fileSizes[n] = 0;
+ continue;
+ }
+ if (fileSize == UTIL_FILESIZE_UNKNOWN) {
+ fileSizes[n] = 0;
+ continue;
+ }
+
+ FILE* const f = fopen(fileNamesTable[n], "rb");
+ assert(f!=NULL);
+
+ assert(pos <= bufferSize);
+ assert(fileSize <= bufferSize - pos);
+
+ { size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f);
+ assert(readSize == fileSize);
+ pos += readSize;
+ }
+ fileSizes[n] = (size_t)fileSize;
+ totalSize += (size_t)fileSize;
+ fclose(f);
+ }
+
+ assert(totalSize == bufferSize);
+ return 0;
+}
+
+
+
+/*--- slice_collection_t ---*/
+
+typedef struct {
+ void** slicePtrs;
+ size_t* capacities;
+ size_t nbSlices;
+} slice_collection_t;
+
+static const slice_collection_t kNullCollection = { NULL, NULL, 0 };
+
+static void freeSliceCollection(slice_collection_t collection)
+{
+ free(collection.slicePtrs);
+ free(collection.capacities);
+}
+
+/* shrinkSizes() :
+ * downsizes sizes of slices within collection, according to `newSizes`.
+ * every `newSizes` entry must be <= than its corresponding collection size */
+void shrinkSizes(slice_collection_t collection,
+ const size_t* newSizes) /* presumed same size as collection */
+{
+ size_t const nbSlices = collection.nbSlices;
+ for (size_t blockNb = 0; blockNb < nbSlices; blockNb++) {
+ assert(newSizes[blockNb] <= collection.capacities[blockNb]);
+ collection.capacities[blockNb] = newSizes[blockNb];
+ }
+}
+
+
+/* splitSlices() :
+ * nbSlices : if == 0, nbSlices is automatically determined from srcSlices and blockSize.
+ * otherwise, creates exactly nbSlices slices,
+ * by either truncating input (when smaller)
+ * or repeating input from beginning */
+static slice_collection_t
+splitSlices(slice_collection_t srcSlices, size_t blockSize, size_t nbSlices)
+{
+ if (blockSize==0) blockSize = (size_t)(-1); /* means "do not cut" */
+ size_t nbSrcBlocks = 0;
+ for (size_t ssnb=0; ssnb < srcSlices.nbSlices; ssnb++) {
+ size_t pos = 0;
+ while (pos <= srcSlices.capacities[ssnb]) {
+ nbSrcBlocks++;
+ pos += blockSize;
+ }
+ }
+
+ if (nbSlices == 0) nbSlices = nbSrcBlocks;
+
+ void** const sliceTable = (void**)malloc(nbSlices * sizeof(*sliceTable));
+ size_t* const capacities = (size_t*)malloc(nbSlices * sizeof(*capacities));
+ if (sliceTable == NULL || capacities == NULL) {
+ free(sliceTable);
+ free(capacities);
+ return kNullCollection;
+ }
+
+ size_t ssnb = 0;
+ for (size_t sliceNb=0; sliceNb < nbSlices; ) {
+ ssnb = (ssnb + 1) % srcSlices.nbSlices;
+ size_t pos = 0;
+ char* const ptr = (char*)srcSlices.slicePtrs[ssnb];
+ while (pos < srcSlices.capacities[ssnb] && sliceNb < nbSlices) {
+ size_t const size = MIN(blockSize, srcSlices.capacities[ssnb] - pos);
+ sliceTable[sliceNb] = ptr + pos;
+ capacities[sliceNb] = size;
+ sliceNb++;
+ pos += blockSize;
+ }
+ }
+
+ slice_collection_t result;
+ result.nbSlices = nbSlices;
+ result.slicePtrs = sliceTable;
+ result.capacities = capacities;
+ return result;
+}
+
+
+static size_t sliceCollection_totalCapacity(slice_collection_t sc)
+{
+ size_t totalSize = 0;
+ for (size_t n=0; n<sc.nbSlices; n++)
+ totalSize += sc.capacities[n];
+ return totalSize;
+}
+
+
+/* --- buffer collection --- */
+
+typedef struct {
+ buffer_t buffer;
+ slice_collection_t slices;
+} buffer_collection_t;
+
+
+static void freeBufferCollection(buffer_collection_t bc)
+{
+ freeBuffer(bc.buffer);
+ freeSliceCollection(bc.slices);
+}
+
+
+static buffer_collection_t
+createBufferCollection_fromSliceCollectionSizes(slice_collection_t sc)
+{
+ size_t const bufferSize = sliceCollection_totalCapacity(sc);
+
+ buffer_t buffer = createBuffer(bufferSize);
+ CONTROL(buffer.ptr != NULL);
+
+ size_t const nbSlices = sc.nbSlices;
+ void** const slices = (void**)malloc(nbSlices * sizeof(*slices));
+ CONTROL(slices != NULL);
+
+ size_t* const capacities = (size_t*)malloc(nbSlices * sizeof(*capacities));
+ CONTROL(capacities != NULL);
+
+ char* const ptr = (char*)buffer.ptr;
+ size_t pos = 0;
+ for (size_t n=0; n < nbSlices; n++) {
+ capacities[n] = sc.capacities[n];
+ slices[n] = ptr + pos;
+ pos += capacities[n];
+ }
+
+ buffer_collection_t result;
+ result.buffer = buffer;
+ result.slices.nbSlices = nbSlices;
+ result.slices.capacities = capacities;
+ result.slices.slicePtrs = slices;
+ return result;
+}
+
+static buffer_collection_t
+createBufferCollection_fromSliceCollection(slice_collection_t sc)
+{
+ size_t const bufferSize = sliceCollection_totalCapacity(sc);
+
+ buffer_t buffer = createBuffer(bufferSize);
+ CONTROL(buffer.ptr != NULL);
+
+ size_t const nbSlices = sc.nbSlices;
+ void** const slices = (void**)malloc(nbSlices * sizeof(*slices));
+ CONTROL(slices != NULL);
+
+ size_t* const capacities = (size_t*)malloc(nbSlices * sizeof(*capacities));
+ CONTROL(capacities != NULL);
+
+ char* const ptr = (char*)buffer.ptr;
+ size_t pos = 0;
+ for (size_t n=0; n < nbSlices; n++) {
+ capacities[n] = sc.capacities[n];
+ slices[n] = ptr + pos;
+ pos += capacities[n];
+ }
+
+ for (size_t i = 0; i < nbSlices; i++) {
+ memcpy(slices[i], sc.slicePtrs[i], sc.capacities[i]);
+ capacities[i] = sc.capacities[i];
+ }
+
+ buffer_collection_t result;
+ result.buffer = buffer;
+ result.slices.nbSlices = nbSlices;
+ result.slices.capacities = capacities;
+ result.slices.slicePtrs = slices;
+
+ return result;
+}
+
+/* @return : kBuffNull if any error */
+static buffer_collection_t
+createBufferCollection_fromFiles(const char* const * fileNamesTable, unsigned nbFiles)
+{
+ U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
+ assert(totalSizeToLoad != UTIL_FILESIZE_UNKNOWN);
+ assert(totalSizeToLoad <= BENCH_SIZE_MAX);
+ size_t const loadedSize = (size_t)totalSizeToLoad;
+ assert(loadedSize > 0);
+ void* const srcBuffer = malloc(loadedSize);
+ assert(srcBuffer != NULL);
+
+ assert(nbFiles > 0);
+ size_t* const fileSizes = (size_t*)calloc(nbFiles, sizeof(*fileSizes));
+ assert(fileSizes != NULL);
+
+ /* Load input buffer */
+ int const errorCode = loadFiles(srcBuffer, loadedSize,
+ fileSizes,
+ fileNamesTable, nbFiles);
+ assert(errorCode == 0);
+
+ void** sliceTable = (void**)malloc(nbFiles * sizeof(*sliceTable));
+ assert(sliceTable != NULL);
+
+ char* const ptr = (char*)srcBuffer;
+ size_t pos = 0;
+ unsigned fileNb = 0;
+ for ( ; (pos < loadedSize) && (fileNb < nbFiles); fileNb++) {
+ sliceTable[fileNb] = ptr + pos;
+ pos += fileSizes[fileNb];
+ }
+ assert(pos == loadedSize);
+ assert(fileNb == nbFiles);
+
+
+ buffer_t buffer;
+ buffer.ptr = srcBuffer;
+ buffer.capacity = loadedSize;
+ buffer.size = loadedSize;
+
+ slice_collection_t slices;
+ slices.slicePtrs = sliceTable;
+ slices.capacities = fileSizes;
+ slices.nbSlices = nbFiles;
+
+ buffer_collection_t bc;
+ bc.buffer = buffer;
+ bc.slices = slices;
+ return bc;
+}
+
+
+
+
+/*--- ddict_collection_t ---*/
+
+typedef struct {
+ ZSTD_DDict** ddicts;
+ size_t nbDDict;
+} ddict_collection_t;
+
+typedef struct {
+ ZSTD_CDict** cdicts;
+ size_t nbCDict;
+} cdict_collection_t;
+
+static const cdict_collection_t kNullCDictCollection = { NULL, 0 };
+
+static void freeCDictCollection(cdict_collection_t cdictc)
+{
+ for (size_t dictNb=0; dictNb < cdictc.nbCDict; dictNb++) {
+ ZSTD_freeCDict(cdictc.cdicts[dictNb]);
+ }
+ free(cdictc.cdicts);
+}
+
+/* returns .buffers=NULL if operation fails */
+static cdict_collection_t createCDictCollection(const void* dictBuffer, size_t dictSize, size_t nbCDict, int cLevel)
+{
+ ZSTD_CDict** const cdicts = malloc(nbCDict * sizeof(ZSTD_CDict*));
+ if (cdicts==NULL) return kNullCDictCollection;
+ for (size_t dictNb=0; dictNb < nbCDict; dictNb++) {
+ cdicts[dictNb] = ZSTD_createCDict(dictBuffer, dictSize, cLevel);
+ CONTROL(cdicts[dictNb] != NULL);
+ }
+ cdict_collection_t cdictc;
+ cdictc.cdicts = cdicts;
+ cdictc.nbCDict = nbCDict;
+ return cdictc;
+}
+
+static const ddict_collection_t kNullDDictCollection = { NULL, 0 };
+
+static void freeDDictCollection(ddict_collection_t ddictc)
+{
+ for (size_t dictNb=0; dictNb < ddictc.nbDDict; dictNb++) {
+ ZSTD_freeDDict(ddictc.ddicts[dictNb]);
+ }
+ free(ddictc.ddicts);
+}
+
+/* returns .buffers=NULL if operation fails */
+static ddict_collection_t createDDictCollection(const void* dictBuffer, size_t dictSize, size_t nbDDict)
+{
+ ZSTD_DDict** const ddicts = malloc(nbDDict * sizeof(ZSTD_DDict*));
+ assert(ddicts != NULL);
+ if (ddicts==NULL) return kNullDDictCollection;
+ for (size_t dictNb=0; dictNb < nbDDict; dictNb++) {
+ ddicts[dictNb] = ZSTD_createDDict(dictBuffer, dictSize);
+ assert(ddicts[dictNb] != NULL);
+ }
+ ddict_collection_t ddictc;
+ ddictc.ddicts = ddicts;
+ ddictc.nbDDict = nbDDict;
+ return ddictc;
+}
+
+
+/* mess with addresses, so that linear scanning dictionaries != linear address scanning */
+void shuffleCDictionaries(cdict_collection_t dicts)
+{
+ size_t const nbDicts = dicts.nbCDict;
+ for (size_t r=0; r<nbDicts; r++) {
+ size_t const d = (size_t)rand() % nbDicts;
+ ZSTD_CDict* tmpd = dicts.cdicts[d];
+ dicts.cdicts[d] = dicts.cdicts[r];
+ dicts.cdicts[r] = tmpd;
+ }
+ for (size_t r=0; r<nbDicts; r++) {
+ size_t const d1 = (size_t)rand() % nbDicts;
+ size_t const d2 = (size_t)rand() % nbDicts;
+ ZSTD_CDict* tmpd = dicts.cdicts[d1];
+ dicts.cdicts[d1] = dicts.cdicts[d2];
+ dicts.cdicts[d2] = tmpd;
+ }
+}
+
+/* mess with addresses, so that linear scanning dictionaries != linear address scanning */
+void shuffleDDictionaries(ddict_collection_t dicts)
+{
+ size_t const nbDicts = dicts.nbDDict;
+ for (size_t r=0; r<nbDicts; r++) {
+ size_t const d = (size_t)rand() % nbDicts;
+ ZSTD_DDict* tmpd = dicts.ddicts[d];
+ dicts.ddicts[d] = dicts.ddicts[r];
+ dicts.ddicts[r] = tmpd;
+ }
+ for (size_t r=0; r<nbDicts; r++) {
+ size_t const d1 = (size_t)rand() % nbDicts;
+ size_t const d2 = (size_t)rand() % nbDicts;
+ ZSTD_DDict* tmpd = dicts.ddicts[d1];
+ dicts.ddicts[d1] = dicts.ddicts[d2];
+ dicts.ddicts[d2] = tmpd;
+ }
+}
+
+
+/* --- Compression --- */
+
+/* compressBlocks() :
+ * @return : total compressed size of all blocks,
+ * or 0 if error.
+ */
+static size_t compressBlocks(size_t* cSizes, /* optional (can be NULL). If present, must contain at least nbBlocks fields */
+ slice_collection_t dstBlockBuffers,
+ slice_collection_t srcBlockBuffers,
+ ZSTD_CDict* cdict, int cLevel)
+{
+ size_t const nbBlocks = srcBlockBuffers.nbSlices;
+ assert(dstBlockBuffers.nbSlices == srcBlockBuffers.nbSlices);
+
+ ZSTD_CCtx* const cctx = ZSTD_createCCtx();
+ assert(cctx != NULL);
+
+ size_t totalCSize = 0;
+ for (size_t blockNb=0; blockNb < nbBlocks; blockNb++) {
+ size_t cBlockSize;
+ if (cdict == NULL) {
+ cBlockSize = ZSTD_compressCCtx(cctx,
+ dstBlockBuffers.slicePtrs[blockNb], dstBlockBuffers.capacities[blockNb],
+ srcBlockBuffers.slicePtrs[blockNb], srcBlockBuffers.capacities[blockNb],
+ cLevel);
+ } else {
+ cBlockSize = ZSTD_compress_usingCDict(cctx,
+ dstBlockBuffers.slicePtrs[blockNb], dstBlockBuffers.capacities[blockNb],
+ srcBlockBuffers.slicePtrs[blockNb], srcBlockBuffers.capacities[blockNb],
+ cdict);
+ }
+ CONTROL(!ZSTD_isError(cBlockSize));
+ if (cSizes) cSizes[blockNb] = cBlockSize;
+ totalCSize += cBlockSize;
+ }
+ return totalCSize;
+}
+
+
+/* --- Benchmark --- */
+
+typedef struct {
+ ZSTD_CCtx* cctx;
+ size_t nbDicts;
+ size_t dictNb;
+ cdict_collection_t dictionaries;
+} compressInstructions;
+
+compressInstructions createCompressInstructions(cdict_collection_t dictionaries)
+{
+ compressInstructions ci;
+ ci.cctx = ZSTD_createCCtx();
+ CONTROL(ci.cctx != NULL);
+ ci.nbDicts = dictionaries.nbCDict;
+ ci.dictNb = 0;
+ ci.dictionaries = dictionaries;
+ return ci;
+}
+
+void freeCompressInstructions(compressInstructions ci)
+{
+ ZSTD_freeCCtx(ci.cctx);
+}
+
+typedef struct {
+ ZSTD_DCtx* dctx;
+ size_t nbDicts;
+ size_t dictNb;
+ ddict_collection_t dictionaries;
+} decompressInstructions;
+
+decompressInstructions createDecompressInstructions(ddict_collection_t dictionaries)
+{
+ decompressInstructions di;
+ di.dctx = ZSTD_createDCtx();
+ assert(di.dctx != NULL);
+ di.nbDicts = dictionaries.nbDDict;
+ di.dictNb = 0;
+ di.dictionaries = dictionaries;
+ return di;
+}
+
+void freeDecompressInstructions(decompressInstructions di)
+{
+ ZSTD_freeDCtx(di.dctx);
+}
+
+/* benched function */
+size_t compress(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* payload)
+{
+ compressInstructions* const ci = (compressInstructions*) payload;
+ (void)dstCapacity;
+
+ ZSTD_compress_usingCDict(ci->cctx,
+ dst, srcSize,
+ src, srcSize,
+ ci->dictionaries.cdicts[ci->dictNb]);
+
+ ci->dictNb = ci->dictNb + 1;
+ if (ci->dictNb >= ci->nbDicts) ci->dictNb = 0;
+
+ return srcSize;
+}
+
+/* benched function */
+size_t decompress(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* payload)
+{
+ decompressInstructions* const di = (decompressInstructions*) payload;
+
+ size_t const result = ZSTD_decompress_usingDDict(di->dctx,
+ dst, dstCapacity,
+ src, srcSize,
+ di->dictionaries.ddicts[di->dictNb]);
+
+ di->dictNb = di->dictNb + 1;
+ if (di->dictNb >= di->nbDicts) di->dictNb = 0;
+
+ return result;
+}
+
+
+static int benchMem(slice_collection_t dstBlocks,
+ slice_collection_t srcBlocks,
+ ddict_collection_t ddictionaries,
+ cdict_collection_t cdictionaries,
+ unsigned nbRounds, int benchCompression)
+{
+ assert(dstBlocks.nbSlices == srcBlocks.nbSlices);
+
+ unsigned const ms_per_round = RUN_TIME_DEFAULT_MS;
+ unsigned const total_time_ms = nbRounds * ms_per_round;
+
+ double bestSpeed = 0.;
+
+ BMK_timedFnState_t* const benchState =
+ BMK_createTimedFnState(total_time_ms, ms_per_round);
+
+ decompressInstructions di = createDecompressInstructions(ddictionaries);
+ compressInstructions ci = createCompressInstructions(cdictionaries);
+ void* payload = benchCompression ? (void*)&ci : (void*)&di;
+ BMK_benchParams_t const bp = {
+ .benchFn = benchCompression ? compress : decompress,
+ .benchPayload = payload,
+ .initFn = NULL,
+ .initPayload = NULL,
+ .errorFn = ZSTD_isError,
+ .blockCount = dstBlocks.nbSlices,
+ .srcBuffers = (const void* const*) srcBlocks.slicePtrs,
+ .srcSizes = srcBlocks.capacities,
+ .dstBuffers = dstBlocks.slicePtrs,
+ .dstCapacities = dstBlocks.capacities,
+ .blockResults = NULL
+ };
+
+ for (;;) {
+ BMK_runOutcome_t const outcome = BMK_benchTimedFn(benchState, bp);
+ CONTROL(BMK_isSuccessful_runOutcome(outcome));
+
+ BMK_runTime_t const result = BMK_extract_runTime(outcome);
+ double const dTime_ns = result.nanoSecPerRun;
+ double const dTime_sec = (double)dTime_ns / 1000000000;
+ size_t const srcSize = result.sumOfReturn;
+ double const speed_MBps = (double)srcSize / dTime_sec / (1 MB);
+ if (speed_MBps > bestSpeed) bestSpeed = speed_MBps;
+ if (benchCompression)
+ DISPLAY("Compression Speed : %.1f MB/s \r", bestSpeed);
+ else
+ DISPLAY("Decompression Speed : %.1f MB/s \r", bestSpeed);
+
+ fflush(stdout);
+ if (BMK_isCompleted_TimedFn(benchState)) break;
+ }
+ DISPLAY("\n");
+
+ freeDecompressInstructions(di);
+ freeCompressInstructions(ci);
+ BMK_freeTimedFnState(benchState);
+
+ return 0; /* success */
+}
+
+
+/*! bench() :
+ * fileName : file to load for benchmarking purpose
+ * dictionary : optional (can be NULL), file to load as dictionary,
+ * if none provided : will be calculated on the fly by the program.
+ * @return : 0 is success, 1+ otherwise */
+int bench(const char** fileNameTable, unsigned nbFiles,
+ const char* dictionary,
+ size_t blockSize, int clevel,
+ unsigned nbDictMax, unsigned nbBlocks,
+ unsigned nbRounds, int benchCompression)
+{
+ int result = 0;
+
+ DISPLAYLEVEL(3, "loading %u files... \n", nbFiles);
+ buffer_collection_t const srcs = createBufferCollection_fromFiles(fileNameTable, nbFiles);
+ CONTROL(srcs.buffer.ptr != NULL);
+ buffer_t srcBuffer = srcs.buffer;
+ size_t const srcSize = srcBuffer.size;
+ DISPLAYLEVEL(3, "created src buffer of size %.1f MB \n",
+ (double)srcSize / (1 MB));
+
+ slice_collection_t const srcSlices = splitSlices(srcs.slices, blockSize, nbBlocks);
+ nbBlocks = (unsigned)(srcSlices.nbSlices);
+ DISPLAYLEVEL(3, "split input into %u blocks ", nbBlocks);
+ if (blockSize)
+ DISPLAYLEVEL(3, "of max size %u bytes ", (unsigned)blockSize);
+ DISPLAYLEVEL(3, "\n");
+ size_t const totalSrcSlicesSize = sliceCollection_totalCapacity(srcSlices);
+
+
+ size_t* const dstCapacities = malloc(nbBlocks * sizeof(*dstCapacities));
+ CONTROL(dstCapacities != NULL);
+ size_t dstBufferCapacity = 0;
+ for (size_t bnb=0; bnb<nbBlocks; bnb++) {
+ dstCapacities[bnb] = ZSTD_compressBound(srcSlices.capacities[bnb]);
+ dstBufferCapacity += dstCapacities[bnb];
+ }
+
+ buffer_t dstBuffer = createBuffer(dstBufferCapacity);
+ CONTROL(dstBuffer.ptr != NULL);
+
+ void** const sliceTable = malloc(nbBlocks * sizeof(*sliceTable));
+ CONTROL(sliceTable != NULL);
+
+ { char* const ptr = dstBuffer.ptr;
+ size_t pos = 0;
+ for (size_t snb=0; snb < nbBlocks; snb++) {
+ sliceTable[snb] = ptr + pos;
+ pos += dstCapacities[snb];
+ } }
+
+ slice_collection_t dstSlices;
+ dstSlices.capacities = dstCapacities;
+ dstSlices.slicePtrs = sliceTable;
+ dstSlices.nbSlices = nbBlocks;
+
+
+ /* dictionary determination */
+ buffer_t const dictBuffer = createDictionaryBuffer(dictionary,
+ srcs.buffer.ptr,
+ srcs.slices.capacities, srcs.slices.nbSlices,
+ DICTSIZE);
+ CONTROL(dictBuffer.ptr != NULL);
+
+ ZSTD_CDict* const cdict = ZSTD_createCDict(dictBuffer.ptr, dictBuffer.size, clevel);
+ CONTROL(cdict != NULL);
+
+ size_t const cTotalSizeNoDict = compressBlocks(NULL, dstSlices, srcSlices, NULL, clevel);
+ CONTROL(cTotalSizeNoDict != 0);
+ DISPLAYLEVEL(3, "compressing at level %u without dictionary : Ratio=%.2f (%u bytes) \n",
+ clevel,
+ (double)totalSrcSlicesSize / cTotalSizeNoDict, (unsigned)cTotalSizeNoDict);
+
+ size_t* const cSizes = malloc(nbBlocks * sizeof(size_t));
+ CONTROL(cSizes != NULL);
+
+ size_t const cTotalSize = compressBlocks(cSizes, dstSlices, srcSlices, cdict, clevel);
+ CONTROL(cTotalSize != 0);
+ DISPLAYLEVEL(3, "compressed using a %u bytes dictionary : Ratio=%.2f (%u bytes) \n",
+ (unsigned)dictBuffer.size,
+ (double)totalSrcSlicesSize / cTotalSize, (unsigned)cTotalSize);
+
+ /* now dstSlices contain the real compressed size of each block, instead of the maximum capacity */
+ shrinkSizes(dstSlices, cSizes);
+
+ unsigned const nbDicts = nbDictMax ? nbDictMax : nbBlocks;
+
+ cdict_collection_t const cdictionaries = createCDictCollection(dictBuffer.ptr, dictBuffer.size, nbDicts, clevel);
+ CONTROL(cdictionaries.cdicts != NULL);
+
+ ddict_collection_t const ddictionaries = createDDictCollection(dictBuffer.ptr, dictBuffer.size, nbDicts);
+ CONTROL(ddictionaries.ddicts != NULL);
+
+ if (benchCompression) {
+ size_t const dictMem = ZSTD_estimateCDictSize(dictBuffer.size, ZSTD_dlm_byCopy);
+ size_t const allDictMem = dictMem * nbDicts;
+ DISPLAYLEVEL(3, "generating %u dictionaries, using %.1f MB of memory \n",
+ nbDicts, (double)allDictMem / (1 MB));
+
+ shuffleCDictionaries(cdictionaries);
+
+ buffer_collection_t resultCollection = createBufferCollection_fromSliceCollection(srcSlices);
+ CONTROL(resultCollection.buffer.ptr != NULL);
+
+ result = benchMem(dstSlices, resultCollection.slices, ddictionaries, cdictionaries, nbRounds, benchCompression);
+
+ freeBufferCollection(resultCollection);
+ } else {
+ size_t const dictMem = ZSTD_estimateDDictSize(dictBuffer.size, ZSTD_dlm_byCopy);
+ size_t const allDictMem = dictMem * nbDicts;
+ DISPLAYLEVEL(3, "generating %u dictionaries, using %.1f MB of memory \n",
+ nbDicts, (double)allDictMem / (1 MB));
+
+ shuffleDDictionaries(ddictionaries);
+
+ buffer_collection_t resultCollection = createBufferCollection_fromSliceCollectionSizes(srcSlices);
+ CONTROL(resultCollection.buffer.ptr != NULL);
+
+ result = benchMem(resultCollection.slices, dstSlices, ddictionaries, cdictionaries, nbRounds, benchCompression);
+
+ freeBufferCollection(resultCollection);
+ }
+
+ /* free all heap objects in reverse order */
+ freeCDictCollection(cdictionaries);
+ freeDDictCollection(ddictionaries);
+ free(cSizes);
+ ZSTD_freeCDict(cdict);
+ freeBuffer(dictBuffer);
+ freeSliceCollection(dstSlices);
+ freeBuffer(dstBuffer);
+ freeSliceCollection(srcSlices);
+ freeBufferCollection(srcs);
+
+ return result;
+}
+
+
+
+/* --- Command Line --- */
+
+/*! readU32FromChar() :
+ * @return : unsigned integer value read from input in `char` format.
+ * allows and interprets K, KB, KiB, M, MB and MiB suffix.
+ * Will also modify `*stringPtr`, advancing it to position where it stopped reading.
+ * Note : function will exit() program if digit sequence overflows */
+static unsigned readU32FromChar(const char** stringPtr)
+{
+ unsigned result = 0;
+ while ((**stringPtr >='0') && (**stringPtr <='9')) {
+ unsigned const max = (((unsigned)(-1)) / 10) - 1;
+ assert(result <= max); /* check overflow */
+ result *= 10, result += (unsigned)**stringPtr - '0', (*stringPtr)++ ;
+ }
+ if ((**stringPtr=='K') || (**stringPtr=='M')) {
+ unsigned const maxK = ((unsigned)(-1)) >> 10;
+ assert(result <= maxK); /* check overflow */
+ result <<= 10;
+ if (**stringPtr=='M') {
+ assert(result <= maxK); /* check overflow */
+ result <<= 10;
+ }
+ (*stringPtr)++; /* skip `K` or `M` */
+ if (**stringPtr=='i') (*stringPtr)++;
+ if (**stringPtr=='B') (*stringPtr)++;
+ }
+ return result;
+}
+
+/** longCommandWArg() :
+ * check if *stringPtr is the same as longCommand.
+ * If yes, @return 1 and advances *stringPtr to the position which immediately follows longCommand.
+ * @return 0 and doesn't modify *stringPtr otherwise.
+ */
+static int longCommandWArg(const char** stringPtr, const char* longCommand)
+{
+ size_t const comSize = strlen(longCommand);
+ int const result = !strncmp(*stringPtr, longCommand, comSize);
+ if (result) *stringPtr += comSize;
+ return result;
+}
+
+
+int usage(const char* exeName)
+{
+ DISPLAY (" \n");
+ DISPLAY (" %s [Options] filename(s) \n", exeName);
+ DISPLAY (" \n");
+ DISPLAY ("Options : \n");
+ DISPLAY ("-z : benchmark compression (default) \n");
+ DISPLAY ("-d : benchmark decompression \n");
+ DISPLAY ("-r : recursively load all files in subdirectories (default: off) \n");
+ DISPLAY ("-B# : split input into blocks of size # (default: no split) \n");
+ DISPLAY ("-# : use compression level # (default: %u) \n", CLEVEL_DEFAULT);
+ DISPLAY ("-D # : use # as a dictionary (default: create one) \n");
+ DISPLAY ("-i# : nb benchmark rounds (default: %u) \n", BENCH_TIME_DEFAULT_S);
+ DISPLAY ("--nbBlocks=#: use # blocks for bench (default: one per file) \n");
+ DISPLAY ("--nbDicts=# : create # dictionaries for bench (default: one per block) \n");
+ DISPLAY ("-h : help (this text) \n");
+ return 0;
+}
+
+int bad_usage(const char* exeName)
+{
+ DISPLAY (" bad usage : \n");
+ usage(exeName);
+ return 1;
+}
+
+int main (int argc, const char** argv)
+{
+ int recursiveMode = 0;
+ int benchCompression = 1;
+ unsigned nbRounds = BENCH_TIME_DEFAULT_S;
+ const char* const exeName = argv[0];
+
+ if (argc < 2) return bad_usage(exeName);
+
+ const char** nameTable = (const char**)malloc((size_t)argc * sizeof(const char*));
+ assert(nameTable != NULL);
+ unsigned nameIdx = 0;
+
+ const char* dictionary = NULL;
+ int cLevel = CLEVEL_DEFAULT;
+ size_t blockSize = BLOCKSIZE_DEFAULT;
+ unsigned nbDicts = 0; /* determine nbDicts automatically: 1 dictionary per block */
+ unsigned nbBlocks = 0; /* determine nbBlocks automatically, from source and blockSize */
+
+ for (int argNb = 1; argNb < argc ; argNb++) {
+ const char* argument = argv[argNb];
+ if (!strcmp(argument, "-h")) { free(nameTable); return usage(exeName); }
+ if (!strcmp(argument, "-d")) { benchCompression = 0; continue; }
+ if (!strcmp(argument, "-z")) { benchCompression = 1; continue; }
+ if (!strcmp(argument, "-r")) { recursiveMode = 1; continue; }
+ if (!strcmp(argument, "-D")) { argNb++; assert(argNb < argc); dictionary = argv[argNb]; continue; }
+ if (longCommandWArg(&argument, "-i")) { nbRounds = readU32FromChar(&argument); continue; }
+ if (longCommandWArg(&argument, "--dictionary=")) { dictionary = argument; continue; }
+ if (longCommandWArg(&argument, "-B")) { blockSize = readU32FromChar(&argument); continue; }
+ if (longCommandWArg(&argument, "--blockSize=")) { blockSize = readU32FromChar(&argument); continue; }
+ if (longCommandWArg(&argument, "--nbDicts=")) { nbDicts = readU32FromChar(&argument); continue; }
+ if (longCommandWArg(&argument, "--nbBlocks=")) { nbBlocks = readU32FromChar(&argument); continue; }
+ if (longCommandWArg(&argument, "--clevel=")) { cLevel = (int)readU32FromChar(&argument); continue; }
+ if (longCommandWArg(&argument, "-")) { cLevel = (int)readU32FromChar(&argument); continue; }
+ /* anything that's not a command is a filename */
+ nameTable[nameIdx++] = argument;
+ }
+
+ FileNamesTable* filenameTable;
+
+ if (recursiveMode) {
+#ifndef UTIL_HAS_CREATEFILELIST
+ assert(0); /* missing capability, do not run */
+#endif
+ filenameTable = UTIL_createExpandedFNT(nameTable, nameIdx, 1 /* follow_links */);
+ } else {
+ filenameTable = UTIL_assembleFileNamesTable(nameTable, nameIdx, NULL);
+ nameTable = NULL; /* UTIL_createFileNamesTable() takes ownership of nameTable */
+ }
+
+ int result = bench(filenameTable->fileNames, (unsigned)filenameTable->tableSize, dictionary, blockSize, cLevel, nbDicts, nbBlocks, nbRounds, benchCompression);
+
+ UTIL_freeFileNamesTable(filenameTable);
+ free(nameTable);
+
+ return result;
+}
diff --git a/src/zstd/contrib/linux-kernel/.gitignore b/src/zstd/contrib/linux-kernel/.gitignore
new file mode 100644
index 000000000..d8dfeef21
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/.gitignore
@@ -0,0 +1,4 @@
+!lib/zstd
+!lib/zstd/*
+*.o
+*.a
diff --git a/src/zstd/contrib/linux-kernel/0000-cover-letter.patch b/src/zstd/contrib/linux-kernel/0000-cover-letter.patch
new file mode 100644
index 000000000..d57ef27e7
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/0000-cover-letter.patch
@@ -0,0 +1,122 @@
+From 308795a7713ca6fcd468b60fba9a2fca99cee6a0 Mon Sep 17 00:00:00 2001
+From: Nick Terrell <terrelln@fb.com>
+Date: Tue, 8 Aug 2017 19:20:25 -0700
+Subject: [PATCH v5 0/5] 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/5)
+- Use div_u64() for division of u64s (2/5)
+- 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/5)
+- No zstd function uses more than 400 B of stack space (2/5)
+
+v2 -> v3:
+- Work around gcc-7 bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388
+ (2/5)
+- Fix bug in dictionary compression from upstream commit cc1522351f (2/5)
+- Port upstream BtrFS commits e1ddce71d6, 389a6cfc2a, and 6acafd1eff (3/5)
+- Change default compression level for BtrFS to 3 (3/5)
+
+v3 -> v4:
+- Fix compiler warnings (2/5)
+- Add missing includes (3/5)
+- Fix minor linter warnings (3/5, 4/5)
+- Add crypto patch (5/5)
+
+v4 -> v5:
+- Fix rare compression bug from upstream commit 308047eb5d (2/5)
+- Fix bug introduced in v3 when working around the gcc-7 bug (2/5)
+- Fix ZSTD_DStream initialization code in squashfs (4/5)
+- Fix patch documentation for patches written by Sean Purcell (4/5)
+
+Nick Terrell (5):
+ lib: Add xxhash module
+ lib: Add zstd modules
+ btrfs: Add zstd support
+ squashfs: Add zstd support
+ crypto: Add zstd support
+
+ crypto/Kconfig | 9 +
+ crypto/Makefile | 1 +
+ crypto/testmgr.c | 10 +
+ crypto/testmgr.h | 71 +
+ crypto/zstd.c | 265 ++++
+ 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 | 432 ++++++
+ 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 | 151 ++
+ 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 | 3484 ++++++++++++++++++++++++++++++++++++++++++++
+ lib/zstd/decompress.c | 2528 ++++++++++++++++++++++++++++++++
+ 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 | 770 ++++++++++
+ lib/zstd/huf_decompress.c | 960 ++++++++++++
+ lib/zstd/mem.h | 151 ++
+ lib/zstd/zstd_common.c | 75 +
+ lib/zstd/zstd_internal.h | 263 ++++
+ lib/zstd/zstd_opt.h | 1014 +++++++++++++
+ 44 files changed, 14756 insertions(+), 12 deletions(-)
+ create mode 100644 crypto/zstd.c
+ 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/src/zstd/contrib/linux-kernel/0001-lib-Add-xxhash-module.patch b/src/zstd/contrib/linux-kernel/0001-lib-Add-xxhash-module.patch
new file mode 100644
index 000000000..83f09924f
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/0001-lib-Add-xxhash-module.patch
@@ -0,0 +1,862 @@
+From a4b1ffb6e89bbccd519f9afa0910635668436105 Mon Sep 17 00:00:00 2001
+From: Nick Terrell <terrelln@fb.com>
+Date: Mon, 17 Jul 2017 17:07:18 -0700
+Subject: [PATCH v5 1/5] 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 <terrelln@fb.com>
+---
+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 <linux/types.h>
++
++/*-****************************
++ * 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 6762529..5e7541f 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -192,6 +192,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 40c1837..d06b68a 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -102,6 +102,7 @@ obj-$(CONFIG_CRC4) += crc4.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 <asm/unaligned.h>
++#include <linux/errno.h>
++#include <linux/compiler.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/xxhash.h>
++
++/*-*************************************
++ * 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/src/zstd/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch b/src/zstd/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch
new file mode 100644
index 000000000..0232d2d4a
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/0002-lib-Add-zstd-modules.patch
@@ -0,0 +1,13285 @@
+From 2b29ec569f8438a0307debd29873859ca6d407fc Mon Sep 17 00:00:00 2001
+From: Nick Terrell <terrelln@fb.com>
+Date: Mon, 17 Jul 2017 17:08:19 -0700
+Subject: [PATCH v5 2/5] lib: Add zstd modules
+
+Add zstd compression and decompression kernel modules.
+zstd offers a wide variety 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 compressor 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. Additionally, 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 <terrelln@fb.com>
+---
+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
+
+v2 -> v3:
+- Work around gcc-7 bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388
+- Fix bug in dictionary compression from upstream commit cc1522351f
+
+v3 -> v4:
+- Fix minor compiler warnings
+
+v4 -> v5:
+- Fix rare compression bug from upstream commit 308047eb5d
+- Fix bug introduced in v3 when working around the gcc-7 bug
+
+ include/linux/zstd.h | 1155 +++++++++++++++
+ lib/Kconfig | 8 +
+ lib/Makefile | 2 +
+ lib/zstd/Makefile | 18 +
+ lib/zstd/bitstream.h | 374 +++++
+ lib/zstd/compress.c | 3482 +++++++++++++++++++++++++++++++++++++++++++++
+ lib/zstd/decompress.c | 2526 ++++++++++++++++++++++++++++++++
+ lib/zstd/entropy_common.c | 243 ++++
+ lib/zstd/error_private.h | 51 +
+ 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 | 770 ++++++++++
+ lib/zstd/huf_decompress.c | 960 +++++++++++++
+ lib/zstd/mem.h | 149 ++
+ lib/zstd/zstd_common.c | 73 +
+ lib/zstd/zstd_internal.h | 261 ++++
+ lib/zstd/zstd_opt.h | 1012 +++++++++++++
+ 19 files changed, 12998 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..305efd0
+--- /dev/null
++++ b/include/linux/zstd.h
+@@ -0,0 +1,1155 @@
++/*
++ * 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.
++ *
++ * 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 <linux/types.h> /* 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 5e7541f..0d49ed0 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -249,6 +249,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 d06b68a..d5c8a4f 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..ff18ae6
+--- /dev/null
++++ b/lib/zstd/compress.c
+@@ -0,0 +1,3482 @@
++/**
++ * 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.
++ *
++ * 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 <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/string.h> /* 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<<wLog, even for dictionary */
++ U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
++ ZSTD_compressionStage_e stage;
++ U32 rep[ZSTD_REP_NUM];
++ U32 repToConfirm[ZSTD_REP_NUM];
++ U32 dictID;
++ ZSTD_parameters params;
++ void *workSpace;
++ size_t workSpaceSize;
++ size_t blockSize;
++ U64 frameContentSize;
++ struct xxh64_state xxhState;
++ ZSTD_customMem customMem;
++
++ seqStore_t seqStore; /* sequences storage ptrs */
++ U32 *hashTable;
++ U32 *hashTable3;
++ U32 *chainTable;
++ HUF_CElt *hufTable;
++ U32 flagStaticTables;
++ HUF_repeat flagStaticHufTable;
++ FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
++ FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
++ FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
++ unsigned tmpCounters[HUF_COMPRESS_WORKSPACE_SIZE_U32];
++};
++
++size_t ZSTD_CCtxWorkspaceBound(ZSTD_compressionParameters cParams)
++{
++ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
++ U32 const divider = (cParams.searchLength == 3) ? 3 : 4;
++ size_t const maxNbSeq = blockSize / divider;
++ size_t const tokenSpace = blockSize + 11 * maxNbSeq;
++ size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
++ size_t const hSize = ((size_t)1) << cParams.hashLog;
++ 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 << 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_internal(ZSTD_CCtx *zc, void *dst, size_t dstCapacity)
++{
++ 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)
++ return op - ostart;
++
++ /* 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;
++ }
++ }
++ return op - ostart;
++}
++
++ZSTD_STATIC size_t ZSTD_compressSequences(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, size_t srcSize)
++{
++ size_t const cSize = ZSTD_compressSequences_internal(zc, dst, dstCapacity);
++ size_t const minGain = ZSTD_minGain(srcSize);
++ size_t const maxCSize = srcSize - minGain;
++ /* If the srcSize <= dstCapacity, then there is enough space to write a
++ * raw uncompressed block. Since we ran out of space, the block must not
++ * be compressible, so fall back to a raw uncompressed block.
++ */
++ int const uncompressibleError = cSize == ERROR(dstSize_tooSmall) && srcSize <= dstCapacity;
++ int i;
++
++ if (ZSTD_isError(cSize) && !uncompressibleError)
++ return cSize;
++ if (cSize >= maxCSize || uncompressibleError) {
++ zc->flagStaticHufTable = HUF_repeat_none;
++ return 0;
++ }
++ /* confirm repcodes */
++ for (i = 0; i < ZSTD_REP_NUM; i++)
++ zc->rep[i] = zc->repToConfirm[i];
++ return cSize;
++}
++
++/*! 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 frameHeaderDescriptionByte = (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] = frameHeaderDescriptionByte;
++ 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(&params, 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..72df4828
+--- /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.
++ *
++ * 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 <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/string.h> /* 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 */
++
++ seq.match = NULL;
++
++ 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..2062ff0
+--- /dev/null
++++ b/lib/zstd/error_private.h
+@@ -0,0 +1,51 @@
++/**
++ * 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.
++ *
++ * 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 <linux/types.h> /* size_t */
++#include <linux/zstd.h> /* 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 <linux/types.h> /* 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<<tableLog)`.
++ */
++size_t FSE_buildCTable_wksp(FSE_CTable *ct, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize);
++
++size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits);
++/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
++
++size_t FSE_buildDTable_rle(FSE_DTable *dt, unsigned char symbolValue);
++/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
++
++size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize);
++/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
++
++/* *****************************************
++* FSE symbol compression API
++*******************************************/
++/*!
++ This API consists of small unitary functions, which highly benefit from being inlined.
++ Hence their body are included in next section.
++*/
++typedef struct {
++ ptrdiff_t value;
++ const void *stateTable;
++ const void *symbolTT;
++ unsigned stateLog;
++} FSE_CState_t;
++
++static void FSE_initCState(FSE_CState_t *CStatePtr, const FSE_CTable *ct);
++
++static void FSE_encodeSymbol(BIT_CStream_t *bitC, FSE_CState_t *CStatePtr, unsigned symbol);
++
++static void FSE_flushCState(BIT_CStream_t *bitC, const FSE_CState_t *CStatePtr);
++
++/**<
++These functions are inner components of FSE_compress_usingCTable().
++They allow the creation of custom streams, mixing multiple tables and bit sources.
++
++A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
++So the first symbol you will encode is the last you will decode, like a LIFO stack.
++
++You will need a few variables to track your CStream. They are :
++
++FSE_CTable ct; // Provided by FSE_buildCTable()
++BIT_CStream_t bitStream; // bitStream tracking structure
++FSE_CState_t state; // State tracking structure (can have several)
++
++
++The first thing to do is to init bitStream and state.
++ size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
++ FSE_initCState(&state, ct);
++
++Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
++You can then encode your input data, byte after byte.
++FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
++Remember decoding will be done in reverse direction.
++ FSE_encodeByte(&bitStream, &state, symbol);
++
++At any time, you can also add any bit sequence.
++Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
++ BIT_addBits(&bitStream, bitField, nbBits);
++
++The above methods don't commit data to memory, they just store it into local register, for speed.
++Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
++Writing data to memory is a manual operation, performed by the flushBits function.
++ BIT_flushBits(&bitStream);
++
++Your last FSE encoding operation shall be to flush your last state value(s).
++ FSE_flushState(&bitStream, &state);
++
++Finally, you must close the bitStream.
++The function returns the size of CStream in bytes.
++If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
++If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
++ size_t size = BIT_closeCStream(&bitStream);
++*/
++
++/* *****************************************
++* FSE symbol decompression API
++*******************************************/
++typedef struct {
++ size_t state;
++ const void *table; /* precise table may vary, depending on U16 */
++} FSE_DState_t;
++
++static void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, const FSE_DTable *dt);
++
++static unsigned char FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD);
++
++static unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr);
++
++/**<
++Let's now decompose FSE_decompress_usingDTable() into its unitary components.
++You will decode FSE-encoded symbols from the bitStream,
++and also any other bitFields you put in, **in reverse order**.
++
++You will need a few variables to track your bitStream. They are :
++
++BIT_DStream_t DStream; // Stream context
++FSE_DState_t DState; // State context. Multiple ones are possible
++FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
++
++The first thing to do is to init the bitStream.
++ errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
++
++You should then retrieve your initial state(s)
++(in reverse flushing order if you have several ones) :
++ errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
++
++You can then decode your data, symbol after symbol.
++For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
++Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
++ unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
++
++You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
++Note : maximum allowed nbBits is 25, for 32-bits compatibility
++ size_t bitField = BIT_readBits(&DStream, nbBits);
++
++All above operations only read from local register (which size depends on size_t).
++Refueling the register from memory is manually performed by the reload method.
++ endSignal = FSE_reloadDStream(&DStream);
++
++BIT_reloadDStream() result tells if there is still some more data to read from DStream.
++BIT_DStream_unfinished : there is still some data left into the DStream.
++BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
++BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
++BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
++
++When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
++to properly detect the exact end of stream.
++After each decoded symbol, check if DStream is fully consumed using this simple test :
++ BIT_reloadDStream(&DStream) >= 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 <linux/compiler.h>
++#include <linux/kernel.h>
++#include <linux/math64.h>
++#include <linux/string.h> /* 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<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
++ * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
++ */
++size_t FSE_buildCTable_wksp(FSE_CTable *ct, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize)
++{
++ U32 const tableSize = 1 << tableLog;
++ U32 const tableMask = tableSize - 1;
++ 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 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 nbOccurrences;
++ for (nbOccurrences = 0; nbOccurrences < normalizedCounter[symbol]; nbOccurrences++) {
++ 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 <linux/compiler.h>
++#include <linux/kernel.h>
++#include <linux/string.h> /* 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 <linux/types.h> /* 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 assumed 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..40055a7
+--- /dev/null
++++ b/lib/zstd/huf_compress.c
+@@ -0,0 +1,770 @@
++/*
++ * 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 <linux/kernel.h>
++#include <linux/string.h> /* 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) 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;
++ 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 <linux/compiler.h>
++#include <linux/kernel.h>
++#include <linux/string.h> /* 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..42a697b
+--- /dev/null
++++ b/lib/zstd/mem.h
+@@ -0,0 +1,149 @@
++/**
++ * 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.
++ *
++ * 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 <asm/unaligned.h>
++#include <linux/string.h> /* memcpy */
++#include <linux/types.h> /* 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..e5f06d7
+--- /dev/null
++++ b/lib/zstd/zstd_common.c
+@@ -0,0 +1,73 @@
++/**
++ * 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.
++ *
++ * 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 <linux/kernel.h>
++
++/*=**************************************************************
++* 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..a0fb83e
+--- /dev/null
++++ b/lib/zstd/zstd_internal.h
+@@ -0,0 +1,261 @@
++/**
++ * 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.
++ *
++ * 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 <linux/compiler.h>
++#include <linux/kernel.h>
++#include <linux/xxhash.h>
++#include <linux/zstd.h>
++
++/*-*************************************
++* 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
++*********************************************/
++ZSTD_STATIC void ZSTD_copy8(void *dst, const void *src) {
++ memcpy(dst, src, 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;
++ /* Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
++ * Avoid the bad case where the loop only runs once by handling the
++ * special case separately. This doesn't trigger the bug because it
++ * doesn't involve pointer/integer overflow.
++ */
++ if (length <= 8)
++ return ZSTD_copy8(dst, src);
++ do {
++ ZSTD_copy8(op, ip);
++ op += 8;
++ ip += 8;
++ } 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..ecdd725
+--- /dev/null
++++ b/lib/zstd/zstd_opt.h
+@@ -0,0 +1,1012 @@
++/**
++ * 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.
++ *
++ * 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.5
diff --git a/src/zstd/contrib/linux-kernel/0003-btrfs-Add-zstd-support.patch b/src/zstd/contrib/linux-kernel/0003-btrfs-Add-zstd-support.patch
new file mode 100644
index 000000000..edc7839a0
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/0003-btrfs-Add-zstd-support.patch
@@ -0,0 +1,740 @@
+From 8a9dddfbf6551afea73911e367dd4be64d62b9fd Mon Sep 17 00:00:00 2001
+From: Nick Terrell <terrelln@fb.com>
+Date: Mon, 17 Jul 2017 17:08:39 -0700
+Subject: [PATCH v5 3/5] 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 <terrelln@fb.com>
+---
+v2 -> v3:
+- Port upstream BtrFS commits e1ddce71d6, 389a6cfc2a, and 6acafd1eff
+- Change default compression level for BtrFS to 3
+
+v3 -> v4:
+- Add missing includes, which fixes the aarch64 build
+- Fix minor linter warnings
+
+ 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 | 432 +++++++++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/btrfs.h | 8 +-
+ 12 files changed, 468 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
++++ b/fs/btrfs/Kconfig
+@@ -6,6 +6,8 @@ config BTRFS_FS
+ select ZLIB_DEFLATE
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
++ select ZSTD_COMPRESS
++ select ZSTD_DECOMPRESS
+ select RAID6_PQ
+ select XOR_BLOCKS
+ select SRCU
+diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
+index 128ce17..962a95a 100644
+--- a/fs/btrfs/Makefile
++++ b/fs/btrfs/Makefile
+@@ -6,7 +6,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
+ transaction.o inode.o file.o tree-defrag.o \
+ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
+ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
+- export.o tree-log.o free-space-cache.o zlib.o lzo.o \
++ export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \
+ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
+ 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 d2ef9ac..4ff42d1 100644
+--- a/fs/btrfs/compression.c
++++ b/fs/btrfs/compression.c
+@@ -704,6 +704,7 @@ static struct {
+ static const struct btrfs_compress_op * const btrfs_compress_op[] = {
+ &btrfs_zlib_compress,
+ &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 87f6d33..2269e00 100644
+--- a/fs/btrfs/compression.h
++++ b/fs/btrfs/compression.h
+@@ -99,8 +99,9 @@ enum btrfs_compression_type {
+ BTRFS_COMPRESS_NONE = 0,
+ BTRFS_COMPRESS_ZLIB = 1,
+ BTRFS_COMPRESS_LZO = 2,
+- BTRFS_COMPRESS_TYPES = 2,
+- BTRFS_COMPRESS_LAST = 3,
++ BTRFS_COMPRESS_ZSTD = 3,
++ BTRFS_COMPRESS_TYPES = 3,
++ BTRFS_COMPRESS_LAST = 4,
+ };
+
+ struct btrfs_compress_op {
+@@ -128,5 +129,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 3f3eb7b..845d77c 100644
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -270,6 +270,7 @@ struct btrfs_super_block {
+ BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
+ BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
+ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
++ BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD | \
+ BTRFS_FEATURE_INCOMPAT_RAID56 | \
+ 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 080e2eb..04632f4 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -2828,6 +2828,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 (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 fa1b78c..b9963d9 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
++ else if (fs_info->compress_type == BTRFS_COMPRESS_ZLIB)
+ comp = "zlib";
++ else
++ comp = "zstd";
+ ret = btrfs_set_prop(inode, "btrfs.compression",
+ comp, strlen(comp), 0);
+ if (ret)
+@@ -1466,6 +1468,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 4b23ae5..20631e9 100644
+--- a/fs/btrfs/props.c
++++ b/fs/btrfs/props.c
+@@ -390,6 +390,8 @@ static int prop_compression_validate(const char *value, size_t len)
+ return 0;
+ else if (!strncmp("zlib", value, len))
+ return 0;
++ else if (!strncmp("zstd", value, len))
++ return 0;
+
+ return -EINVAL;
+ }
+@@ -412,6 +414,8 @@ static int prop_compression_apply(struct inode *inode,
+ type = BTRFS_COMPRESS_LZO;
+ else if (!strncmp("zlib", value, len))
+ type = BTRFS_COMPRESS_ZLIB;
++ else if (!strncmp("zstd", value, len))
++ type = BTRFS_COMPRESS_ZSTD;
+ else
+ return -EINVAL;
+
+@@ -429,6 +433,8 @@ static const char *prop_compression_extract(struct inode *inode)
+ return "zlib";
+ case BTRFS_COMPRESS_LZO:
+ return "lzo";
++ case BTRFS_COMPRESS_ZSTD:
++ return "zstd";
+ }
+
+ return NULL;
+diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
+index 12540b6..c370dea 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,
+ btrfs_clear_opt(info->mount_opt, NODATASUM);
+ btrfs_set_fs_incompat(info, COMPRESS_LZO);
+ no_compress = 0;
++ } else if (strcmp(args[0].from, "zstd") == 0) {
++ compress_type = "zstd";
++ info->compress_type = BTRFS_COMPRESS_ZSTD;
++ btrfs_set_opt(info->mount_opt, COMPRESS);
++ btrfs_clear_opt(info->mount_opt, NODATACOW);
++ btrfs_clear_opt(info->mount_opt, NODATASUM);
++ btrfs_set_fs_incompat(info, COMPRESS_ZSTD);
++ no_compress = 0;
+ } else if (strncmp(args[0].from, "no", 2) == 0) {
+ compress_type = "no";
+ btrfs_clear_opt(info->mount_opt, COMPRESS);
+@@ -1227,8 +1235,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";
+- else
++ else if (info->compress_type == BTRFS_COMPRESS_LZO)
+ compress_type = "lzo";
++ else
++ compress_type = "zstd";
+ if (btrfs_test_opt(info, FORCE_COMPRESS))
+ seq_printf(seq, ",compress-force=%s", compress_type);
+ else
+diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
+index c2d5f35..2b6d37c 100644
+--- a/fs/btrfs/sysfs.c
++++ b/fs/btrfs/sysfs.c
+@@ -200,6 +200,7 @@ BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF);
+ BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL);
+ BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS);
+ BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO);
++BTRFS_FEAT_ATTR_INCOMPAT(compress_zstd, COMPRESS_ZSTD);
+ BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA);
+ BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF);
+ BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56);
+@@ -212,6 +213,7 @@ static struct attribute *btrfs_supported_feature_attrs[] = {
+ BTRFS_FEAT_ATTR_PTR(default_subvol),
+ BTRFS_FEAT_ATTR_PTR(mixed_groups),
+ BTRFS_FEAT_ATTR_PTR(compress_lzo),
++ BTRFS_FEAT_ATTR_PTR(compress_zstd),
+ BTRFS_FEAT_ATTR_PTR(big_metadata),
+ BTRFS_FEAT_ATTR_PTR(extended_iref),
+ BTRFS_FEAT_ATTR_PTR(raid56),
+diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
+new file mode 100644
+index 0000000..607ce47
+--- /dev/null
++++ b/fs/btrfs/zstd.c
+@@ -0,0 +1,432 @@
++/*
++ * 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.
++ */
++#include <linux/bio.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/refcount.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/zstd.h>
++#include "compression.h"
++
++#define ZSTD_BTRFS_MAX_WINDOWLOG 17
++#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
++#define ZSTD_BTRFS_DEFAULT_LEVEL 3
++
++static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len)
++{
++ ZSTD_parameters params = ZSTD_getParams(ZSTD_BTRFS_DEFAULT_LEVEL,
++ src_len, 0);
++
++ if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG)
++ params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG;
++ WARN_ON(src_len > ZSTD_BTRFS_MAX_INPUT);
++ return params;
++}
++
++struct workspace {
++ void *mem;
++ size_t size;
++ char *buf;
++ struct list_head list;
++};
++
++static void zstd_free_workspace(struct list_head *ws)
++{
++ struct workspace *workspace = list_entry(ws, struct workspace, list);
++
++ kvfree(workspace->mem);
++ kfree(workspace->buf);
++ kfree(workspace);
++}
++
++static struct list_head *zstd_alloc_workspace(void)
++{
++ ZSTD_parameters params =
++ zstd_get_btrfs_parameters(ZSTD_BTRFS_MAX_INPUT);
++ struct workspace *workspace;
++
++ workspace = kzalloc(sizeof(*workspace), GFP_KERNEL);
++ if (!workspace)
++ return ERR_PTR(-ENOMEM);
++
++ workspace->size = max_t(size_t,
++ ZSTD_CStreamWorkspaceBound(params.cParams),
++ ZSTD_DStreamWorkspaceBound(ZSTD_BTRFS_MAX_INPUT));
++ workspace->mem = kvmalloc(workspace->size, GFP_KERNEL);
++ workspace->buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!workspace->mem || !workspace->buf)
++ goto fail;
++
++ INIT_LIST_HEAD(&workspace->list);
++
++ return &workspace->list;
++fail:
++ zstd_free_workspace(&workspace->list);
++ return ERR_PTR(-ENOMEM);
++}
++
++static int zstd_compress_pages(struct list_head *ws,
++ struct address_space *mapping,
++ u64 start,
++ struct page **pages,
++ unsigned long *out_pages,
++ unsigned long *total_in,
++ unsigned long *total_out)
++{
++ struct workspace *workspace = list_entry(ws, struct workspace, list);
++ ZSTD_CStream *stream;
++ int ret = 0;
++ int nr_pages = 0;
++ struct page *in_page = NULL; /* The current page to read */
++ struct page *out_page = NULL; /* The current page to write to */
++ ZSTD_inBuffer in_buf = { NULL, 0, 0 };
++ ZSTD_outBuffer out_buf = { NULL, 0, 0 };
++ unsigned long tot_in = 0;
++ unsigned long tot_out = 0;
++ unsigned long len = *total_out;
++ const unsigned long nr_dest_pages = *out_pages;
++ unsigned long max_out = nr_dest_pages * PAGE_SIZE;
++ ZSTD_parameters params = zstd_get_btrfs_parameters(len);
++
++ *out_pages = 0;
++ *total_out = 0;
++ *total_in = 0;
++
++ /* Initialize the stream */
++ stream = ZSTD_initCStream(params, len, workspace->mem,
++ workspace->size);
++ if (!stream) {
++ pr_warn("BTRFS: ZSTD_initCStream failed\n");
++ ret = -EIO;
++ goto out;
++ }
++
++ /* map in the first page of input data */
++ in_page = find_get_page(mapping, start >> PAGE_SHIFT);
++ in_buf.src = kmap(in_page);
++ in_buf.pos = 0;
++ in_buf.size = min_t(size_t, len, PAGE_SIZE);
++
++
++ /* Allocate and map in the output buffer */
++ out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
++ if (out_page == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ pages[nr_pages++] = out_page;
++ out_buf.dst = kmap(out_page);
++ out_buf.pos = 0;
++ out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
++
++ while (1) {
++ size_t ret2;
++
++ ret2 = ZSTD_compressStream(stream, &out_buf, &in_buf);
++ if (ZSTD_isError(ret2)) {
++ pr_debug("BTRFS: ZSTD_compressStream returned %d\n",
++ ZSTD_getErrorCode(ret2));
++ ret = -EIO;
++ goto out;
++ }
++
++ /* Check to see if we are making it bigger */
++ if (tot_in + in_buf.pos > 8192 &&
++ tot_in + in_buf.pos <
++ tot_out + out_buf.pos) {
++ ret = -E2BIG;
++ goto out;
++ }
++
++ /* We've reached the end of our output range */
++ if (out_buf.pos >= max_out) {
++ tot_out += out_buf.pos;
++ ret = -E2BIG;
++ goto out;
++ }
++
++ /* Check if we need more output space */
++ if (out_buf.pos == out_buf.size) {
++ tot_out += PAGE_SIZE;
++ max_out -= PAGE_SIZE;
++ kunmap(out_page);
++ if (nr_pages == nr_dest_pages) {
++ out_page = NULL;
++ ret = -E2BIG;
++ goto out;
++ }
++ out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
++ if (out_page == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ pages[nr_pages++] = out_page;
++ out_buf.dst = kmap(out_page);
++ out_buf.pos = 0;
++ out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
++ }
++
++ /* We've reached the end of the input */
++ if (in_buf.pos >= len) {
++ tot_in += in_buf.pos;
++ break;
++ }
++
++ /* Check if we need more input */
++ if (in_buf.pos == in_buf.size) {
++ tot_in += PAGE_SIZE;
++ kunmap(in_page);
++ put_page(in_page);
++
++ start += PAGE_SIZE;
++ len -= PAGE_SIZE;
++ in_page = find_get_page(mapping, start >> PAGE_SHIFT);
++ in_buf.src = kmap(in_page);
++ in_buf.pos = 0;
++ in_buf.size = min_t(size_t, len, PAGE_SIZE);
++ }
++ }
++ while (1) {
++ size_t ret2;
++
++ ret2 = ZSTD_endStream(stream, &out_buf);
++ if (ZSTD_isError(ret2)) {
++ pr_debug("BTRFS: ZSTD_endStream returned %d\n",
++ ZSTD_getErrorCode(ret2));
++ ret = -EIO;
++ goto out;
++ }
++ if (ret2 == 0) {
++ tot_out += out_buf.pos;
++ break;
++ }
++ if (out_buf.pos >= max_out) {
++ tot_out += out_buf.pos;
++ ret = -E2BIG;
++ goto out;
++ }
++
++ tot_out += PAGE_SIZE;
++ max_out -= PAGE_SIZE;
++ kunmap(out_page);
++ if (nr_pages == nr_dest_pages) {
++ out_page = NULL;
++ ret = -E2BIG;
++ goto out;
++ }
++ out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
++ if (out_page == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ pages[nr_pages++] = out_page;
++ out_buf.dst = kmap(out_page);
++ out_buf.pos = 0;
++ out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
++ }
++
++ if (tot_out >= tot_in) {
++ ret = -E2BIG;
++ goto out;
++ }
++
++ ret = 0;
++ *total_in = tot_in;
++ *total_out = tot_out;
++out:
++ *out_pages = nr_pages;
++ /* Cleanup */
++ if (in_page) {
++ kunmap(in_page);
++ put_page(in_page);
++ }
++ if (out_page)
++ kunmap(out_page);
++ return ret;
++}
++
++static int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
++{
++ struct workspace *workspace = list_entry(ws, struct workspace, list);
++ struct page **pages_in = cb->compressed_pages;
++ u64 disk_start = cb->start;
++ struct bio *orig_bio = cb->orig_bio;
++ size_t srclen = cb->compressed_len;
++ ZSTD_DStream *stream;
++ int ret = 0;
++ unsigned long page_in_index = 0;
++ unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
++ unsigned long buf_start;
++ unsigned long total_out = 0;
++ ZSTD_inBuffer in_buf = { NULL, 0, 0 };
++ ZSTD_outBuffer out_buf = { NULL, 0, 0 };
++
++ stream = ZSTD_initDStream(
++ ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);
++ if (!stream) {
++ pr_debug("BTRFS: ZSTD_initDStream failed\n");
++ ret = -EIO;
++ goto done;
++ }
++
++ in_buf.src = kmap(pages_in[page_in_index]);
++ in_buf.pos = 0;
++ in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
++
++ out_buf.dst = workspace->buf;
++ out_buf.pos = 0;
++ out_buf.size = PAGE_SIZE;
++
++ while (1) {
++ size_t ret2;
++
++ ret2 = ZSTD_decompressStream(stream, &out_buf, &in_buf);
++ if (ZSTD_isError(ret2)) {
++ pr_debug("BTRFS: ZSTD_decompressStream returned %d\n",
++ ZSTD_getErrorCode(ret2));
++ ret = -EIO;
++ goto done;
++ }
++ buf_start = total_out;
++ total_out += out_buf.pos;
++ out_buf.pos = 0;
++
++ ret = btrfs_decompress_buf2page(out_buf.dst, buf_start,
++ total_out, disk_start, orig_bio);
++ if (ret == 0)
++ break;
++
++ if (in_buf.pos >= srclen)
++ break;
++
++ /* Check if we've hit the end of a frame */
++ if (ret2 == 0)
++ break;
++
++ if (in_buf.pos == in_buf.size) {
++ kunmap(pages_in[page_in_index++]);
++ if (page_in_index >= total_pages_in) {
++ in_buf.src = NULL;
++ ret = -EIO;
++ goto done;
++ }
++ srclen -= PAGE_SIZE;
++ in_buf.src = kmap(pages_in[page_in_index]);
++ in_buf.pos = 0;
++ in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
++ }
++ }
++ ret = 0;
++ zero_fill_bio(orig_bio);
++done:
++ if (in_buf.src)
++ kunmap(pages_in[page_in_index]);
++ return ret;
++}
++
++static int zstd_decompress(struct list_head *ws, unsigned char *data_in,
++ struct page *dest_page,
++ unsigned long start_byte,
++ size_t srclen, size_t destlen)
++{
++ struct workspace *workspace = list_entry(ws, struct workspace, list);
++ ZSTD_DStream *stream;
++ int ret = 0;
++ size_t ret2;
++ ZSTD_inBuffer in_buf = { NULL, 0, 0 };
++ ZSTD_outBuffer out_buf = { NULL, 0, 0 };
++ unsigned long total_out = 0;
++ unsigned long pg_offset = 0;
++ char *kaddr;
++
++ stream = ZSTD_initDStream(
++ ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);
++ if (!stream) {
++ pr_warn("BTRFS: ZSTD_initDStream failed\n");
++ ret = -EIO;
++ goto finish;
++ }
++
++ destlen = min_t(size_t, destlen, PAGE_SIZE);
++
++ in_buf.src = data_in;
++ in_buf.pos = 0;
++ in_buf.size = srclen;
++
++ out_buf.dst = workspace->buf;
++ out_buf.pos = 0;
++ out_buf.size = PAGE_SIZE;
++
++ ret2 = 1;
++ while (pg_offset < destlen && in_buf.pos < in_buf.size) {
++ unsigned long buf_start;
++ unsigned long buf_offset;
++ unsigned long bytes;
++
++ /* Check if the frame is over and we still need more input */
++ if (ret2 == 0) {
++ pr_debug("BTRFS: ZSTD_decompressStream ended early\n");
++ ret = -EIO;
++ goto finish;
++ }
++ ret2 = ZSTD_decompressStream(stream, &out_buf, &in_buf);
++ if (ZSTD_isError(ret2)) {
++ pr_debug("BTRFS: ZSTD_decompressStream returned %d\n",
++ ZSTD_getErrorCode(ret2));
++ ret = -EIO;
++ goto finish;
++ }
++
++ buf_start = total_out;
++ total_out += out_buf.pos;
++ out_buf.pos = 0;
++
++ if (total_out <= start_byte)
++ continue;
++
++ if (total_out > start_byte && buf_start < start_byte)
++ buf_offset = start_byte - buf_start;
++ else
++ buf_offset = 0;
++
++ bytes = min_t(unsigned long, destlen - pg_offset,
++ out_buf.size - buf_offset);
++
++ kaddr = kmap_atomic(dest_page);
++ memcpy(kaddr + pg_offset, out_buf.dst + buf_offset, bytes);
++ kunmap_atomic(kaddr);
++
++ pg_offset += bytes;
++ }
++ ret = 0;
++finish:
++ if (pg_offset < destlen) {
++ kaddr = kmap_atomic(dest_page);
++ memset(kaddr + pg_offset, 0, destlen - pg_offset);
++ kunmap_atomic(kaddr);
++ }
++ return ret;
++}
++
++const struct btrfs_compress_op btrfs_zstd_compress = {
++ .alloc_workspace = zstd_alloc_workspace,
++ .free_workspace = zstd_free_workspace,
++ .compress_pages = zstd_compress_pages,
++ .decompress_bio = zstd_decompress_bio,
++ .decompress = zstd_decompress,
++};
+diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
+index 9aa74f3..378230c 100644
+--- a/include/uapi/linux/btrfs.h
++++ b/include/uapi/linux/btrfs.h
+@@ -255,13 +255,7 @@ struct btrfs_ioctl_fs_info_args {
+ #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1)
+ #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2)
+ #define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3)
+-/*
+- * some patches floated around with a second compression method
+- * lets save that incompat here for when they do get in
+- * Note we don't actually support it, we're just reserving the
+- * number
+- */
+-#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/src/zstd/contrib/linux-kernel/0004-squashfs-Add-zstd-support.patch b/src/zstd/contrib/linux-kernel/0004-squashfs-Add-zstd-support.patch
new file mode 100644
index 000000000..36cdf71df
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/0004-squashfs-Add-zstd-support.patch
@@ -0,0 +1,306 @@
+From 46bf8f6d30d6ddf2446c110f122482b5e5e16933 Mon Sep 17 00:00:00 2001
+From: Sean Purcell <me@seanp.xyz>
+Date: Mon, 17 Jul 2017 17:08:59 -0700
+Subject: [PATCH v5 4/5] squashfs: Add zstd support
+
+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 <me@seanp.xyz>, 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
+
+Signed-off-by: Sean Purcell <me@seanp.xyz>
+Signed-off-by: Nick Terrell <terrelln@fb.com>
+---
+v3 -> v4:
+- Fix minor linter warnings
+
+v4 -> v5:
+- Fix ZSTD_DStream initialization code in squashfs
+- Fix patch documentation to reflect that Sean Purcell is the author
+
+ 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 | 151 +++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 178 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
++ select ZSTD_DECOMPRESS
++ help
++ Saying Y here includes support for reading Squashfs file systems
++ compressed with ZSTD compression. ZSTD gives better compression than
++ the default ZLIB compression, while using less CPU.
++
++ ZSTD is not the standard compression used in Squashfs and so most
++ file systems will be readable without selecting this option.
++
++ If unsure, say N.
++
+ config SQUASHFS_4K_DEVBLK_SIZE
+ bool "Use 4K device block size?"
+ depends on SQUASHFS
+diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
+index 246a6f3..6655631 100644
+--- a/fs/squashfs/Makefile
++++ b/fs/squashfs/Makefile
+@@ -15,3 +15,4 @@ squashfs-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o
+ squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o
+ squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o
+ squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o
++squashfs-$(CONFIG_SQUASHFS_ZSTD) += zstd_wrapper.o
+diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
+index d2bc136..8366398 100644
+--- a/fs/squashfs/decompressor.c
++++ b/fs/squashfs/decompressor.c
+@@ -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
++};
++#endif
++
+ static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
+ NULL, NULL, NULL, NULL, 0, "unknown", 0
+ };
+@@ -75,6 +81,7 @@ static const struct squashfs_decompressor *decompressor[] = {
+ &squashfs_lzo_comp_ops,
+ &squashfs_xz_comp_ops,
+ &squashfs_lzma_unsupported_comp_ops,
++ &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
++++ b/fs/squashfs/decompressor.h
+@@ -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
++
+ #endif
+diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h
+index 506f4ba..24d12fd 100644
+--- a/fs/squashfs/squashfs_fs.h
++++ b/fs/squashfs/squashfs_fs.h
+@@ -241,6 +241,7 @@ struct meta_index {
+ #define LZO_COMPRESSION 3
+ #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..eeaabf8
+--- /dev/null
++++ b/fs/squashfs/zstd_wrapper.c
+@@ -0,0 +1,151 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * 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
++ * as published by the Free Software Foundation; either version 2,
++ * 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.
++ *
++ * zstd_wrapper.c
++ */
++
++#include <linux/mutex.h>
++#include <linux/buffer_head.h>
++#include <linux/slab.h>
++#include <linux/zstd.h>
++#include <linux/vmalloc.h>
++
++#include "squashfs_fs.h"
++#include "squashfs_fs_sb.h"
++#include "squashfs.h"
++#include "decompressor.h"
++#include "page_actor.h"
++
++struct workspace {
++ void *mem;
++ size_t mem_size;
++ size_t window_size;
++};
++
++static void *zstd_init(struct squashfs_sb_info *msblk, void *buff)
++{
++ struct workspace *wksp = kmalloc(sizeof(*wksp), GFP_KERNEL);
++
++ if (wksp == NULL)
++ goto failed;
++ wksp->window_size = max_t(size_t,
++ msblk->block_size, SQUASHFS_METADATA_SIZE);
++ wksp->mem_size = ZSTD_DStreamWorkspaceBound(wksp->window_size);
++ wksp->mem = vmalloc(wksp->mem_size);
++ if (wksp->mem == NULL)
++ goto failed;
++
++ return wksp;
++
++failed:
++ ERROR("Failed to allocate zstd workspace\n");
++ kfree(wksp);
++ return ERR_PTR(-ENOMEM);
++}
++
++
++static void zstd_free(void *strm)
++{
++ struct workspace *wksp = strm;
++
++ if (wksp)
++ vfree(wksp->mem);
++ kfree(wksp);
++}
++
++
++static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
++ struct buffer_head **bh, int b, int offset, int length,
++ struct squashfs_page_actor *output)
++{
++ struct workspace *wksp = strm;
++ ZSTD_DStream *stream;
++ size_t total_out = 0;
++ size_t zstd_err;
++ int k = 0;
++ ZSTD_inBuffer in_buf = { NULL, 0, 0 };
++ ZSTD_outBuffer out_buf = { NULL, 0, 0 };
++
++ stream = ZSTD_initDStream(wksp->window_size, wksp->mem, wksp->mem_size);
++
++ if (!stream) {
++ ERROR("Failed to initialize zstd decompressor\n");
++ goto out;
++ }
++
++ out_buf.size = PAGE_SIZE;
++ out_buf.dst = squashfs_first_page(output);
++
++ do {
++ if (in_buf.pos == in_buf.size && k < b) {
++ int avail = min(length, msblk->devblksize - offset);
++
++ length -= avail;
++ in_buf.src = bh[k]->b_data + offset;
++ in_buf.size = avail;
++ in_buf.pos = 0;
++ offset = 0;
++ }
++
++ if (out_buf.pos == out_buf.size) {
++ out_buf.dst = squashfs_next_page(output);
++ if (out_buf.dst == NULL) {
++ /* Shouldn't run out of pages
++ * before stream is done.
++ */
++ squashfs_finish_page(output);
++ goto out;
++ }
++ out_buf.pos = 0;
++ out_buf.size = PAGE_SIZE;
++ }
++
++ total_out -= out_buf.pos;
++ zstd_err = ZSTD_decompressStream(stream, &out_buf, &in_buf);
++ total_out += out_buf.pos; /* add the additional data produced */
++
++ if (in_buf.pos == in_buf.size && k < b)
++ put_bh(bh[k++]);
++ } while (zstd_err != 0 && !ZSTD_isError(zstd_err));
++
++ squashfs_finish_page(output);
++
++ if (ZSTD_isError(zstd_err)) {
++ ERROR("zstd decompression error: %d\n",
++ (int)ZSTD_getErrorCode(zstd_err));
++ goto out;
++ }
++
++ if (k < b)
++ goto out;
++
++ return (int)total_out;
++
++out:
++ for (; k < b; k++)
++ put_bh(bh[k]);
++
++ return -EIO;
++}
++
++const struct squashfs_decompressor squashfs_zstd_comp_ops = {
++ .init = zstd_init,
++ .free = zstd_free,
++ .decompress = zstd_uncompress,
++ .id = ZSTD_COMPRESSION,
++ .name = "zstd",
++ .supported = 1
++};
+--
+2.9.3
diff --git a/src/zstd/contrib/linux-kernel/0005-crypto-Add-zstd-support.patch b/src/zstd/contrib/linux-kernel/0005-crypto-Add-zstd-support.patch
new file mode 100644
index 000000000..971b06345
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/0005-crypto-Add-zstd-support.patch
@@ -0,0 +1,424 @@
+From 308795a7713ca6fcd468b60fba9a2fca99cee6a0 Mon Sep 17 00:00:00 2001
+From: Nick Terrell <terrelln@fb.com>
+Date: Wed, 2 Aug 2017 18:02:13 -0700
+Subject: [PATCH v5 5/5] crypto: Add zstd support
+
+Adds zstd support to crypto and scompress. Only supports the default
+level.
+
+Signed-off-by: Nick Terrell <terrelln@fb.com>
+---
+ crypto/Kconfig | 9 ++
+ crypto/Makefile | 1 +
+ crypto/testmgr.c | 10 +++
+ crypto/testmgr.h | 71 +++++++++++++++
+ crypto/zstd.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 356 insertions(+)
+ create mode 100644 crypto/zstd.c
+
+diff --git a/crypto/Kconfig b/crypto/Kconfig
+index caa770e..4fc3936 100644
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1662,6 +1662,15 @@ config CRYPTO_LZ4HC
+ help
+ This is the LZ4 high compression mode algorithm.
+
++config CRYPTO_ZSTD
++ tristate "Zstd compression algorithm"
++ select CRYPTO_ALGAPI
++ select CRYPTO_ACOMP2
++ select ZSTD_COMPRESS
++ select ZSTD_DECOMPRESS
++ help
++ This is the zstd algorithm.
++
+ comment "Random Number Generation"
+
+ config CRYPTO_ANSI_CPRNG
+diff --git a/crypto/Makefile b/crypto/Makefile
+index d41f033..b22e1e8 100644
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -133,6 +133,7 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
+ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
+ obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
+ obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
++obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
+
+ ecdh_generic-y := ecc.o
+ ecdh_generic-y += ecdh.o
+diff --git a/crypto/testmgr.c b/crypto/testmgr.c
+index 7125ba3..8a124d3 100644
+--- a/crypto/testmgr.c
++++ b/crypto/testmgr.c
+@@ -3603,6 +3603,16 @@ static const struct alg_test_desc alg_test_descs[] = {
+ .decomp = __VECS(zlib_deflate_decomp_tv_template)
+ }
+ }
++ }, {
++ .alg = "zstd",
++ .test = alg_test_comp,
++ .fips_allowed = 1,
++ .suite = {
++ .comp = {
++ .comp = __VECS(zstd_comp_tv_template),
++ .decomp = __VECS(zstd_decomp_tv_template)
++ }
++ }
+ }
+ };
+
+diff --git a/crypto/testmgr.h b/crypto/testmgr.h
+index 6ceb0e2..e6b5920 100644
+--- a/crypto/testmgr.h
++++ b/crypto/testmgr.h
+@@ -34631,4 +34631,75 @@ static const struct comp_testvec lz4hc_decomp_tv_template[] = {
+ },
+ };
+
++static const struct comp_testvec zstd_comp_tv_template[] = {
++ {
++ .inlen = 68,
++ .outlen = 39,
++ .input = "The algorithm is zstd. "
++ "The algorithm is zstd. "
++ "The algorithm is zstd.",
++ .output = "\x28\xb5\x2f\xfd\x00\x50\xf5\x00\x00\xb8\x54\x68\x65"
++ "\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x69\x73"
++ "\x20\x7a\x73\x74\x64\x2e\x20\x01\x00\x55\x73\x36\x01"
++ ,
++ },
++ {
++ .inlen = 244,
++ .outlen = 151,
++ .input = "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.",
++ .output = "\x28\xb5\x2f\xfd\x00\x50\x75\x04\x00\x42\x4b\x1e\x17"
++ "\x90\x81\x31\x00\xf2\x2f\xe4\x36\xc9\xef\x92\x88\x32"
++ "\xc9\xf2\x24\x94\xd8\x68\x9a\x0f\x00\x0c\xc4\x31\x6f"
++ "\x0d\x0c\x38\xac\x5c\x48\x03\xcd\x63\x67\xc0\xf3\xad"
++ "\x4e\x90\xaa\x78\xa0\xa4\xc5\x99\xda\x2f\xb6\x24\x60"
++ "\xe2\x79\x4b\xaa\xb6\x6b\x85\x0b\xc9\xc6\x04\x66\x86"
++ "\xe2\xcc\xe2\x25\x3f\x4f\x09\xcd\xb8\x9d\xdb\xc1\x90"
++ "\xa9\x11\xbc\x35\x44\x69\x2d\x9c\x64\x4f\x13\x31\x64"
++ "\xcc\xfb\x4d\x95\x93\x86\x7f\x33\x7f\x1a\xef\xe9\x30"
++ "\xf9\x67\xa1\x94\x0a\x69\x0f\x60\xcd\xc3\xab\x99\xdc"
++ "\x42\xed\x97\x05\x00\x33\xc3\x15\x95\x3a\x06\xa0\x0e"
++ "\x20\xa9\x0e\x82\xb9\x43\x45\x01",
++ },
++};
++
++static const struct comp_testvec zstd_decomp_tv_template[] = {
++ {
++ .inlen = 43,
++ .outlen = 68,
++ .input = "\x28\xb5\x2f\xfd\x04\x50\xf5\x00\x00\xb8\x54\x68\x65"
++ "\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x20\x69\x73"
++ "\x20\x7a\x73\x74\x64\x2e\x20\x01\x00\x55\x73\x36\x01"
++ "\x6b\xf4\x13\x35",
++ .output = "The algorithm is zstd. "
++ "The algorithm is zstd. "
++ "The algorithm is zstd.",
++ },
++ {
++ .inlen = 155,
++ .outlen = 244,
++ .input = "\x28\xb5\x2f\xfd\x04\x50\x75\x04\x00\x42\x4b\x1e\x17"
++ "\x90\x81\x31\x00\xf2\x2f\xe4\x36\xc9\xef\x92\x88\x32"
++ "\xc9\xf2\x24\x94\xd8\x68\x9a\x0f\x00\x0c\xc4\x31\x6f"
++ "\x0d\x0c\x38\xac\x5c\x48\x03\xcd\x63\x67\xc0\xf3\xad"
++ "\x4e\x90\xaa\x78\xa0\xa4\xc5\x99\xda\x2f\xb6\x24\x60"
++ "\xe2\x79\x4b\xaa\xb6\x6b\x85\x0b\xc9\xc6\x04\x66\x86"
++ "\xe2\xcc\xe2\x25\x3f\x4f\x09\xcd\xb8\x9d\xdb\xc1\x90"
++ "\xa9\x11\xbc\x35\x44\x69\x2d\x9c\x64\x4f\x13\x31\x64"
++ "\xcc\xfb\x4d\x95\x93\x86\x7f\x33\x7f\x1a\xef\xe9\x30"
++ "\xf9\x67\xa1\x94\x0a\x69\x0f\x60\xcd\xc3\xab\x99\xdc"
++ "\x42\xed\x97\x05\x00\x33\xc3\x15\x95\x3a\x06\xa0\x0e"
++ "\x20\xa9\x0e\x82\xb9\x43\x45\x01\xaa\x6d\xda\x0d",
++ .output = "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.",
++ },
++};
+ #endif /* _CRYPTO_TESTMGR_H */
+diff --git a/crypto/zstd.c b/crypto/zstd.c
+new file mode 100644
+index 0000000..9a76b3e
+--- /dev/null
++++ b/crypto/zstd.c
+@@ -0,0 +1,265 @@
++/*
++ * Cryptographic API.
++ *
++ * Copyright (c) 2017-present, Facebook, Inc.
++ *
++ * 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 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.
++ */
++#include <linux/crypto.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/net.h>
++#include <linux/vmalloc.h>
++#include <linux/zstd.h>
++#include <crypto/internal/scompress.h>
++
++
++#define ZSTD_DEF_LEVEL 3
++
++struct zstd_ctx {
++ ZSTD_CCtx *cctx;
++ ZSTD_DCtx *dctx;
++ void *cwksp;
++ void *dwksp;
++};
++
++static ZSTD_parameters zstd_params(void)
++{
++ return ZSTD_getParams(ZSTD_DEF_LEVEL, 0, 0);
++}
++
++static int zstd_comp_init(struct zstd_ctx *ctx)
++{
++ int ret = 0;
++ const ZSTD_parameters params = zstd_params();
++ const size_t wksp_size = ZSTD_CCtxWorkspaceBound(params.cParams);
++
++ ctx->cwksp = vzalloc(wksp_size);
++ if (!ctx->cwksp) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ ctx->cctx = ZSTD_initCCtx(ctx->cwksp, wksp_size);
++ if (!ctx->cctx) {
++ ret = -EINVAL;
++ goto out_free;
++ }
++out:
++ return ret;
++out_free:
++ vfree(ctx->cwksp);
++ goto out;
++}
++
++static int zstd_decomp_init(struct zstd_ctx *ctx)
++{
++ int ret = 0;
++ const size_t wksp_size = ZSTD_DCtxWorkspaceBound();
++
++ ctx->dwksp = vzalloc(wksp_size);
++ if (!ctx->dwksp) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ ctx->dctx = ZSTD_initDCtx(ctx->dwksp, wksp_size);
++ if (!ctx->dctx) {
++ ret = -EINVAL;
++ goto out_free;
++ }
++out:
++ return ret;
++out_free:
++ vfree(ctx->dwksp);
++ goto out;
++}
++
++static void zstd_comp_exit(struct zstd_ctx *ctx)
++{
++ vfree(ctx->cwksp);
++ ctx->cwksp = NULL;
++ ctx->cctx = NULL;
++}
++
++static void zstd_decomp_exit(struct zstd_ctx *ctx)
++{
++ vfree(ctx->dwksp);
++ ctx->dwksp = NULL;
++ ctx->dctx = NULL;
++}
++
++static int __zstd_init(void *ctx)
++{
++ int ret;
++
++ ret = zstd_comp_init(ctx);
++ if (ret)
++ return ret;
++ ret = zstd_decomp_init(ctx);
++ if (ret)
++ zstd_comp_exit(ctx);
++ return ret;
++}
++
++static void *zstd_alloc_ctx(struct crypto_scomp *tfm)
++{
++ int ret;
++ struct zstd_ctx *ctx;
++
++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
++ if (!ctx)
++ return ERR_PTR(-ENOMEM);
++
++ ret = __zstd_init(ctx);
++ if (ret) {
++ kfree(ctx);
++ return ERR_PTR(ret);
++ }
++
++ return ctx;
++}
++
++static int zstd_init(struct crypto_tfm *tfm)
++{
++ struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ return __zstd_init(ctx);
++}
++
++static void __zstd_exit(void *ctx)
++{
++ zstd_comp_exit(ctx);
++ zstd_decomp_exit(ctx);
++}
++
++static void zstd_free_ctx(struct crypto_scomp *tfm, void *ctx)
++{
++ __zstd_exit(ctx);
++ kzfree(ctx);
++}
++
++static void zstd_exit(struct crypto_tfm *tfm)
++{
++ struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ __zstd_exit(ctx);
++}
++
++static int __zstd_compress(const u8 *src, unsigned int slen,
++ u8 *dst, unsigned int *dlen, void *ctx)
++{
++ size_t out_len;
++ struct zstd_ctx *zctx = ctx;
++ const ZSTD_parameters params = zstd_params();
++
++ out_len = ZSTD_compressCCtx(zctx->cctx, dst, *dlen, src, slen, params);
++ if (ZSTD_isError(out_len))
++ return -EINVAL;
++ *dlen = out_len;
++ return 0;
++}
++
++static int zstd_compress(struct crypto_tfm *tfm, const u8 *src,
++ unsigned int slen, u8 *dst, unsigned int *dlen)
++{
++ struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ return __zstd_compress(src, slen, dst, dlen, ctx);
++}
++
++static int zstd_scompress(struct crypto_scomp *tfm, const u8 *src,
++ unsigned int slen, u8 *dst, unsigned int *dlen,
++ void *ctx)
++{
++ return __zstd_compress(src, slen, dst, dlen, ctx);
++}
++
++static int __zstd_decompress(const u8 *src, unsigned int slen,
++ u8 *dst, unsigned int *dlen, void *ctx)
++{
++ size_t out_len;
++ struct zstd_ctx *zctx = ctx;
++
++ out_len = ZSTD_decompressDCtx(zctx->dctx, dst, *dlen, src, slen);
++ if (ZSTD_isError(out_len))
++ return -EINVAL;
++ *dlen = out_len;
++ return 0;
++}
++
++static int zstd_decompress(struct crypto_tfm *tfm, const u8 *src,
++ unsigned int slen, u8 *dst, unsigned int *dlen)
++{
++ struct zstd_ctx *ctx = crypto_tfm_ctx(tfm);
++
++ return __zstd_decompress(src, slen, dst, dlen, ctx);
++}
++
++static int zstd_sdecompress(struct crypto_scomp *tfm, const u8 *src,
++ unsigned int slen, u8 *dst, unsigned int *dlen,
++ void *ctx)
++{
++ return __zstd_decompress(src, slen, dst, dlen, ctx);
++}
++
++static struct crypto_alg alg = {
++ .cra_name = "zstd",
++ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
++ .cra_ctxsize = sizeof(struct zstd_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_init = zstd_init,
++ .cra_exit = zstd_exit,
++ .cra_u = { .compress = {
++ .coa_compress = zstd_compress,
++ .coa_decompress = zstd_decompress } }
++};
++
++static struct scomp_alg scomp = {
++ .alloc_ctx = zstd_alloc_ctx,
++ .free_ctx = zstd_free_ctx,
++ .compress = zstd_scompress,
++ .decompress = zstd_sdecompress,
++ .base = {
++ .cra_name = "zstd",
++ .cra_driver_name = "zstd-scomp",
++ .cra_module = THIS_MODULE,
++ }
++};
++
++static int __init zstd_mod_init(void)
++{
++ int ret;
++
++ ret = crypto_register_alg(&alg);
++ if (ret)
++ return ret;
++
++ ret = crypto_register_scomp(&scomp);
++ if (ret)
++ crypto_unregister_alg(&alg);
++
++ return ret;
++}
++
++static void __exit zstd_mod_fini(void)
++{
++ crypto_unregister_alg(&alg);
++ crypto_unregister_scomp(&scomp);
++}
++
++module_init(zstd_mod_init);
++module_exit(zstd_mod_fini);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Zstd Compression Algorithm");
++MODULE_ALIAS_CRYPTO("zstd");
+--
+2.9.3
diff --git a/src/zstd/contrib/linux-kernel/0006-squashfs-tools-Add-zstd-support.patch b/src/zstd/contrib/linux-kernel/0006-squashfs-tools-Add-zstd-support.patch
new file mode 100644
index 000000000..00d24e2b5
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/0006-squashfs-tools-Add-zstd-support.patch
@@ -0,0 +1,420 @@
+From 57a3cf95b276946559f9e044c7352c11303bb9c1 Mon Sep 17 00:00:00 2001
+From: Sean Purcell <me@seanp.xyz>
+Date: Thu, 3 Aug 2017 17:47:03 -0700
+Subject: [PATCH v6] squashfs-tools: Add zstd support
+
+This patch adds zstd support to squashfs-tools. It works with zstd
+versions >= 1.0.0. It was originally written by Sean Purcell.
+
+Signed-off-by: Sean Purcell <me@seanp.xyz>
+Signed-off-by: Nick Terrell <terrelln@fb.com>
+---
+v4 -> v5:
+- Fix patch documentation to reflect that Sean Purcell is the author
+- Don't strip trailing whitespace of unrelated code
+- Make zstd_display_options() static
+
+v5 -> v6:
+- Fix build instructions in Makefile
+
+ squashfs-tools/Makefile | 20 ++++
+ squashfs-tools/compressor.c | 8 ++
+ squashfs-tools/squashfs_fs.h | 1 +
+ squashfs-tools/zstd_wrapper.c | 254 ++++++++++++++++++++++++++++++++++++++++++
+ squashfs-tools/zstd_wrapper.h | 48 ++++++++
+ 5 files changed, 331 insertions(+)
+ create mode 100644 squashfs-tools/zstd_wrapper.c
+ create mode 100644 squashfs-tools/zstd_wrapper.h
+
+diff --git a/squashfs-tools/Makefile b/squashfs-tools/Makefile
+index 52d2582..22fc559 100644
+--- a/squashfs-tools/Makefile
++++ b/squashfs-tools/Makefile
+@@ -75,6 +75,18 @@ GZIP_SUPPORT = 1
+ #LZMA_SUPPORT = 1
+ #LZMA_DIR = ../../../../LZMA/lzma465
+
++
++########### Building ZSTD support ############
++#
++# The ZSTD library is supported
++# ZSTD homepage: http://zstd.net
++# ZSTD source repository: https://github.com/facebook/zstd
++#
++# To build using the ZSTD library - install the library and uncomment the
++# ZSTD_SUPPORT line below.
++#
++#ZSTD_SUPPORT = 1
++
+ ######## Specifying default compression ########
+ #
+ # The next line specifies which compression algorithm is used by default
+@@ -177,6 +189,14 @@ LIBS += -llz4
+ COMPRESSORS += lz4
+ endif
+
++ifeq ($(ZSTD_SUPPORT),1)
++CFLAGS += -DZSTD_SUPPORT
++MKSQUASHFS_OBJS += zstd_wrapper.o
++UNSQUASHFS_OBJS += zstd_wrapper.o
++LIBS += -lzstd
++COMPRESSORS += zstd
++endif
++
+ ifeq ($(XATTR_SUPPORT),1)
+ ifeq ($(XATTR_DEFAULT),1)
+ CFLAGS += -DXATTR_SUPPORT -DXATTR_DEFAULT
+diff --git a/squashfs-tools/compressor.c b/squashfs-tools/compressor.c
+index 525e316..02b5e90 100644
+--- a/squashfs-tools/compressor.c
++++ b/squashfs-tools/compressor.c
+@@ -65,6 +65,13 @@ static struct compressor xz_comp_ops = {
+ extern struct compressor xz_comp_ops;
+ #endif
+
++#ifndef ZSTD_SUPPORT
++static struct compressor zstd_comp_ops = {
++ ZSTD_COMPRESSION, "zstd"
++};
++#else
++extern struct compressor zstd_comp_ops;
++#endif
+
+ static struct compressor unknown_comp_ops = {
+ 0, "unknown"
+@@ -77,6 +84,7 @@ struct compressor *compressor[] = {
+ &lzo_comp_ops,
+ &lz4_comp_ops,
+ &xz_comp_ops,
++ &zstd_comp_ops,
+ &unknown_comp_ops
+ };
+
+diff --git a/squashfs-tools/squashfs_fs.h b/squashfs-tools/squashfs_fs.h
+index 791fe12..afca918 100644
+--- a/squashfs-tools/squashfs_fs.h
++++ b/squashfs-tools/squashfs_fs.h
+@@ -277,6 +277,7 @@ typedef long long squashfs_inode;
+ #define LZO_COMPRESSION 3
+ #define XZ_COMPRESSION 4
+ #define LZ4_COMPRESSION 5
++#define ZSTD_COMPRESSION 6
+
+ struct squashfs_super_block {
+ unsigned int s_magic;
+diff --git a/squashfs-tools/zstd_wrapper.c b/squashfs-tools/zstd_wrapper.c
+new file mode 100644
+index 0000000..dcab75a
+--- /dev/null
++++ b/squashfs-tools/zstd_wrapper.c
+@@ -0,0 +1,254 @@
++/*
++ * Copyright (c) 2017
++ * Phillip Lougher <phillip@squashfs.org.uk>
++ *
++ * 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,
++ * 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.
++ *
++ * zstd_wrapper.c
++ *
++ * Support for ZSTD compression http://zstd.net
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <zstd.h>
++#include <zstd_errors.h>
++
++#include "squashfs_fs.h"
++#include "zstd_wrapper.h"
++#include "compressor.h"
++
++static int compression_level = ZSTD_DEFAULT_COMPRESSION_LEVEL;
++
++/*
++ * This function is called by the options parsing code in mksquashfs.c
++ * to parse any -X compressor option.
++ *
++ * This function returns:
++ * >=0 (number of additional args parsed) on success
++ * -1 if the option was unrecognised, or
++ * -2 if the option was recognised, but otherwise bad in
++ * some way (e.g. invalid parameter)
++ *
++ * Note: this function sets internal compressor state, but does not
++ * pass back the results of the parsing other than success/failure.
++ * The zstd_dump_options() function is called later to get the options in
++ * a format suitable for writing to the filesystem.
++ */
++static int zstd_options(char *argv[], int argc)
++{
++ if (strcmp(argv[0], "-Xcompression-level") == 0) {
++ if (argc < 2) {
++ fprintf(stderr, "zstd: -Xcompression-level missing "
++ "compression level\n");
++ fprintf(stderr, "zstd: -Xcompression-level it should "
++ "be 1 <= n <= %d\n", ZSTD_maxCLevel());
++ goto failed;
++ }
++
++ compression_level = atoi(argv[1]);
++ if (compression_level < 1 ||
++ compression_level > ZSTD_maxCLevel()) {
++ fprintf(stderr, "zstd: -Xcompression-level invalid, it "
++ "should be 1 <= n <= %d\n", ZSTD_maxCLevel());
++ goto failed;
++ }
++
++ return 1;
++ }
++
++ return -1;
++failed:
++ return -2;
++}
++
++/*
++ * This function is called by mksquashfs to dump the parsed
++ * compressor options in a format suitable for writing to the
++ * compressor options field in the filesystem (stored immediately
++ * after the superblock).
++ *
++ * This function returns a pointer to the compression options structure
++ * to be stored (and the size), or NULL if there are no compression
++ * options.
++ */
++static void *zstd_dump_options(int block_size, int *size)
++{
++ static struct zstd_comp_opts comp_opts;
++
++ /* don't return anything if the options are all default */
++ if (compression_level == ZSTD_DEFAULT_COMPRESSION_LEVEL)
++ return NULL;
++
++ comp_opts.compression_level = compression_level;
++
++ SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
++
++ *size = sizeof(comp_opts);
++ return &comp_opts;
++}
++
++/*
++ * This function is a helper specifically for the append mode of
++ * mksquashfs. Its purpose is to set the internal compressor state
++ * to the stored compressor options in the passed compressor options
++ * structure.
++ *
++ * In effect this function sets up the compressor options
++ * to the same state they were when the filesystem was originally
++ * generated, this is to ensure on appending, the compressor uses
++ * the same compression options that were used to generate the
++ * original filesystem.
++ *
++ * Note, even if there are no compressor options, this function is still
++ * called with an empty compressor structure (size == 0), to explicitly
++ * set the default options, this is to ensure any user supplied
++ * -X options on the appending mksquashfs command line are over-ridden.
++ *
++ * This function returns 0 on successful extraction of options, and -1 on error.
++ */
++static int zstd_extract_options(int block_size, void *buffer, int size)
++{
++ struct zstd_comp_opts *comp_opts = buffer;
++
++ if (size == 0) {
++ /* Set default values */
++ compression_level = ZSTD_DEFAULT_COMPRESSION_LEVEL;
++ return 0;
++ }
++
++ /* we expect a comp_opts structure of sufficient size to be present */
++ if (size < sizeof(*comp_opts))
++ goto failed;
++
++ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
++
++ if (comp_opts->compression_level < 1 ||
++ comp_opts->compression_level > ZSTD_maxCLevel()) {
++ fprintf(stderr, "zstd: bad compression level in compression "
++ "options structure\n");
++ goto failed;
++ }
++
++ compression_level = comp_opts->compression_level;
++
++ return 0;
++
++failed:
++ fprintf(stderr, "zstd: error reading stored compressor options from "
++ "filesystem!\n");
++
++ return -1;
++}
++
++static void zstd_display_options(void *buffer, int size)
++{
++ struct zstd_comp_opts *comp_opts = buffer;
++
++ /* we expect a comp_opts structure of sufficient size to be present */
++ if (size < sizeof(*comp_opts))
++ goto failed;
++
++ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
++
++ if (comp_opts->compression_level < 1 ||
++ comp_opts->compression_level > ZSTD_maxCLevel()) {
++ fprintf(stderr, "zstd: bad compression level in compression "
++ "options structure\n");
++ goto failed;
++ }
++
++ printf("\tcompression-level %d\n", comp_opts->compression_level);
++
++ return;
++
++failed:
++ fprintf(stderr, "zstd: error reading stored compressor options from "
++ "filesystem!\n");
++}
++
++/*
++ * This function is called by mksquashfs to initialise the
++ * compressor, before compress() is called.
++ *
++ * This function returns 0 on success, and -1 on error.
++ */
++static int zstd_init(void **strm, int block_size, int datablock)
++{
++ ZSTD_CCtx *cctx = ZSTD_createCCtx();
++
++ if (!cctx) {
++ fprintf(stderr, "zstd: failed to allocate compression "
++ "context!\n");
++ return -1;
++ }
++
++ *strm = cctx;
++ return 0;
++}
++
++static int zstd_compress(void *strm, void *dest, void *src, int size,
++ int block_size, int *error)
++{
++ const size_t res = ZSTD_compressCCtx((ZSTD_CCtx*)strm, dest, block_size,
++ src, size, compression_level);
++
++ if (ZSTD_isError(res)) {
++ /* FIXME:
++ * zstd does not expose stable error codes. The error enum may
++ * change between versions. Until upstream zstd stablizes the
++ * error codes, we have no way of knowing why the error occurs.
++ * zstd shouldn't fail to compress any input unless there isn't
++ * enough output space. We assume that is the cause and return
++ * the special error code for not enough output space.
++ */
++ return 0;
++ }
++
++ return (int)res;
++}
++
++static int zstd_uncompress(void *dest, void *src, int size, int outsize,
++ int *error)
++{
++ const size_t res = ZSTD_decompress(dest, outsize, src, size);
++
++ if (ZSTD_isError(res)) {
++ fprintf(stderr, "\t%d %d\n", outsize, size);
++
++ *error = (int)ZSTD_getErrorCode(res);
++ return -1;
++ }
++
++ return (int)res;
++}
++
++static void zstd_usage(void)
++{
++ fprintf(stderr, "\t -Xcompression-level <compression-level>\n");
++ fprintf(stderr, "\t\t<compression-level> should be 1 .. %d (default "
++ "%d)\n", ZSTD_maxCLevel(), ZSTD_DEFAULT_COMPRESSION_LEVEL);
++}
++
++struct compressor zstd_comp_ops = {
++ .init = zstd_init,
++ .compress = zstd_compress,
++ .uncompress = zstd_uncompress,
++ .options = zstd_options,
++ .dump_options = zstd_dump_options,
++ .extract_options = zstd_extract_options,
++ .display_options = zstd_display_options,
++ .usage = zstd_usage,
++ .id = ZSTD_COMPRESSION,
++ .name = "zstd",
++ .supported = 1
++};
+diff --git a/squashfs-tools/zstd_wrapper.h b/squashfs-tools/zstd_wrapper.h
+new file mode 100644
+index 0000000..4fbef0a
+--- /dev/null
++++ b/squashfs-tools/zstd_wrapper.h
+@@ -0,0 +1,48 @@
++#ifndef ZSTD_WRAPPER_H
++#define ZSTD_WRAPPER_H
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2017
++ * Phillip Lougher <phillip@squashfs.org.uk>
++ *
++ * 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,
++ * 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.
++ *
++ * zstd_wrapper.h
++ *
++ */
++
++#ifndef linux
++#define __BYTE_ORDER BYTE_ORDER
++#define __BIG_ENDIAN BIG_ENDIAN
++#define __LITTLE_ENDIAN LITTLE_ENDIAN
++#else
++#include <endian.h>
++#endif
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++extern unsigned int inswap_le16(unsigned short);
++extern unsigned int inswap_le32(unsigned int);
++
++#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
++ (s)->compression_level = inswap_le32((s)->compression_level); \
++}
++#else
++#define SQUASHFS_INSWAP_COMP_OPTS(s)
++#endif
++
++/* Default compression */
++#define ZSTD_DEFAULT_COMPRESSION_LEVEL 15
++
++struct zstd_comp_opts {
++ int compression_level;
++};
++#endif
+--
+2.9.5
diff --git a/src/zstd/contrib/linux-kernel/COPYING b/src/zstd/contrib/linux-kernel/COPYING
new file mode 100644
index 000000000..ecbc05937
--- /dev/null
+++ b/src/zstd/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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. \ No newline at end of file
diff --git a/src/zstd/contrib/linux-kernel/README.md b/src/zstd/contrib/linux-kernel/README.md
new file mode 100644
index 000000000..86552b8bd
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/README.md
@@ -0,0 +1,101 @@
+# Linux Kernel 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.
+
+## xxHash kernel module
+
+* The patch is located 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 located 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
+ ```
+
+## BtrFS
+
+* The patch is located in `btrfs.diff`.
+* Additionally `fs/btrfs/zstd.c` is provided as a source for convenience.
+* The patch seems to be working, it doesn't crash the kernel, and compresses at speeds and ratios that are expected.
+ It could still use some more testing for fringe features, like printing options.
+
+### Benchmarks
+
+Benchmarks run on a Ubuntu 14.04 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 kernel running was built from the master branch with the patch.
+
+The compression benchmark is copying 10 copies of the
+unzipped [silesia corpus](http://mattmahoney.net/dc/silesia.html) into a BtrFS
+filesystem mounted with `-o compress-force={none, lzo, zlib, zstd}`.
+The decompression benchmark is timing 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 `btrfs-benchmark.sh` for details.
+
+| Algorithm | Compression ratio | Compression speed | Decompression speed |
+|-----------|-------------------|-------------------|---------------------|
+| None | 0.99 | 504 MB/s | 686 MB/s |
+| lzo | 1.66 | 398 MB/s | 442 MB/s |
+| zlib | 2.58 | 65 MB/s | 241 MB/s |
+| zstd 1 | 2.57 | 260 MB/s | 383 MB/s |
+| zstd 3 | 2.71 | 174 MB/s | 408 MB/s |
+| zstd 6 | 2.87 | 70 MB/s | 398 MB/s |
+| zstd 9 | 2.92 | 43 MB/s | 406 MB/s |
+| zstd 12 | 2.93 | 21 MB/s | 408 MB/s |
+| zstd 15 | 3.01 | 11 MB/s | 354 MB/s |
+
+
+## SquashFS
+
+* The patch is located in `squashfs.diff`
+* Additionally `fs/squashfs/zstd_wrapper.c` is provided as a source for convenience.
+* The patch has been tested on the master branch of the kernel.
+
+### Benchmarks
+
+Benchmarks run on a Ubuntu 14.04 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 kernel running was built from the master branch with the patch.
+
+The compression benchmark is the file tree from the SquashFS archive found in the
+Ubuntu 16.10 desktop image (ubuntu-16.10-desktop-amd64.iso).
+The compression benchmark uses mksquashfs with the default block size (128 KB)
+and various compression algorithms/compression levels.
+`xz` and `zstd` are also benchmarked with 256 KB blocks.
+The decompression benchmark is timing how long it takes to `tar` the file tree
+into `/dev/null`.
+See `squashfs-benchmark.sh` for details.
+
+| Algorithm | Compression ratio | Compression speed | Decompression speed |
+|----------------|-------------------|-------------------|---------------------|
+| gzip | 2.92 | 15 MB/s | 128 MB/s |
+| lzo | 2.64 | 9.5 MB/s | 217 MB/s |
+| lz4 | 2.12 | 94 MB/s | 218 MB/s |
+| xz | 3.43 | 5.5 MB/s | 35 MB/s |
+| xz 256 KB | 3.53 | 5.4 MB/s | 40 MB/s |
+| zstd 1 | 2.71 | 96 MB/s | 210 MB/s |
+| zstd 5 | 2.93 | 69 MB/s | 198 MB/s |
+| zstd 10 | 3.01 | 41 MB/s | 225 MB/s |
+| zstd 15 | 3.13 | 11.4 MB/s | 224 MB/s |
+| zstd 16 256 KB | 3.24 | 8.1 MB/s | 210 MB/s |
diff --git a/src/zstd/contrib/linux-kernel/btrfs-benchmark.sh b/src/zstd/contrib/linux-kernel/btrfs-benchmark.sh
new file mode 100755
index 000000000..5e28da9c6
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/btrfs-benchmark.sh
@@ -0,0 +1,104 @@
+# !/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_DIR="$HOME/silesia/"
+N=10
+
+# 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 "Compression"
+time sh -c "for i in \$(seq $N); do sudo cp -r $BENCHMARK_DIR /mnt/btrfs/\$i; done; sync"
+
+echo "Approximate 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 "Decompression"
+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.
+# Ran zstd with compression levels {1, 3, 6, 9, 12, 15}.
+# Original size: 2119415342 B (using du /mnt/btrfs)
+
+# none
+# compress: 4.205 s
+# decompress: 3.090 s
+# ratio: 0.99
+
+# lzo
+# compress: 5.328 s
+# decompress: 4.793 s
+# ratio: 1.66
+
+# zlib
+# compress: 32.588 s
+# decompress: 8.791 s
+# ratio : 2.58
+
+# zstd 1
+# compress: 8.147 s
+# decompress: 5.527 s
+# ratio : 2.57
+
+# zstd 3
+# compress: 12.207 s
+# decompress: 5.195 s
+# ratio : 2.71
+
+# zstd 6
+# compress: 30.253 s
+# decompress: 5.324 s
+# ratio : 2.87
+
+# zstd 9
+# compress: 49.659 s
+# decompress: 5.220 s
+# ratio : 2.92
+
+# zstd 12
+# compress: 99.245 s
+# decompress: 5.193 s
+# ratio : 2.93
+
+# zstd 15
+# compress: 196.997 s
+# decompress: 5.992 s
+# ratio : 3.01
diff --git a/src/zstd/contrib/linux-kernel/btrfs-extract-benchmark.sh b/src/zstd/contrib/linux-kernel/btrfs-extract-benchmark.sh
new file mode 100755
index 000000000..69721d093
--- /dev/null
+++ b/src/zstd/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/src/zstd/contrib/linux-kernel/fs/btrfs/zstd.c b/src/zstd/contrib/linux-kernel/fs/btrfs/zstd.c
new file mode 100644
index 000000000..607ce47b4
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/fs/btrfs/zstd.c
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ */
+#include <linux/bio.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/refcount.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/zstd.h>
+#include "compression.h"
+
+#define ZSTD_BTRFS_MAX_WINDOWLOG 17
+#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
+#define ZSTD_BTRFS_DEFAULT_LEVEL 3
+
+static ZSTD_parameters zstd_get_btrfs_parameters(size_t src_len)
+{
+ ZSTD_parameters params = ZSTD_getParams(ZSTD_BTRFS_DEFAULT_LEVEL,
+ src_len, 0);
+
+ if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG)
+ params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG;
+ WARN_ON(src_len > ZSTD_BTRFS_MAX_INPUT);
+ return params;
+}
+
+struct workspace {
+ void *mem;
+ size_t size;
+ char *buf;
+ struct list_head list;
+};
+
+static void zstd_free_workspace(struct list_head *ws)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+
+ kvfree(workspace->mem);
+ kfree(workspace->buf);
+ kfree(workspace);
+}
+
+static struct list_head *zstd_alloc_workspace(void)
+{
+ ZSTD_parameters params =
+ zstd_get_btrfs_parameters(ZSTD_BTRFS_MAX_INPUT);
+ struct workspace *workspace;
+
+ workspace = kzalloc(sizeof(*workspace), GFP_KERNEL);
+ if (!workspace)
+ return ERR_PTR(-ENOMEM);
+
+ workspace->size = max_t(size_t,
+ ZSTD_CStreamWorkspaceBound(params.cParams),
+ ZSTD_DStreamWorkspaceBound(ZSTD_BTRFS_MAX_INPUT));
+ workspace->mem = kvmalloc(workspace->size, GFP_KERNEL);
+ workspace->buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!workspace->mem || !workspace->buf)
+ goto fail;
+
+ INIT_LIST_HEAD(&workspace->list);
+
+ return &workspace->list;
+fail:
+ zstd_free_workspace(&workspace->list);
+ return ERR_PTR(-ENOMEM);
+}
+
+static int zstd_compress_pages(struct list_head *ws,
+ struct address_space *mapping,
+ u64 start,
+ struct page **pages,
+ unsigned long *out_pages,
+ unsigned long *total_in,
+ unsigned long *total_out)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+ ZSTD_CStream *stream;
+ int ret = 0;
+ int nr_pages = 0;
+ struct page *in_page = NULL; /* The current page to read */
+ struct page *out_page = NULL; /* The current page to write to */
+ ZSTD_inBuffer in_buf = { NULL, 0, 0 };
+ ZSTD_outBuffer out_buf = { NULL, 0, 0 };
+ unsigned long tot_in = 0;
+ unsigned long tot_out = 0;
+ unsigned long len = *total_out;
+ const unsigned long nr_dest_pages = *out_pages;
+ unsigned long max_out = nr_dest_pages * PAGE_SIZE;
+ ZSTD_parameters params = zstd_get_btrfs_parameters(len);
+
+ *out_pages = 0;
+ *total_out = 0;
+ *total_in = 0;
+
+ /* Initialize the stream */
+ stream = ZSTD_initCStream(params, len, workspace->mem,
+ workspace->size);
+ if (!stream) {
+ pr_warn("BTRFS: ZSTD_initCStream failed\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ /* map in the first page of input data */
+ in_page = find_get_page(mapping, start >> PAGE_SHIFT);
+ in_buf.src = kmap(in_page);
+ in_buf.pos = 0;
+ in_buf.size = min_t(size_t, len, PAGE_SIZE);
+
+
+ /* Allocate and map in the output buffer */
+ out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (out_page == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pages[nr_pages++] = out_page;
+ out_buf.dst = kmap(out_page);
+ out_buf.pos = 0;
+ out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
+
+ while (1) {
+ size_t ret2;
+
+ ret2 = ZSTD_compressStream(stream, &out_buf, &in_buf);
+ if (ZSTD_isError(ret2)) {
+ pr_debug("BTRFS: ZSTD_compressStream returned %d\n",
+ ZSTD_getErrorCode(ret2));
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Check to see if we are making it bigger */
+ if (tot_in + in_buf.pos > 8192 &&
+ tot_in + in_buf.pos <
+ tot_out + out_buf.pos) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ /* We've reached the end of our output range */
+ if (out_buf.pos >= max_out) {
+ tot_out += out_buf.pos;
+ ret = -E2BIG;
+ goto out;
+ }
+
+ /* Check if we need more output space */
+ if (out_buf.pos == out_buf.size) {
+ tot_out += PAGE_SIZE;
+ max_out -= PAGE_SIZE;
+ kunmap(out_page);
+ if (nr_pages == nr_dest_pages) {
+ out_page = NULL;
+ ret = -E2BIG;
+ goto out;
+ }
+ out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (out_page == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pages[nr_pages++] = out_page;
+ out_buf.dst = kmap(out_page);
+ out_buf.pos = 0;
+ out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
+ }
+
+ /* We've reached the end of the input */
+ if (in_buf.pos >= len) {
+ tot_in += in_buf.pos;
+ break;
+ }
+
+ /* Check if we need more input */
+ if (in_buf.pos == in_buf.size) {
+ tot_in += PAGE_SIZE;
+ kunmap(in_page);
+ put_page(in_page);
+
+ start += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ in_page = find_get_page(mapping, start >> PAGE_SHIFT);
+ in_buf.src = kmap(in_page);
+ in_buf.pos = 0;
+ in_buf.size = min_t(size_t, len, PAGE_SIZE);
+ }
+ }
+ while (1) {
+ size_t ret2;
+
+ ret2 = ZSTD_endStream(stream, &out_buf);
+ if (ZSTD_isError(ret2)) {
+ pr_debug("BTRFS: ZSTD_endStream returned %d\n",
+ ZSTD_getErrorCode(ret2));
+ ret = -EIO;
+ goto out;
+ }
+ if (ret2 == 0) {
+ tot_out += out_buf.pos;
+ break;
+ }
+ if (out_buf.pos >= max_out) {
+ tot_out += out_buf.pos;
+ ret = -E2BIG;
+ goto out;
+ }
+
+ tot_out += PAGE_SIZE;
+ max_out -= PAGE_SIZE;
+ kunmap(out_page);
+ if (nr_pages == nr_dest_pages) {
+ out_page = NULL;
+ ret = -E2BIG;
+ goto out;
+ }
+ out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (out_page == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pages[nr_pages++] = out_page;
+ out_buf.dst = kmap(out_page);
+ out_buf.pos = 0;
+ out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
+ }
+
+ if (tot_out >= tot_in) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ ret = 0;
+ *total_in = tot_in;
+ *total_out = tot_out;
+out:
+ *out_pages = nr_pages;
+ /* Cleanup */
+ if (in_page) {
+ kunmap(in_page);
+ put_page(in_page);
+ }
+ if (out_page)
+ kunmap(out_page);
+ return ret;
+}
+
+static int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+ struct page **pages_in = cb->compressed_pages;
+ u64 disk_start = cb->start;
+ struct bio *orig_bio = cb->orig_bio;
+ size_t srclen = cb->compressed_len;
+ ZSTD_DStream *stream;
+ int ret = 0;
+ unsigned long page_in_index = 0;
+ unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
+ unsigned long buf_start;
+ unsigned long total_out = 0;
+ ZSTD_inBuffer in_buf = { NULL, 0, 0 };
+ ZSTD_outBuffer out_buf = { NULL, 0, 0 };
+
+ stream = ZSTD_initDStream(
+ ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);
+ if (!stream) {
+ pr_debug("BTRFS: ZSTD_initDStream failed\n");
+ ret = -EIO;
+ goto done;
+ }
+
+ in_buf.src = kmap(pages_in[page_in_index]);
+ in_buf.pos = 0;
+ in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
+
+ out_buf.dst = workspace->buf;
+ out_buf.pos = 0;
+ out_buf.size = PAGE_SIZE;
+
+ while (1) {
+ size_t ret2;
+
+ ret2 = ZSTD_decompressStream(stream, &out_buf, &in_buf);
+ if (ZSTD_isError(ret2)) {
+ pr_debug("BTRFS: ZSTD_decompressStream returned %d\n",
+ ZSTD_getErrorCode(ret2));
+ ret = -EIO;
+ goto done;
+ }
+ buf_start = total_out;
+ total_out += out_buf.pos;
+ out_buf.pos = 0;
+
+ ret = btrfs_decompress_buf2page(out_buf.dst, buf_start,
+ total_out, disk_start, orig_bio);
+ if (ret == 0)
+ break;
+
+ if (in_buf.pos >= srclen)
+ break;
+
+ /* Check if we've hit the end of a frame */
+ if (ret2 == 0)
+ break;
+
+ if (in_buf.pos == in_buf.size) {
+ kunmap(pages_in[page_in_index++]);
+ if (page_in_index >= total_pages_in) {
+ in_buf.src = NULL;
+ ret = -EIO;
+ goto done;
+ }
+ srclen -= PAGE_SIZE;
+ in_buf.src = kmap(pages_in[page_in_index]);
+ in_buf.pos = 0;
+ in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
+ }
+ }
+ ret = 0;
+ zero_fill_bio(orig_bio);
+done:
+ if (in_buf.src)
+ kunmap(pages_in[page_in_index]);
+ return ret;
+}
+
+static int zstd_decompress(struct list_head *ws, unsigned char *data_in,
+ struct page *dest_page,
+ unsigned long start_byte,
+ size_t srclen, size_t destlen)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+ ZSTD_DStream *stream;
+ int ret = 0;
+ size_t ret2;
+ ZSTD_inBuffer in_buf = { NULL, 0, 0 };
+ ZSTD_outBuffer out_buf = { NULL, 0, 0 };
+ unsigned long total_out = 0;
+ unsigned long pg_offset = 0;
+ char *kaddr;
+
+ stream = ZSTD_initDStream(
+ ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);
+ if (!stream) {
+ pr_warn("BTRFS: ZSTD_initDStream failed\n");
+ ret = -EIO;
+ goto finish;
+ }
+
+ destlen = min_t(size_t, destlen, PAGE_SIZE);
+
+ in_buf.src = data_in;
+ in_buf.pos = 0;
+ in_buf.size = srclen;
+
+ out_buf.dst = workspace->buf;
+ out_buf.pos = 0;
+ out_buf.size = PAGE_SIZE;
+
+ ret2 = 1;
+ while (pg_offset < destlen && in_buf.pos < in_buf.size) {
+ unsigned long buf_start;
+ unsigned long buf_offset;
+ unsigned long bytes;
+
+ /* Check if the frame is over and we still need more input */
+ if (ret2 == 0) {
+ pr_debug("BTRFS: ZSTD_decompressStream ended early\n");
+ ret = -EIO;
+ goto finish;
+ }
+ ret2 = ZSTD_decompressStream(stream, &out_buf, &in_buf);
+ if (ZSTD_isError(ret2)) {
+ pr_debug("BTRFS: ZSTD_decompressStream returned %d\n",
+ ZSTD_getErrorCode(ret2));
+ ret = -EIO;
+ goto finish;
+ }
+
+ buf_start = total_out;
+ total_out += out_buf.pos;
+ out_buf.pos = 0;
+
+ if (total_out <= start_byte)
+ continue;
+
+ if (total_out > start_byte && buf_start < start_byte)
+ buf_offset = start_byte - buf_start;
+ else
+ buf_offset = 0;
+
+ bytes = min_t(unsigned long, destlen - pg_offset,
+ out_buf.size - buf_offset);
+
+ kaddr = kmap_atomic(dest_page);
+ memcpy(kaddr + pg_offset, out_buf.dst + buf_offset, bytes);
+ kunmap_atomic(kaddr);
+
+ pg_offset += bytes;
+ }
+ ret = 0;
+finish:
+ if (pg_offset < destlen) {
+ kaddr = kmap_atomic(dest_page);
+ memset(kaddr + pg_offset, 0, destlen - pg_offset);
+ kunmap_atomic(kaddr);
+ }
+ return ret;
+}
+
+const struct btrfs_compress_op btrfs_zstd_compress = {
+ .alloc_workspace = zstd_alloc_workspace,
+ .free_workspace = zstd_free_workspace,
+ .compress_pages = zstd_compress_pages,
+ .decompress_bio = zstd_decompress_bio,
+ .decompress = zstd_decompress,
+};
diff --git a/src/zstd/contrib/linux-kernel/fs/squashfs/zstd_wrapper.c b/src/zstd/contrib/linux-kernel/fs/squashfs/zstd_wrapper.c
new file mode 100644
index 000000000..eeaabf881
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/fs/squashfs/zstd_wrapper.c
@@ -0,0 +1,151 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * 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
+ * as published by the Free Software Foundation; either version 2,
+ * 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.
+ *
+ * zstd_wrapper.c
+ */
+
+#include <linux/mutex.h>
+#include <linux/buffer_head.h>
+#include <linux/slab.h>
+#include <linux/zstd.h>
+#include <linux/vmalloc.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs.h"
+#include "decompressor.h"
+#include "page_actor.h"
+
+struct workspace {
+ void *mem;
+ size_t mem_size;
+ size_t window_size;
+};
+
+static void *zstd_init(struct squashfs_sb_info *msblk, void *buff)
+{
+ struct workspace *wksp = kmalloc(sizeof(*wksp), GFP_KERNEL);
+
+ if (wksp == NULL)
+ goto failed;
+ wksp->window_size = max_t(size_t,
+ msblk->block_size, SQUASHFS_METADATA_SIZE);
+ wksp->mem_size = ZSTD_DStreamWorkspaceBound(wksp->window_size);
+ wksp->mem = vmalloc(wksp->mem_size);
+ if (wksp->mem == NULL)
+ goto failed;
+
+ return wksp;
+
+failed:
+ ERROR("Failed to allocate zstd workspace\n");
+ kfree(wksp);
+ return ERR_PTR(-ENOMEM);
+}
+
+
+static void zstd_free(void *strm)
+{
+ struct workspace *wksp = strm;
+
+ if (wksp)
+ vfree(wksp->mem);
+ kfree(wksp);
+}
+
+
+static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
+ struct buffer_head **bh, int b, int offset, int length,
+ struct squashfs_page_actor *output)
+{
+ struct workspace *wksp = strm;
+ ZSTD_DStream *stream;
+ size_t total_out = 0;
+ size_t zstd_err;
+ int k = 0;
+ ZSTD_inBuffer in_buf = { NULL, 0, 0 };
+ ZSTD_outBuffer out_buf = { NULL, 0, 0 };
+
+ stream = ZSTD_initDStream(wksp->window_size, wksp->mem, wksp->mem_size);
+
+ if (!stream) {
+ ERROR("Failed to initialize zstd decompressor\n");
+ goto out;
+ }
+
+ out_buf.size = PAGE_SIZE;
+ out_buf.dst = squashfs_first_page(output);
+
+ do {
+ if (in_buf.pos == in_buf.size && k < b) {
+ int avail = min(length, msblk->devblksize - offset);
+
+ length -= avail;
+ in_buf.src = bh[k]->b_data + offset;
+ in_buf.size = avail;
+ in_buf.pos = 0;
+ offset = 0;
+ }
+
+ if (out_buf.pos == out_buf.size) {
+ out_buf.dst = squashfs_next_page(output);
+ if (out_buf.dst == NULL) {
+ /* Shouldn't run out of pages
+ * before stream is done.
+ */
+ squashfs_finish_page(output);
+ goto out;
+ }
+ out_buf.pos = 0;
+ out_buf.size = PAGE_SIZE;
+ }
+
+ total_out -= out_buf.pos;
+ zstd_err = ZSTD_decompressStream(stream, &out_buf, &in_buf);
+ total_out += out_buf.pos; /* add the additional data produced */
+
+ if (in_buf.pos == in_buf.size && k < b)
+ put_bh(bh[k++]);
+ } while (zstd_err != 0 && !ZSTD_isError(zstd_err));
+
+ squashfs_finish_page(output);
+
+ if (ZSTD_isError(zstd_err)) {
+ ERROR("zstd decompression error: %d\n",
+ (int)ZSTD_getErrorCode(zstd_err));
+ goto out;
+ }
+
+ if (k < b)
+ goto out;
+
+ return (int)total_out;
+
+out:
+ for (; k < b; k++)
+ put_bh(bh[k]);
+
+ return -EIO;
+}
+
+const struct squashfs_decompressor squashfs_zstd_comp_ops = {
+ .init = zstd_init,
+ .free = zstd_free,
+ .decompress = zstd_uncompress,
+ .id = ZSTD_COMPRESSION,
+ .name = "zstd",
+ .supported = 1
+};
diff --git a/src/zstd/contrib/linux-kernel/include/linux/xxhash.h b/src/zstd/contrib/linux-kernel/include/linux/xxhash.h
new file mode 100644
index 000000000..9e1f42cb5
--- /dev/null
+++ b/src/zstd/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 <linux/types.h>
+
+/*-****************************
+ * 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/src/zstd/contrib/linux-kernel/include/linux/zstd.h b/src/zstd/contrib/linux-kernel/include/linux/zstd.h
new file mode 100644
index 000000000..305efd093
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/include/linux/zstd.h
@@ -0,0 +1,1155 @@
+/*
+ * 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.
+ *
+ * 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 <linux/types.h> /* 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/src/zstd/contrib/linux-kernel/kernelize.sh b/src/zstd/contrib/linux-kernel/kernelize.sh
new file mode 100755
index 000000000..21aa2ecdc
--- /dev/null
+++ b/src/zstd/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 <<EOF
+s/current/curr/g
+s/MEM_STATIC/ZSTD_STATIC/g
+s/MEM_check/ZSTD_check/g
+s/MEM_32bits/ZSTD_32bits/g
+s/MEM_64bits/ZSTD_64bits/g
+s/MEM_LITTLE_ENDIAN/ZSTD_LITTLE_ENDIAN/g
+s/MEM_isLittleEndian/ZSTD_isLittleEndian/g
+s/MEM_read/ZSTD_read/g
+s/MEM_write/ZSTD_write/g
+EOF
+
+prompt "Do you wish to run these sed commands $(cat $SED_COMMANDS)?"
+if [ ! -z "$yes" ]
+then
+ sed -i '' -f $SED_COMMANDS $LIB*.{h,c}
+fi
+rm -f $SED_COMMANDS
+
+prompt "Do you wish to clang-format $LIB*.{h,c}?"
+if [ ! -z "$yes" ]
+then
+ $CLANG_FORMAT -i ${LIB}*.{h,c}
+fi
+
+prompt "Do you wish to run some checks?"
+if [ ! -z "$yes" ]
+then
+ check_present_in_file ZSTD_STATIC_ASSERT ${LIB}zstd_internal.h
+ check_not_present_in_file STATIC_ASSERT ${LIB}mem.h
+ check_not_present_in_file "#define ZSTD_STATIC_ASSERT" ${LIB}compress.c
+ check_not_present MEM_STATIC
+ check_not_present FSE_COMMONDEFS_ONLY
+ check_not_present "#if 0"
+ check_not_present "#if 1"
+ check_not_present _MSC_VER
+ check_not_present __cplusplus
+ check_not_present __STDC_VERSION__
+ check_not_present __VMS
+ check_not_present __GNUC__
+ check_not_present __INTEL_COMPILER
+ check_not_present FORCE_MEMORY_ACCESS
+ check_not_present STATIC_LINKING_ONLY
+fi
diff --git a/src/zstd/contrib/linux-kernel/lib/Kconfig.diff b/src/zstd/contrib/linux-kernel/lib/Kconfig.diff
new file mode 100644
index 000000000..227c6e2cc
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/Kconfig.diff
@@ -0,0 +1,19 @@
+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/src/zstd/contrib/linux-kernel/lib/Makefile.diff b/src/zstd/contrib/linux-kernel/lib/Makefile.diff
new file mode 100644
index 000000000..f92efe8e9
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/Makefile.diff
@@ -0,0 +1,13 @@
+diff --git a/lib/Makefile b/lib/Makefile
+index e16f94a..0cfd529 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -115,6 +115,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/src/zstd/contrib/linux-kernel/lib/xxhash.c b/src/zstd/contrib/linux-kernel/lib/xxhash.c
new file mode 100644
index 000000000..aa61e2a38
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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 <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/xxhash.h>
+
+/*-*************************************
+ * 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/src/zstd/contrib/linux-kernel/lib/zstd/.clang-format b/src/zstd/contrib/linux-kernel/lib/zstd/.clang-format
new file mode 100644
index 000000000..0c6cf3ba7
--- /dev/null
+++ b/src/zstd/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/src/zstd/contrib/linux-kernel/lib/zstd/Makefile b/src/zstd/contrib/linux-kernel/lib/zstd/Makefile
new file mode 100644
index 000000000..dd0a359c1
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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/src/zstd/contrib/linux-kernel/lib/zstd/bitstream.h b/src/zstd/contrib/linux-kernel/lib/zstd/bitstream.h
new file mode 100644
index 000000000..a826b99e1
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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/src/zstd/contrib/linux-kernel/lib/zstd/compress.c b/src/zstd/contrib/linux-kernel/lib/zstd/compress.c
new file mode 100644
index 000000000..43535b8db
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/zstd/compress.c
@@ -0,0 +1,3482 @@
+/**
+ * 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.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h> /* 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<<wLog, even for dictionary */
+ U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
+ ZSTD_compressionStage_e stage;
+ U32 rep[ZSTD_REP_NUM];
+ U32 repToConfirm[ZSTD_REP_NUM];
+ U32 dictID;
+ ZSTD_parameters params;
+ void *workSpace;
+ size_t workSpaceSize;
+ size_t blockSize;
+ U64 frameContentSize;
+ struct xxh64_state xxhState;
+ ZSTD_customMem customMem;
+
+ seqStore_t seqStore; /* sequences storage ptrs */
+ U32 *hashTable;
+ U32 *hashTable3;
+ U32 *chainTable;
+ HUF_CElt *hufTable;
+ U32 flagStaticTables;
+ HUF_repeat flagStaticHufTable;
+ FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
+ FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
+ FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
+ unsigned tmpCounters[HUF_COMPRESS_WORKSPACE_SIZE_U32];
+};
+
+size_t ZSTD_CCtxWorkspaceBound(ZSTD_compressionParameters cParams)
+{
+ size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
+ U32 const divider = (cParams.searchLength == 3) ? 3 : 4;
+ size_t const maxNbSeq = blockSize / divider;
+ size_t const tokenSpace = blockSize + 11 * maxNbSeq;
+ size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
+ size_t const hSize = ((size_t)1) << cParams.hashLog;
+ 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 << 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_internal(ZSTD_CCtx *zc, void *dst, size_t dstCapacity)
+{
+ 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)
+ return op - ostart;
+
+ /* 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;
+ }
+ }
+ return op - ostart;
+}
+
+ZSTD_STATIC size_t ZSTD_compressSequences(ZSTD_CCtx *zc, void *dst, size_t dstCapacity, size_t srcSize)
+{
+ size_t const cSize = ZSTD_compressSequences_internal(zc, dst, dstCapacity);
+ size_t const minGain = ZSTD_minGain(srcSize);
+ size_t const maxCSize = srcSize - minGain;
+ /* If the srcSize <= dstCapacity, then there is enough space to write a
+ * raw uncompressed block. Since we ran out of space, the block must not
+ * be compressible, so fall back to a raw uncompressed block.
+ */
+ int const uncompressibleError = cSize == ERROR(dstSize_tooSmall) && srcSize <= dstCapacity;
+ int i;
+
+ if (ZSTD_isError(cSize) && !uncompressibleError)
+ return cSize;
+ if (cSize >= maxCSize || uncompressibleError) {
+ zc->flagStaticHufTable = HUF_repeat_none;
+ return 0;
+ }
+ /* confirm repcodes */
+ for (i = 0; i < ZSTD_REP_NUM; i++)
+ zc->rep[i] = zc->repToConfirm[i];
+ return cSize;
+}
+
+/*! 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 frameHeaderDescriptionByte = (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] = frameHeaderDescriptionByte;
+ 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(&params, 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/src/zstd/contrib/linux-kernel/lib/zstd/decompress.c b/src/zstd/contrib/linux-kernel/lib/zstd/decompress.c
new file mode 100644
index 000000000..72df4828d
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h> /* 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 */
+
+ seq.match = NULL;
+
+ 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/src/zstd/contrib/linux-kernel/lib/zstd/entropy_common.c b/src/zstd/contrib/linux-kernel/lib/zstd/entropy_common.c
new file mode 100644
index 000000000..2b0a643c3
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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/src/zstd/contrib/linux-kernel/lib/zstd/error_private.h b/src/zstd/contrib/linux-kernel/lib/zstd/error_private.h
new file mode 100644
index 000000000..2062ff05a
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/zstd/error_private.h
@@ -0,0 +1,51 @@
+/**
+ * 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.
+ *
+ * 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 <linux/types.h> /* size_t */
+#include <linux/zstd.h> /* 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/src/zstd/contrib/linux-kernel/lib/zstd/fse.h b/src/zstd/contrib/linux-kernel/lib/zstd/fse.h
new file mode 100644
index 000000000..a694199fd
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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 <linux/types.h> /* 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) + 4 /* constant for initial fse states */ )
+#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<<tableLog)`.
+ */
+size_t FSE_buildCTable_wksp(FSE_CTable *ct, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize);
+
+size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits);
+/**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
+
+size_t FSE_buildDTable_rle(FSE_DTable *dt, unsigned char symbolValue);
+/**< build a fake FSE_DTable, designed to always generate the same symbolValue */
+
+size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize);
+/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
+
+/* *****************************************
+* FSE symbol compression API
+*******************************************/
+/*!
+ This API consists of small unitary functions, which highly benefit from being inlined.
+ Hence their body are included in next section.
+*/
+typedef struct {
+ ptrdiff_t value;
+ const void *stateTable;
+ const void *symbolTT;
+ unsigned stateLog;
+} FSE_CState_t;
+
+static void FSE_initCState(FSE_CState_t *CStatePtr, const FSE_CTable *ct);
+
+static void FSE_encodeSymbol(BIT_CStream_t *bitC, FSE_CState_t *CStatePtr, unsigned symbol);
+
+static void FSE_flushCState(BIT_CStream_t *bitC, const FSE_CState_t *CStatePtr);
+
+/**<
+These functions are inner components of FSE_compress_usingCTable().
+They allow the creation of custom streams, mixing multiple tables and bit sources.
+
+A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
+So the first symbol you will encode is the last you will decode, like a LIFO stack.
+
+You will need a few variables to track your CStream. They are :
+
+FSE_CTable ct; // Provided by FSE_buildCTable()
+BIT_CStream_t bitStream; // bitStream tracking structure
+FSE_CState_t state; // State tracking structure (can have several)
+
+
+The first thing to do is to init bitStream and state.
+ size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
+ FSE_initCState(&state, ct);
+
+Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
+You can then encode your input data, byte after byte.
+FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
+Remember decoding will be done in reverse direction.
+ FSE_encodeByte(&bitStream, &state, symbol);
+
+At any time, you can also add any bit sequence.
+Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
+ BIT_addBits(&bitStream, bitField, nbBits);
+
+The above methods don't commit data to memory, they just store it into local register, for speed.
+Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
+Writing data to memory is a manual operation, performed by the flushBits function.
+ BIT_flushBits(&bitStream);
+
+Your last FSE encoding operation shall be to flush your last state value(s).
+ FSE_flushState(&bitStream, &state);
+
+Finally, you must close the bitStream.
+The function returns the size of CStream in bytes.
+If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
+If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
+ size_t size = BIT_closeCStream(&bitStream);
+*/
+
+/* *****************************************
+* FSE symbol decompression API
+*******************************************/
+typedef struct {
+ size_t state;
+ const void *table; /* precise table may vary, depending on U16 */
+} FSE_DState_t;
+
+static void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, const FSE_DTable *dt);
+
+static unsigned char FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD);
+
+static unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr);
+
+/**<
+Let's now decompose FSE_decompress_usingDTable() into its unitary components.
+You will decode FSE-encoded symbols from the bitStream,
+and also any other bitFields you put in, **in reverse order**.
+
+You will need a few variables to track your bitStream. They are :
+
+BIT_DStream_t DStream; // Stream context
+FSE_DState_t DState; // State context. Multiple ones are possible
+FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
+
+The first thing to do is to init the bitStream.
+ errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
+
+You should then retrieve your initial state(s)
+(in reverse flushing order if you have several ones) :
+ errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
+
+You can then decode your data, symbol after symbol.
+For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
+Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
+ unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
+
+You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
+Note : maximum allowed nbBits is 25, for 32-bits compatibility
+ size_t bitField = BIT_readBits(&DStream, nbBits);
+
+All above operations only read from local register (which size depends on size_t).
+Refueling the register from memory is manually performed by the reload method.
+ endSignal = FSE_reloadDStream(&DStream);
+
+BIT_reloadDStream() result tells if there is still some more data to read from DStream.
+BIT_DStream_unfinished : there is still some data left into the DStream.
+BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
+BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
+BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
+
+When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
+to properly detect the exact end of stream.
+After each decoded symbol, check if DStream is fully consumed using this simple test :
+ BIT_reloadDStream(&DStream) >= 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/src/zstd/contrib/linux-kernel/lib/zstd/fse_compress.c b/src/zstd/contrib/linux-kernel/lib/zstd/fse_compress.c
new file mode 100644
index 000000000..0fe468edf
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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 <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/string.h> /* 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<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
+ * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
+ */
+size_t FSE_buildCTable_wksp(FSE_CTable *ct, const short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t workspaceSize)
+{
+ U32 const tableSize = 1 << tableLog;
+ U32 const tableMask = tableSize - 1;
+ 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 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 nbOccurrences;
+ for (nbOccurrences = 0; nbOccurrences < normalizedCounter[symbol]; nbOccurrences++) {
+ 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/src/zstd/contrib/linux-kernel/lib/zstd/fse_decompress.c b/src/zstd/contrib/linux-kernel/lib/zstd/fse_decompress.c
new file mode 100644
index 000000000..a84300e5a
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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 <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/string.h> /* 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/src/zstd/contrib/linux-kernel/lib/zstd/huf.h b/src/zstd/contrib/linux-kernel/lib/zstd/huf.h
new file mode 100644
index 000000000..923218d12
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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 <linux/types.h> /* 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 assumed 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/src/zstd/contrib/linux-kernel/lib/zstd/huf_compress.c b/src/zstd/contrib/linux-kernel/lib/zstd/huf_compress.c
new file mode 100644
index 000000000..40055a701
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/zstd/huf_compress.c
@@ -0,0 +1,770 @@
+/*
+ * 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 <linux/kernel.h>
+#include <linux/string.h> /* 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) 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;
+ 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/src/zstd/contrib/linux-kernel/lib/zstd/huf_decompress.c b/src/zstd/contrib/linux-kernel/lib/zstd/huf_decompress.c
new file mode 100644
index 000000000..652648204
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/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 <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/string.h> /* 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/src/zstd/contrib/linux-kernel/lib/zstd/mem.h b/src/zstd/contrib/linux-kernel/lib/zstd/mem.h
new file mode 100644
index 000000000..42a697b74
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/zstd/mem.h
@@ -0,0 +1,149 @@
+/**
+ * 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.
+ *
+ * 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 <asm/unaligned.h>
+#include <linux/string.h> /* memcpy */
+#include <linux/types.h> /* 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/src/zstd/contrib/linux-kernel/lib/zstd/zstd_common.c b/src/zstd/contrib/linux-kernel/lib/zstd/zstd_common.c
new file mode 100644
index 000000000..e5f06d771
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/zstd/zstd_common.c
@@ -0,0 +1,73 @@
+/**
+ * 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.
+ *
+ * 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 <linux/kernel.h>
+
+/*=**************************************************************
+* 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/src/zstd/contrib/linux-kernel/lib/zstd/zstd_internal.h b/src/zstd/contrib/linux-kernel/lib/zstd/zstd_internal.h
new file mode 100644
index 000000000..a0fb83e34
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/zstd/zstd_internal.h
@@ -0,0 +1,261 @@
+/**
+ * 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.
+ *
+ * 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 <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/xxhash.h>
+#include <linux/zstd.h>
+
+/*-*************************************
+* 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
+*********************************************/
+ZSTD_STATIC void ZSTD_copy8(void *dst, const void *src) {
+ memcpy(dst, src, 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;
+ /* Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
+ * Avoid the bad case where the loop only runs once by handling the
+ * special case separately. This doesn't trigger the bug because it
+ * doesn't involve pointer/integer overflow.
+ */
+ if (length <= 8)
+ return ZSTD_copy8(dst, src);
+ do {
+ ZSTD_copy8(op, ip);
+ op += 8;
+ ip += 8;
+ } 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/src/zstd/contrib/linux-kernel/lib/zstd/zstd_opt.h b/src/zstd/contrib/linux-kernel/lib/zstd/zstd_opt.h
new file mode 100644
index 000000000..ecdd7259e
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/lib/zstd/zstd_opt.h
@@ -0,0 +1,1012 @@
+/**
+ * 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.
+ *
+ * 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 */
diff --git a/src/zstd/contrib/linux-kernel/squashfs-benchmark.sh b/src/zstd/contrib/linux-kernel/squashfs-benchmark.sh
new file mode 100755
index 000000000..02dfd7325
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/squashfs-benchmark.sh
@@ -0,0 +1,39 @@
+# !/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.
+
+# $BENCHMARK_DIR is generated with the following commands, from the Ubuntu image
+# ubuntu-16.10-desktop-amd64.iso.
+# > mkdir mnt
+# > sudo mount -o loop ubuntu-16.10-desktop-amd64.iso mnt
+# > cp mnt/casper/filesystem.squashfs .
+# > sudo unsquashfs filesystem.squashfs
+
+# $HOME is on a ext4 filesystem
+BENCHMARK_DIR="$HOME/squashfs-root/"
+BENCHMARK_FS="$HOME/filesystem.squashfs"
+
+# Normalize the environment
+sudo rm -f $BENCHMARK_FS 2> /dev/null > /dev/null || true
+sudo umount /mnt/squashfs 2> /dev/null > /dev/null || true
+
+# Run the benchmark
+echo "Compression"
+echo "sudo mksquashfs $BENCHMARK_DIR $BENCHMARK_FS $@"
+time sudo mksquashfs $BENCHMARK_DIR $BENCHMARK_FS $@ 2> /dev/null > /dev/null
+
+echo "Approximate compression ratio"
+printf "%d / %d\n" \
+ $(sudo du -sx --block-size=1 $BENCHMARK_DIR | cut -f1) \
+ $(sudo du -sx --block-size=1 $BENCHMARK_FS | cut -f1);
+
+# Mount the filesystem
+sudo mount -t squashfs $BENCHMARK_FS /mnt/squashfs
+
+echo "Decompression"
+time sudo tar -c /mnt/squashfs 2> /dev/null | wc -c > /dev/null
+
+sudo umount /mnt/squashfs
diff --git a/src/zstd/contrib/linux-kernel/test/.gitignore b/src/zstd/contrib/linux-kernel/test/.gitignore
new file mode 100644
index 000000000..4fc10228d
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/.gitignore
@@ -0,0 +1 @@
+*Test
diff --git a/src/zstd/contrib/linux-kernel/test/DecompressCrash.c b/src/zstd/contrib/linux-kernel/test/DecompressCrash.c
new file mode 100644
index 000000000..2ab7dfe52
--- /dev/null
+++ b/src/zstd/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 both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/*
+ 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 <stddef.h> /* size_t */
+#include <stdlib.h> /* malloc, free, exit */
+#include <stdio.h> /* fprintf */
+#include <linux/zstd.h>
+
+/*===========================================
+* 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/src/zstd/contrib/linux-kernel/test/Makefile b/src/zstd/contrib/linux-kernel/test/Makefile
new file mode 100644
index 000000000..8411462c9
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/Makefile
@@ -0,0 +1,43 @@
+
+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 -g -O3 -Wcast-align
+CFLAGS += -g -O3 -Wframe-larger-than=400 -Wcast-align
+CPPFLAGS += $(IFLAGS)
+
+../lib/zstd/libzstd.a: $(OBJECTS)
+ $(AR) $(ARFLAGS) $@ $^
+
+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:
+ @$(RM) -rf googletest
+ @git clone https://github.com/google/googletest
+ @mkdir -p googletest/build
+ @cd googletest/build && cmake .. && $(MAKE)
+
+clean:
+ $(RM) -f *.{o,a} ../lib/zstd/*.{o,a} ../lib/*.o
+ $(RM) -f DecompressCrash RoundTripCrash UserlandTest XXHashUserlandTest
diff --git a/src/zstd/contrib/linux-kernel/test/RoundTripCrash.c b/src/zstd/contrib/linux-kernel/test/RoundTripCrash.c
new file mode 100644
index 000000000..4f968023d
--- /dev/null
+++ b/src/zstd/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 both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/*
+ 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 <stddef.h> /* size_t */
+#include <stdlib.h> /* malloc, free, exit */
+#include <stdio.h> /* fprintf */
+#include <linux/xxhash.h>
+#include <linux/zstd.h>
+
+/*===========================================
+* 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; pos++)
+ if (ip1[pos]!=ip2[pos])
+ break;
+
+ return pos;
+}
+
+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 roundTripCheck(const void* srcBuff, size_t srcBuffSize)
+{
+ size_t const neededBuffSize = ZSTD_compressBound(srcBuffSize);
+
+ /* Allocate all buffers and contexts if not already allocated */
+ if (neededBuffSize > 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/src/zstd/contrib/linux-kernel/test/UserlandTest.cpp b/src/zstd/contrib/linux-kernel/test/UserlandTest.cpp
new file mode 100644
index 000000000..03058382f
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/UserlandTest.cpp
@@ -0,0 +1,565 @@
+extern "C" {
+#include <linux/zstd.h>
+}
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+#include <iostream>
+
+using namespace std;
+
+namespace {
+struct WorkspaceDeleter {
+ void *memory;
+
+ template <typename T> void operator()(T const *) { free(memory); }
+};
+
+std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter>
+createCCtx(ZSTD_compressionParameters cParams) {
+ size_t const workspaceSize = ZSTD_CCtxWorkspaceBound(cParams);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter> cctx{
+ ZSTD_initCCtx(workspace, workspaceSize), WorkspaceDeleter{workspace}};
+ if (!cctx) {
+ throw std::runtime_error{"Bad cctx"};
+ }
+ return cctx;
+}
+
+std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter>
+createCCtx(int level, unsigned long long estimatedSrcSize = 0,
+ size_t dictSize = 0) {
+ auto const cParams = ZSTD_getCParams(level, estimatedSrcSize, dictSize);
+ return createCCtx(cParams);
+}
+
+std::unique_ptr<ZSTD_DCtx, WorkspaceDeleter>
+createDCtx() {
+ size_t const workspaceSize = ZSTD_DCtxWorkspaceBound();
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_DCtx, WorkspaceDeleter> dctx{
+ ZSTD_initDCtx(workspace, workspaceSize), WorkspaceDeleter{workspace}};
+ if (!dctx) {
+ throw std::runtime_error{"Bad dctx"};
+ }
+ return dctx;
+}
+
+std::unique_ptr<ZSTD_CDict, WorkspaceDeleter>
+createCDict(std::string const& dict, ZSTD_parameters params) {
+ size_t const workspaceSize = ZSTD_CDictWorkspaceBound(params.cParams);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_CDict, WorkspaceDeleter> cdict{
+ ZSTD_initCDict(dict.data(), dict.size(), params, workspace,
+ workspaceSize),
+ WorkspaceDeleter{workspace}};
+ if (!cdict) {
+ throw std::runtime_error{"Bad cdict"};
+ }
+ return cdict;
+}
+
+std::unique_ptr<ZSTD_CDict, WorkspaceDeleter>
+createCDict(std::string const& dict, int level) {
+ auto const params = ZSTD_getParams(level, 0, dict.size());
+ return createCDict(dict, params);
+}
+
+std::unique_ptr<ZSTD_DDict, WorkspaceDeleter>
+createDDict(std::string const& dict) {
+ size_t const workspaceSize = ZSTD_DDictWorkspaceBound();
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_DDict, WorkspaceDeleter> ddict{
+ ZSTD_initDDict(dict.data(), dict.size(), workspace, workspaceSize),
+ WorkspaceDeleter{workspace}};
+ if (!ddict) {
+ throw std::runtime_error{"Bad ddict"};
+ }
+ return ddict;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(ZSTD_parameters params, unsigned long long pledgedSrcSize = 0) {
+ size_t const workspaceSize = ZSTD_CStreamWorkspaceBound(params.cParams);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_CStream, WorkspaceDeleter> zcs{
+ ZSTD_initCStream(params, pledgedSrcSize, workspace, workspaceSize)};
+ if (!zcs) {
+ throw std::runtime_error{"bad cstream"};
+ }
+ return zcs;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(ZSTD_compressionParameters cParams, ZSTD_CDict const &cdict,
+ unsigned long long pledgedSrcSize = 0) {
+ size_t const workspaceSize = ZSTD_CStreamWorkspaceBound(cParams);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_CStream, WorkspaceDeleter> zcs{
+ ZSTD_initCStream_usingCDict(&cdict, pledgedSrcSize, workspace,
+ workspaceSize)};
+ if (!zcs) {
+ throw std::runtime_error{"bad cstream"};
+ }
+ return zcs;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(int level, unsigned long long pledgedSrcSize = 0) {
+ auto const params = ZSTD_getParams(level, pledgedSrcSize, 0);
+ return createCStream(params, pledgedSrcSize);
+}
+
+std::unique_ptr<ZSTD_DStream, WorkspaceDeleter>
+createDStream(size_t maxWindowSize = (1ULL << ZSTD_WINDOWLOG_MAX),
+ ZSTD_DDict const *ddict = nullptr) {
+ size_t const workspaceSize = ZSTD_DStreamWorkspaceBound(maxWindowSize);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_DStream, WorkspaceDeleter> zds{
+ ddict == nullptr
+ ? ZSTD_initDStream(maxWindowSize, workspace, workspaceSize)
+ : ZSTD_initDStream_usingDDict(maxWindowSize, ddict, workspace,
+ workspaceSize)};
+ if (!zds) {
+ throw std::runtime_error{"bad dstream"};
+ }
+ return zds;
+}
+
+std::string compress(ZSTD_CCtx &cctx, std::string const &data,
+ ZSTD_parameters params, std::string const &dict = "") {
+ std::string compressed;
+ compressed.resize(ZSTD_compressBound(data.size()));
+ size_t const rc =
+ dict.empty()
+ ? ZSTD_compressCCtx(&cctx, &compressed[0], compressed.size(),
+ data.data(), data.size(), params)
+ : ZSTD_compress_usingDict(&cctx, &compressed[0], compressed.size(),
+ data.data(), data.size(), dict.data(),
+ dict.size(), params);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"compression error"};
+ }
+ compressed.resize(rc);
+ return compressed;
+}
+
+std::string compress(ZSTD_CCtx& cctx, std::string const& data, int level, std::string const& dict = "") {
+ auto const params = ZSTD_getParams(level, 0, dict.size());
+ return compress(cctx, data, params, dict);
+}
+
+std::string decompress(ZSTD_DCtx& dctx, std::string const& compressed, size_t decompressedSize, std::string const& dict = "") {
+ std::string decompressed;
+ decompressed.resize(decompressedSize);
+ size_t const rc =
+ dict.empty()
+ ? ZSTD_decompressDCtx(&dctx, &decompressed[0], decompressed.size(),
+ compressed.data(), compressed.size())
+ : ZSTD_decompress_usingDict(
+ &dctx, &decompressed[0], decompressed.size(), compressed.data(),
+ compressed.size(), dict.data(), dict.size());
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"decompression error"};
+ }
+ decompressed.resize(rc);
+ return decompressed;
+}
+
+std::string compress(ZSTD_CCtx& cctx, std::string const& data, ZSTD_CDict& cdict) {
+ std::string compressed;
+ compressed.resize(ZSTD_compressBound(data.size()));
+ size_t const rc =
+ ZSTD_compress_usingCDict(&cctx, &compressed[0], compressed.size(),
+ data.data(), data.size(), &cdict);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"compression error"};
+ }
+ compressed.resize(rc);
+ return compressed;
+}
+
+std::string decompress(ZSTD_DCtx& dctx, std::string const& compressed, size_t decompressedSize, ZSTD_DDict& ddict) {
+ std::string decompressed;
+ decompressed.resize(decompressedSize);
+ size_t const rc =
+ ZSTD_decompress_usingDDict(&dctx, &decompressed[0], decompressed.size(),
+ compressed.data(), compressed.size(), &ddict);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"decompression error"};
+ }
+ decompressed.resize(rc);
+ return decompressed;
+}
+
+std::string compress(ZSTD_CStream& zcs, std::string const& data) {
+ std::string compressed;
+ compressed.resize(ZSTD_compressBound(data.size()));
+ ZSTD_inBuffer in = {data.data(), data.size(), 0};
+ ZSTD_outBuffer out = {&compressed[0], compressed.size(), 0};
+ while (in.pos != in.size) {
+ size_t const rc = ZSTD_compressStream(&zcs, &out, &in);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"compress stream failed"};
+ }
+ }
+ size_t const rc = ZSTD_endStream(&zcs, &out);
+ if (rc != 0) {
+ throw std::runtime_error{"compress end failed"};
+ }
+ compressed.resize(out.pos);
+ return compressed;
+}
+
+std::string decompress(ZSTD_DStream &zds, std::string const &compressed,
+ size_t decompressedSize) {
+ std::string decompressed;
+ decompressed.resize(decompressedSize);
+ ZSTD_inBuffer in = {compressed.data(), compressed.size(), 0};
+ ZSTD_outBuffer out = {&decompressed[0], decompressed.size(), 0};
+ while (in.pos != in.size) {
+ size_t const rc = ZSTD_decompressStream(&zds, &out, &in);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"decompress stream failed"};
+ }
+ }
+ decompressed.resize(out.pos);
+ return decompressed;
+}
+
+std::string makeData(size_t size) {
+ std::string result;
+ result.reserve(size + 20);
+ while (result.size() < size) {
+ result += "Hello world";
+ }
+ return result;
+}
+
+std::string const kData = "Hello world";
+std::string const kPlainDict = makeData(10000);
+std::string const kZstdDict{
+ "\x37\xA4\x30\xEC\x99\x69\x58\x1C\x21\x10\xD8\x4A\x84\x01\xCC\xF3"
+ "\x3C\xCF\x9B\x25\xBB\xC9\x6E\xB2\x9B\xEC\x26\xAD\xCF\xDF\x4E\xCD"
+ "\xF3\x2C\x3A\x21\x84\x10\x42\x08\x21\x01\x33\xF1\x78\x3C\x1E\x8F"
+ "\xC7\xE3\xF1\x78\x3C\xCF\xF3\xBC\xF7\xD4\x42\x41\x41\x41\x41\x41"
+ "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
+ "\x41\x41\x41\x41\xA1\x50\x28\x14\x0A\x85\x42\xA1\x50\x28\x14\x0A"
+ "\x85\xA2\x28\x8A\xA2\x28\x4A\x29\x7D\x74\xE1\xE1\xE1\xE1\xE1\xE1"
+ "\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xF1\x78\x3C"
+ "\x1E\x8F\xC7\xE3\xF1\x78\x9E\xE7\x79\xEF\x01\x01\x00\x00\x00\x04"
+ "\x00\x00\x00\x08\x00\x00\x00"
+ "0123456789",
+ 161};
+}
+
+TEST(Block, CCtx) {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1);
+ auto dctx = createDCtx();
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, NoContentSize) {
+ auto cctx = createCCtx(1);
+ auto const c = compress(*cctx, kData, 1);
+ auto const size = ZSTD_findDecompressedSize(c.data(), c.size());
+ EXPECT_EQ(ZSTD_CONTENTSIZE_UNKNOWN, size);
+}
+
+TEST(Block, ContentSize) {
+ auto cctx = createCCtx(1);
+ auto params = ZSTD_getParams(1, 0, 0);
+ params.fParams.contentSizeFlag = 1;
+ auto const c = compress(*cctx, kData, params);
+ auto const size = ZSTD_findDecompressedSize(c.data(), c.size());
+ EXPECT_EQ(kData.size(), size);
+}
+
+TEST(Block, CCtxLevelIncrease) {
+ std::string c;
+ auto cctx = createCCtx(22);
+ auto dctx = createDCtx();
+ 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);
+ }
+}
+
+TEST(Block, PlainDict) {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1, kPlainDict);
+ auto dctx = createDCtx();
+ EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+ auto const decompressed =
+ decompress(*dctx, compressed, kData.size(), kPlainDict);
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, ZstdDict) {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1, kZstdDict);
+ auto dctx = createDCtx();
+ EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+ auto const decompressed =
+ decompress(*dctx, compressed, kData.size(), kZstdDict);
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, PreprocessedPlainDict) {
+ auto cctx = createCCtx(1);
+ auto const cdict = createCDict(kPlainDict, 1);
+ auto const compressed = compress(*cctx, kData, *cdict);
+ auto dctx = createDCtx();
+ auto const ddict = createDDict(kPlainDict);
+ EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+ auto const decompressed =
+ decompress(*dctx, compressed, kData.size(), *ddict);
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, PreprocessedZstdDict) {
+ auto cctx = createCCtx(1);
+ auto const cdict = createCDict(kZstdDict, 1);
+ auto const compressed = compress(*cctx, kData, *cdict);
+ auto dctx = createDCtx();
+ auto const ddict = createDDict(kZstdDict);
+ EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+ auto const decompressed =
+ decompress(*dctx, compressed, kData.size(), *ddict);
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, ReinitializeCCtx) {
+ auto cctx = createCCtx(1);
+ {
+ auto const compressed = compress(*cctx, kData, 1);
+ auto dctx = createDCtx();
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+ // Create the cctx with the same memory
+ auto d = cctx.get_deleter();
+ auto raw = cctx.release();
+ auto params = ZSTD_getParams(1, 0, 0);
+ cctx.reset(
+ ZSTD_initCCtx(d.memory, ZSTD_CCtxWorkspaceBound(params.cParams)));
+ // Repeat
+ {
+ auto const compressed = compress(*cctx, kData, 1);
+ auto dctx = createDCtx();
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
+TEST(Block, ReinitializeDCtx) {
+ auto dctx = createDCtx();
+ {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1);
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+ // Create the cctx with the same memory
+ auto d = dctx.get_deleter();
+ auto raw = dctx.release();
+ dctx.reset(ZSTD_initDCtx(d.memory, ZSTD_DCtxWorkspaceBound()));
+ // Repeat
+ {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1);
+ auto dctx = createDCtx();
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
+TEST(Stream, Basic) {
+ auto zcs = createCStream(1);
+ auto const compressed = compress(*zcs, kData);
+ auto zds = createDStream();
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, PlainDict) {
+ auto params = ZSTD_getParams(1, kData.size(), kPlainDict.size());
+ params.cParams.windowLog = 17;
+ auto cdict = createCDict(kPlainDict, params);
+ auto zcs = createCStream(params.cParams, *cdict, kData.size());
+ auto const compressed = compress(*zcs, kData);
+ auto const contentSize =
+ ZSTD_findDecompressedSize(compressed.data(), compressed.size());
+ EXPECT_ANY_THROW(decompress(*createDStream(), compressed, kData.size()));
+ auto ddict = createDDict(kPlainDict);
+ auto zds = createDStream(1 << 17, ddict.get());
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, ZstdDict) {
+ auto params = ZSTD_getParams(1, 0, 0);
+ params.cParams.windowLog = 17;
+ auto cdict = createCDict(kZstdDict, 1);
+ auto zcs = createCStream(params.cParams, *cdict);
+ auto const compressed = compress(*zcs, kData);
+ EXPECT_ANY_THROW(decompress(*createDStream(), compressed, kData.size()));
+ auto ddict = createDDict(kZstdDict);
+ auto zds = createDStream(1 << 17, ddict.get());
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, ResetCStream) {
+ auto zcs = createCStream(1);
+ auto zds = createDStream();
+ {
+ auto const compressed = compress(*zcs, kData);
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+ {
+ ZSTD_resetCStream(zcs.get(), 0);
+ auto const compressed = compress(*zcs, kData);
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
+TEST(Stream, ResetDStream) {
+ auto zcs = createCStream(1);
+ auto zds = createDStream();
+ auto const compressed = compress(*zcs, kData);
+ EXPECT_ANY_THROW(decompress(*zds, kData, kData.size()));
+ EXPECT_ANY_THROW(decompress(*zds, compressed, kData.size()));
+ ZSTD_resetDStream(zds.get());
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, Flush) {
+ auto zcs = createCStream(1);
+ auto zds = createDStream();
+ std::string compressed;
+ {
+ compressed.resize(ZSTD_compressBound(kData.size()));
+ ZSTD_inBuffer in = {kData.data(), kData.size(), 0};
+ ZSTD_outBuffer out = {&compressed[0], compressed.size(), 0};
+ while (in.pos != in.size) {
+ size_t const rc = ZSTD_compressStream(zcs.get(), &out, &in);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"compress stream failed"};
+ }
+ }
+ EXPECT_EQ(0, out.pos);
+ size_t const rc = ZSTD_flushStream(zcs.get(), &out);
+ if (rc != 0) {
+ throw std::runtime_error{"compress end failed"};
+ }
+ compressed.resize(out.pos);
+ EXPECT_LT(0, out.pos);
+ }
+ std::string decompressed;
+ {
+ decompressed.resize(kData.size());
+ ZSTD_inBuffer in = {compressed.data(), compressed.size(), 0};
+ ZSTD_outBuffer out = {&decompressed[0], decompressed.size(), 0};
+ while (in.pos != in.size) {
+ size_t const rc = ZSTD_decompressStream(zds.get(), &out, &in);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"decompress stream failed"};
+ }
+ }
+ }
+ 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; \
+ EXPECT_NE((void *)0, __##symbol); \
+ } while (0)
+
+TEST(API, Symbols) {
+ TEST_SYMBOL(ZSTD_CCtxWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initCCtx);
+ TEST_SYMBOL(ZSTD_compressCCtx);
+ TEST_SYMBOL(ZSTD_compress_usingDict);
+ TEST_SYMBOL(ZSTD_DCtxWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initDCtx);
+ TEST_SYMBOL(ZSTD_decompressDCtx);
+ TEST_SYMBOL(ZSTD_decompress_usingDict);
+
+ TEST_SYMBOL(ZSTD_CDictWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initCDict);
+ TEST_SYMBOL(ZSTD_compress_usingCDict);
+ TEST_SYMBOL(ZSTD_DDictWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initDDict);
+ TEST_SYMBOL(ZSTD_decompress_usingDDict);
+
+ TEST_SYMBOL(ZSTD_CStreamWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initCStream);
+ TEST_SYMBOL(ZSTD_initCStream_usingCDict);
+ TEST_SYMBOL(ZSTD_resetCStream);
+ TEST_SYMBOL(ZSTD_compressStream);
+ TEST_SYMBOL(ZSTD_flushStream);
+ TEST_SYMBOL(ZSTD_endStream);
+ TEST_SYMBOL(ZSTD_CStreamInSize);
+ TEST_SYMBOL(ZSTD_CStreamOutSize);
+ TEST_SYMBOL(ZSTD_DStreamWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initDStream);
+ TEST_SYMBOL(ZSTD_initDStream_usingDDict);
+ TEST_SYMBOL(ZSTD_resetDStream);
+ TEST_SYMBOL(ZSTD_decompressStream);
+ TEST_SYMBOL(ZSTD_DStreamInSize);
+ TEST_SYMBOL(ZSTD_DStreamOutSize);
+
+ TEST_SYMBOL(ZSTD_findFrameCompressedSize);
+ TEST_SYMBOL(ZSTD_getFrameContentSize);
+ TEST_SYMBOL(ZSTD_findDecompressedSize);
+
+ TEST_SYMBOL(ZSTD_getCParams);
+ TEST_SYMBOL(ZSTD_getParams);
+ TEST_SYMBOL(ZSTD_checkCParams);
+ TEST_SYMBOL(ZSTD_adjustCParams);
+
+ TEST_SYMBOL(ZSTD_isFrame);
+ TEST_SYMBOL(ZSTD_getDictID_fromDict);
+ TEST_SYMBOL(ZSTD_getDictID_fromDDict);
+ TEST_SYMBOL(ZSTD_getDictID_fromFrame);
+
+ TEST_SYMBOL(ZSTD_compressBegin);
+ TEST_SYMBOL(ZSTD_compressBegin_usingDict);
+ TEST_SYMBOL(ZSTD_compressBegin_advanced);
+ TEST_SYMBOL(ZSTD_copyCCtx);
+ TEST_SYMBOL(ZSTD_compressBegin_usingCDict);
+ TEST_SYMBOL(ZSTD_compressContinue);
+ TEST_SYMBOL(ZSTD_compressEnd);
+ TEST_SYMBOL(ZSTD_getFrameParams);
+ TEST_SYMBOL(ZSTD_decompressBegin);
+ TEST_SYMBOL(ZSTD_decompressBegin_usingDict);
+ TEST_SYMBOL(ZSTD_copyDCtx);
+ TEST_SYMBOL(ZSTD_nextSrcSizeToDecompress);
+ TEST_SYMBOL(ZSTD_decompressContinue);
+ TEST_SYMBOL(ZSTD_nextInputType);
+
+ TEST_SYMBOL(ZSTD_getBlockSizeMax);
+ TEST_SYMBOL(ZSTD_compressBlock);
+ TEST_SYMBOL(ZSTD_decompressBlock);
+ TEST_SYMBOL(ZSTD_insertBlock);
+}
diff --git a/src/zstd/contrib/linux-kernel/test/XXHashUserlandTest.cpp b/src/zstd/contrib/linux-kernel/test/XXHashUserlandTest.cpp
new file mode 100644
index 000000000..f50401a2e
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/XXHashUserlandTest.cpp
@@ -0,0 +1,166 @@
+extern "C" {
+#include <linux/errno.h>
+#include <linux/xxhash.h>
+}
+#include <gtest/gtest.h>
+#include <array>
+#include <iostream>
+#include <memory>
+#include <string>
+#define XXH_STATIC_LINKING_ONLY
+#include <xxhash.h>
+
+using namespace std;
+
+namespace {
+const std::array<std::string, 11> 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/src/zstd/contrib/linux-kernel/test/include/asm/unaligned.h b/src/zstd/contrib/linux-kernel/test/include/asm/unaligned.h
new file mode 100644
index 000000000..4f4828126
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/asm/unaligned.h
@@ -0,0 +1,177 @@
+#ifndef ASM_UNALIGNED_H
+#define ASM_UNALIGNED_H
+
+#include <assert.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define _LITTLE_ENDIAN 1
+
+static unsigned _isLittleEndian(void)
+{
+ const union { uint32_t u; uint8_t c[4]; } one = { 1 };
+ assert(_LITTLE_ENDIAN == one.c[0]);
+ return _LITTLE_ENDIAN;
+}
+
+static uint16_t _swap16(uint16_t in)
+{
+ return ((in & 0xF) << 8) + ((in & 0xF0) >> 8);
+}
+
+static uint32_t _swap32(uint32_t in)
+{
+ return __builtin_bswap32(in);
+}
+
+static uint64_t _swap64(uint64_t in)
+{
+ return __builtin_bswap64(in);
+}
+
+/* Little endian */
+static uint16_t get_unaligned_le16(const void* memPtr)
+{
+ uint16_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (!_isLittleEndian()) _swap16(val);
+ return val;
+}
+
+static uint32_t get_unaligned_le32(const void* memPtr)
+{
+ uint32_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (!_isLittleEndian()) _swap32(val);
+ return val;
+}
+
+static uint64_t get_unaligned_le64(const void* memPtr)
+{
+ uint64_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (!_isLittleEndian()) _swap64(val);
+ return val;
+}
+
+static void put_unaligned_le16(uint16_t value, void* memPtr)
+{
+ if (!_isLittleEndian()) value = _swap16(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_le32(uint32_t value, void* memPtr)
+{
+ if (!_isLittleEndian()) value = _swap32(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_le64(uint64_t value, void* memPtr)
+{
+ if (!_isLittleEndian()) value = _swap64(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+/* big endian */
+static uint32_t get_unaligned_be32(const void* memPtr)
+{
+ uint32_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (_isLittleEndian()) _swap32(val);
+ return val;
+}
+
+static uint64_t get_unaligned_be64(const void* memPtr)
+{
+ uint64_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (_isLittleEndian()) _swap64(val);
+ return val;
+}
+
+static void put_unaligned_be32(uint32_t value, void* memPtr)
+{
+ if (_isLittleEndian()) value = _swap32(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_be64(uint64_t value, void* memPtr)
+{
+ if (_isLittleEndian()) value = _swap64(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+/* generic */
+extern void __bad_unaligned_access_size(void);
+
+#define __get_unaligned_le(ptr) ((typeof(*(ptr)))({ \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \
+ __bad_unaligned_access_size())))); \
+ }))
+
+#define __get_unaligned_be(ptr) ((typeof(*(ptr)))({ \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \
+ __bad_unaligned_access_size())))); \
+ }))
+
+#define __put_unaligned_le(val, ptr) \
+ ({ \
+ void *__gu_p = (ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ *(uint8_t *)__gu_p = (uint8_t)(val); \
+ break; \
+ case 2: \
+ put_unaligned_le16((uint16_t)(val), __gu_p); \
+ break; \
+ case 4: \
+ put_unaligned_le32((uint32_t)(val), __gu_p); \
+ break; \
+ case 8: \
+ put_unaligned_le64((uint64_t)(val), __gu_p); \
+ break; \
+ default: \
+ __bad_unaligned_access_size(); \
+ break; \
+ } \
+ (void)0; \
+ })
+
+#define __put_unaligned_be(val, ptr) \
+ ({ \
+ void *__gu_p = (ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ *(uint8_t *)__gu_p = (uint8_t)(val); \
+ break; \
+ case 2: \
+ put_unaligned_be16((uint16_t)(val), __gu_p); \
+ break; \
+ case 4: \
+ put_unaligned_be32((uint32_t)(val), __gu_p); \
+ break; \
+ case 8: \
+ put_unaligned_be64((uint64_t)(val), __gu_p); \
+ break; \
+ default: \
+ __bad_unaligned_access_size(); \
+ break; \
+ } \
+ (void)0; \
+ })
+
+#if _LITTLE_ENDIAN
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+#else
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+#endif
+
+#endif // ASM_UNALIGNED_H
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/compiler.h b/src/zstd/contrib/linux-kernel/test/include/linux/compiler.h
new file mode 100644
index 000000000..4fb4f42e2
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/compiler.h
@@ -0,0 +1,12 @@
+#ifndef LINUX_COMPILER_H_
+#define LINUX_COMPILER_H_
+
+#ifndef __always_inline
+# define __always_inline inline
+#endif
+
+#ifndef noinline
+# define noinline __attribute__((__noinline__))
+#endif
+
+#endif // LINUX_COMPILER_H_
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/errno.h b/src/zstd/contrib/linux-kernel/test/include/linux/errno.h
new file mode 100644
index 000000000..b9db08524
--- /dev/null
+++ b/src/zstd/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/src/zstd/contrib/linux-kernel/test/include/linux/kernel.h b/src/zstd/contrib/linux-kernel/test/include/linux/kernel.h
new file mode 100644
index 000000000..3ef2f7fe8
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/kernel.h
@@ -0,0 +1,16 @@
+#ifndef LINUX_KERNEL_H_
+#define LINUX_KERNEL_H_
+
+#define ALIGN(x, a) ({ \
+ typeof(x) const __xe = (x); \
+ typeof(a) const __ae = (a); \
+ typeof(a) const __m = __ae - 1; \
+ typeof(x) const __r = __xe & __m; \
+ __xe + (__r ? (__ae - __r) : 0); \
+ })
+
+#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/src/zstd/contrib/linux-kernel/test/include/linux/math64.h b/src/zstd/contrib/linux-kernel/test/include/linux/math64.h
new file mode 100644
index 000000000..3d0ae72d5
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/math64.h
@@ -0,0 +1,11 @@
+#ifndef LINUX_MATH64_H
+#define LINUX_MATH64_H
+
+#include <stdint.h>
+
+static uint64_t div_u64(uint64_t n, uint32_t d)
+{
+ return n / d;
+}
+
+#endif
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/module.h b/src/zstd/contrib/linux-kernel/test/include/linux/module.h
new file mode 100644
index 000000000..ef514c349
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/module.h
@@ -0,0 +1,10 @@
+#ifndef LINUX_MODULE_H_
+#define LINUX_MODULE_H_
+
+#define EXPORT_SYMBOL(symbol) \
+ void* __##symbol = symbol
+#define MODULE_LICENSE(license) static char const *const LICENSE = license
+#define MODULE_DESCRIPTION(description) \
+ static char const *const DESCRIPTION = description
+
+#endif // LINUX_MODULE_H_
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/string.h b/src/zstd/contrib/linux-kernel/test/include/linux/string.h
new file mode 100644
index 000000000..3b2f59002
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/string.h
@@ -0,0 +1 @@
+#include <string.h>
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/types.h b/src/zstd/contrib/linux-kernel/test/include/linux/types.h
new file mode 100644
index 000000000..c2d4f4b72
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/types.h
@@ -0,0 +1,2 @@
+#include <stddef.h>
+#include <stdint.h>
diff --git a/src/zstd/contrib/linux-kernel/xxhash_test.c b/src/zstd/contrib/linux-kernel/xxhash_test.c
new file mode 100644
index 000000000..eb0fb1cd7
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/xxhash_test.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/* 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+
+#if DO_XXH
+#include <linux/xxhash.h>
+#endif
+
+#if DO_CRC
+#include <linux/crc32.h>
+#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/src/zstd/contrib/linux-kernel/zstd_compress_test.c b/src/zstd/contrib/linux-kernel/zstd_compress_test.c
new file mode 100644
index 000000000..dc17adf81
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/zstd_compress_test.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/* 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+
+#if DO_ZSTD
+#include <linux/zstd.h>
+#endif
+
+#if DO_ZLIB
+#include <linux/zlib.h>
+#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/src/zstd/contrib/linux-kernel/zstd_decompress_test.c b/src/zstd/contrib/linux-kernel/zstd_decompress_test.c
new file mode 100644
index 000000000..f6efddd30
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/zstd_decompress_test.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/* 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+
+#if DO_ZSTD
+#include <linux/zstd.h>
+#endif
+
+#if DO_ZLIB
+#include <linux/zlib.h>
+#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/src/zstd/contrib/match_finders/README.md b/src/zstd/contrib/match_finders/README.md
new file mode 100644
index 000000000..0f4a3b1ce
--- /dev/null
+++ b/src/zstd/contrib/match_finders/README.md
@@ -0,0 +1,42 @@
+## Edit Distance Match Finder
+
+```
+/* This match finder leverages techniques used in file comparison algorithms
+ * to find matches between a dictionary and a source file.
+ *
+ * The original motivation for studying this approach was to try and optimize
+ * Zstandard for the use case of patching: the most common scenario being
+ * updating an existing software package with the next version. When patching,
+ * the difference between the old version of the package and the new version
+ * is generally tiny (most of the new file will be identical to
+ * the old one). In more technical terms, the edit distance (the minimal number
+ * of changes required to take one sequence of bytes to another) between the
+ * files would be small relative to the size of the file.
+ *
+ * Various 'diffing' algorithms utilize this notion of edit distance and
+ * the corrensponding concept of a minimal edit script between two
+ * sequences to identify the regions within two files where they differ.
+ * The core algorithm used in this match finder is described in:
+ *
+ * "An O(ND) Difference Algorithm and its Variations", Eugene W. Myers,
+ * Algorithmica Vol. 1, 1986, pp. 251-266,
+ * <https://doi.org/10.1007/BF01840446>.
+ *
+ * Additional algorithmic heuristics for speed improvement have also been included.
+ * These we inspired from implementations of various regular and binary diffing
+ * algorithms such as GNU diff, bsdiff, and Xdelta.
+ *
+ * Note: after some experimentation, this approach proved to not provide enough
+ * utility to justify the additional CPU used in finding matches. The one area
+ * where this approach consistenly outperforms Zstandard even on level 19 is
+ * when compressing small files (<10 KB) using a equally small dictionary that
+ * is very similar to the source file. For the use case that this was intended,
+ * (large similar files) this approach by itself took 5-10X longer than zstd-19 and
+ * generally resulted in 2-3X larger files. The core advantage that zstd-19 has
+ * over this appraoch for match finding is the overlapping matches. This approach
+ * cannot find any.
+ *
+ * I'm leaving this in the contrib section in case this ever becomes interesting
+ * to explore again.
+ * */
+```
diff --git a/src/zstd/contrib/match_finders/zstd_edist.c b/src/zstd/contrib/match_finders/zstd_edist.c
new file mode 100644
index 000000000..aab545fd3
--- /dev/null
+++ b/src/zstd/contrib/match_finders/zstd_edist.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/*-*************************************
+* Dependencies
+***************************************/
+
+/* Currently relies on qsort when combining contiguous matches. This can probabily
+ * be avoided but would require changes to the algorithm. The qsort is far from
+ * the bottleneck in this algorithm even for medium sized files so it's probably
+ * not worth trying to address */
+#include <stdlib.h>
+#include <assert.h>
+
+#include "zstd_edist.h"
+#include "mem.h"
+
+/*-*************************************
+* Constants
+***************************************/
+
+/* Just a sential for the entires of the diagnomal matrix */
+#define ZSTD_EDIST_DIAG_MAX (S32)(1 << 30)
+
+/* How large should a snake be to be considered a 'big' snake.
+ * For an explanation of what a 'snake' is with respect to the
+ * edit distance matrix, see the linked paper in zstd_edist.h */
+#define ZSTD_EDIST_SNAKE_THRESH 20
+
+/* After how many iterations should we start to use the heuristic
+ * based on 'big' snakes */
+#define ZSTD_EDIST_SNAKE_ITER_THRESH 200
+
+/* After how many iterations should be just give up and take
+ * the best availabe edit script for this round */
+#define ZSTD_EDIST_EXPENSIVE_THRESH 1024
+
+/*-*************************************
+* Structures
+***************************************/
+
+typedef struct {
+ U32 dictIdx;
+ U32 srcIdx;
+ U32 matchLength;
+} ZSTD_eDist_match;
+
+typedef struct {
+ const BYTE* dict;
+ const BYTE* src;
+ size_t dictSize;
+ size_t srcSize;
+ S32* forwardDiag; /* Entires of the forward diagonal stored here */
+ S32* backwardDiag; /* Entires of the backward diagonal stored here.
+ * Note: this buffer and the 'forwardDiag' buffer
+ * are contiguous. See the ZSTD_eDist_genSequences */
+ ZSTD_eDist_match* matches; /* Accumulate matches of length 1 in this buffer.
+ * In a subsequence post-processing step, we combine
+ * contiguous matches. */
+ U32 nbMatches;
+} ZSTD_eDist_state;
+
+typedef struct {
+ S32 dictMid; /* The mid diagonal for the dictionary */
+ S32 srcMid; /* The mid diagonal for the source */
+ int lowUseHeuristics; /* Should we use heuristics for the low part */
+ int highUseHeuristics; /* Should we use heuristics for the high part */
+} ZSTD_eDist_partition;
+
+/*-*************************************
+* Internal
+***************************************/
+
+static void ZSTD_eDist_diag(ZSTD_eDist_state* state,
+ ZSTD_eDist_partition* partition,
+ S32 dictLow, S32 dictHigh, S32 srcLow,
+ S32 srcHigh, int useHeuristics)
+{
+ S32* const forwardDiag = state->forwardDiag;
+ S32* const backwardDiag = state->backwardDiag;
+ const BYTE* const dict = state->dict;
+ const BYTE* const src = state->src;
+
+ S32 const diagMin = dictLow - srcHigh;
+ S32 const diagMax = dictHigh - srcLow;
+ S32 const forwardMid = dictLow - srcLow;
+ S32 const backwardMid = dictHigh - srcHigh;
+
+ S32 forwardMin = forwardMid;
+ S32 forwardMax = forwardMid;
+ S32 backwardMin = backwardMid;
+ S32 backwardMax = backwardMid;
+ int odd = (forwardMid - backwardMid) & 1;
+ U32 iterations;
+
+ forwardDiag[forwardMid] = dictLow;
+ backwardDiag[backwardMid] = dictHigh;
+
+ /* Main loop for updating diag entries. Unless useHeuristics is
+ * set to false, this loop will run until it finds the minimal
+ * edit script */
+ for (iterations = 1;;iterations++) {
+ S32 diag;
+ int bigSnake = 0;
+
+ if (forwardMin > diagMin) {
+ forwardMin--;
+ forwardDiag[forwardMin - 1] = -1;
+ } else {
+ forwardMin++;
+ }
+
+ if (forwardMax < diagMax) {
+ forwardMax++;
+ forwardDiag[forwardMax + 1] = -1;
+ } else {
+ forwardMax--;
+ }
+
+ for (diag = forwardMax; diag >= forwardMin; diag -= 2) {
+ S32 dictIdx;
+ S32 srcIdx;
+ S32 low = forwardDiag[diag - 1];
+ S32 high = forwardDiag[diag + 1];
+ S32 dictIdx0 = low < high ? high : low + 1;
+
+ for (dictIdx = dictIdx0, srcIdx = dictIdx0 - diag;
+ dictIdx < dictHigh && srcIdx < srcHigh && dict[dictIdx] == src[srcIdx];
+ dictIdx++, srcIdx++) continue;
+
+ if (dictIdx - dictIdx0 > ZSTD_EDIST_SNAKE_THRESH)
+ bigSnake = 1;
+
+ forwardDiag[diag] = dictIdx;
+
+ if (odd && backwardMin <= diag && diag <= backwardMax && backwardDiag[diag] <= dictIdx) {
+ partition->dictMid = dictIdx;
+ partition->srcMid = srcIdx;
+ partition->lowUseHeuristics = 0;
+ partition->highUseHeuristics = 0;
+ return;
+ }
+ }
+
+ if (backwardMin > diagMin) {
+ backwardMin--;
+ backwardDiag[backwardMin - 1] = ZSTD_EDIST_DIAG_MAX;
+ } else {
+ backwardMin++;
+ }
+
+ if (backwardMax < diagMax) {
+ backwardMax++;
+ backwardDiag[backwardMax + 1] = ZSTD_EDIST_DIAG_MAX;
+ } else {
+ backwardMax--;
+ }
+
+
+ for (diag = backwardMax; diag >= backwardMin; diag -= 2) {
+ S32 dictIdx;
+ S32 srcIdx;
+ S32 low = backwardDiag[diag - 1];
+ S32 high = backwardDiag[diag + 1];
+ S32 dictIdx0 = low < high ? low : high - 1;
+
+ for (dictIdx = dictIdx0, srcIdx = dictIdx0 - diag;
+ dictLow < dictIdx && srcLow < srcIdx && dict[dictIdx - 1] == src[srcIdx - 1];
+ dictIdx--, srcIdx--) continue;
+
+ if (dictIdx0 - dictIdx > ZSTD_EDIST_SNAKE_THRESH)
+ bigSnake = 1;
+
+ backwardDiag[diag] = dictIdx;
+
+ if (!odd && forwardMin <= diag && diag <= forwardMax && dictIdx <= forwardDiag[diag]) {
+ partition->dictMid = dictIdx;
+ partition->srcMid = srcIdx;
+ partition->lowUseHeuristics = 0;
+ partition->highUseHeuristics = 0;
+ return;
+ }
+ }
+
+ if (!useHeuristics)
+ continue;
+
+ /* Everything under this point is a heuritic. Using these will
+ * substantially speed up the match finding. In some cases, taking
+ * the total match finding time from several minutes to seconds.
+ * Of course, the caveat is that the edit script found may no longer
+ * be optimal */
+
+ /* Big snake heuristic */
+ if (iterations > ZSTD_EDIST_SNAKE_ITER_THRESH && bigSnake) {
+ {
+ S32 best = 0;
+
+ for (diag = forwardMax; diag >= forwardMin; diag -= 2) {
+ S32 diagDiag = diag - forwardMid;
+ S32 dictIdx = forwardDiag[diag];
+ S32 srcIdx = dictIdx - diag;
+ S32 v = (dictIdx - dictLow) * 2 - diagDiag;
+
+ if (v > 12 * (iterations + (diagDiag < 0 ? -diagDiag : diagDiag))) {
+ if (v > best
+ && dictLow + ZSTD_EDIST_SNAKE_THRESH <= dictIdx && dictIdx <= dictHigh
+ && srcLow + ZSTD_EDIST_SNAKE_THRESH <= srcIdx && srcIdx <= srcHigh) {
+ S32 k;
+ for (k = 1; dict[dictIdx - k] == src[srcIdx - k]; k++) {
+ if (k == ZSTD_EDIST_SNAKE_THRESH) {
+ best = v;
+ partition->dictMid = dictIdx;
+ partition->srcMid = srcIdx;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (best > 0) {
+ partition->lowUseHeuristics = 0;
+ partition->highUseHeuristics = 1;
+ return;
+ }
+ }
+
+ {
+ S32 best = 0;
+
+ for (diag = backwardMax; diag >= backwardMin; diag -= 2) {
+ S32 diagDiag = diag - backwardMid;
+ S32 dictIdx = backwardDiag[diag];
+ S32 srcIdx = dictIdx - diag;
+ S32 v = (dictHigh - dictIdx) * 2 + diagDiag;
+
+ if (v > 12 * (iterations + (diagDiag < 0 ? -diagDiag : diagDiag))) {
+ if (v > best
+ && dictLow < dictIdx && dictIdx <= dictHigh - ZSTD_EDIST_SNAKE_THRESH
+ && srcLow < srcIdx && srcIdx <= srcHigh - ZSTD_EDIST_SNAKE_THRESH) {
+ int k;
+ for (k = 0; dict[dictIdx + k] == src[srcIdx + k]; k++) {
+ if (k == ZSTD_EDIST_SNAKE_THRESH - 1) {
+ best = v;
+ partition->dictMid = dictIdx;
+ partition->srcMid = srcIdx;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (best > 0) {
+ partition->lowUseHeuristics = 1;
+ partition->highUseHeuristics = 0;
+ return;
+ }
+ }
+ }
+
+ /* More general 'too expensive' heuristic */
+ if (iterations >= ZSTD_EDIST_EXPENSIVE_THRESH) {
+ S32 forwardDictSrcBest;
+ S32 forwardDictBest = 0;
+ S32 backwardDictSrcBest;
+ S32 backwardDictBest = 0;
+
+ forwardDictSrcBest = -1;
+ for (diag = forwardMax; diag >= forwardMin; diag -= 2) {
+ S32 dictIdx = MIN(forwardDiag[diag], dictHigh);
+ S32 srcIdx = dictIdx - diag;
+
+ if (srcHigh < srcIdx) {
+ dictIdx = srcHigh + diag;
+ srcIdx = srcHigh;
+ }
+
+ if (forwardDictSrcBest < dictIdx + srcIdx) {
+ forwardDictSrcBest = dictIdx + srcIdx;
+ forwardDictBest = dictIdx;
+ }
+ }
+
+ backwardDictSrcBest = ZSTD_EDIST_DIAG_MAX;
+ for (diag = backwardMax; diag >= backwardMin; diag -= 2) {
+ S32 dictIdx = MAX(dictLow, backwardDiag[diag]);
+ S32 srcIdx = dictIdx - diag;
+
+ if (srcIdx < srcLow) {
+ dictIdx = srcLow + diag;
+ srcIdx = srcLow;
+ }
+
+ if (dictIdx + srcIdx < backwardDictSrcBest) {
+ backwardDictSrcBest = dictIdx + srcIdx;
+ backwardDictBest = dictIdx;
+ }
+ }
+
+ if ((dictHigh + srcHigh) - backwardDictSrcBest < forwardDictSrcBest - (dictLow + srcLow)) {
+ partition->dictMid = forwardDictBest;
+ partition->srcMid = forwardDictSrcBest - forwardDictBest;
+ partition->lowUseHeuristics = 0;
+ partition->highUseHeuristics = 1;
+ } else {
+ partition->dictMid = backwardDictBest;
+ partition->srcMid = backwardDictSrcBest - backwardDictBest;
+ partition->lowUseHeuristics = 1;
+ partition->highUseHeuristics = 0;
+ }
+ return;
+ }
+ }
+}
+
+static void ZSTD_eDist_insertMatch(ZSTD_eDist_state* state,
+ S32 const dictIdx, S32 const srcIdx)
+{
+ state->matches[state->nbMatches].dictIdx = dictIdx;
+ state->matches[state->nbMatches].srcIdx = srcIdx;
+ state->matches[state->nbMatches].matchLength = 1;
+ state->nbMatches++;
+}
+
+static int ZSTD_eDist_compare(ZSTD_eDist_state* state,
+ S32 dictLow, S32 dictHigh, S32 srcLow,
+ S32 srcHigh, int useHeuristics)
+{
+ const BYTE* const dict = state->dict;
+ const BYTE* const src = state->src;
+
+ /* Found matches while traversing from the low end */
+ while (dictLow < dictHigh && srcLow < srcHigh && dict[dictLow] == src[srcLow]) {
+ ZSTD_eDist_insertMatch(state, dictLow, srcLow);
+ dictLow++;
+ srcLow++;
+ }
+
+ /* Found matches while traversing from the high end */
+ while (dictLow < dictHigh && srcLow < srcHigh && dict[dictHigh - 1] == src[srcHigh - 1]) {
+ ZSTD_eDist_insertMatch(state, dictHigh - 1, srcHigh - 1);
+ dictHigh--;
+ srcHigh--;
+ }
+
+ /* If the low and high end end up touching. If we wanted to make
+ * note of the differences like most diffing algorithms do, we would
+ * do so here. In our case, we're only concerned with matches
+ * Note: if you wanted to find the edit distance of the algorithm,
+ * you could just accumulate the cost for an insertion/deletion
+ * below. */
+ if (dictLow == dictHigh) {
+ while (srcLow < srcHigh) {
+ /* Reaching this point means inserting src[srcLow] into
+ * the current position of dict */
+ srcLow++;
+ }
+ } else if (srcLow == srcHigh) {
+ while (dictLow < dictHigh) {
+ /* Reaching this point means deleteing dict[dictLow] from
+ * the current positino of dict */
+ dictLow++;
+ }
+ } else {
+ ZSTD_eDist_partition partition;
+ partition.dictMid = 0;
+ partition.srcMid = 0;
+ ZSTD_eDist_diag(state, &partition, dictLow, dictHigh,
+ srcLow, srcHigh, useHeuristics);
+ if (ZSTD_eDist_compare(state, dictLow, partition.dictMid,
+ srcLow, partition.srcMid, partition.lowUseHeuristics))
+ return 1;
+ if (ZSTD_eDist_compare(state, partition.dictMid, dictHigh,
+ partition.srcMid, srcHigh, partition.highUseHeuristics))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ZSTD_eDist_matchComp(const void* p, const void* q)
+{
+ S32 const l = ((ZSTD_eDist_match*)p)->srcIdx;
+ S32 const r = ((ZSTD_eDist_match*)q)->srcIdx;
+ return (l - r);
+}
+
+/* The matches from the approach above will all be of the form
+ * (dictIdx, srcIdx, 1). this method combines contiguous matches
+ * of length MINMATCH or greater. Matches less than MINMATCH
+ * are discarded */
+static void ZSTD_eDist_combineMatches(ZSTD_eDist_state* state)
+{
+ /* Create a new buffer to put the combined matches into
+ * and memcpy to state->matches after */
+ ZSTD_eDist_match* combinedMatches =
+ ZSTD_malloc(state->nbMatches * sizeof(ZSTD_eDist_match),
+ ZSTD_defaultCMem);
+
+ U32 nbCombinedMatches = 1;
+ size_t i;
+
+ /* Make sure that the srcIdx and dictIdx are in sorted order.
+ * The combination step won't work otherwise */
+ qsort(state->matches, state->nbMatches, sizeof(ZSTD_eDist_match), ZSTD_eDist_matchComp);
+
+ memcpy(combinedMatches, state->matches, sizeof(ZSTD_eDist_match));
+ for (i = 1; i < state->nbMatches; i++) {
+ ZSTD_eDist_match const match = state->matches[i];
+ ZSTD_eDist_match const combinedMatch =
+ combinedMatches[nbCombinedMatches - 1];
+ if (combinedMatch.srcIdx + combinedMatch.matchLength == match.srcIdx &&
+ combinedMatch.dictIdx + combinedMatch.matchLength == match.dictIdx) {
+ combinedMatches[nbCombinedMatches - 1].matchLength++;
+ } else {
+ /* Discard matches that are less than MINMATCH */
+ if (combinedMatches[nbCombinedMatches - 1].matchLength < MINMATCH) {
+ nbCombinedMatches--;
+ }
+
+ memcpy(combinedMatches + nbCombinedMatches,
+ state->matches + i, sizeof(ZSTD_eDist_match));
+ nbCombinedMatches++;
+ }
+ }
+ memcpy(state->matches, combinedMatches, nbCombinedMatches * sizeof(ZSTD_eDist_match));
+ state->nbMatches = nbCombinedMatches;
+ ZSTD_free(combinedMatches, ZSTD_defaultCMem);
+}
+
+static size_t ZSTD_eDist_convertMatchesToSequences(ZSTD_Sequence* sequences,
+ ZSTD_eDist_state* state)
+{
+ const ZSTD_eDist_match* matches = state->matches;
+ size_t const nbMatches = state->nbMatches;
+ size_t const dictSize = state->dictSize;
+ size_t nbSequences = 0;
+ size_t i;
+ for (i = 0; i < nbMatches; i++) {
+ ZSTD_eDist_match const match = matches[i];
+ U32 const litLength = !i ? match.srcIdx :
+ match.srcIdx - (matches[i - 1].srcIdx + matches[i - 1].matchLength);
+ U32 const offset = (match.srcIdx + dictSize) - match.dictIdx;
+ U32 const matchLength = match.matchLength;
+ sequences[nbSequences].offset = offset;
+ sequences[nbSequences].litLength = litLength;
+ sequences[nbSequences].matchLength = matchLength;
+ nbSequences++;
+ }
+ return nbSequences;
+}
+
+/*-*************************************
+* Interal utils
+***************************************/
+
+static size_t ZSTD_eDist_hamingDist(const BYTE* const a,
+ const BYTE* const b, size_t n)
+{
+ size_t i;
+ size_t dist = 0;
+ for (i = 0; i < n; i++)
+ dist += a[i] != b[i];
+ return dist;
+}
+
+/* This is a pretty naive recursive implementation that should only
+ * be used for quick tests obviously. Don't try and run this on a
+ * GB file or something. There are faster implementations. Use those
+ * if you need to run it for large files. */
+static size_t ZSTD_eDist_levenshteinDist(const BYTE* const s,
+ size_t const sn, const BYTE* const t,
+ size_t const tn)
+{
+ size_t a, b, c;
+
+ if (!sn)
+ return tn;
+ if (!tn)
+ return sn;
+
+ if (s[sn - 1] == t[tn - 1])
+ return ZSTD_eDist_levenshteinDist(
+ s, sn - 1, t, tn - 1);
+
+ a = ZSTD_eDist_levenshteinDist(s, sn - 1, t, tn - 1);
+ b = ZSTD_eDist_levenshteinDist(s, sn, t, tn - 1);
+ c = ZSTD_eDist_levenshteinDist(s, sn - 1, t, tn);
+
+ if (a > b)
+ a = b;
+ if (a > c)
+ a = c;
+
+ return a + 1;
+}
+
+static void ZSTD_eDist_validateMatches(ZSTD_eDist_match* matches,
+ size_t const nbMatches, const BYTE* const dict,
+ size_t const dictSize, const BYTE* const src,
+ size_t const srcSize)
+{
+ size_t i;
+ for (i = 0; i < nbMatches; i++) {
+ ZSTD_eDist_match match = matches[i];
+ U32 const dictIdx = match.dictIdx;
+ U32 const srcIdx = match.srcIdx;
+ U32 const matchLength = match.matchLength;
+
+ assert(dictIdx + matchLength < dictSize);
+ assert(srcIdx + matchLength < srcSize);
+ assert(!memcmp(dict + dictIdx, src + srcIdx, matchLength));
+ }
+}
+
+/*-*************************************
+* API
+***************************************/
+
+size_t ZSTD_eDist_genSequences(ZSTD_Sequence* sequences,
+ const void* dict, size_t dictSize,
+ const void* src, size_t srcSize,
+ int useHeuristics)
+{
+ size_t const nbDiags = dictSize + srcSize + 3;
+ S32* buffer = ZSTD_malloc(nbDiags * 2 * sizeof(S32), ZSTD_defaultCMem);
+ ZSTD_eDist_state state;
+ size_t nbSequences = 0;
+
+ state.dict = (const BYTE*)dict;
+ state.src = (const BYTE*)src;
+ state.dictSize = dictSize;
+ state.srcSize = srcSize;
+ state.forwardDiag = buffer;
+ state.backwardDiag = buffer + nbDiags;
+ state.forwardDiag += srcSize + 1;
+ state.backwardDiag += srcSize + 1;
+ state.matches = ZSTD_malloc(srcSize * sizeof(ZSTD_eDist_match), ZSTD_defaultCMem);
+ state.nbMatches = 0;
+
+ ZSTD_eDist_compare(&state, 0, dictSize, 0, srcSize, 1);
+ ZSTD_eDist_combineMatches(&state);
+ nbSequences = ZSTD_eDist_convertMatchesToSequences(sequences, &state);
+
+ ZSTD_free(buffer, ZSTD_defaultCMem);
+ ZSTD_free(state.matches, ZSTD_defaultCMem);
+
+ return nbSequences;
+}
diff --git a/src/zstd/contrib/match_finders/zstd_edist.h b/src/zstd/contrib/match_finders/zstd_edist.h
new file mode 100644
index 000000000..c775a4985
--- /dev/null
+++ b/src/zstd/contrib/match_finders/zstd_edist.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* This match finder leverages techniques used in file comparison algorithms
+ * to find matches between a dictionary and a source file.
+ *
+ * The original motivation for studying this approach was to try and optimize
+ * Zstandard for the use case of patching: the most common scenario being
+ * updating an existing software package with the next version. When patching,
+ * the difference between the old version of the package and the new version
+ * is generally tiny (most of the new file will be identical to
+ * the old one). In more technical terms, the edit distance (the minimal number
+ * of changes required to take one sequence of bytes to another) between the
+ * files would be small relative to the size of the file.
+ *
+ * Various 'diffing' algorithms utilize this notion of edit distance and
+ * the corrensponding concept of a minimal edit script between two
+ * sequences to identify the regions within two files where they differ.
+ * The core algorithm used in this match finder is described in:
+ *
+ * "An O(ND) Difference Algorithm and its Variations", Eugene W. Myers,
+ * Algorithmica Vol. 1, 1986, pp. 251-266,
+ * <https://doi.org/10.1007/BF01840446>.
+ *
+ * Additional algorithmic heuristics for speed improvement have also been included.
+ * These we inspired from implementations of various regular and binary diffing
+ * algorithms such as GNU diff, bsdiff, and Xdelta.
+ *
+ * Note: after some experimentation, this approach proved to not provide enough
+ * utility to justify the additional CPU used in finding matches. The one area
+ * where this approach consistenly outperforms Zstandard even on level 19 is
+ * when compressing small files (<10 KB) using a equally small dictionary that
+ * is very similar to the source file. For the use case that this was intended,
+ * (large similar files) this approach by itself took 5-10X longer than zstd-19 and
+ * generally resulted in 2-3X larger files. The core advantage that zstd-19 has
+ * over this appraoch for match finding is the overlapping matches. This approach
+ * cannot find any.
+ *
+ * I'm leaving this in the contrib section in case this ever becomes interesting
+ * to explore again.
+ * */
+
+#ifndef ZSTD_EDIST_H
+#define ZSTD_EDIST_H
+
+/*-*************************************
+* Dependencies
+***************************************/
+
+#include <stddef.h>
+#include "zstd_internal.h" /* ZSTD_Sequence */
+
+/*! ZSTD_eDist_genSequences() :
+ * Will populate the provided ZSTD_Sequence buffer with sequences
+ * based on the optimal or near-optimal (depending on 'useHeuristics')
+ * edit script between 'dict' and 'src.'
+ * @return : the number of sequences found */
+size_t ZSTD_eDist_genSequences(ZSTD_Sequence* sequences,
+ const void* dict, size_t dictSize,
+ const void* src, size_t srcSize,
+ int useHeuristics);
+
+#endif
diff --git a/src/zstd/contrib/premake/premake4.lua b/src/zstd/contrib/premake/premake4.lua
new file mode 100644
index 000000000..6675e2e48
--- /dev/null
+++ b/src/zstd/contrib/premake/premake4.lua
@@ -0,0 +1,6 @@
+-- Include zstd.lua in your GENie or premake4 file, which exposes a project_zstd function
+dofile('zstd.lua')
+
+solution 'example'
+ configurations { 'Debug', 'Release' }
+ project_zstd('../../lib/')
diff --git a/src/zstd/contrib/premake/zstd.lua b/src/zstd/contrib/premake/zstd.lua
new file mode 100644
index 000000000..df1ace3ee
--- /dev/null
+++ b/src/zstd/contrib/premake/zstd.lua
@@ -0,0 +1,80 @@
+-- This GENie/premake file copies the behavior of the Makefile in the lib folder.
+-- Basic usage: project_zstd(ZSTD_DIR)
+
+function project_zstd(dir, compression, decompression, deprecated, dictbuilder, legacy)
+ if compression == nil then compression = true end
+ if decompression == nil then decompression = true end
+ if deprecated == nil then deprecated = false end
+ if dictbuilder == nil then dictbuilder = false end
+
+ if legacy == nil then legacy = 0 end
+
+ if not compression then
+ dictbuilder = false
+ deprecated = false
+ end
+
+ if not decompression then
+ legacy = 0
+ deprecated = false
+ end
+
+ project 'zstd'
+ kind 'StaticLib'
+ language 'C'
+
+ files {
+ dir .. 'zstd.h',
+ dir .. 'common/**.c',
+ dir .. 'common/**.h'
+ }
+
+ if compression then
+ files {
+ dir .. 'compress/**.c',
+ dir .. 'compress/**.h'
+ }
+ end
+
+ if decompression then
+ files {
+ dir .. 'decompress/**.c',
+ dir .. 'decompress/**.h'
+ }
+ end
+
+ if dictbuilder then
+ files {
+ dir .. 'dictBuilder/**.c',
+ dir .. 'dictBuilder/**.h'
+ }
+ end
+
+ if deprecated then
+ files {
+ dir .. 'deprecated/**.c',
+ dir .. 'deprecated/**.h'
+ }
+ end
+
+ if legacy ~= 0 then
+ if legacy >= 8 then
+ files {
+ dir .. 'legacy/zstd_v0' .. (legacy - 7) .. '.*'
+ }
+ end
+ includedirs {
+ dir .. 'legacy'
+ }
+ end
+
+ includedirs {
+ dir,
+ dir .. 'common'
+ }
+
+ defines {
+ 'XXH_NAMESPACE=ZSTD_',
+ 'ZSTD_LEGACY_SUPPORT=' .. legacy
+ }
+end
diff --git a/src/zstd/contrib/pzstd/.gitignore b/src/zstd/contrib/pzstd/.gitignore
new file mode 100644
index 000000000..84e68fb07
--- /dev/null
+++ b/src/zstd/contrib/pzstd/.gitignore
@@ -0,0 +1,2 @@
+# compilation result
+pzstd
diff --git a/src/zstd/contrib/pzstd/BUCK b/src/zstd/contrib/pzstd/BUCK
new file mode 100644
index 000000000..d04eeedd8
--- /dev/null
+++ b/src/zstd/contrib/pzstd/BUCK
@@ -0,0 +1,72 @@
+cxx_library(
+ name='libpzstd',
+ visibility=['PUBLIC'],
+ header_namespace='',
+ exported_headers=[
+ 'ErrorHolder.h',
+ 'Logging.h',
+ 'Pzstd.h',
+ ],
+ headers=[
+ 'SkippableFrame.h',
+ ],
+ srcs=[
+ 'Pzstd.cpp',
+ 'SkippableFrame.cpp',
+ ],
+ deps=[
+ ':options',
+ '//contrib/pzstd/utils:utils',
+ '//lib:mem',
+ '//lib:zstd',
+ ],
+)
+
+cxx_library(
+ name='options',
+ visibility=['PUBLIC'],
+ header_namespace='',
+ exported_headers=['Options.h'],
+ srcs=['Options.cpp'],
+ deps=[
+ '//contrib/pzstd/utils:scope_guard',
+ '//lib:zstd',
+ '//programs:util',
+ ],
+)
+
+cxx_binary(
+ name='pzstd',
+ visibility=['PUBLIC'],
+ srcs=['main.cpp'],
+ deps=[
+ ':libpzstd',
+ ':options',
+ ],
+)
+
+# Must run "make googletest" first
+cxx_library(
+ name='gtest',
+ srcs=glob([
+ 'googletest/googletest/src/gtest-all.cc',
+ 'googletest/googlemock/src/gmock-all.cc',
+ 'googletest/googlemock/src/gmock_main.cc',
+ ]),
+ header_namespace='',
+ exported_headers=subdir_glob([
+ ('googletest/googletest/include', '**/*.h'),
+ ('googletest/googlemock/include', '**/*.h'),
+ ]),
+ headers=subdir_glob([
+ ('googletest/googletest', 'src/*.cc'),
+ ('googletest/googletest', 'src/*.h'),
+ ('googletest/googlemock', 'src/*.cc'),
+ ('googletest/googlemock', 'src/*.h'),
+ ]),
+ platform_linker_flags=[
+ ('android', []),
+ ('', ['-lpthread']),
+ ],
+ visibility=['PUBLIC'],
+)
diff --git a/src/zstd/contrib/pzstd/ErrorHolder.h b/src/zstd/contrib/pzstd/ErrorHolder.h
new file mode 100644
index 000000000..829651c59
--- /dev/null
+++ b/src/zstd/contrib/pzstd/ErrorHolder.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include <atomic>
+#include <cassert>
+#include <stdexcept>
+#include <string>
+
+namespace pzstd {
+
+// Coordinates graceful shutdown of the pzstd pipeline
+class ErrorHolder {
+ std::atomic<bool> error_;
+ std::string message_;
+
+ public:
+ ErrorHolder() : error_(false) {}
+
+ bool hasError() noexcept {
+ return error_.load();
+ }
+
+ void setError(std::string message) noexcept {
+ // Given multiple possibly concurrent calls, exactly one will ever succeed.
+ bool expected = false;
+ if (error_.compare_exchange_strong(expected, true)) {
+ message_ = std::move(message);
+ }
+ }
+
+ bool check(bool predicate, std::string message) noexcept {
+ if (!predicate) {
+ setError(std::move(message));
+ }
+ return !hasError();
+ }
+
+ std::string getError() noexcept {
+ error_.store(false);
+ return std::move(message_);
+ }
+
+ ~ErrorHolder() {
+ assert(!hasError());
+ }
+};
+}
diff --git a/src/zstd/contrib/pzstd/Logging.h b/src/zstd/contrib/pzstd/Logging.h
new file mode 100644
index 000000000..16a63932c
--- /dev/null
+++ b/src/zstd/contrib/pzstd/Logging.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include <cstdio>
+#include <mutex>
+
+namespace pzstd {
+
+constexpr int ERROR = 1;
+constexpr int INFO = 2;
+constexpr int DEBUG = 3;
+constexpr int VERBOSE = 4;
+
+class Logger {
+ std::mutex mutex_;
+ FILE* out_;
+ const int level_;
+
+ using Clock = std::chrono::system_clock;
+ Clock::time_point lastUpdate_;
+ std::chrono::milliseconds refreshRate_;
+
+ public:
+ explicit Logger(int level, FILE* out = stderr)
+ : out_(out), level_(level), lastUpdate_(Clock::now()),
+ refreshRate_(150) {}
+
+
+ bool logsAt(int level) {
+ return level <= level_;
+ }
+
+ template <typename... Args>
+ void operator()(int level, const char *fmt, Args... args) {
+ if (level > level_) {
+ return;
+ }
+ std::lock_guard<std::mutex> lock(mutex_);
+ std::fprintf(out_, fmt, args...);
+ }
+
+ template <typename... Args>
+ void update(int level, const char *fmt, Args... args) {
+ if (level > level_) {
+ return;
+ }
+ std::lock_guard<std::mutex> lock(mutex_);
+ auto now = Clock::now();
+ if (now - lastUpdate_ > refreshRate_) {
+ lastUpdate_ = now;
+ std::fprintf(out_, "\r");
+ std::fprintf(out_, fmt, args...);
+ }
+ }
+
+ void clear(int level) {
+ if (level > level_) {
+ return;
+ }
+ std::lock_guard<std::mutex> lock(mutex_);
+ std::fprintf(out_, "\r%79s\r", "");
+ }
+};
+
+}
diff --git a/src/zstd/contrib/pzstd/Makefile b/src/zstd/contrib/pzstd/Makefile
new file mode 100644
index 000000000..8d2b1932e
--- /dev/null
+++ b/src/zstd/contrib/pzstd/Makefile
@@ -0,0 +1,271 @@
+# ################################################################
+# Copyright (c) 2016-present, Facebook, Inc.
+# All rights reserved.
+#
+# This source code is licensed under both the BSD-style license (found in the
+# LICENSE file in the root directory of this source tree) and the GPLv2 (found
+# in the COPYING file in the root directory of this source tree).
+# ################################################################
+
+# Standard variables for installation
+DESTDIR ?=
+PREFIX ?= /usr/local
+BINDIR := $(DESTDIR)$(PREFIX)/bin
+
+ZSTDDIR = ../../lib
+PROGDIR = ../../programs
+
+# External program to use to run tests, e.g. qemu or valgrind
+TESTPROG ?=
+# Flags to pass to the tests
+TESTFLAGS ?=
+
+# We use gcc/clang to generate the header dependencies of files
+DEPFLAGS = -MMD -MP -MF $*.Td
+POSTCOMPILE = mv -f $*.Td $*.d
+
+# CFLAGS, CXXFLAGS, CPPFLAGS, and LDFLAGS are for the users to override
+CFLAGS ?= -O3 -Wall -Wextra
+CXXFLAGS ?= -O3 -Wall -Wextra -pedantic
+CPPFLAGS ?=
+LDFLAGS ?=
+
+# Include flags
+PZSTD_INC = -I$(ZSTDDIR) -I$(ZSTDDIR)/common -I$(PROGDIR) -I.
+GTEST_INC = -isystem googletest/googletest/include
+
+PZSTD_CPPFLAGS = $(PZSTD_INC)
+PZSTD_CCXXFLAGS =
+PZSTD_CFLAGS = $(PZSTD_CCXXFLAGS)
+PZSTD_CXXFLAGS = $(PZSTD_CCXXFLAGS) -std=c++11
+PZSTD_LDFLAGS =
+EXTRA_FLAGS =
+ALL_CFLAGS = $(EXTRA_FLAGS) $(CPPFLAGS) $(PZSTD_CPPFLAGS) $(CFLAGS) $(PZSTD_CFLAGS)
+ALL_CXXFLAGS = $(EXTRA_FLAGS) $(CPPFLAGS) $(PZSTD_CPPFLAGS) $(CXXFLAGS) $(PZSTD_CXXFLAGS)
+ALL_LDFLAGS = $(EXTRA_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(PZSTD_LDFLAGS)
+
+
+# gtest libraries need to go before "-lpthread" because they depend on it.
+GTEST_LIB = -L googletest/build/googlemock/gtest
+LIBS =
+
+# Compilation commands
+LD_COMMAND = $(CXX) $^ $(ALL_LDFLAGS) $(LIBS) -pthread -o $@
+CC_COMMAND = $(CC) $(DEPFLAGS) $(ALL_CFLAGS) -c $< -o $@
+CXX_COMMAND = $(CXX) $(DEPFLAGS) $(ALL_CXXFLAGS) -c $< -o $@
+
+# Get a list of all zstd files so we rebuild the static library when we need to
+ZSTDCOMMON_FILES := $(wildcard $(ZSTDDIR)/common/*.c) \
+ $(wildcard $(ZSTDDIR)/common/*.h)
+ZSTDCOMP_FILES := $(wildcard $(ZSTDDIR)/compress/*.c) \
+ $(wildcard $(ZSTDDIR)/compress/*.h)
+ZSTDDECOMP_FILES := $(wildcard $(ZSTDDIR)/decompress/*.c) \
+ $(wildcard $(ZSTDDIR)/decompress/*.h)
+ZSTDPROG_FILES := $(wildcard $(PROGDIR)/*.c) \
+ $(wildcard $(PROGDIR)/*.h)
+ZSTD_FILES := $(wildcard $(ZSTDDIR)/*.h) \
+ $(ZSTDDECOMP_FILES) $(ZSTDCOMMON_FILES) $(ZSTDCOMP_FILES) \
+ $(ZSTDPROG_FILES)
+
+# List all the pzstd source files so we can determine their dependencies
+PZSTD_SRCS := $(wildcard *.cpp)
+PZSTD_TESTS := $(wildcard test/*.cpp)
+UTILS_TESTS := $(wildcard utils/test/*.cpp)
+ALL_SRCS := $(PZSTD_SRCS) $(PZSTD_TESTS) $(UTILS_TESTS)
+
+
+# Define *.exe as extension for Windows systems
+ifneq (,$(filter Windows%,$(OS)))
+EXT =.exe
+else
+EXT =
+endif
+
+# Standard targets
+.PHONY: default
+default: all
+
+.PHONY: test-pzstd
+test-pzstd: TESTFLAGS=--gtest_filter=-*ExtremelyLarge*
+test-pzstd: clean googletest pzstd tests check
+
+.PHONY: test-pzstd32
+test-pzstd32: clean googletest32 all32 check
+
+.PHONY: test-pzstd-tsan
+test-pzstd-tsan: LDFLAGS=-fuse-ld=gold
+test-pzstd-tsan: TESTFLAGS=--gtest_filter=-*ExtremelyLarge*
+test-pzstd-tsan: clean googletest tsan check
+
+.PHONY: test-pzstd-asan
+test-pzstd-asan: LDFLAGS=-fuse-ld=gold
+test-pzstd-asan: TESTFLAGS=--gtest_filter=-*ExtremelyLarge*
+test-pzstd-asan: clean asan check
+
+.PHONY: check
+check:
+ $(TESTPROG) ./utils/test/BufferTest$(EXT) $(TESTFLAGS)
+ $(TESTPROG) ./utils/test/RangeTest$(EXT) $(TESTFLAGS)
+ $(TESTPROG) ./utils/test/ResourcePoolTest$(EXT) $(TESTFLAGS)
+ $(TESTPROG) ./utils/test/ScopeGuardTest$(EXT) $(TESTFLAGS)
+ $(TESTPROG) ./utils/test/ThreadPoolTest$(EXT) $(TESTFLAGS)
+ $(TESTPROG) ./utils/test/WorkQueueTest$(EXT) $(TESTFLAGS)
+ $(TESTPROG) ./test/OptionsTest$(EXT) $(TESTFLAGS)
+ $(TESTPROG) ./test/PzstdTest$(EXT) $(TESTFLAGS)
+
+.PHONY: install
+install: PZSTD_CPPFLAGS += -DNDEBUG
+install: pzstd$(EXT)
+ install -d -m 755 $(BINDIR)/
+ install -m 755 pzstd$(EXT) $(BINDIR)/pzstd$(EXT)
+
+.PHONY: uninstall
+uninstall:
+ $(RM) $(BINDIR)/pzstd$(EXT)
+
+# Targets for many different builds
+.PHONY: all
+all: PZSTD_CPPFLAGS += -DNDEBUG
+all: pzstd$(EXT)
+
+.PHONY: debug
+debug: EXTRA_FLAGS += -g
+debug: pzstd$(EXT) tests roundtrip
+
+.PHONY: tsan
+tsan: PZSTD_CCXXFLAGS += -fsanitize=thread -fPIC
+tsan: PZSTD_LDFLAGS += -fsanitize=thread
+tsan: debug
+
+.PHONY: asan
+asan: EXTRA_FLAGS += -fsanitize=address
+asan: debug
+
+.PHONY: ubsan
+ubsan: EXTRA_FLAGS += -fsanitize=undefined
+ubsan: debug
+
+.PHONY: all32
+all32: EXTRA_FLAGS += -m32
+all32: all tests roundtrip
+
+.PHONY: debug32
+debug32: EXTRA_FLAGS += -m32
+debug32: debug
+
+.PHONY: asan32
+asan32: EXTRA_FLAGS += -m32
+asan32: asan
+
+.PHONY: tsan32
+tsan32: EXTRA_FLAGS += -m32
+tsan32: tsan
+
+.PHONY: ubsan32
+ubsan32: EXTRA_FLAGS += -m32
+ubsan32: ubsan
+
+# Run long round trip tests
+.PHONY: roundtripcheck
+roundtripcheck: roundtrip check
+ $(TESTPROG) ./test/RoundTripTest$(EXT) $(TESTFLAGS)
+
+# Build the main binary
+pzstd$(EXT): main.o $(PROGDIR)/util.o Options.o Pzstd.o SkippableFrame.o $(ZSTDDIR)/libzstd.a
+ $(LD_COMMAND)
+
+# Target that depends on all the tests
+.PHONY: tests
+tests: EXTRA_FLAGS += -Wno-deprecated-declarations
+tests: $(patsubst %,%$(EXT),$(basename $(PZSTD_TESTS) $(UTILS_TESTS)))
+
+# Build the round trip tests
+.PHONY: roundtrip
+roundtrip: EXTRA_FLAGS += -Wno-deprecated-declarations
+roundtrip: test/RoundTripTest$(EXT)
+
+# Use the static library that zstd builds for simplicity and
+# so we get the compiler options correct
+$(ZSTDDIR)/libzstd.a: $(ZSTD_FILES)
+ CFLAGS="$(ALL_CFLAGS)" LDFLAGS="$(ALL_LDFLAGS)" $(MAKE) -C $(ZSTDDIR) libzstd.a
+
+# Rules to build the tests
+test/RoundTripTest$(EXT): test/RoundTripTest.o $(PROGDIR)/datagen.o \
+ $(PROGDIR)/util.o Options.o \
+ Pzstd.o SkippableFrame.o $(ZSTDDIR)/libzstd.a
+ $(LD_COMMAND)
+
+test/%Test$(EXT): PZSTD_LDFLAGS += $(GTEST_LIB)
+test/%Test$(EXT): LIBS += -lgtest -lgtest_main
+test/%Test$(EXT): test/%Test.o $(PROGDIR)/datagen.o \
+ $(PROGDIR)/util.o Options.o Pzstd.o \
+ SkippableFrame.o $(ZSTDDIR)/libzstd.a
+ $(LD_COMMAND)
+
+utils/test/%Test$(EXT): PZSTD_LDFLAGS += $(GTEST_LIB)
+utils/test/%Test$(EXT): LIBS += -lgtest -lgtest_main
+utils/test/%Test$(EXT): utils/test/%Test.o
+ $(LD_COMMAND)
+
+
+GTEST_CMAKEFLAGS =
+
+# Install googletest
+.PHONY: googletest
+googletest: PZSTD_CCXXFLAGS += -fPIC
+googletest:
+ @$(RM) -rf googletest
+ @git clone https://github.com/google/googletest
+ @mkdir -p googletest/build
+ @cd googletest/build && cmake $(GTEST_CMAKEFLAGS) -DCMAKE_CXX_FLAGS="$(ALL_CXXFLAGS)" .. && $(MAKE)
+
+.PHONY: googletest32
+googletest32: PZSTD_CCXXFLAGS += -m32
+googletest32: googletest
+
+.PHONY: googletest-mingw64
+googletest-mingw64: GTEST_CMAKEFLAGS += -G "MSYS Makefiles"
+googletest-mingw64: googletest
+
+.PHONY: clean
+clean:
+ $(RM) -f *.o pzstd$(EXT) *.Td *.d
+ $(RM) -f test/*.o test/*Test$(EXT) test/*.Td test/*.d
+ $(RM) -f utils/test/*.o utils/test/*Test$(EXT) utils/test/*.Td utils/test/*.d
+ $(RM) -f $(PROGDIR)/*.o $(PROGDIR)/*.Td $(PROGDIR)/*.d
+ $(MAKE) -C $(ZSTDDIR) clean
+ @echo Cleaning completed
+
+
+# Cancel implicit rules
+%.o: %.c
+%.o: %.cpp
+
+# Object file rules
+%.o: %.c
+ $(CC_COMMAND)
+ $(POSTCOMPILE)
+
+$(PROGDIR)/%.o: $(PROGDIR)/%.c
+ $(CC_COMMAND)
+ $(POSTCOMPILE)
+
+%.o: %.cpp
+ $(CXX_COMMAND)
+ $(POSTCOMPILE)
+
+test/%.o: PZSTD_CPPFLAGS += $(GTEST_INC)
+test/%.o: test/%.cpp
+ $(CXX_COMMAND)
+ $(POSTCOMPILE)
+
+utils/test/%.o: PZSTD_CPPFLAGS += $(GTEST_INC)
+utils/test/%.o: utils/test/%.cpp
+ $(CXX_COMMAND)
+ $(POSTCOMPILE)
+
+# Dependency file stuff
+.PRECIOUS: %.d test/%.d utils/test/%.d
+
+# Include rules that specify header file dependencies
+-include $(patsubst %,%.d,$(basename $(ALL_SRCS)))
diff --git a/src/zstd/contrib/pzstd/Options.cpp b/src/zstd/contrib/pzstd/Options.cpp
new file mode 100644
index 000000000..37292221b
--- /dev/null
+++ b/src/zstd/contrib/pzstd/Options.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "Options.h"
+#include "util.h"
+#include "utils/ScopeGuard.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <iterator>
+#include <thread>
+#include <vector>
+
+
+namespace pzstd {
+
+namespace {
+unsigned defaultNumThreads() {
+#ifdef PZSTD_NUM_THREADS
+ return PZSTD_NUM_THREADS;
+#else
+ return std::thread::hardware_concurrency();
+#endif
+}
+
+unsigned parseUnsigned(const char **arg) {
+ unsigned result = 0;
+ while (**arg >= '0' && **arg <= '9') {
+ result *= 10;
+ result += **arg - '0';
+ ++(*arg);
+ }
+ return result;
+}
+
+const char *getArgument(const char *options, const char **argv, int &i,
+ int argc) {
+ if (options[1] != 0) {
+ return options + 1;
+ }
+ ++i;
+ if (i == argc) {
+ std::fprintf(stderr, "Option -%c requires an argument, but none provided\n",
+ *options);
+ return nullptr;
+ }
+ return argv[i];
+}
+
+const std::string kZstdExtension = ".zst";
+constexpr char kStdIn[] = "-";
+constexpr char kStdOut[] = "-";
+constexpr unsigned kDefaultCompressionLevel = 3;
+constexpr unsigned kMaxNonUltraCompressionLevel = 19;
+
+#ifdef _WIN32
+const char nullOutput[] = "nul";
+#else
+const char nullOutput[] = "/dev/null";
+#endif
+
+void notSupported(const char *option) {
+ std::fprintf(stderr, "Operation not supported: %s\n", option);
+}
+
+void usage() {
+ std::fprintf(stderr, "Usage:\n");
+ std::fprintf(stderr, " pzstd [args] [FILE(s)]\n");
+ std::fprintf(stderr, "Parallel ZSTD options:\n");
+ std::fprintf(stderr, " -p, --processes # : number of threads to use for (de)compression (default:<numcpus>)\n");
+
+ std::fprintf(stderr, "ZSTD options:\n");
+ std::fprintf(stderr, " -# : # compression level (1-%d, default:%d)\n", kMaxNonUltraCompressionLevel, kDefaultCompressionLevel);
+ std::fprintf(stderr, " -d, --decompress : decompression\n");
+ std::fprintf(stderr, " -o file : result stored into `file` (only if 1 input file)\n");
+ std::fprintf(stderr, " -f, --force : overwrite output without prompting, (de)compress links\n");
+ std::fprintf(stderr, " --rm : remove source file(s) after successful (de)compression\n");
+ std::fprintf(stderr, " -k, --keep : preserve source file(s) (default)\n");
+ std::fprintf(stderr, " -h, --help : display help and exit\n");
+ std::fprintf(stderr, " -V, --version : display version number and exit\n");
+ std::fprintf(stderr, " -v, --verbose : verbose mode; specify multiple times to increase log level (default:2)\n");
+ std::fprintf(stderr, " -q, --quiet : suppress warnings; specify twice to suppress errors too\n");
+ std::fprintf(stderr, " -c, --stdout : force write to standard output, even if it is the console\n");
+#ifdef UTIL_HAS_CREATEFILELIST
+ std::fprintf(stderr, " -r : operate recursively on directories\n");
+#endif
+ std::fprintf(stderr, " --ultra : enable levels beyond %i, up to %i (requires more memory)\n", kMaxNonUltraCompressionLevel, ZSTD_maxCLevel());
+ std::fprintf(stderr, " -C, --check : integrity check (default)\n");
+ std::fprintf(stderr, " --no-check : no integrity check\n");
+ std::fprintf(stderr, " -t, --test : test compressed file integrity\n");
+ std::fprintf(stderr, " -- : all arguments after \"--\" are treated as files\n");
+}
+} // anonymous namespace
+
+Options::Options()
+ : numThreads(defaultNumThreads()), maxWindowLog(23),
+ compressionLevel(kDefaultCompressionLevel), decompress(false),
+ overwrite(false), keepSource(true), writeMode(WriteMode::Auto),
+ checksum(true), verbosity(2) {}
+
+Options::Status Options::parse(int argc, const char **argv) {
+ bool test = false;
+ bool recursive = false;
+ bool ultra = false;
+ bool forceStdout = false;
+ bool followLinks = false;
+ // Local copy of input files, which are pointers into argv.
+ std::vector<const char *> localInputFiles;
+ for (int i = 1; i < argc; ++i) {
+ const char *arg = argv[i];
+ // Protect against empty arguments
+ if (arg[0] == 0) {
+ continue;
+ }
+ // Everything after "--" is an input file
+ if (!std::strcmp(arg, "--")) {
+ ++i;
+ std::copy(argv + i, argv + argc, std::back_inserter(localInputFiles));
+ break;
+ }
+ // Long arguments that don't have a short option
+ {
+ bool isLongOption = true;
+ if (!std::strcmp(arg, "--rm")) {
+ keepSource = false;
+ } else if (!std::strcmp(arg, "--ultra")) {
+ ultra = true;
+ maxWindowLog = 0;
+ } else if (!std::strcmp(arg, "--no-check")) {
+ checksum = false;
+ } else if (!std::strcmp(arg, "--sparse")) {
+ writeMode = WriteMode::Sparse;
+ notSupported("Sparse mode");
+ return Status::Failure;
+ } else if (!std::strcmp(arg, "--no-sparse")) {
+ writeMode = WriteMode::Regular;
+ notSupported("Sparse mode");
+ return Status::Failure;
+ } else if (!std::strcmp(arg, "--dictID")) {
+ notSupported(arg);
+ return Status::Failure;
+ } else if (!std::strcmp(arg, "--no-dictID")) {
+ notSupported(arg);
+ return Status::Failure;
+ } else {
+ isLongOption = false;
+ }
+ if (isLongOption) {
+ continue;
+ }
+ }
+ // Arguments with a short option simply set their short option.
+ const char *options = nullptr;
+ if (!std::strcmp(arg, "--processes")) {
+ options = "p";
+ } else if (!std::strcmp(arg, "--version")) {
+ options = "V";
+ } else if (!std::strcmp(arg, "--help")) {
+ options = "h";
+ } else if (!std::strcmp(arg, "--decompress")) {
+ options = "d";
+ } else if (!std::strcmp(arg, "--force")) {
+ options = "f";
+ } else if (!std::strcmp(arg, "--stdout")) {
+ options = "c";
+ } else if (!std::strcmp(arg, "--keep")) {
+ options = "k";
+ } else if (!std::strcmp(arg, "--verbose")) {
+ options = "v";
+ } else if (!std::strcmp(arg, "--quiet")) {
+ options = "q";
+ } else if (!std::strcmp(arg, "--check")) {
+ options = "C";
+ } else if (!std::strcmp(arg, "--test")) {
+ options = "t";
+ } else if (arg[0] == '-' && arg[1] != 0) {
+ options = arg + 1;
+ } else {
+ localInputFiles.emplace_back(arg);
+ continue;
+ }
+ assert(options != nullptr);
+
+ bool finished = false;
+ while (!finished && *options != 0) {
+ // Parse the compression level
+ if (*options >= '0' && *options <= '9') {
+ compressionLevel = parseUnsigned(&options);
+ continue;
+ }
+
+ switch (*options) {
+ case 'h':
+ case 'H':
+ usage();
+ return Status::Message;
+ case 'V':
+ std::fprintf(stderr, "PZSTD version: %s.\n", ZSTD_VERSION_STRING);
+ return Status::Message;
+ case 'p': {
+ finished = true;
+ const char *optionArgument = getArgument(options, argv, i, argc);
+ if (optionArgument == nullptr) {
+ return Status::Failure;
+ }
+ if (*optionArgument < '0' || *optionArgument > '9') {
+ std::fprintf(stderr, "Option -p expects a number, but %s provided\n",
+ optionArgument);
+ return Status::Failure;
+ }
+ numThreads = parseUnsigned(&optionArgument);
+ if (*optionArgument != 0) {
+ std::fprintf(stderr,
+ "Option -p expects a number, but %u%s provided\n",
+ numThreads, optionArgument);
+ return Status::Failure;
+ }
+ break;
+ }
+ case 'o': {
+ finished = true;
+ const char *optionArgument = getArgument(options, argv, i, argc);
+ if (optionArgument == nullptr) {
+ return Status::Failure;
+ }
+ outputFile = optionArgument;
+ break;
+ }
+ case 'C':
+ checksum = true;
+ break;
+ case 'k':
+ keepSource = true;
+ break;
+ case 'd':
+ decompress = true;
+ break;
+ case 'f':
+ overwrite = true;
+ forceStdout = true;
+ followLinks = true;
+ break;
+ case 't':
+ test = true;
+ decompress = true;
+ break;
+#ifdef UTIL_HAS_CREATEFILELIST
+ case 'r':
+ recursive = true;
+ break;
+#endif
+ case 'c':
+ outputFile = kStdOut;
+ forceStdout = true;
+ break;
+ case 'v':
+ ++verbosity;
+ break;
+ case 'q':
+ --verbosity;
+ // Ignore them for now
+ break;
+ // Unsupported options from Zstd
+ case 'D':
+ case 's':
+ notSupported("Zstd dictionaries.");
+ return Status::Failure;
+ case 'b':
+ case 'e':
+ case 'i':
+ case 'B':
+ notSupported("Zstd benchmarking options.");
+ return Status::Failure;
+ default:
+ std::fprintf(stderr, "Invalid argument: %s\n", arg);
+ return Status::Failure;
+ }
+ if (!finished) {
+ ++options;
+ }
+ } // while (*options != 0);
+ } // for (int i = 1; i < argc; ++i);
+
+ // Set options for test mode
+ if (test) {
+ outputFile = nullOutput;
+ keepSource = true;
+ }
+
+ // Input file defaults to standard input if not provided.
+ if (localInputFiles.empty()) {
+ localInputFiles.emplace_back(kStdIn);
+ }
+
+ // Check validity of input files
+ if (localInputFiles.size() > 1) {
+ const auto it = std::find(localInputFiles.begin(), localInputFiles.end(),
+ std::string{kStdIn});
+ if (it != localInputFiles.end()) {
+ std::fprintf(
+ stderr,
+ "Cannot specify standard input when handling multiple files\n");
+ return Status::Failure;
+ }
+ }
+ if (localInputFiles.size() > 1 || recursive) {
+ if (!outputFile.empty() && outputFile != nullOutput) {
+ std::fprintf(
+ stderr,
+ "Cannot specify an output file when handling multiple inputs\n");
+ return Status::Failure;
+ }
+ }
+
+ g_utilDisplayLevel = verbosity;
+ // Remove local input files that are symbolic links
+ if (!followLinks) {
+ std::remove_if(localInputFiles.begin(), localInputFiles.end(),
+ [&](const char *path) {
+ bool isLink = UTIL_isLink(path);
+ if (isLink && verbosity >= 2) {
+ std::fprintf(
+ stderr,
+ "Warning : %s is symbolic link, ignoring\n",
+ path);
+ }
+ return isLink;
+ });
+ }
+
+ // Translate input files/directories into files to (de)compress
+ if (recursive) {
+ FileNamesTable* const files = UTIL_createExpandedFNT(localInputFiles.data(), localInputFiles.size(), followLinks);
+ if (files == nullptr) {
+ std::fprintf(stderr, "Error traversing directories\n");
+ return Status::Failure;
+ }
+ auto guard =
+ makeScopeGuard([&] { UTIL_freeFileNamesTable(files); });
+ if (files->tableSize == 0) {
+ std::fprintf(stderr, "No files found\n");
+ return Status::Failure;
+ }
+ inputFiles.resize(files->tableSize);
+ std::copy(files->fileNames, files->fileNames + files->tableSize, inputFiles.begin());
+ } else {
+ inputFiles.resize(localInputFiles.size());
+ std::copy(localInputFiles.begin(), localInputFiles.end(),
+ inputFiles.begin());
+ }
+ localInputFiles.clear();
+ assert(!inputFiles.empty());
+
+ // If reading from standard input, default to standard output
+ if (inputFiles[0] == kStdIn && outputFile.empty()) {
+ assert(inputFiles.size() == 1);
+ outputFile = "-";
+ }
+
+ if (inputFiles[0] == kStdIn && IS_CONSOLE(stdin)) {
+ assert(inputFiles.size() == 1);
+ std::fprintf(stderr, "Cannot read input from interactive console\n");
+ return Status::Failure;
+ }
+ if (outputFile == "-" && IS_CONSOLE(stdout) && !(forceStdout && decompress)) {
+ std::fprintf(stderr, "Will not write to console stdout unless -c or -f is "
+ "specified and decompressing\n");
+ return Status::Failure;
+ }
+
+ // Check compression level
+ {
+ unsigned maxCLevel =
+ ultra ? ZSTD_maxCLevel() : kMaxNonUltraCompressionLevel;
+ if (compressionLevel > maxCLevel || compressionLevel == 0) {
+ std::fprintf(stderr, "Invalid compression level %u.\n", compressionLevel);
+ return Status::Failure;
+ }
+ }
+
+ // Check that numThreads is set
+ if (numThreads == 0) {
+ std::fprintf(stderr, "Invalid arguments: # of threads not specified "
+ "and unable to determine hardware concurrency.\n");
+ return Status::Failure;
+ }
+
+ // Modify verbosity
+ // If we are piping input and output, turn off interaction
+ if (inputFiles[0] == kStdIn && outputFile == kStdOut && verbosity == 2) {
+ verbosity = 1;
+ }
+ // If we are in multi-file mode, turn off interaction
+ if (inputFiles.size() > 1 && verbosity == 2) {
+ verbosity = 1;
+ }
+
+ return Status::Success;
+}
+
+std::string Options::getOutputFile(const std::string &inputFile) const {
+ if (!outputFile.empty()) {
+ return outputFile;
+ }
+ // Attempt to add/remove zstd extension from the input file
+ if (decompress) {
+ int stemSize = inputFile.size() - kZstdExtension.size();
+ if (stemSize > 0 && inputFile.substr(stemSize) == kZstdExtension) {
+ return inputFile.substr(0, stemSize);
+ } else {
+ return "";
+ }
+ } else {
+ return inputFile + kZstdExtension;
+ }
+}
+}
diff --git a/src/zstd/contrib/pzstd/Options.h b/src/zstd/contrib/pzstd/Options.h
new file mode 100644
index 000000000..f4f2aaa49
--- /dev/null
+++ b/src/zstd/contrib/pzstd/Options.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#define ZSTD_STATIC_LINKING_ONLY
+#include "zstd.h"
+#undef ZSTD_STATIC_LINKING_ONLY
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace pzstd {
+
+struct Options {
+ enum class WriteMode { Regular, Auto, Sparse };
+
+ unsigned numThreads;
+ unsigned maxWindowLog;
+ unsigned compressionLevel;
+ bool decompress;
+ std::vector<std::string> inputFiles;
+ std::string outputFile;
+ bool overwrite;
+ bool keepSource;
+ WriteMode writeMode;
+ bool checksum;
+ int verbosity;
+
+ enum class Status {
+ Success, // Successfully parsed options
+ Failure, // Failure to parse options
+ Message // Options specified to print a message (e.g. "-h")
+ };
+
+ Options();
+ Options(unsigned numThreads, unsigned maxWindowLog, unsigned compressionLevel,
+ bool decompress, std::vector<std::string> inputFiles,
+ std::string outputFile, bool overwrite, bool keepSource,
+ WriteMode writeMode, bool checksum, int verbosity)
+ : numThreads(numThreads), maxWindowLog(maxWindowLog),
+ compressionLevel(compressionLevel), decompress(decompress),
+ inputFiles(std::move(inputFiles)), outputFile(std::move(outputFile)),
+ overwrite(overwrite), keepSource(keepSource), writeMode(writeMode),
+ checksum(checksum), verbosity(verbosity) {}
+
+ Status parse(int argc, const char **argv);
+
+ ZSTD_parameters determineParameters() const {
+ ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, 0);
+ params.fParams.contentSizeFlag = 0;
+ params.fParams.checksumFlag = checksum;
+ if (maxWindowLog != 0 && params.cParams.windowLog > maxWindowLog) {
+ params.cParams.windowLog = maxWindowLog;
+ params.cParams = ZSTD_adjustCParams(params.cParams, 0, 0);
+ }
+ return params;
+ }
+
+ std::string getOutputFile(const std::string &inputFile) const;
+};
+}
diff --git a/src/zstd/contrib/pzstd/Pzstd.cpp b/src/zstd/contrib/pzstd/Pzstd.cpp
new file mode 100644
index 000000000..652187c3b
--- /dev/null
+++ b/src/zstd/contrib/pzstd/Pzstd.cpp
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "platform.h" /* Large Files support, SET_BINARY_MODE */
+#include "Pzstd.h"
+#include "SkippableFrame.h"
+#include "utils/FileSystem.h"
+#include "utils/Range.h"
+#include "utils/ScopeGuard.h"
+#include "utils/ThreadPool.h"
+#include "utils/WorkQueue.h"
+
+#include <chrono>
+#include <cinttypes>
+#include <cstddef>
+#include <cstdio>
+#include <memory>
+#include <string>
+
+
+namespace pzstd {
+
+namespace {
+#ifdef _WIN32
+const std::string nullOutput = "nul";
+#else
+const std::string nullOutput = "/dev/null";
+#endif
+}
+
+using std::size_t;
+
+static std::uintmax_t fileSizeOrZero(const std::string &file) {
+ if (file == "-") {
+ return 0;
+ }
+ std::error_code ec;
+ auto size = file_size(file, ec);
+ if (ec) {
+ size = 0;
+ }
+ return size;
+}
+
+static std::uint64_t handleOneInput(const Options &options,
+ const std::string &inputFile,
+ FILE* inputFd,
+ const std::string &outputFile,
+ FILE* outputFd,
+ SharedState& state) {
+ auto inputSize = fileSizeOrZero(inputFile);
+ // WorkQueue outlives ThreadPool so in the case of error we are certain
+ // we don't accidentally try to call push() on it after it is destroyed
+ WorkQueue<std::shared_ptr<BufferWorkQueue>> outs{options.numThreads + 1};
+ std::uint64_t bytesRead;
+ std::uint64_t bytesWritten;
+ {
+ // Initialize the (de)compression thread pool with numThreads
+ ThreadPool executor(options.numThreads);
+ // Run the reader thread on an extra thread
+ ThreadPool readExecutor(1);
+ if (!options.decompress) {
+ // Add a job that reads the input and starts all the compression jobs
+ readExecutor.add(
+ [&state, &outs, &executor, inputFd, inputSize, &options, &bytesRead] {
+ bytesRead = asyncCompressChunks(
+ state,
+ outs,
+ executor,
+ inputFd,
+ inputSize,
+ options.numThreads,
+ options.determineParameters());
+ });
+ // Start writing
+ bytesWritten = writeFile(state, outs, outputFd, options.decompress);
+ } else {
+ // Add a job that reads the input and starts all the decompression jobs
+ readExecutor.add([&state, &outs, &executor, inputFd, &bytesRead] {
+ bytesRead = asyncDecompressFrames(state, outs, executor, inputFd);
+ });
+ // Start writing
+ bytesWritten = writeFile(state, outs, outputFd, options.decompress);
+ }
+ }
+ if (!state.errorHolder.hasError()) {
+ std::string inputFileName = inputFile == "-" ? "stdin" : inputFile;
+ std::string outputFileName = outputFile == "-" ? "stdout" : outputFile;
+ if (!options.decompress) {
+ double ratio = static_cast<double>(bytesWritten) /
+ static_cast<double>(bytesRead + !bytesRead);
+ state.log(INFO, "%-20s :%6.2f%% (%6" PRIu64 " => %6" PRIu64
+ " bytes, %s)\n",
+ inputFileName.c_str(), ratio * 100, bytesRead, bytesWritten,
+ outputFileName.c_str());
+ } else {
+ state.log(INFO, "%-20s: %" PRIu64 " bytes \n",
+ inputFileName.c_str(),bytesWritten);
+ }
+ }
+ return bytesWritten;
+}
+
+static FILE *openInputFile(const std::string &inputFile,
+ ErrorHolder &errorHolder) {
+ if (inputFile == "-") {
+ SET_BINARY_MODE(stdin);
+ return stdin;
+ }
+ // Check if input file is a directory
+ {
+ std::error_code ec;
+ if (is_directory(inputFile, ec)) {
+ errorHolder.setError("Output file is a directory -- ignored");
+ return nullptr;
+ }
+ }
+ auto inputFd = std::fopen(inputFile.c_str(), "rb");
+ if (!errorHolder.check(inputFd != nullptr, "Failed to open input file")) {
+ return nullptr;
+ }
+ return inputFd;
+}
+
+static FILE *openOutputFile(const Options &options,
+ const std::string &outputFile,
+ SharedState& state) {
+ if (outputFile == "-") {
+ SET_BINARY_MODE(stdout);
+ return stdout;
+ }
+ // Check if the output file exists and then open it
+ if (!options.overwrite && outputFile != nullOutput) {
+ auto outputFd = std::fopen(outputFile.c_str(), "rb");
+ if (outputFd != nullptr) {
+ std::fclose(outputFd);
+ if (!state.log.logsAt(INFO)) {
+ state.errorHolder.setError("Output file exists");
+ return nullptr;
+ }
+ state.log(
+ INFO,
+ "pzstd: %s already exists; do you wish to overwrite (y/n) ? ",
+ outputFile.c_str());
+ int c = getchar();
+ if (c != 'y' && c != 'Y') {
+ state.errorHolder.setError("Not overwritten");
+ return nullptr;
+ }
+ }
+ }
+ auto outputFd = std::fopen(outputFile.c_str(), "wb");
+ if (!state.errorHolder.check(
+ outputFd != nullptr, "Failed to open output file")) {
+ return nullptr;
+ }
+ return outputFd;
+}
+
+int pzstdMain(const Options &options) {
+ int returnCode = 0;
+ SharedState state(options);
+ for (const auto& input : options.inputFiles) {
+ // Setup the shared state
+ auto printErrorGuard = makeScopeGuard([&] {
+ if (state.errorHolder.hasError()) {
+ returnCode = 1;
+ state.log(ERROR, "pzstd: %s: %s.\n", input.c_str(),
+ state.errorHolder.getError().c_str());
+ }
+ });
+ // Open the input file
+ auto inputFd = openInputFile(input, state.errorHolder);
+ if (inputFd == nullptr) {
+ continue;
+ }
+ auto closeInputGuard = makeScopeGuard([&] { std::fclose(inputFd); });
+ // Open the output file
+ auto outputFile = options.getOutputFile(input);
+ if (!state.errorHolder.check(outputFile != "",
+ "Input file does not have extension .zst")) {
+ continue;
+ }
+ auto outputFd = openOutputFile(options, outputFile, state);
+ if (outputFd == nullptr) {
+ continue;
+ }
+ auto closeOutputGuard = makeScopeGuard([&] { std::fclose(outputFd); });
+ // (de)compress the file
+ handleOneInput(options, input, inputFd, outputFile, outputFd, state);
+ if (state.errorHolder.hasError()) {
+ continue;
+ }
+ // Delete the input file if necessary
+ if (!options.keepSource) {
+ // Be sure that we are done and have written everything before we delete
+ if (!state.errorHolder.check(std::fclose(inputFd) == 0,
+ "Failed to close input file")) {
+ continue;
+ }
+ closeInputGuard.dismiss();
+ if (!state.errorHolder.check(std::fclose(outputFd) == 0,
+ "Failed to close output file")) {
+ continue;
+ }
+ closeOutputGuard.dismiss();
+ if (std::remove(input.c_str()) != 0) {
+ state.errorHolder.setError("Failed to remove input file");
+ continue;
+ }
+ }
+ }
+ // Returns 1 if any of the files failed to (de)compress.
+ return returnCode;
+}
+
+/// Construct a `ZSTD_inBuffer` that points to the data in `buffer`.
+static ZSTD_inBuffer makeZstdInBuffer(const Buffer& buffer) {
+ return ZSTD_inBuffer{buffer.data(), buffer.size(), 0};
+}
+
+/**
+ * Advance `buffer` and `inBuffer` by the amount of data read, as indicated by
+ * `inBuffer.pos`.
+ */
+void advance(Buffer& buffer, ZSTD_inBuffer& inBuffer) {
+ auto pos = inBuffer.pos;
+ inBuffer.src = static_cast<const unsigned char*>(inBuffer.src) + pos;
+ inBuffer.size -= pos;
+ inBuffer.pos = 0;
+ return buffer.advance(pos);
+}
+
+/// Construct a `ZSTD_outBuffer` that points to the data in `buffer`.
+static ZSTD_outBuffer makeZstdOutBuffer(Buffer& buffer) {
+ return ZSTD_outBuffer{buffer.data(), buffer.size(), 0};
+}
+
+/**
+ * Split `buffer` and advance `outBuffer` by the amount of data written, as
+ * indicated by `outBuffer.pos`.
+ */
+Buffer split(Buffer& buffer, ZSTD_outBuffer& outBuffer) {
+ auto pos = outBuffer.pos;
+ outBuffer.dst = static_cast<unsigned char*>(outBuffer.dst) + pos;
+ outBuffer.size -= pos;
+ outBuffer.pos = 0;
+ return buffer.splitAt(pos);
+}
+
+/**
+ * Stream chunks of input from `in`, compress it, and stream it out to `out`.
+ *
+ * @param state The shared state
+ * @param in Queue that we `pop()` input buffers from
+ * @param out Queue that we `push()` compressed output buffers to
+ * @param maxInputSize An upper bound on the size of the input
+ */
+static void compress(
+ SharedState& state,
+ std::shared_ptr<BufferWorkQueue> in,
+ std::shared_ptr<BufferWorkQueue> out,
+ size_t maxInputSize) {
+ auto& errorHolder = state.errorHolder;
+ auto guard = makeScopeGuard([&] { out->finish(); });
+ // Initialize the CCtx
+ auto ctx = state.cStreamPool->get();
+ if (!errorHolder.check(ctx != nullptr, "Failed to allocate ZSTD_CStream")) {
+ return;
+ }
+ {
+ auto err = ZSTD_resetCStream(ctx.get(), 0);
+ if (!errorHolder.check(!ZSTD_isError(err), ZSTD_getErrorName(err))) {
+ return;
+ }
+ }
+
+ // Allocate space for the result
+ auto outBuffer = Buffer(ZSTD_compressBound(maxInputSize));
+ auto zstdOutBuffer = makeZstdOutBuffer(outBuffer);
+ {
+ Buffer inBuffer;
+ // Read a buffer in from the input queue
+ while (in->pop(inBuffer) && !errorHolder.hasError()) {
+ auto zstdInBuffer = makeZstdInBuffer(inBuffer);
+ // Compress the whole buffer and send it to the output queue
+ while (!inBuffer.empty() && !errorHolder.hasError()) {
+ if (!errorHolder.check(
+ !outBuffer.empty(), "ZSTD_compressBound() was too small")) {
+ return;
+ }
+ // Compress
+ auto err =
+ ZSTD_compressStream(ctx.get(), &zstdOutBuffer, &zstdInBuffer);
+ if (!errorHolder.check(!ZSTD_isError(err), ZSTD_getErrorName(err))) {
+ return;
+ }
+ // Split the compressed data off outBuffer and pass to the output queue
+ out->push(split(outBuffer, zstdOutBuffer));
+ // Forget about the data we already compressed
+ advance(inBuffer, zstdInBuffer);
+ }
+ }
+ }
+ // Write the epilog
+ size_t bytesLeft;
+ do {
+ if (!errorHolder.check(
+ !outBuffer.empty(), "ZSTD_compressBound() was too small")) {
+ return;
+ }
+ bytesLeft = ZSTD_endStream(ctx.get(), &zstdOutBuffer);
+ if (!errorHolder.check(
+ !ZSTD_isError(bytesLeft), ZSTD_getErrorName(bytesLeft))) {
+ return;
+ }
+ out->push(split(outBuffer, zstdOutBuffer));
+ } while (bytesLeft != 0 && !errorHolder.hasError());
+}
+
+/**
+ * Calculates how large each independently compressed frame should be.
+ *
+ * @param size The size of the source if known, 0 otherwise
+ * @param numThreads The number of threads available to run compression jobs on
+ * @param params The zstd parameters to be used for compression
+ */
+static size_t calculateStep(
+ std::uintmax_t size,
+ size_t numThreads,
+ const ZSTD_parameters &params) {
+ (void)size;
+ (void)numThreads;
+ return size_t{1} << (params.cParams.windowLog + 2);
+}
+
+namespace {
+enum class FileStatus { Continue, Done, Error };
+/// Determines the status of the file descriptor `fd`.
+FileStatus fileStatus(FILE* fd) {
+ if (std::feof(fd)) {
+ return FileStatus::Done;
+ } else if (std::ferror(fd)) {
+ return FileStatus::Error;
+ }
+ return FileStatus::Continue;
+}
+} // anonymous namespace
+
+/**
+ * Reads `size` data in chunks of `chunkSize` and puts it into `queue`.
+ * Will read less if an error or EOF occurs.
+ * Returns the status of the file after all of the reads have occurred.
+ */
+static FileStatus
+readData(BufferWorkQueue& queue, size_t chunkSize, size_t size, FILE* fd,
+ std::uint64_t *totalBytesRead) {
+ Buffer buffer(size);
+ while (!buffer.empty()) {
+ auto bytesRead =
+ std::fread(buffer.data(), 1, std::min(chunkSize, buffer.size()), fd);
+ *totalBytesRead += bytesRead;
+ queue.push(buffer.splitAt(bytesRead));
+ auto status = fileStatus(fd);
+ if (status != FileStatus::Continue) {
+ return status;
+ }
+ }
+ return FileStatus::Continue;
+}
+
+std::uint64_t asyncCompressChunks(
+ SharedState& state,
+ WorkQueue<std::shared_ptr<BufferWorkQueue>>& chunks,
+ ThreadPool& executor,
+ FILE* fd,
+ std::uintmax_t size,
+ size_t numThreads,
+ ZSTD_parameters params) {
+ auto chunksGuard = makeScopeGuard([&] { chunks.finish(); });
+ std::uint64_t bytesRead = 0;
+
+ // Break the input up into chunks of size `step` and compress each chunk
+ // independently.
+ size_t step = calculateStep(size, numThreads, params);
+ state.log(DEBUG, "Chosen frame size: %zu\n", step);
+ auto status = FileStatus::Continue;
+ while (status == FileStatus::Continue && !state.errorHolder.hasError()) {
+ // Make a new input queue that we will put the chunk's input data into.
+ auto in = std::make_shared<BufferWorkQueue>();
+ auto inGuard = makeScopeGuard([&] { in->finish(); });
+ // Make a new output queue that compress will put the compressed data into.
+ auto out = std::make_shared<BufferWorkQueue>();
+ // Start compression in the thread pool
+ executor.add([&state, in, out, step] {
+ return compress(
+ state, std::move(in), std::move(out), step);
+ });
+ // Pass the output queue to the writer thread.
+ chunks.push(std::move(out));
+ state.log(VERBOSE, "%s\n", "Starting a new frame");
+ // Fill the input queue for the compression job we just started
+ status = readData(*in, ZSTD_CStreamInSize(), step, fd, &bytesRead);
+ }
+ state.errorHolder.check(status != FileStatus::Error, "Error reading input");
+ return bytesRead;
+}
+
+/**
+ * Decompress a frame, whose data is streamed into `in`, and stream the output
+ * to `out`.
+ *
+ * @param state The shared state
+ * @param in Queue that we `pop()` input buffers from. It contains
+ * exactly one compressed frame.
+ * @param out Queue that we `push()` decompressed output buffers to
+ */
+static void decompress(
+ SharedState& state,
+ std::shared_ptr<BufferWorkQueue> in,
+ std::shared_ptr<BufferWorkQueue> out) {
+ auto& errorHolder = state.errorHolder;
+ auto guard = makeScopeGuard([&] { out->finish(); });
+ // Initialize the DCtx
+ auto ctx = state.dStreamPool->get();
+ if (!errorHolder.check(ctx != nullptr, "Failed to allocate ZSTD_DStream")) {
+ return;
+ }
+ {
+ auto err = ZSTD_resetDStream(ctx.get());
+ if (!errorHolder.check(!ZSTD_isError(err), ZSTD_getErrorName(err))) {
+ return;
+ }
+ }
+
+ const size_t outSize = ZSTD_DStreamOutSize();
+ Buffer inBuffer;
+ size_t returnCode = 0;
+ // Read a buffer in from the input queue
+ while (in->pop(inBuffer) && !errorHolder.hasError()) {
+ auto zstdInBuffer = makeZstdInBuffer(inBuffer);
+ // Decompress the whole buffer and send it to the output queue
+ while (!inBuffer.empty() && !errorHolder.hasError()) {
+ // Allocate a buffer with at least outSize bytes.
+ Buffer outBuffer(outSize);
+ auto zstdOutBuffer = makeZstdOutBuffer(outBuffer);
+ // Decompress
+ returnCode =
+ ZSTD_decompressStream(ctx.get(), &zstdOutBuffer, &zstdInBuffer);
+ if (!errorHolder.check(
+ !ZSTD_isError(returnCode), ZSTD_getErrorName(returnCode))) {
+ return;
+ }
+ // Pass the buffer with the decompressed data to the output queue
+ out->push(split(outBuffer, zstdOutBuffer));
+ // Advance past the input we already read
+ advance(inBuffer, zstdInBuffer);
+ if (returnCode == 0) {
+ // The frame is over, prepare to (maybe) start a new frame
+ ZSTD_initDStream(ctx.get());
+ }
+ }
+ }
+ if (!errorHolder.check(returnCode <= 1, "Incomplete block")) {
+ return;
+ }
+ // We've given ZSTD_decompressStream all of our data, but there may still
+ // be data to read.
+ while (returnCode == 1) {
+ // Allocate a buffer with at least outSize bytes.
+ Buffer outBuffer(outSize);
+ auto zstdOutBuffer = makeZstdOutBuffer(outBuffer);
+ // Pass in no input.
+ ZSTD_inBuffer zstdInBuffer{nullptr, 0, 0};
+ // Decompress
+ returnCode =
+ ZSTD_decompressStream(ctx.get(), &zstdOutBuffer, &zstdInBuffer);
+ if (!errorHolder.check(
+ !ZSTD_isError(returnCode), ZSTD_getErrorName(returnCode))) {
+ return;
+ }
+ // Pass the buffer with the decompressed data to the output queue
+ out->push(split(outBuffer, zstdOutBuffer));
+ }
+}
+
+std::uint64_t asyncDecompressFrames(
+ SharedState& state,
+ WorkQueue<std::shared_ptr<BufferWorkQueue>>& frames,
+ ThreadPool& executor,
+ FILE* fd) {
+ auto framesGuard = makeScopeGuard([&] { frames.finish(); });
+ std::uint64_t totalBytesRead = 0;
+
+ // Split the source up into its component frames.
+ // If we find our recognized skippable frame we know the next frames size
+ // which means that we can decompress each standard frame in independently.
+ // Otherwise, we will decompress using only one decompression task.
+ const size_t chunkSize = ZSTD_DStreamInSize();
+ auto status = FileStatus::Continue;
+ while (status == FileStatus::Continue && !state.errorHolder.hasError()) {
+ // Make a new input queue that we will put the frames's bytes into.
+ auto in = std::make_shared<BufferWorkQueue>();
+ auto inGuard = makeScopeGuard([&] { in->finish(); });
+ // Make a output queue that decompress will put the decompressed data into
+ auto out = std::make_shared<BufferWorkQueue>();
+
+ size_t frameSize;
+ {
+ // Calculate the size of the next frame.
+ // frameSize is 0 if the frame info can't be decoded.
+ Buffer buffer(SkippableFrame::kSize);
+ auto bytesRead = std::fread(buffer.data(), 1, buffer.size(), fd);
+ totalBytesRead += bytesRead;
+ status = fileStatus(fd);
+ if (bytesRead == 0 && status != FileStatus::Continue) {
+ break;
+ }
+ buffer.subtract(buffer.size() - bytesRead);
+ frameSize = SkippableFrame::tryRead(buffer.range());
+ in->push(std::move(buffer));
+ }
+ if (frameSize == 0) {
+ // We hit a non SkippableFrame, so this will be the last job.
+ // Make sure that we don't use too much memory
+ in->setMaxSize(64);
+ out->setMaxSize(64);
+ }
+ // Start decompression in the thread pool
+ executor.add([&state, in, out] {
+ return decompress(state, std::move(in), std::move(out));
+ });
+ // Pass the output queue to the writer thread
+ frames.push(std::move(out));
+ if (frameSize == 0) {
+ // We hit a non SkippableFrame ==> not compressed by pzstd or corrupted
+ // Pass the rest of the source to this decompression task
+ state.log(VERBOSE, "%s\n",
+ "Input not in pzstd format, falling back to serial decompression");
+ while (status == FileStatus::Continue && !state.errorHolder.hasError()) {
+ status = readData(*in, chunkSize, chunkSize, fd, &totalBytesRead);
+ }
+ break;
+ }
+ state.log(VERBOSE, "Decompressing a frame of size %zu", frameSize);
+ // Fill the input queue for the decompression job we just started
+ status = readData(*in, chunkSize, frameSize, fd, &totalBytesRead);
+ }
+ state.errorHolder.check(status != FileStatus::Error, "Error reading input");
+ return totalBytesRead;
+}
+
+/// Write `data` to `fd`, returns true iff success.
+static bool writeData(ByteRange data, FILE* fd) {
+ while (!data.empty()) {
+ data.advance(std::fwrite(data.begin(), 1, data.size(), fd));
+ if (std::ferror(fd)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+std::uint64_t writeFile(
+ SharedState& state,
+ WorkQueue<std::shared_ptr<BufferWorkQueue>>& outs,
+ FILE* outputFd,
+ bool decompress) {
+ auto& errorHolder = state.errorHolder;
+ auto lineClearGuard = makeScopeGuard([&state] {
+ state.log.clear(INFO);
+ });
+ std::uint64_t bytesWritten = 0;
+ std::shared_ptr<BufferWorkQueue> out;
+ // Grab the output queue for each decompression job (in order).
+ 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
+ // compressed size.
+ // Wait for the compressed size to be available and write skippable frame
+ SkippableFrame frame(out->size());
+ if (!writeData(frame.data(), outputFd)) {
+ errorHolder.setError("Failed to write output");
+ return bytesWritten;
+ }
+ bytesWritten += frame.kSize;
+ }
+ // For each chunk of the frame: Pop it from the queue and write it
+ Buffer buffer;
+ while (out->pop(buffer) && !errorHolder.hasError()) {
+ if (!writeData(buffer.range(), outputFd)) {
+ errorHolder.setError("Failed to write output");
+ return bytesWritten;
+ }
+ bytesWritten += buffer.size();
+ state.log.update(INFO, "Written: %u MB ",
+ static_cast<std::uint32_t>(bytesWritten >> 20));
+ }
+ }
+ return bytesWritten;
+}
+}
diff --git a/src/zstd/contrib/pzstd/Pzstd.h b/src/zstd/contrib/pzstd/Pzstd.h
new file mode 100644
index 000000000..79d1fcca2
--- /dev/null
+++ b/src/zstd/contrib/pzstd/Pzstd.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include "ErrorHolder.h"
+#include "Logging.h"
+#include "Options.h"
+#include "utils/Buffer.h"
+#include "utils/Range.h"
+#include "utils/ResourcePool.h"
+#include "utils/ThreadPool.h"
+#include "utils/WorkQueue.h"
+#define ZSTD_STATIC_LINKING_ONLY
+#include "zstd.h"
+#undef ZSTD_STATIC_LINKING_ONLY
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+namespace pzstd {
+/**
+ * Runs pzstd with `options` and returns the number of bytes written.
+ * An error occurred if `errorHandler.hasError()`.
+ *
+ * @param options The pzstd options to use for (de)compression
+ * @returns 0 upon success and non-zero on failure.
+ */
+int pzstdMain(const Options& options);
+
+class SharedState {
+ public:
+ SharedState(const Options& options) : log(options.verbosity) {
+ if (!options.decompress) {
+ auto parameters = options.determineParameters();
+ cStreamPool.reset(new ResourcePool<ZSTD_CStream>{
+ [this, parameters]() -> ZSTD_CStream* {
+ this->log(VERBOSE, "%s\n", "Creating new ZSTD_CStream");
+ auto zcs = ZSTD_createCStream();
+ if (zcs) {
+ auto err = ZSTD_initCStream_advanced(
+ zcs, nullptr, 0, parameters, 0);
+ if (ZSTD_isError(err)) {
+ ZSTD_freeCStream(zcs);
+ return nullptr;
+ }
+ }
+ return zcs;
+ },
+ [](ZSTD_CStream *zcs) {
+ ZSTD_freeCStream(zcs);
+ }});
+ } else {
+ dStreamPool.reset(new ResourcePool<ZSTD_DStream>{
+ [this]() -> ZSTD_DStream* {
+ this->log(VERBOSE, "%s\n", "Creating new ZSTD_DStream");
+ auto zds = ZSTD_createDStream();
+ if (zds) {
+ auto err = ZSTD_initDStream(zds);
+ if (ZSTD_isError(err)) {
+ ZSTD_freeDStream(zds);
+ return nullptr;
+ }
+ }
+ return zds;
+ },
+ [](ZSTD_DStream *zds) {
+ ZSTD_freeDStream(zds);
+ }});
+ }
+ }
+
+ ~SharedState() {
+ // The resource pools have references to this, so destroy them first.
+ cStreamPool.reset();
+ dStreamPool.reset();
+ }
+
+ Logger log;
+ ErrorHolder errorHolder;
+ std::unique_ptr<ResourcePool<ZSTD_CStream>> cStreamPool;
+ std::unique_ptr<ResourcePool<ZSTD_DStream>> dStreamPool;
+};
+
+/**
+ * Streams input from `fd`, breaks input up into chunks, and compresses each
+ * chunk independently. Output of each chunk gets streamed to a queue, and
+ * the output queues get put into `chunks` in order.
+ *
+ * @param state The shared state
+ * @param chunks Each compression jobs output queue gets `pushed()` here
+ * as soon as it is available
+ * @param executor The thread pool to run compression jobs in
+ * @param fd The input file descriptor
+ * @param size The size of the input file if known, 0 otherwise
+ * @param numThreads The number of threads in the thread pool
+ * @param parameters The zstd parameters to use for compression
+ * @returns The number of bytes read from the file
+ */
+std::uint64_t asyncCompressChunks(
+ SharedState& state,
+ WorkQueue<std::shared_ptr<BufferWorkQueue>>& chunks,
+ ThreadPool& executor,
+ FILE* fd,
+ std::uintmax_t size,
+ std::size_t numThreads,
+ ZSTD_parameters parameters);
+
+/**
+ * Streams input from `fd`. If pzstd headers are available it breaks the input
+ * up into independent frames. It sends each frame to an independent
+ * decompression job. Output of each frame gets streamed to a queue, and
+ * the output queues get put into `frames` in order.
+ *
+ * @param state The shared state
+ * @param frames Each decompression jobs output queue gets `pushed()` here
+ * as soon as it is available
+ * @param executor The thread pool to run compression jobs in
+ * @param fd The input file descriptor
+ * @returns The number of bytes read from the file
+ */
+std::uint64_t asyncDecompressFrames(
+ SharedState& state,
+ WorkQueue<std::shared_ptr<BufferWorkQueue>>& frames,
+ ThreadPool& executor,
+ FILE* fd);
+
+/**
+ * Streams input in from each queue in `outs` in order, and writes the data to
+ * `outputFd`.
+ *
+ * @param state The shared state
+ * @param outs A queue of output queues, one for each
+ * (de)compression job.
+ * @param outputFd The file descriptor to write to
+ * @param decompress Are we decompressing?
+ * @returns The number of bytes written
+ */
+std::uint64_t writeFile(
+ SharedState& state,
+ WorkQueue<std::shared_ptr<BufferWorkQueue>>& outs,
+ FILE* outputFd,
+ bool decompress);
+}
diff --git a/src/zstd/contrib/pzstd/README.md b/src/zstd/contrib/pzstd/README.md
new file mode 100644
index 000000000..84d945815
--- /dev/null
+++ b/src/zstd/contrib/pzstd/README.md
@@ -0,0 +1,56 @@
+# Parallel Zstandard (PZstandard)
+
+Parallel Zstandard is a Pigz-like tool for Zstandard.
+It provides Zstandard format compatible compression and decompression that is able to utilize multiple cores.
+It breaks the input up into equal sized chunks and compresses each chunk independently into a Zstandard frame.
+It then concatenates the frames together to produce the final compressed output.
+Pzstandard will write a 12 byte header for each frame that is a skippable frame in the Zstandard format, which tells PZstandard the size of the next compressed frame.
+PZstandard supports parallel decompression of files compressed with PZstandard.
+When decompressing files compressed with Zstandard, PZstandard does IO in one thread, and decompression in another.
+
+## Usage
+
+PZstandard supports the same command line interface as Zstandard, but also provides the `-p` option to specify the number of threads.
+Dictionary mode is not currently supported.
+
+Basic usage
+
+ pzstd input-file -o output-file -p num-threads -# # Compression
+ pzstd -d input-file -o output-file -p num-threads # Decompression
+
+PZstandard also supports piping and fifo pipes
+
+ cat input-file | pzstd -p num-threads -# -c > /dev/null
+
+For more options
+
+ pzstd --help
+
+PZstandard tries to pick a smart default number of threads if not specified (displayed in `pzstd --help`).
+If this number is not suitable, during compilation you can define `PZSTD_NUM_THREADS` to the number of threads you prefer.
+
+## Benchmarks
+
+As a reference, PZstandard and Pigz were compared on an Intel Core i7 @ 3.1 GHz, each using 4 threads, with the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia).
+
+Compression Speed vs Ratio with 4 Threads | Decompression Speed with 4 Threads
+------------------------------------------|-----------------------------------
+![Compression Speed vs Ratio](images/Cspeed.png "Compression Speed vs Ratio") | ![Decompression Speed](images/Dspeed.png "Decompression Speed")
+
+The test procedure was to run each of the following commands 2 times for each compression level, and take the minimum time.
+
+ time pzstd -# -p 4 -c silesia.tar > silesia.tar.zst
+ time pzstd -d -p 4 -c silesia.tar.zst > /dev/null
+
+ time pigz -# -p 4 -k -c silesia.tar > silesia.tar.gz
+ time pigz -d -p 4 -k -c silesia.tar.gz > /dev/null
+
+PZstandard was tested using compression levels 1-19, and Pigz was tested using compression levels 1-9.
+Pigz cannot do parallel decompression, it simply does each of reading, decompression, and writing on separate threads.
+
+## Tests
+
+Tests require that you have [gtest](https://github.com/google/googletest) installed.
+Set `GTEST_INC` and `GTEST_LIB` in `Makefile` to specify the location of the gtest headers and libraries.
+Alternatively, run `make googletest`, which will clone googletest and build it.
+Run `make tests && make check` to run tests.
diff --git a/src/zstd/contrib/pzstd/SkippableFrame.cpp b/src/zstd/contrib/pzstd/SkippableFrame.cpp
new file mode 100644
index 000000000..769866dfc
--- /dev/null
+++ b/src/zstd/contrib/pzstd/SkippableFrame.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "SkippableFrame.h"
+#include "mem.h"
+#include "utils/Range.h"
+
+#include <cstdio>
+
+using namespace pzstd;
+
+SkippableFrame::SkippableFrame(std::uint32_t size) : frameSize_(size) {
+ MEM_writeLE32(data_.data(), kSkippableFrameMagicNumber);
+ MEM_writeLE32(data_.data() + 4, kFrameContentsSize);
+ MEM_writeLE32(data_.data() + 8, frameSize_);
+}
+
+/* static */ std::size_t SkippableFrame::tryRead(ByteRange bytes) {
+ if (bytes.size() < SkippableFrame::kSize ||
+ MEM_readLE32(bytes.begin()) != kSkippableFrameMagicNumber ||
+ MEM_readLE32(bytes.begin() + 4) != kFrameContentsSize) {
+ return 0;
+ }
+ return MEM_readLE32(bytes.begin() + 8);
+}
diff --git a/src/zstd/contrib/pzstd/SkippableFrame.h b/src/zstd/contrib/pzstd/SkippableFrame.h
new file mode 100644
index 000000000..60deed040
--- /dev/null
+++ b/src/zstd/contrib/pzstd/SkippableFrame.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include "utils/Range.h"
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+
+namespace pzstd {
+/**
+ * We put a skippable frame before each frame.
+ * It contains a skippable frame magic number, the size of the skippable frame,
+ * and the size of the next frame.
+ * Each skippable frame is exactly 12 bytes in little endian format.
+ * The first 8 bytes are for compatibility with the ZSTD format.
+ * If we have N threads, the output will look like
+ *
+ * [0x184D2A50|4|size1] [frame1 of size size1]
+ * [0x184D2A50|4|size2] [frame2 of size size2]
+ * ...
+ * [0x184D2A50|4|sizeN] [frameN of size sizeN]
+ *
+ * Each sizeX is 4 bytes.
+ *
+ * These skippable frames should allow us to skip through the compressed file
+ * and only load at most N pages.
+ */
+class SkippableFrame {
+ public:
+ static constexpr std::size_t kSize = 12;
+
+ private:
+ std::uint32_t frameSize_;
+ std::array<std::uint8_t, kSize> data_;
+ static constexpr std::uint32_t kSkippableFrameMagicNumber = 0x184D2A50;
+ // Could be improved if the size fits in less bytes
+ static constexpr std::uint32_t kFrameContentsSize = kSize - 8;
+
+ public:
+ // Write the skippable frame to data_ in LE format.
+ explicit SkippableFrame(std::uint32_t size);
+
+ // Read the skippable frame from bytes in LE format.
+ static std::size_t tryRead(ByteRange bytes);
+
+ ByteRange data() const {
+ return {data_.data(), data_.size()};
+ }
+
+ // Size of the next frame.
+ std::size_t frameSize() const {
+ return frameSize_;
+ }
+};
+}
diff --git a/src/zstd/contrib/pzstd/images/Cspeed.png b/src/zstd/contrib/pzstd/images/Cspeed.png
new file mode 100644
index 000000000..aca4f663e
--- /dev/null
+++ b/src/zstd/contrib/pzstd/images/Cspeed.png
Binary files differ
diff --git a/src/zstd/contrib/pzstd/images/Dspeed.png b/src/zstd/contrib/pzstd/images/Dspeed.png
new file mode 100644
index 000000000..e48881bcd
--- /dev/null
+++ b/src/zstd/contrib/pzstd/images/Dspeed.png
Binary files differ
diff --git a/src/zstd/contrib/pzstd/main.cpp b/src/zstd/contrib/pzstd/main.cpp
new file mode 100644
index 000000000..b93f043b1
--- /dev/null
+++ b/src/zstd/contrib/pzstd/main.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "ErrorHolder.h"
+#include "Options.h"
+#include "Pzstd.h"
+
+using namespace pzstd;
+
+int main(int argc, const char** argv) {
+ Options options;
+ switch (options.parse(argc, argv)) {
+ case Options::Status::Failure:
+ return 1;
+ case Options::Status::Message:
+ return 0;
+ default:
+ break;
+ }
+
+ return pzstdMain(options);
+}
diff --git a/src/zstd/contrib/pzstd/test/BUCK b/src/zstd/contrib/pzstd/test/BUCK
new file mode 100644
index 000000000..6d3fdd3c2
--- /dev/null
+++ b/src/zstd/contrib/pzstd/test/BUCK
@@ -0,0 +1,37 @@
+cxx_test(
+ name='options_test',
+ srcs=['OptionsTest.cpp'],
+ deps=['//contrib/pzstd:options'],
+)
+
+cxx_test(
+ name='pzstd_test',
+ srcs=['PzstdTest.cpp'],
+ deps=[
+ ':round_trip',
+ '//contrib/pzstd:libpzstd',
+ '//contrib/pzstd/utils:scope_guard',
+ '//programs:datagen',
+ ],
+)
+
+cxx_binary(
+ name='round_trip_test',
+ srcs=['RoundTripTest.cpp'],
+ deps=[
+ ':round_trip',
+ '//contrib/pzstd/utils:scope_guard',
+ '//programs:datagen',
+ ]
+)
+
+cxx_library(
+ name='round_trip',
+ header_namespace='test',
+ exported_headers=['RoundTrip.h'],
+ deps=[
+ '//contrib/pzstd:libpzstd',
+ '//contrib/pzstd:options',
+ '//contrib/pzstd/utils:scope_guard',
+ ]
+)
diff --git a/src/zstd/contrib/pzstd/test/OptionsTest.cpp b/src/zstd/contrib/pzstd/test/OptionsTest.cpp
new file mode 100644
index 000000000..e60114825
--- /dev/null
+++ b/src/zstd/contrib/pzstd/test/OptionsTest.cpp
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "Options.h"
+
+#include <array>
+#include <gtest/gtest.h>
+
+using namespace pzstd;
+
+namespace pzstd {
+bool operator==(const Options &lhs, const Options &rhs) {
+ return lhs.numThreads == rhs.numThreads &&
+ lhs.maxWindowLog == rhs.maxWindowLog &&
+ lhs.compressionLevel == rhs.compressionLevel &&
+ lhs.decompress == rhs.decompress && lhs.inputFiles == rhs.inputFiles &&
+ lhs.outputFile == rhs.outputFile && lhs.overwrite == rhs.overwrite &&
+ lhs.keepSource == rhs.keepSource && lhs.writeMode == rhs.writeMode &&
+ lhs.checksum == rhs.checksum && lhs.verbosity == rhs.verbosity;
+}
+
+std::ostream &operator<<(std::ostream &out, const Options &opt) {
+ out << "{";
+ {
+ out << "\n\t"
+ << "numThreads: " << opt.numThreads;
+ out << ",\n\t"
+ << "maxWindowLog: " << opt.maxWindowLog;
+ out << ",\n\t"
+ << "compressionLevel: " << opt.compressionLevel;
+ out << ",\n\t"
+ << "decompress: " << opt.decompress;
+ out << ",\n\t"
+ << "inputFiles: {";
+ {
+ bool first = true;
+ for (const auto &file : opt.inputFiles) {
+ if (!first) {
+ out << ",";
+ }
+ first = false;
+ out << "\n\t\t" << file;
+ }
+ }
+ out << "\n\t}";
+ out << ",\n\t"
+ << "outputFile: " << opt.outputFile;
+ out << ",\n\t"
+ << "overwrite: " << opt.overwrite;
+ out << ",\n\t"
+ << "keepSource: " << opt.keepSource;
+ out << ",\n\t"
+ << "writeMode: " << static_cast<int>(opt.writeMode);
+ out << ",\n\t"
+ << "checksum: " << opt.checksum;
+ out << ",\n\t"
+ << "verbosity: " << opt.verbosity;
+ }
+ out << "\n}";
+ return out;
+}
+}
+
+namespace {
+#ifdef _WIN32
+const char nullOutput[] = "nul";
+#else
+const char nullOutput[] = "/dev/null";
+#endif
+
+constexpr auto autoMode = Options::WriteMode::Auto;
+} // anonymous namespace
+
+#define EXPECT_SUCCESS(...) EXPECT_EQ(Options::Status::Success, __VA_ARGS__)
+#define EXPECT_FAILURE(...) EXPECT_EQ(Options::Status::Failure, __VA_ARGS__)
+#define EXPECT_MESSAGE(...) EXPECT_EQ(Options::Status::Message, __VA_ARGS__)
+
+template <typename... Args>
+std::array<const char *, sizeof...(Args) + 1> makeArray(Args... args) {
+ return {{nullptr, args...}};
+}
+
+TEST(Options, ValidInputs) {
+ {
+ Options options;
+ auto args = makeArray("--processes", "5", "-o", "x", "y", "-f");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {5, 23, 3, false, {"y"}, "x",
+ true, true, autoMode, true, 2};
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("-p", "1", "input", "-19");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {1, 23, 19, false, {"input"}, "",
+ false, true, autoMode, true, 2};
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args =
+ makeArray("--ultra", "-22", "-p", "1", "-o", "x", "-d", "x.zst", "-f");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {1, 0, 22, true, {"x.zst"}, "x",
+ true, true, autoMode, true, 2};
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("--processes", "100", "hello.zst", "--decompress",
+ "--force");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {100, 23, 3, true, {"hello.zst"}, "", true,
+ true, autoMode, true, 2};
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-dp", "1", "-c");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {1, 23, 3, true, {"x"}, "-",
+ false, true, autoMode, true, 2};
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-dp", "1", "--stdout");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {1, 23, 3, true, {"x"}, "-",
+ false, true, autoMode, true, 2};
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("-p", "1", "x", "-5", "-fo", "-", "--ultra", "-d");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {1, 0, 5, true, {"x"}, "-",
+ true, true, autoMode, true, 2};
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("silesia.tar", "-o", "silesia.tar.pzstd", "-p", "2");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {2,
+ 23,
+ 3,
+ false,
+ {"silesia.tar"},
+ "silesia.tar.pzstd",
+ false,
+ true,
+ autoMode,
+ true,
+ 2};
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-p", "1");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-p", "1");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ }
+}
+
+TEST(Options, GetOutputFile) {
+ {
+ Options options;
+ auto args = makeArray("x");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ("x.zst", options.getOutputFile(options.inputFiles[0]));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "y", "-o", nullOutput);
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(nullOutput, options.getOutputFile(options.inputFiles[0]));
+ }
+ {
+ Options options;
+ auto args = makeArray("x.zst", "-do", nullOutput);
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(nullOutput, options.getOutputFile(options.inputFiles[0]));
+ }
+ {
+ Options options;
+ auto args = makeArray("x.zst", "-d");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ("x", options.getOutputFile(options.inputFiles[0]));
+ }
+ {
+ Options options;
+ auto args = makeArray("xzst", "-d");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ("", options.getOutputFile(options.inputFiles[0]));
+ }
+ {
+ Options options;
+ auto args = makeArray("xzst", "-doxx");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ("xx", options.getOutputFile(options.inputFiles[0]));
+ }
+}
+
+TEST(Options, MultipleFiles) {
+ {
+ Options options;
+ auto args = makeArray("x", "y", "z");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected;
+ expected.inputFiles = {"x", "y", "z"};
+ expected.verbosity = 1;
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "y", "z", "-o", nullOutput);
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected;
+ expected.inputFiles = {"x", "y", "z"};
+ expected.outputFile = nullOutput;
+ expected.verbosity = 1;
+ EXPECT_EQ(expected, options);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "y", "-o-");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "y", "-o", "file");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("-qqvd12qp4", "-f", "x", "--", "--rm", "-c");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ Options expected = {4, 23, 12, true, {"x", "--rm", "-c"},
+ "", true, true, autoMode, true,
+ 0};
+ EXPECT_EQ(expected, options);
+ }
+}
+
+TEST(Options, NumThreads) {
+ {
+ Options options;
+ auto args = makeArray("x", "-dfo", "-");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-p", "0", "-fo", "-");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("-f", "-p", "-o", "-");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+}
+
+TEST(Options, BadCompressionLevel) {
+ {
+ Options options;
+ auto args = makeArray("x", "-20");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "--ultra", "-23");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "--1"); // negative 1?
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+}
+
+TEST(Options, InvalidOption) {
+ {
+ Options options;
+ auto args = makeArray("x", "-x");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+}
+
+TEST(Options, BadOutputFile) {
+ {
+ Options options;
+ auto args = makeArray("notzst", "-d", "-p", "1");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ("", options.getOutputFile(options.inputFiles.front()));
+ }
+}
+
+TEST(Options, BadOptionsWithArguments) {
+ {
+ Options options;
+ auto args = makeArray("x", "-pf");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-p", "10f");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-p");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-o");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-o");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+}
+
+TEST(Options, KeepSource) {
+ {
+ Options options;
+ auto args = makeArray("x", "--rm", "-k");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(true, options.keepSource);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "--rm", "--keep");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(true, options.keepSource);
+ }
+ {
+ Options options;
+ auto args = makeArray("x");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(true, options.keepSource);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "--rm");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(false, options.keepSource);
+ }
+}
+
+TEST(Options, Verbosity) {
+ {
+ Options options;
+ auto args = makeArray("x");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(2, options.verbosity);
+ }
+ {
+ Options options;
+ auto args = makeArray("--quiet", "-qq", "x");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(-1, options.verbosity);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "y");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(1, options.verbosity);
+ }
+ {
+ Options options;
+ auto args = makeArray("--", "x", "y");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(1, options.verbosity);
+ }
+ {
+ Options options;
+ auto args = makeArray("-qv", "x", "y");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(1, options.verbosity);
+ }
+ {
+ Options options;
+ auto args = makeArray("-v", "x", "y");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(3, options.verbosity);
+ }
+ {
+ Options options;
+ auto args = makeArray("-v", "x");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(3, options.verbosity);
+ }
+}
+
+TEST(Options, TestMode) {
+ {
+ Options options;
+ auto args = makeArray("x", "-t");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(true, options.keepSource);
+ EXPECT_EQ(true, options.decompress);
+ EXPECT_EQ(nullOutput, options.outputFile);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "--test", "--rm", "-ohello");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(true, options.keepSource);
+ EXPECT_EQ(true, options.decompress);
+ EXPECT_EQ(nullOutput, options.outputFile);
+ }
+}
+
+TEST(Options, Checksum) {
+ {
+ Options options;
+ auto args = makeArray("x.zst", "--no-check", "-Cd");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(true, options.checksum);
+ }
+ {
+ Options options;
+ auto args = makeArray("x");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(true, options.checksum);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "--no-check", "--check");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(true, options.checksum);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "--no-check");
+ EXPECT_SUCCESS(options.parse(args.size(), args.data()));
+ EXPECT_EQ(false, options.checksum);
+ }
+}
+
+TEST(Options, InputFiles) {
+ {
+ Options options;
+ auto args = makeArray("-cd");
+ options.parse(args.size(), args.data());
+ EXPECT_EQ(1, options.inputFiles.size());
+ EXPECT_EQ("-", options.inputFiles[0]);
+ EXPECT_EQ("-", options.outputFile);
+ }
+ {
+ Options options;
+ auto args = makeArray();
+ options.parse(args.size(), args.data());
+ EXPECT_EQ(1, options.inputFiles.size());
+ EXPECT_EQ("-", options.inputFiles[0]);
+ EXPECT_EQ("-", options.outputFile);
+ }
+ {
+ Options options;
+ auto args = makeArray("-d");
+ options.parse(args.size(), args.data());
+ EXPECT_EQ(1, options.inputFiles.size());
+ EXPECT_EQ("-", options.inputFiles[0]);
+ EXPECT_EQ("-", options.outputFile);
+ }
+ {
+ Options options;
+ auto args = makeArray("x", "-");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+}
+
+TEST(Options, InvalidOptions) {
+ {
+ Options options;
+ auto args = makeArray("-ibasdf");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("- ");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("-n15");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("-0", "x");
+ EXPECT_FAILURE(options.parse(args.size(), args.data()));
+ }
+}
+
+TEST(Options, Extras) {
+ {
+ Options options;
+ auto args = makeArray("-h");
+ EXPECT_MESSAGE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("-H");
+ EXPECT_MESSAGE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("-V");
+ EXPECT_MESSAGE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("--help");
+ EXPECT_MESSAGE(options.parse(args.size(), args.data()));
+ }
+ {
+ Options options;
+ auto args = makeArray("--version");
+ EXPECT_MESSAGE(options.parse(args.size(), args.data()));
+ }
+}
diff --git a/src/zstd/contrib/pzstd/test/PzstdTest.cpp b/src/zstd/contrib/pzstd/test/PzstdTest.cpp
new file mode 100644
index 000000000..5c7d66310
--- /dev/null
+++ b/src/zstd/contrib/pzstd/test/PzstdTest.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "Pzstd.h"
+extern "C" {
+#include "datagen.h"
+}
+#include "test/RoundTrip.h"
+#include "utils/ScopeGuard.h"
+
+#include <cstddef>
+#include <cstdio>
+#include <gtest/gtest.h>
+#include <memory>
+#include <random>
+
+using namespace std;
+using namespace pzstd;
+
+TEST(Pzstd, SmallSizes) {
+ unsigned seed = std::random_device{}();
+ std::fprintf(stderr, "Pzstd.SmallSizes seed: %u\n", seed);
+ std::mt19937 gen(seed);
+
+ for (unsigned len = 1; len < 256; ++len) {
+ if (len % 16 == 0) {
+ std::fprintf(stderr, "%u / 16\n", len / 16);
+ }
+ std::string inputFile = std::tmpnam(nullptr);
+ auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); });
+ {
+ static uint8_t buf[256];
+ RDG_genBuffer(buf, len, 0.5, 0.0, gen());
+ auto fd = std::fopen(inputFile.c_str(), "wb");
+ auto written = std::fwrite(buf, 1, len, fd);
+ std::fclose(fd);
+ ASSERT_EQ(written, len);
+ }
+ for (unsigned numThreads = 1; numThreads <= 2; ++numThreads) {
+ for (unsigned level = 1; level <= 4; level *= 4) {
+ auto errorGuard = makeScopeGuard([&] {
+ std::fprintf(stderr, "# threads: %u\n", numThreads);
+ std::fprintf(stderr, "compression level: %u\n", level);
+ });
+ Options options;
+ options.overwrite = true;
+ options.inputFiles = {inputFile};
+ options.numThreads = numThreads;
+ options.compressionLevel = level;
+ options.verbosity = 1;
+ ASSERT_TRUE(roundTrip(options));
+ errorGuard.dismiss();
+ }
+ }
+ }
+}
+
+TEST(Pzstd, LargeSizes) {
+ unsigned seed = std::random_device{}();
+ std::fprintf(stderr, "Pzstd.LargeSizes seed: %u\n", seed);
+ std::mt19937 gen(seed);
+
+ for (unsigned len = 1 << 20; len <= (1 << 24); len *= 2) {
+ std::string inputFile = std::tmpnam(nullptr);
+ auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); });
+ {
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[len]);
+ RDG_genBuffer(buf.get(), len, 0.5, 0.0, gen());
+ auto fd = std::fopen(inputFile.c_str(), "wb");
+ auto written = std::fwrite(buf.get(), 1, len, fd);
+ std::fclose(fd);
+ ASSERT_EQ(written, len);
+ }
+ for (unsigned numThreads = 1; numThreads <= 16; numThreads *= 4) {
+ for (unsigned level = 1; level <= 4; level *= 4) {
+ auto errorGuard = makeScopeGuard([&] {
+ std::fprintf(stderr, "# threads: %u\n", numThreads);
+ std::fprintf(stderr, "compression level: %u\n", level);
+ });
+ Options options;
+ options.overwrite = true;
+ options.inputFiles = {inputFile};
+ options.numThreads = std::min(numThreads, options.numThreads);
+ options.compressionLevel = level;
+ options.verbosity = 1;
+ ASSERT_TRUE(roundTrip(options));
+ errorGuard.dismiss();
+ }
+ }
+ }
+}
+
+TEST(Pzstd, DISABLED_ExtremelyLargeSize) {
+ unsigned seed = std::random_device{}();
+ std::fprintf(stderr, "Pzstd.ExtremelyLargeSize seed: %u\n", seed);
+ std::mt19937 gen(seed);
+
+ std::string inputFile = std::tmpnam(nullptr);
+ auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); });
+
+ {
+ // Write 4GB + 64 MB
+ constexpr size_t kLength = 1 << 26;
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[kLength]);
+ auto fd = std::fopen(inputFile.c_str(), "wb");
+ auto closeGuard = makeScopeGuard([&] { std::fclose(fd); });
+ for (size_t i = 0; i < (1 << 6) + 1; ++i) {
+ RDG_genBuffer(buf.get(), kLength, 0.5, 0.0, gen());
+ auto written = std::fwrite(buf.get(), 1, kLength, fd);
+ if (written != kLength) {
+ std::fprintf(stderr, "Failed to write file, skipping test\n");
+ return;
+ }
+ }
+ }
+
+ Options options;
+ options.overwrite = true;
+ options.inputFiles = {inputFile};
+ options.compressionLevel = 1;
+ if (options.numThreads == 0) {
+ options.numThreads = 1;
+ }
+ ASSERT_TRUE(roundTrip(options));
+}
+
+TEST(Pzstd, ExtremelyCompressible) {
+ std::string inputFile = std::tmpnam(nullptr);
+ auto guard = makeScopeGuard([&] { std::remove(inputFile.c_str()); });
+ {
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[10000]);
+ std::memset(buf.get(), 'a', 10000);
+ auto fd = std::fopen(inputFile.c_str(), "wb");
+ auto written = std::fwrite(buf.get(), 1, 10000, fd);
+ std::fclose(fd);
+ ASSERT_EQ(written, 10000);
+ }
+ Options options;
+ options.overwrite = true;
+ options.inputFiles = {inputFile};
+ options.numThreads = 1;
+ options.compressionLevel = 1;
+ ASSERT_TRUE(roundTrip(options));
+}
diff --git a/src/zstd/contrib/pzstd/test/RoundTrip.h b/src/zstd/contrib/pzstd/test/RoundTrip.h
new file mode 100644
index 000000000..c6364ecb4
--- /dev/null
+++ b/src/zstd/contrib/pzstd/test/RoundTrip.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include "Options.h"
+#include "Pzstd.h"
+#include "utils/ScopeGuard.h"
+
+#include <cstdio>
+#include <string>
+#include <cstdint>
+#include <memory>
+
+namespace pzstd {
+
+inline bool check(std::string source, std::string decompressed) {
+ std::unique_ptr<std::uint8_t[]> sBuf(new std::uint8_t[1024]);
+ std::unique_ptr<std::uint8_t[]> dBuf(new std::uint8_t[1024]);
+
+ auto sFd = std::fopen(source.c_str(), "rb");
+ auto dFd = std::fopen(decompressed.c_str(), "rb");
+ auto guard = makeScopeGuard([&] {
+ std::fclose(sFd);
+ std::fclose(dFd);
+ });
+
+ size_t sRead, dRead;
+
+ do {
+ sRead = std::fread(sBuf.get(), 1, 1024, sFd);
+ dRead = std::fread(dBuf.get(), 1, 1024, dFd);
+ if (std::ferror(sFd) || std::ferror(dFd)) {
+ return false;
+ }
+ if (sRead != dRead) {
+ return false;
+ }
+
+ for (size_t i = 0; i < sRead; ++i) {
+ if (sBuf.get()[i] != dBuf.get()[i]) {
+ return false;
+ }
+ }
+ } while (sRead == 1024);
+ if (!std::feof(sFd) || !std::feof(dFd)) {
+ return false;
+ }
+ return true;
+}
+
+inline bool roundTrip(Options& options) {
+ if (options.inputFiles.size() != 1) {
+ return false;
+ }
+ std::string source = options.inputFiles.front();
+ std::string compressedFile = std::tmpnam(nullptr);
+ std::string decompressedFile = std::tmpnam(nullptr);
+ auto guard = makeScopeGuard([&] {
+ std::remove(compressedFile.c_str());
+ std::remove(decompressedFile.c_str());
+ });
+
+ {
+ options.outputFile = compressedFile;
+ options.decompress = false;
+ if (pzstdMain(options) != 0) {
+ return false;
+ }
+ }
+ {
+ options.decompress = true;
+ options.inputFiles.front() = compressedFile;
+ options.outputFile = decompressedFile;
+ if (pzstdMain(options) != 0) {
+ return false;
+ }
+ }
+ return check(source, decompressedFile);
+}
+}
diff --git a/src/zstd/contrib/pzstd/test/RoundTripTest.cpp b/src/zstd/contrib/pzstd/test/RoundTripTest.cpp
new file mode 100644
index 000000000..36af0673a
--- /dev/null
+++ b/src/zstd/contrib/pzstd/test/RoundTripTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+extern "C" {
+#include "datagen.h"
+}
+#include "Options.h"
+#include "test/RoundTrip.h"
+#include "utils/ScopeGuard.h"
+
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <random>
+
+using namespace std;
+using namespace pzstd;
+
+namespace {
+string
+writeData(size_t size, double matchProba, double litProba, unsigned seed) {
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[size]);
+ RDG_genBuffer(buf.get(), size, matchProba, litProba, seed);
+ string file = tmpnam(nullptr);
+ auto fd = std::fopen(file.c_str(), "wb");
+ auto guard = makeScopeGuard([&] { std::fclose(fd); });
+ auto bytesWritten = std::fwrite(buf.get(), 1, size, fd);
+ if (bytesWritten != size) {
+ std::abort();
+ }
+ return file;
+}
+
+template <typename Generator>
+string generateInputFile(Generator& gen) {
+ // Use inputs ranging from 1 Byte to 2^16 Bytes
+ std::uniform_int_distribution<size_t> size{1, 1 << 16};
+ std::uniform_real_distribution<> prob{0, 1};
+ return writeData(size(gen), prob(gen), prob(gen), gen());
+}
+
+template <typename Generator>
+Options generateOptions(Generator& gen, const string& inputFile) {
+ Options options;
+ options.inputFiles = {inputFile};
+ options.overwrite = true;
+
+ std::uniform_int_distribution<unsigned> numThreads{1, 32};
+ std::uniform_int_distribution<unsigned> compressionLevel{1, 10};
+
+ options.numThreads = numThreads(gen);
+ options.compressionLevel = compressionLevel(gen);
+
+ return options;
+}
+}
+
+int main() {
+ std::mt19937 gen(std::random_device{}());
+
+ auto newlineGuard = makeScopeGuard([] { std::fprintf(stderr, "\n"); });
+ for (unsigned i = 0; i < 10000; ++i) {
+ if (i % 100 == 0) {
+ std::fprintf(stderr, "Progress: %u%%\r", i / 100);
+ }
+ auto inputFile = generateInputFile(gen);
+ auto inputGuard = makeScopeGuard([&] { std::remove(inputFile.c_str()); });
+ for (unsigned i = 0; i < 10; ++i) {
+ auto options = generateOptions(gen, inputFile);
+ if (!roundTrip(options)) {
+ std::fprintf(stderr, "numThreads: %u\n", options.numThreads);
+ std::fprintf(stderr, "level: %u\n", options.compressionLevel);
+ std::fprintf(stderr, "decompress? %u\n", (unsigned)options.decompress);
+ std::fprintf(stderr, "file: %s\n", inputFile.c_str());
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/zstd/contrib/pzstd/utils/BUCK b/src/zstd/contrib/pzstd/utils/BUCK
new file mode 100644
index 000000000..e757f4120
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/BUCK
@@ -0,0 +1,75 @@
+cxx_library(
+ name='buffer',
+ visibility=['PUBLIC'],
+ header_namespace='utils',
+ exported_headers=['Buffer.h'],
+ deps=[':range'],
+)
+
+cxx_library(
+ name='file_system',
+ visibility=['PUBLIC'],
+ header_namespace='utils',
+ exported_headers=['FileSystem.h'],
+ deps=[':range'],
+)
+
+cxx_library(
+ name='likely',
+ visibility=['PUBLIC'],
+ header_namespace='utils',
+ exported_headers=['Likely.h'],
+)
+
+cxx_library(
+ name='range',
+ visibility=['PUBLIC'],
+ header_namespace='utils',
+ exported_headers=['Range.h'],
+ deps=[':likely'],
+)
+
+cxx_library(
+ name='resource_pool',
+ visibility=['PUBLIC'],
+ header_namespace='utils',
+ exported_headers=['ResourcePool.h'],
+)
+
+cxx_library(
+ name='scope_guard',
+ visibility=['PUBLIC'],
+ header_namespace='utils',
+ exported_headers=['ScopeGuard.h'],
+)
+
+cxx_library(
+ name='thread_pool',
+ visibility=['PUBLIC'],
+ header_namespace='utils',
+ exported_headers=['ThreadPool.h'],
+ deps=[':work_queue'],
+)
+
+cxx_library(
+ name='work_queue',
+ visibility=['PUBLIC'],
+ header_namespace='utils',
+ exported_headers=['WorkQueue.h'],
+ deps=[':buffer'],
+)
+
+cxx_library(
+ name='utils',
+ visibility=['PUBLIC'],
+ deps=[
+ ':buffer',
+ ':file_system',
+ ':likely',
+ ':range',
+ ':resource_pool',
+ ':scope_guard',
+ ':thread_pool',
+ ':work_queue',
+ ],
+)
diff --git a/src/zstd/contrib/pzstd/utils/Buffer.h b/src/zstd/contrib/pzstd/utils/Buffer.h
new file mode 100644
index 000000000..f69c3b4d9
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/Buffer.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include "utils/Range.h"
+
+#include <array>
+#include <cstddef>
+#include <memory>
+
+namespace pzstd {
+
+/**
+ * A `Buffer` has a pointer to a shared buffer, and a range of the buffer that
+ * it owns.
+ * The idea is that you can allocate one buffer, and write chunks into it
+ * and break off those chunks.
+ * The underlying buffer is reference counted, and will be destroyed when all
+ * `Buffer`s that reference it are destroyed.
+ */
+class Buffer {
+ std::shared_ptr<unsigned char> buffer_;
+ MutableByteRange range_;
+
+ static void delete_buffer(unsigned char* buffer) {
+ delete[] buffer;
+ }
+
+ public:
+ /// Construct an empty buffer that owns no data.
+ explicit Buffer() {}
+
+ /// Construct a `Buffer` that owns a new underlying buffer of size `size`.
+ explicit Buffer(std::size_t size)
+ : buffer_(new unsigned char[size], delete_buffer),
+ range_(buffer_.get(), buffer_.get() + size) {}
+
+ explicit Buffer(std::shared_ptr<unsigned char> buffer, MutableByteRange data)
+ : buffer_(buffer), range_(data) {}
+
+ Buffer(Buffer&&) = default;
+ Buffer& operator=(Buffer&&) & = default;
+
+ /**
+ * Splits the data into two pieces: [begin, begin + n), [begin + n, end).
+ * Their data both points into the same underlying buffer.
+ * Modifies the original `Buffer` to point to only [begin + n, end).
+ *
+ * @param n The offset to split at.
+ * @returns A buffer that owns the data [begin, begin + n).
+ */
+ Buffer splitAt(std::size_t n) {
+ auto firstPiece = range_.subpiece(0, n);
+ range_.advance(n);
+ return Buffer(buffer_, firstPiece);
+ }
+
+ /// Modifies the buffer to point to the range [begin + n, end).
+ void advance(std::size_t n) {
+ range_.advance(n);
+ }
+
+ /// Modifies the buffer to point to the range [begin, end - n).
+ void subtract(std::size_t n) {
+ range_.subtract(n);
+ }
+
+ /// Returns a read only `Range` pointing to the `Buffer`s data.
+ ByteRange range() const {
+ return range_;
+ }
+ /// Returns a mutable `Range` pointing to the `Buffer`s data.
+ MutableByteRange range() {
+ return range_;
+ }
+
+ const unsigned char* data() const {
+ return range_.data();
+ }
+
+ unsigned char* data() {
+ return range_.data();
+ }
+
+ std::size_t size() const {
+ return range_.size();
+ }
+
+ bool empty() const {
+ return range_.empty();
+ }
+};
+}
diff --git a/src/zstd/contrib/pzstd/utils/FileSystem.h b/src/zstd/contrib/pzstd/utils/FileSystem.h
new file mode 100644
index 000000000..3cfbe86e5
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/FileSystem.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include "utils/Range.h"
+
+#include <sys/stat.h>
+#include <cerrno>
+#include <cstdint>
+#include <system_error>
+
+// A small subset of `std::filesystem`.
+// `std::filesystem` should be a drop in replacement.
+// See http://en.cppreference.com/w/cpp/filesystem for documentation.
+
+namespace pzstd {
+
+// using file_status = ... causes gcc to emit a false positive warning
+#if defined(_MSC_VER)
+typedef struct ::_stat64 file_status;
+#else
+typedef struct ::stat file_status;
+#endif
+
+/// http://en.cppreference.com/w/cpp/filesystem/status
+inline file_status status(StringPiece path, std::error_code& ec) noexcept {
+ file_status status;
+#if defined(_MSC_VER)
+ const auto error = ::_stat64(path.data(), &status);
+#else
+ const auto error = ::stat(path.data(), &status);
+#endif
+ if (error) {
+ ec.assign(errno, std::generic_category());
+ } else {
+ ec.clear();
+ }
+ return status;
+}
+
+/// http://en.cppreference.com/w/cpp/filesystem/is_regular_file
+inline bool is_regular_file(file_status status) noexcept {
+#if defined(S_ISREG)
+ return S_ISREG(status.st_mode);
+#elif !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
+ return (status.st_mode & S_IFMT) == S_IFREG;
+#else
+ static_assert(false, "No POSIX stat() support.");
+#endif
+}
+
+/// http://en.cppreference.com/w/cpp/filesystem/is_regular_file
+inline bool is_regular_file(StringPiece path, std::error_code& ec) noexcept {
+ return is_regular_file(status(path, ec));
+}
+
+/// http://en.cppreference.com/w/cpp/filesystem/is_directory
+inline bool is_directory(file_status status) noexcept {
+#if defined(S_ISDIR)
+ return S_ISDIR(status.st_mode);
+#elif !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
+ return (status.st_mode & S_IFMT) == S_IFDIR;
+#else
+ static_assert(false, "NO POSIX stat() support.");
+#endif
+}
+
+/// http://en.cppreference.com/w/cpp/filesystem/is_directory
+inline bool is_directory(StringPiece path, std::error_code& ec) noexcept {
+ return is_directory(status(path, ec));
+}
+
+/// http://en.cppreference.com/w/cpp/filesystem/file_size
+inline std::uintmax_t file_size(
+ StringPiece path,
+ std::error_code& ec) noexcept {
+ auto stat = status(path, ec);
+ if (ec) {
+ return -1;
+ }
+ if (!is_regular_file(stat)) {
+ ec.assign(ENOTSUP, std::generic_category());
+ return -1;
+ }
+ ec.clear();
+ return stat.st_size;
+}
+}
diff --git a/src/zstd/contrib/pzstd/utils/Likely.h b/src/zstd/contrib/pzstd/utils/Likely.h
new file mode 100644
index 000000000..7cea8da27
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/Likely.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/**
+ * Compiler hints to indicate the fast path of an "if" branch: whether
+ * the if condition is likely to be true or false.
+ *
+ * @author Tudor Bosman (tudorb@fb.com)
+ */
+
+#pragma once
+
+#undef LIKELY
+#undef UNLIKELY
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define LIKELY(x) (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+#else
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif
diff --git a/src/zstd/contrib/pzstd/utils/Range.h b/src/zstd/contrib/pzstd/utils/Range.h
new file mode 100644
index 000000000..fedb5d786
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/Range.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/**
+ * A subset of `folly/Range.h`.
+ * All code copied verbatim modulo formatting
+ */
+#pragma once
+
+#include "utils/Likely.h"
+
+#include <cstddef>
+#include <cstring>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+
+namespace pzstd {
+
+namespace detail {
+/*
+ *Use IsCharPointer<T>::type to enable const char* or char*.
+ *Use IsCharPointer<T>::const_type to enable only const char*.
+*/
+template <class T>
+struct IsCharPointer {};
+
+template <>
+struct IsCharPointer<char*> {
+ typedef int type;
+};
+
+template <>
+struct IsCharPointer<const char*> {
+ typedef int const_type;
+ typedef int type;
+};
+
+} // namespace detail
+
+template <typename Iter>
+class Range {
+ Iter b_;
+ Iter e_;
+
+ public:
+ using size_type = std::size_t;
+ using iterator = Iter;
+ using const_iterator = Iter;
+ using value_type = typename std::remove_reference<
+ typename std::iterator_traits<Iter>::reference>::type;
+ using reference = typename std::iterator_traits<Iter>::reference;
+
+ constexpr Range() : b_(), e_() {}
+ constexpr Range(Iter begin, Iter end) : b_(begin), e_(end) {}
+
+ constexpr Range(Iter begin, size_type size) : b_(begin), e_(begin + size) {}
+
+ template <class T = Iter, typename detail::IsCharPointer<T>::type = 0>
+ /* implicit */ Range(Iter str) : b_(str), e_(str + std::strlen(str)) {}
+
+ template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
+ /* implicit */ Range(const std::string& str)
+ : b_(str.data()), e_(b_ + str.size()) {}
+
+ // Allow implicit conversion from Range<From> to Range<To> if From is
+ // implicitly convertible to To.
+ template <
+ class OtherIter,
+ typename std::enable_if<
+ (!std::is_same<Iter, OtherIter>::value &&
+ std::is_convertible<OtherIter, Iter>::value),
+ int>::type = 0>
+ constexpr /* implicit */ Range(const Range<OtherIter>& other)
+ : b_(other.begin()), e_(other.end()) {}
+
+ Range(const Range&) = default;
+ Range(Range&&) = default;
+
+ Range& operator=(const Range&) & = default;
+ Range& operator=(Range&&) & = default;
+
+ constexpr size_type size() const {
+ return e_ - b_;
+ }
+ bool empty() const {
+ return b_ == e_;
+ }
+ Iter data() const {
+ return b_;
+ }
+ Iter begin() const {
+ return b_;
+ }
+ Iter end() const {
+ return e_;
+ }
+
+ void advance(size_type n) {
+ if (UNLIKELY(n > size())) {
+ throw std::out_of_range("index out of range");
+ }
+ b_ += n;
+ }
+
+ void subtract(size_type n) {
+ if (UNLIKELY(n > size())) {
+ throw std::out_of_range("index out of range");
+ }
+ e_ -= n;
+ }
+
+ Range subpiece(size_type first, size_type length = std::string::npos) const {
+ if (UNLIKELY(first > size())) {
+ throw std::out_of_range("index out of range");
+ }
+
+ return Range(b_ + first, std::min(length, size() - first));
+ }
+};
+
+using ByteRange = Range<const unsigned char*>;
+using MutableByteRange = Range<unsigned char*>;
+using StringPiece = Range<const char*>;
+}
diff --git a/src/zstd/contrib/pzstd/utils/ResourcePool.h b/src/zstd/contrib/pzstd/utils/ResourcePool.h
new file mode 100644
index 000000000..8dfcdd765
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/ResourcePool.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include <cassert>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+namespace pzstd {
+
+/**
+ * An unbounded pool of resources.
+ * A `ResourcePool<T>` requires a factory function that takes allocates `T*` and
+ * a free function that frees a `T*`.
+ * Calling `ResourcePool::get()` will give you a new `ResourcePool::UniquePtr`
+ * to a `T`, and when it goes out of scope the resource will be returned to the
+ * pool.
+ * The `ResourcePool<T>` *must* survive longer than any resources it hands out.
+ * Remember that `ResourcePool<T>` hands out mutable `T`s, so make sure to clean
+ * up the resource before or after every use.
+ */
+template <typename T>
+class ResourcePool {
+ public:
+ class Deleter;
+ using Factory = std::function<T*()>;
+ using Free = std::function<void(T*)>;
+ using UniquePtr = std::unique_ptr<T, Deleter>;
+
+ private:
+ std::mutex mutex_;
+ Factory factory_;
+ Free free_;
+ std::vector<T*> resources_;
+ unsigned inUse_;
+
+ public:
+ /**
+ * Creates a `ResourcePool`.
+ *
+ * @param factory The function to use to create new resources.
+ * @param free The function to use to free resources created by `factory`.
+ */
+ ResourcePool(Factory factory, Free free)
+ : factory_(std::move(factory)), free_(std::move(free)), inUse_(0) {}
+
+ /**
+ * @returns A unique pointer to a resource. The resource is null iff
+ * there are no available resources and `factory()` returns null.
+ */
+ UniquePtr get() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!resources_.empty()) {
+ UniquePtr resource{resources_.back(), Deleter{*this}};
+ resources_.pop_back();
+ ++inUse_;
+ return resource;
+ }
+ UniquePtr resource{factory_(), Deleter{*this}};
+ ++inUse_;
+ return resource;
+ }
+
+ ~ResourcePool() noexcept {
+ assert(inUse_ == 0);
+ for (const auto resource : resources_) {
+ free_(resource);
+ }
+ }
+
+ class Deleter {
+ ResourcePool *pool_;
+ public:
+ explicit Deleter(ResourcePool &pool) : pool_(&pool) {}
+
+ void operator() (T *resource) {
+ std::lock_guard<std::mutex> lock(pool_->mutex_);
+ // Make sure we don't put null resources into the pool
+ if (resource) {
+ pool_->resources_.push_back(resource);
+ }
+ assert(pool_->inUse_ > 0);
+ --pool_->inUse_;
+ }
+ };
+};
+
+}
diff --git a/src/zstd/contrib/pzstd/utils/ScopeGuard.h b/src/zstd/contrib/pzstd/utils/ScopeGuard.h
new file mode 100644
index 000000000..31768f43d
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/ScopeGuard.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include <utility>
+
+namespace pzstd {
+
+/**
+ * Dismissable scope guard.
+ * `Function` must be callable and take no parameters.
+ * Unless `dissmiss()` is called, the callable is executed upon destruction of
+ * `ScopeGuard`.
+ *
+ * Example:
+ *
+ * auto guard = makeScopeGuard([&] { cleanup(); });
+ */
+template <typename Function>
+class ScopeGuard {
+ Function function;
+ bool dismissed;
+
+ public:
+ explicit ScopeGuard(Function&& function)
+ : function(std::move(function)), dismissed(false) {}
+
+ void dismiss() {
+ dismissed = true;
+ }
+
+ ~ScopeGuard() noexcept {
+ if (!dismissed) {
+ function();
+ }
+ }
+};
+
+/// Creates a scope guard from `function`.
+template <typename Function>
+ScopeGuard<Function> makeScopeGuard(Function&& function) {
+ return ScopeGuard<Function>(std::forward<Function>(function));
+}
+}
diff --git a/src/zstd/contrib/pzstd/utils/ThreadPool.h b/src/zstd/contrib/pzstd/utils/ThreadPool.h
new file mode 100644
index 000000000..8ece8e0da
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/ThreadPool.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include "utils/WorkQueue.h"
+
+#include <cstddef>
+#include <functional>
+#include <thread>
+#include <vector>
+
+namespace pzstd {
+/// A simple thread pool that pulls tasks off its queue in FIFO order.
+class ThreadPool {
+ std::vector<std::thread> threads_;
+
+ WorkQueue<std::function<void()>> tasks_;
+
+ public:
+ /// Constructs a thread pool with `numThreads` threads.
+ explicit ThreadPool(std::size_t numThreads) {
+ threads_.reserve(numThreads);
+ for (std::size_t i = 0; i < numThreads; ++i) {
+ threads_.emplace_back([this] {
+ std::function<void()> task;
+ while (tasks_.pop(task)) {
+ task();
+ }
+ });
+ }
+ }
+
+ /// Finishes all tasks currently in the queue.
+ ~ThreadPool() {
+ tasks_.finish();
+ for (auto& thread : threads_) {
+ thread.join();
+ }
+ }
+
+ /**
+ * Adds `task` to the queue of tasks to execute. Since `task` is a
+ * `std::function<>`, it cannot be a move only type. So any lambda passed must
+ * not capture move only types (like `std::unique_ptr`).
+ *
+ * @param task The task to execute.
+ */
+ void add(std::function<void()> task) {
+ tasks_.push(std::move(task));
+ }
+};
+}
diff --git a/src/zstd/contrib/pzstd/utils/WorkQueue.h b/src/zstd/contrib/pzstd/utils/WorkQueue.h
new file mode 100644
index 000000000..1d14d922c
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/WorkQueue.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#pragma once
+
+#include "utils/Buffer.h"
+
+#include <atomic>
+#include <cassert>
+#include <cstddef>
+#include <condition_variable>
+#include <cstddef>
+#include <functional>
+#include <mutex>
+#include <queue>
+
+namespace pzstd {
+
+/// Unbounded thread-safe work queue.
+template <typename T>
+class WorkQueue {
+ // Protects all member variable access
+ std::mutex mutex_;
+ std::condition_variable readerCv_;
+ std::condition_variable writerCv_;
+ std::condition_variable finishCv_;
+
+ std::queue<T> queue_;
+ bool done_;
+ std::size_t maxSize_;
+
+ // Must have lock to call this function
+ bool full() const {
+ if (maxSize_ == 0) {
+ return false;
+ }
+ return queue_.size() >= maxSize_;
+ }
+
+ public:
+ /**
+ * Constructs an empty work queue with an optional max size.
+ * If `maxSize == 0` the queue size is unbounded.
+ *
+ * @param maxSize The maximum allowed size of the work queue.
+ */
+ WorkQueue(std::size_t maxSize = 0) : done_(false), maxSize_(maxSize) {}
+
+ /**
+ * Push an item onto the work queue. Notify a single thread that work is
+ * available. If `finish()` has been called, do nothing and return false.
+ * If `push()` returns false, then `item` has not been moved from.
+ *
+ * @param item Item to push onto the queue.
+ * @returns True upon success, false if `finish()` has been called. An
+ * item was pushed iff `push()` returns true.
+ */
+ bool push(T&& item) {
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (full() && !done_) {
+ writerCv_.wait(lock);
+ }
+ if (done_) {
+ return false;
+ }
+ queue_.push(std::move(item));
+ }
+ readerCv_.notify_one();
+ return true;
+ }
+
+ /**
+ * Attempts to pop an item off the work queue. It will block until data is
+ * available or `finish()` has been called.
+ *
+ * @param[out] item If `pop` returns `true`, it contains the popped item.
+ * If `pop` returns `false`, it is unmodified.
+ * @returns True upon success. False if the queue is empty and
+ * `finish()` has been called.
+ */
+ bool pop(T& item) {
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (queue_.empty() && !done_) {
+ readerCv_.wait(lock);
+ }
+ if (queue_.empty()) {
+ assert(done_);
+ return false;
+ }
+ item = std::move(queue_.front());
+ queue_.pop();
+ }
+ writerCv_.notify_one();
+ return true;
+ }
+
+ /**
+ * Sets the maximum queue size. If `maxSize == 0` then it is unbounded.
+ *
+ * @param maxSize The new maximum queue size.
+ */
+ void setMaxSize(std::size_t maxSize) {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ maxSize_ = maxSize;
+ }
+ writerCv_.notify_all();
+ }
+
+ /**
+ * Promise that `push()` won't be called again, so once the queue is empty
+ * there will never any more work.
+ */
+ void finish() {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ assert(!done_);
+ done_ = true;
+ }
+ readerCv_.notify_all();
+ writerCv_.notify_all();
+ finishCv_.notify_all();
+ }
+
+ /// Blocks until `finish()` has been called (but the queue may not be empty).
+ void waitUntilFinished() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (!done_) {
+ finishCv_.wait(lock);
+ }
+ }
+};
+
+/// Work queue for `Buffer`s that knows the total number of bytes in the queue.
+class BufferWorkQueue {
+ WorkQueue<Buffer> queue_;
+ std::atomic<std::size_t> size_;
+
+ public:
+ BufferWorkQueue(std::size_t maxSize = 0) : queue_(maxSize), size_(0) {}
+
+ void push(Buffer buffer) {
+ size_.fetch_add(buffer.size());
+ queue_.push(std::move(buffer));
+ }
+
+ bool pop(Buffer& buffer) {
+ bool result = queue_.pop(buffer);
+ if (result) {
+ size_.fetch_sub(buffer.size());
+ }
+ return result;
+ }
+
+ void setMaxSize(std::size_t maxSize) {
+ queue_.setMaxSize(maxSize);
+ }
+
+ void finish() {
+ queue_.finish();
+ }
+
+ /**
+ * Blocks until `finish()` has been called.
+ *
+ * @returns The total number of bytes of all the `Buffer`s currently in the
+ * queue.
+ */
+ std::size_t size() {
+ queue_.waitUntilFinished();
+ return size_.load();
+ }
+};
+}
diff --git a/src/zstd/contrib/pzstd/utils/test/BUCK b/src/zstd/contrib/pzstd/utils/test/BUCK
new file mode 100644
index 000000000..a5113cab6
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/test/BUCK
@@ -0,0 +1,35 @@
+cxx_test(
+ name='buffer_test',
+ srcs=['BufferTest.cpp'],
+ deps=['//contrib/pzstd/utils:buffer'],
+)
+
+cxx_test(
+ name='range_test',
+ srcs=['RangeTest.cpp'],
+ deps=['//contrib/pzstd/utils:range'],
+)
+
+cxx_test(
+ name='resource_pool_test',
+ srcs=['ResourcePoolTest.cpp'],
+ deps=['//contrib/pzstd/utils:resource_pool'],
+)
+
+cxx_test(
+ name='scope_guard_test',
+ srcs=['ScopeGuardTest.cpp'],
+ deps=['//contrib/pzstd/utils:scope_guard'],
+)
+
+cxx_test(
+ name='thread_pool_test',
+ srcs=['ThreadPoolTest.cpp'],
+ deps=['//contrib/pzstd/utils:thread_pool'],
+)
+
+cxx_test(
+ name='work_queue_test',
+ srcs=['RangeTest.cpp'],
+ deps=['//contrib/pzstd/utils:work_queue'],
+)
diff --git a/src/zstd/contrib/pzstd/utils/test/BufferTest.cpp b/src/zstd/contrib/pzstd/utils/test/BufferTest.cpp
new file mode 100644
index 000000000..fbba74e82
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/test/BufferTest.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "utils/Buffer.h"
+#include "utils/Range.h"
+
+#include <gtest/gtest.h>
+#include <memory>
+
+using namespace pzstd;
+
+namespace {
+void deleter(const unsigned char* buf) {
+ delete[] buf;
+}
+}
+
+TEST(Buffer, Constructors) {
+ Buffer empty;
+ EXPECT_TRUE(empty.empty());
+ EXPECT_EQ(0, empty.size());
+
+ Buffer sized(5);
+ EXPECT_FALSE(sized.empty());
+ EXPECT_EQ(5, sized.size());
+
+ Buffer moved(std::move(sized));
+ EXPECT_FALSE(sized.empty());
+ EXPECT_EQ(5, sized.size());
+
+ Buffer assigned;
+ assigned = std::move(moved);
+ EXPECT_FALSE(sized.empty());
+ EXPECT_EQ(5, sized.size());
+}
+
+TEST(Buffer, BufferManagement) {
+ std::shared_ptr<unsigned char> buf(new unsigned char[10], deleter);
+ {
+ Buffer acquired(buf, MutableByteRange(buf.get(), buf.get() + 10));
+ EXPECT_EQ(2, buf.use_count());
+ Buffer moved(std::move(acquired));
+ EXPECT_EQ(2, buf.use_count());
+ Buffer assigned;
+ assigned = std::move(moved);
+ EXPECT_EQ(2, buf.use_count());
+
+ Buffer split = assigned.splitAt(5);
+ EXPECT_EQ(3, buf.use_count());
+
+ split.advance(1);
+ assigned.subtract(1);
+ EXPECT_EQ(3, buf.use_count());
+ }
+ EXPECT_EQ(1, buf.use_count());
+}
+
+TEST(Buffer, Modifiers) {
+ Buffer buf(10);
+ {
+ unsigned char i = 0;
+ for (auto& byte : buf.range()) {
+ byte = i++;
+ }
+ }
+
+ auto prefix = buf.splitAt(2);
+
+ ASSERT_EQ(2, prefix.size());
+ EXPECT_EQ(0, *prefix.data());
+
+ ASSERT_EQ(8, buf.size());
+ EXPECT_EQ(2, *buf.data());
+
+ buf.advance(2);
+ EXPECT_EQ(4, *buf.data());
+
+ EXPECT_EQ(9, *(buf.range().end() - 1));
+
+ buf.subtract(2);
+ EXPECT_EQ(7, *(buf.range().end() - 1));
+
+ EXPECT_EQ(4, buf.size());
+}
diff --git a/src/zstd/contrib/pzstd/utils/test/RangeTest.cpp b/src/zstd/contrib/pzstd/utils/test/RangeTest.cpp
new file mode 100644
index 000000000..755b50fa6
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/test/RangeTest.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "utils/Range.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+using namespace pzstd;
+
+// Range is directly copied from folly.
+// Just some sanity tests to make sure everything seems to work.
+
+TEST(Range, Constructors) {
+ StringPiece empty;
+ EXPECT_TRUE(empty.empty());
+ EXPECT_EQ(0, empty.size());
+
+ std::string str = "hello";
+ {
+ Range<std::string::const_iterator> piece(str.begin(), str.end());
+ EXPECT_EQ(5, piece.size());
+ EXPECT_EQ('h', *piece.data());
+ EXPECT_EQ('o', *(piece.end() - 1));
+ }
+
+ {
+ StringPiece piece(str.data(), str.size());
+ EXPECT_EQ(5, piece.size());
+ EXPECT_EQ('h', *piece.data());
+ EXPECT_EQ('o', *(piece.end() - 1));
+ }
+
+ {
+ StringPiece piece(str);
+ EXPECT_EQ(5, piece.size());
+ EXPECT_EQ('h', *piece.data());
+ EXPECT_EQ('o', *(piece.end() - 1));
+ }
+
+ {
+ StringPiece piece(str.c_str());
+ EXPECT_EQ(5, piece.size());
+ EXPECT_EQ('h', *piece.data());
+ EXPECT_EQ('o', *(piece.end() - 1));
+ }
+}
+
+TEST(Range, Modifiers) {
+ StringPiece range("hello world");
+ ASSERT_EQ(11, range.size());
+
+ {
+ auto hello = range.subpiece(0, 5);
+ EXPECT_EQ(5, hello.size());
+ EXPECT_EQ('h', *hello.data());
+ EXPECT_EQ('o', *(hello.end() - 1));
+ }
+ {
+ auto hello = range;
+ hello.subtract(6);
+ EXPECT_EQ(5, hello.size());
+ EXPECT_EQ('h', *hello.data());
+ EXPECT_EQ('o', *(hello.end() - 1));
+ }
+ {
+ auto world = range;
+ world.advance(6);
+ EXPECT_EQ(5, world.size());
+ EXPECT_EQ('w', *world.data());
+ EXPECT_EQ('d', *(world.end() - 1));
+ }
+
+ std::string expected = "hello world";
+ EXPECT_EQ(expected, std::string(range.begin(), range.end()));
+ EXPECT_EQ(expected, std::string(range.data(), range.size()));
+}
diff --git a/src/zstd/contrib/pzstd/utils/test/ResourcePoolTest.cpp b/src/zstd/contrib/pzstd/utils/test/ResourcePoolTest.cpp
new file mode 100644
index 000000000..6fe145180
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/test/ResourcePoolTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "utils/ResourcePool.h"
+
+#include <gtest/gtest.h>
+#include <atomic>
+#include <thread>
+
+using namespace pzstd;
+
+TEST(ResourcePool, FullTest) {
+ unsigned numCreated = 0;
+ unsigned numDeleted = 0;
+ {
+ ResourcePool<int> pool(
+ [&numCreated] { ++numCreated; return new int{5}; },
+ [&numDeleted](int *x) { ++numDeleted; delete x; });
+
+ {
+ auto i = pool.get();
+ EXPECT_EQ(5, *i);
+ *i = 6;
+ }
+ {
+ auto i = pool.get();
+ EXPECT_EQ(6, *i);
+ auto j = pool.get();
+ EXPECT_EQ(5, *j);
+ *j = 7;
+ }
+ {
+ auto i = pool.get();
+ EXPECT_EQ(6, *i);
+ auto j = pool.get();
+ EXPECT_EQ(7, *j);
+ }
+ }
+ EXPECT_EQ(2, numCreated);
+ EXPECT_EQ(numCreated, numDeleted);
+}
+
+TEST(ResourcePool, ThreadSafe) {
+ std::atomic<unsigned> numCreated{0};
+ std::atomic<unsigned> numDeleted{0};
+ {
+ ResourcePool<int> pool(
+ [&numCreated] { ++numCreated; return new int{0}; },
+ [&numDeleted](int *x) { ++numDeleted; delete x; });
+ auto push = [&pool] {
+ for (int i = 0; i < 100; ++i) {
+ auto x = pool.get();
+ ++*x;
+ }
+ };
+ std::thread t1{push};
+ std::thread t2{push};
+ t1.join();
+ t2.join();
+
+ auto x = pool.get();
+ auto y = pool.get();
+ EXPECT_EQ(200, *x + *y);
+ }
+ EXPECT_GE(2, numCreated);
+ EXPECT_EQ(numCreated, numDeleted);
+}
diff --git a/src/zstd/contrib/pzstd/utils/test/ScopeGuardTest.cpp b/src/zstd/contrib/pzstd/utils/test/ScopeGuardTest.cpp
new file mode 100644
index 000000000..7bc624da7
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/test/ScopeGuardTest.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "utils/ScopeGuard.h"
+
+#include <gtest/gtest.h>
+
+using namespace pzstd;
+
+TEST(ScopeGuard, Dismiss) {
+ {
+ auto guard = makeScopeGuard([&] { EXPECT_TRUE(false); });
+ guard.dismiss();
+ }
+}
+
+TEST(ScopeGuard, Executes) {
+ bool executed = false;
+ {
+ auto guard = makeScopeGuard([&] { executed = true; });
+ }
+ EXPECT_TRUE(executed);
+}
diff --git a/src/zstd/contrib/pzstd/utils/test/ThreadPoolTest.cpp b/src/zstd/contrib/pzstd/utils/test/ThreadPoolTest.cpp
new file mode 100644
index 000000000..703fd4c9c
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/test/ThreadPoolTest.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "utils/ThreadPool.h"
+
+#include <gtest/gtest.h>
+#include <atomic>
+#include <iostream>
+#include <thread>
+#include <vector>
+
+using namespace pzstd;
+
+TEST(ThreadPool, Ordering) {
+ std::vector<int> results;
+
+ {
+ ThreadPool executor(1);
+ for (int i = 0; i < 10; ++i) {
+ executor.add([ &results, i ] { results.push_back(i); });
+ }
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(i, results[i]);
+ }
+}
+
+TEST(ThreadPool, AllJobsFinished) {
+ std::atomic<unsigned> numFinished{0};
+ std::atomic<bool> start{false};
+ {
+ std::cerr << "Creating executor" << std::endl;
+ ThreadPool executor(5);
+ for (int i = 0; i < 10; ++i) {
+ executor.add([ &numFinished, &start ] {
+ while (!start.load()) {
+ std::this_thread::yield();
+ }
+ ++numFinished;
+ });
+ }
+ std::cerr << "Starting" << std::endl;
+ start.store(true);
+ std::cerr << "Finishing" << std::endl;
+ }
+ EXPECT_EQ(10, numFinished.load());
+}
+
+TEST(ThreadPool, AddJobWhileJoining) {
+ std::atomic<bool> done{false};
+ {
+ ThreadPool executor(1);
+ executor.add([&executor, &done] {
+ while (!done.load()) {
+ std::this_thread::yield();
+ }
+ // Sleep for a second to be sure that we are joining
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ executor.add([] {
+ EXPECT_TRUE(false);
+ });
+ });
+ done.store(true);
+ }
+}
diff --git a/src/zstd/contrib/pzstd/utils/test/WorkQueueTest.cpp b/src/zstd/contrib/pzstd/utils/test/WorkQueueTest.cpp
new file mode 100644
index 000000000..14cf77304
--- /dev/null
+++ b/src/zstd/contrib/pzstd/utils/test/WorkQueueTest.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+#include "utils/Buffer.h"
+#include "utils/WorkQueue.h"
+
+#include <gtest/gtest.h>
+#include <iostream>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+using namespace pzstd;
+
+namespace {
+struct Popper {
+ WorkQueue<int>* queue;
+ int* results;
+ std::mutex* mutex;
+
+ void operator()() {
+ int result;
+ while (queue->pop(result)) {
+ std::lock_guard<std::mutex> lock(*mutex);
+ results[result] = result;
+ }
+ }
+};
+}
+
+TEST(WorkQueue, SingleThreaded) {
+ WorkQueue<int> queue;
+ int result;
+
+ queue.push(5);
+ EXPECT_TRUE(queue.pop(result));
+ EXPECT_EQ(5, result);
+
+ queue.push(1);
+ queue.push(2);
+ EXPECT_TRUE(queue.pop(result));
+ EXPECT_EQ(1, result);
+ EXPECT_TRUE(queue.pop(result));
+ EXPECT_EQ(2, result);
+
+ queue.push(1);
+ queue.push(2);
+ queue.finish();
+ EXPECT_TRUE(queue.pop(result));
+ EXPECT_EQ(1, result);
+ EXPECT_TRUE(queue.pop(result));
+ EXPECT_EQ(2, result);
+ EXPECT_FALSE(queue.pop(result));
+
+ queue.waitUntilFinished();
+}
+
+TEST(WorkQueue, SPSC) {
+ WorkQueue<int> queue;
+ const int max = 100;
+
+ for (int i = 0; i < 10; ++i) {
+ queue.push(int{i});
+ }
+
+ std::thread thread([ &queue, max ] {
+ int result;
+ for (int i = 0;; ++i) {
+ if (!queue.pop(result)) {
+ EXPECT_EQ(i, max);
+ break;
+ }
+ EXPECT_EQ(i, result);
+ }
+ });
+
+ std::this_thread::yield();
+ for (int i = 10; i < max; ++i) {
+ queue.push(int{i});
+ }
+ queue.finish();
+
+ thread.join();
+}
+
+TEST(WorkQueue, SPMC) {
+ WorkQueue<int> queue;
+ std::vector<int> results(50, -1);
+ std::mutex mutex;
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 5; ++i) {
+ threads.emplace_back(Popper{&queue, results.data(), &mutex});
+ }
+
+ for (int i = 0; i < 50; ++i) {
+ queue.push(int{i});
+ }
+ queue.finish();
+
+ for (auto& thread : threads) {
+ thread.join();
+ }
+
+ for (int i = 0; i < 50; ++i) {
+ EXPECT_EQ(i, results[i]);
+ }
+}
+
+TEST(WorkQueue, MPMC) {
+ WorkQueue<int> queue;
+ std::vector<int> results(100, -1);
+ std::mutex mutex;
+ std::vector<std::thread> popperThreads;
+ for (int i = 0; i < 4; ++i) {
+ popperThreads.emplace_back(Popper{&queue, results.data(), &mutex});
+ }
+
+ std::vector<std::thread> pusherThreads;
+ for (int i = 0; i < 2; ++i) {
+ auto min = i * 50;
+ auto max = (i + 1) * 50;
+ pusherThreads.emplace_back(
+ [ &queue, min, max ] {
+ for (int i = min; i < max; ++i) {
+ queue.push(int{i});
+ }
+ });
+ }
+
+ for (auto& thread : pusherThreads) {
+ thread.join();
+ }
+ queue.finish();
+
+ for (auto& thread : popperThreads) {
+ thread.join();
+ }
+
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_EQ(i, results[i]);
+ }
+}
+
+TEST(WorkQueue, BoundedSizeWorks) {
+ WorkQueue<int> queue(1);
+ int result;
+ queue.push(5);
+ queue.pop(result);
+ queue.push(5);
+ queue.pop(result);
+ queue.push(5);
+ queue.finish();
+ queue.pop(result);
+ EXPECT_EQ(5, result);
+}
+
+TEST(WorkQueue, BoundedSizePushAfterFinish) {
+ WorkQueue<int> queue(1);
+ int result;
+ queue.push(5);
+ std::thread pusher([&queue] {
+ queue.push(6);
+ });
+ // Dirtily try and make sure that pusher has run.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ queue.finish();
+ EXPECT_TRUE(queue.pop(result));
+ EXPECT_EQ(5, result);
+ EXPECT_FALSE(queue.pop(result));
+
+ pusher.join();
+}
+
+TEST(WorkQueue, SetMaxSize) {
+ WorkQueue<int> queue(2);
+ int result;
+ queue.push(5);
+ queue.push(6);
+ queue.setMaxSize(1);
+ std::thread pusher([&queue] {
+ queue.push(7);
+ });
+ // Dirtily try and make sure that pusher has run.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ queue.finish();
+ EXPECT_TRUE(queue.pop(result));
+ EXPECT_EQ(5, result);
+ EXPECT_TRUE(queue.pop(result));
+ EXPECT_EQ(6, result);
+ EXPECT_FALSE(queue.pop(result));
+
+ pusher.join();
+}
+
+TEST(WorkQueue, BoundedSizeMPMC) {
+ WorkQueue<int> queue(10);
+ std::vector<int> results(200, -1);
+ std::mutex mutex;
+ std::cerr << "Creating popperThreads" << std::endl;
+ std::vector<std::thread> popperThreads;
+ for (int i = 0; i < 4; ++i) {
+ popperThreads.emplace_back(Popper{&queue, results.data(), &mutex});
+ }
+
+ std::cerr << "Creating pusherThreads" << std::endl;
+ std::vector<std::thread> pusherThreads;
+ for (int i = 0; i < 2; ++i) {
+ auto min = i * 100;
+ auto max = (i + 1) * 100;
+ pusherThreads.emplace_back(
+ [ &queue, min, max ] {
+ for (int i = min; i < max; ++i) {
+ queue.push(int{i});
+ }
+ });
+ }
+
+ std::cerr << "Joining pusherThreads" << std::endl;
+ for (auto& thread : pusherThreads) {
+ thread.join();
+ }
+ std::cerr << "Finishing queue" << std::endl;
+ queue.finish();
+
+ std::cerr << "Joining popperThreads" << std::endl;
+ for (auto& thread : popperThreads) {
+ thread.join();
+ }
+
+ std::cerr << "Inspecting results" << std::endl;
+ for (int i = 0; i < 200; ++i) {
+ EXPECT_EQ(i, results[i]);
+ }
+}
+
+TEST(WorkQueue, FailedPush) {
+ WorkQueue<std::unique_ptr<int>> queue;
+ std::unique_ptr<int> x(new int{5});
+ EXPECT_TRUE(queue.push(std::move(x)));
+ EXPECT_EQ(nullptr, x);
+ queue.finish();
+ x.reset(new int{6});
+ EXPECT_FALSE(queue.push(std::move(x)));
+ EXPECT_NE(nullptr, x);
+ EXPECT_EQ(6, *x);
+}
+
+TEST(BufferWorkQueue, SizeCalculatedCorrectly) {
+ {
+ BufferWorkQueue queue;
+ queue.finish();
+ EXPECT_EQ(0, queue.size());
+ }
+ {
+ BufferWorkQueue queue;
+ queue.push(Buffer(10));
+ queue.finish();
+ EXPECT_EQ(10, queue.size());
+ }
+ {
+ BufferWorkQueue queue;
+ queue.push(Buffer(10));
+ queue.push(Buffer(5));
+ queue.finish();
+ EXPECT_EQ(15, queue.size());
+ }
+ {
+ BufferWorkQueue queue;
+ queue.push(Buffer(10));
+ queue.push(Buffer(5));
+ queue.finish();
+ Buffer buffer;
+ queue.pop(buffer);
+ EXPECT_EQ(5, queue.size());
+ }
+}
diff --git a/src/zstd/contrib/seekable_format/examples/.gitignore b/src/zstd/contrib/seekable_format/examples/.gitignore
new file mode 100644
index 000000000..0b83f5e11
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/examples/.gitignore
@@ -0,0 +1,5 @@
+seekable_compression
+seekable_decompression
+seekable_decompression_mem
+parallel_processing
+parallel_compression
diff --git a/src/zstd/contrib/seekable_format/examples/Makefile b/src/zstd/contrib/seekable_format/examples/Makefile
new file mode 100644
index 000000000..543780f75
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/examples/Makefile
@@ -0,0 +1,53 @@
+# ################################################################
+# Copyright (c) 2017-present, Facebook, Inc.
+# All rights reserved.
+#
+# This source code is licensed under both the BSD-style license (found in the
+# LICENSE file in the root directory of this source tree) and the GPLv2 (found
+# in the COPYING file in the root directory of this source tree).
+# ################################################################
+
+# This Makefile presumes libzstd is built, using `make` in / or /lib/
+
+ZSTDLIB_PATH = ../../../lib
+ZSTDLIB_NAME = libzstd.a
+ZSTDLIB = $(ZSTDLIB_PATH)/$(ZSTDLIB_NAME)
+
+CPPFLAGS += -I../ -I../../../lib -I../../../lib/common
+
+CFLAGS ?= -O3
+CFLAGS += -g
+
+SEEKABLE_OBJS = ../zstdseek_compress.c ../zstdseek_decompress.c $(ZSTDLIB)
+
+.PHONY: default all clean test
+
+default: all
+
+all: seekable_compression seekable_decompression seekable_decompression_mem \
+ parallel_processing
+
+$(ZSTDLIB):
+ make -C $(ZSTDLIB_PATH) $(ZSTDLIB_NAME)
+
+seekable_compression : seekable_compression.c $(SEEKABLE_OBJS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+seekable_decompression : seekable_decompression.c $(SEEKABLE_OBJS)
+ $(CC) $(CPPFLAGS) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+seekable_decompression_mem : seekable_decompression_mem.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 \
+ seekable_decompression_mem \
+ parallel_processing parallel_compression
+ @echo Cleaning completed
diff --git a/src/zstd/contrib/seekable_format/examples/parallel_compression.c b/src/zstd/contrib/seekable_format/examples/parallel_compression.c
new file mode 100644
index 000000000..69644d2b3
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/examples/parallel_compression.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+#include <stdlib.h> // malloc, free, exit, atoi
+#include <stdio.h> // fprintf, perror, feof, fopen, etc.
+#include <string.h> // strlen, memset, strcat
+#define ZSTD_STATIC_LINKING_ONLY
+#include <zstd.h> // presumes zstd library is installed
+#include <zstd_errors.h>
+#if defined(WIN32) || defined(_WIN32)
+# include <windows.h>
+# define SLEEP(x) Sleep(x)
+#else
+# include <unistd.h>
+# 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/src/zstd/contrib/seekable_format/examples/parallel_processing.c b/src/zstd/contrib/seekable_format/examples/parallel_processing.c
new file mode 100644
index 000000000..36226b49f
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/examples/parallel_processing.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/*
+ * A simple demo that sums up all the bytes in the file in parallel using
+ * seekable decompression and the zstd thread pool
+ */
+
+#include <stdlib.h> // malloc, exit
+#include <stdio.h> // fprintf, perror, feof
+#include <string.h> // strerror
+#include <errno.h> // errno
+#define ZSTD_STATIC_LINKING_ONLY
+#include <zstd.h> // presumes zstd library is installed
+#include <zstd_errors.h>
+#if defined(WIN32) || defined(_WIN32)
+# include <windows.h>
+# define SLEEP(x) Sleep(x)
+#else
+# include <unistd.h>
+# 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); }
+
+ unsigned const numFrames = ZSTD_seekable_getNumFrames(seekable);
+ struct sum_job* jobs = (struct sum_job*)malloc(numFrames * sizeof(struct sum_job));
+
+ unsigned fnb;
+ for (fnb = 0; fnb < numFrames; fnb++) {
+ jobs[fnb] = (struct sum_job){ fname, 0, fnb, 0 };
+ POOL_add(pool, sumFrame, &jobs[fnb]);
+ }
+
+ unsigned long long total = 0;
+
+ for (fnb = 0; fnb < numFrames; fnb++) {
+ while (!jobs[fnb].done) SLEEP(5); /* wake up every 5 milliseconds to check */
+ total += jobs[fnb].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/src/zstd/contrib/seekable_format/examples/seekable_compression.c b/src/zstd/contrib/seekable_format/examples/seekable_compression.c
new file mode 100644
index 000000000..9a331a895
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/examples/seekable_compression.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+#include <stdlib.h> // malloc, free, exit, atoi
+#include <stdio.h> // fprintf, perror, feof, fopen, etc.
+#include <string.h> // strlen, memset, strcat
+#define ZSTD_STATIC_LINKING_ONLY
+#include <zstd.h> // presumes zstd library is installed
+
+#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 compressFile_orDie(const char* fname, const char* outName, int cLevel, unsigned frameSize)
+{
+ FILE* const fin = fopen_orDie(fname, "rb");
+ FILE* const fout = fopen_orDie(outName, "wb");
+ size_t const buffInSize = ZSTD_CStreamInSize(); /* can always read one full block */
+ void* const buffIn = malloc_orDie(buffInSize);
+ size_t const buffOutSize = ZSTD_CStreamOutSize(); /* can always flush a full block */
+ void* const buffOut = malloc_orDie(buffOutSize);
+
+ ZSTD_seekable_CStream* const cstream = ZSTD_seekable_createCStream();
+ if (cstream==NULL) { fprintf(stderr, "ZSTD_seekable_createCStream() error \n"); exit(10); }
+ size_t const initResult = ZSTD_seekable_initCStream(cstream, cLevel, 1, frameSize);
+ if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_seekable_initCStream() error : %s \n", ZSTD_getErrorName(initResult)); exit(11); }
+
+ size_t read, toRead = buffInSize;
+ while( (read = fread_orDie(buffIn, toRead, fin)) ) {
+ ZSTD_inBuffer input = { buffIn, read, 0 };
+ while (input.pos < input.size) {
+ ZSTD_outBuffer output = { buffOut, buffOutSize, 0 };
+ toRead = ZSTD_seekable_compressStream(cstream, &output , &input); /* toRead is guaranteed to be <= ZSTD_CStreamInSize() */
+ if (ZSTD_isError(toRead)) { fprintf(stderr, "ZSTD_seekable_compressStream() error : %s \n", ZSTD_getErrorName(toRead)); exit(12); }
+ if (toRead > buffInSize) toRead = buffInSize; /* Safely handle case when `buffInSize` is manually changed to a value < ZSTD_CStreamInSize()*/
+ fwrite_orDie(buffOut, output.pos, fout);
+ }
+ }
+
+ while (1) {
+ ZSTD_outBuffer output = { buffOut, buffOutSize, 0 };
+ size_t const remainingToFlush = ZSTD_seekable_endStream(cstream, &output); /* close stream */
+ if (ZSTD_isError(remainingToFlush)) { fprintf(stderr, "ZSTD_seekable_endStream() error : %s \n", ZSTD_getErrorName(remainingToFlush)); exit(13); }
+ fwrite_orDie(buffOut, output.pos, fout);
+ if (!remainingToFlush) break;
+ }
+
+ ZSTD_seekable_freeCStream(cstream);
+ fclose_orDie(fout);
+ fclose_orDie(fin);
+ free(buffIn);
+ free(buffOut);
+}
+
+static 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 (char*)outSpace;
+}
+
+int main(int argc, const char** argv) {
+ const char* const exeName = argv[0];
+ if (argc!=3) {
+ printf("wrong arguments\n");
+ printf("usage:\n");
+ printf("%s FILE FRAME_SIZE\n", exeName);
+ return 1;
+ }
+
+ { const char* const inFileName = argv[1];
+ unsigned const frameSize = (unsigned)atoi(argv[2]);
+
+ char* const outFileName = createOutFilename_orDie(inFileName);
+ compressFile_orDie(inFileName, outFileName, 5, frameSize);
+ free(outFileName);
+ }
+
+ return 0;
+}
diff --git a/src/zstd/contrib/seekable_format/examples/seekable_decompression.c b/src/zstd/contrib/seekable_format/examples/seekable_decompression.c
new file mode 100644
index 000000000..7050e0fa5
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/examples/seekable_decompression.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+
+#include <stdlib.h> // malloc, exit
+#include <stdio.h> // fprintf, perror, feof
+#include <string.h> // strerror
+#include <errno.h> // errno
+#define ZSTD_STATIC_LINKING_ONLY
+#include <zstd.h> // presumes zstd library is installed
+#include <zstd_errors.h>
+
+#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);
+}
+
+
+static void decompressFile_orDie(const char* fname, off_t startOffset, off_t endOffset)
+{
+ FILE* const fin = fopen_orDie(fname, "rb");
+ FILE* const fout = stdout;
+ size_t const buffOutSize = ZSTD_DStreamOutSize(); /* Guarantee to successfully flush at least one complete compressed block in all circumstances. */
+ void* const buffOut = malloc_orDie(buffOutSize);
+
+ 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); }
+
+ while (startOffset < endOffset) {
+ size_t const result = ZSTD_seekable_decompress(seekable, buffOut, MIN(endOffset - startOffset, buffOutSize), startOffset);
+
+ if (ZSTD_isError(result)) {
+ fprintf(stderr, "ZSTD_seekable_decompress() error : %s \n",
+ ZSTD_getErrorName(result));
+ exit(12);
+ }
+ fwrite_orDie(buffOut, result, fout);
+ startOffset += result;
+ }
+
+ ZSTD_seekable_free(seekable);
+ fclose_orDie(fin);
+ fclose_orDie(fout);
+ free(buffOut);
+}
+
+
+int main(int argc, const char** argv)
+{
+ const char* const exeName = argv[0];
+
+ if (argc!=4) {
+ fprintf(stderr, "wrong arguments\n");
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "%s FILE START END\n", exeName);
+ return 1;
+ }
+
+ {
+ const char* const inFilename = argv[1];
+ off_t const startOffset = atoll(argv[2]);
+ off_t const endOffset = atoll(argv[3]);
+ decompressFile_orDie(inFilename, startOffset, endOffset);
+ }
+
+ return 0;
+}
diff --git a/src/zstd/contrib/seekable_format/examples/seekable_decompression_mem.c b/src/zstd/contrib/seekable_format/examples/seekable_decompression_mem.c
new file mode 100644
index 000000000..c36d2221f
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/examples/seekable_decompression_mem.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+
+#include <stdlib.h> // malloc, exit
+#include <stdio.h> // fprintf, perror, feof
+#include <string.h> // strerror
+#include <errno.h> // errno
+#define ZSTD_STATIC_LINKING_ONLY
+#include <zstd.h> // presumes zstd library is installed
+#include <zstd_errors.h>
+
+#include "zstd_seekable.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#define MAX_FILE_SIZE (8 * 1024 * 1024)
+
+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);
+}
+
+
+static void decompressFile_orDie(const char* fname, off_t startOffset, off_t endOffset)
+{
+ FILE* const fin = fopen_orDie(fname, "rb");
+ FILE* const fout = stdout;
+ // Just for demo purposes, assume file is <= MAX_FILE_SIZE
+ void* const buffIn = malloc_orDie(MAX_FILE_SIZE);
+ size_t const inSize = fread_orDie(buffIn, MAX_FILE_SIZE, fin);
+ size_t const buffOutSize = ZSTD_DStreamOutSize(); /* Guarantee to successfully flush at least one complete compressed block in all circumstances. */
+ void* const buffOut = malloc_orDie(buffOutSize);
+
+ 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_initBuff(seekable, buffIn, inSize);
+ if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_seekable_init() error : %s \n", ZSTD_getErrorName(initResult)); exit(11); }
+
+ while (startOffset < endOffset) {
+ size_t const result = ZSTD_seekable_decompress(seekable, buffOut, MIN(endOffset - startOffset, buffOutSize), startOffset);
+
+ if (ZSTD_isError(result)) {
+ fprintf(stderr, "ZSTD_seekable_decompress() error : %s \n",
+ ZSTD_getErrorName(result));
+ exit(12);
+ }
+ fwrite_orDie(buffOut, result, fout);
+ startOffset += result;
+ }
+
+ ZSTD_seekable_free(seekable);
+ fclose_orDie(fin);
+ fclose_orDie(fout);
+ free(buffIn);
+ free(buffOut);
+}
+
+
+int main(int argc, const char** argv)
+{
+ const char* const exeName = argv[0];
+
+ if (argc!=4) {
+ fprintf(stderr, "wrong arguments\n");
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "%s FILE START END\n", exeName);
+ return 1;
+ }
+
+ {
+ const char* const inFilename = argv[1];
+ off_t const startOffset = atoll(argv[2]);
+ off_t const endOffset = atoll(argv[3]);
+ decompressFile_orDie(inFilename, startOffset, endOffset);
+ }
+
+ return 0;
+}
diff --git a/src/zstd/contrib/seekable_format/zstd_seekable.h b/src/zstd/contrib/seekable_format/zstd_seekable.h
new file mode 100644
index 000000000..7ffd1ba0a
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/zstd_seekable.h
@@ -0,0 +1,186 @@
+#ifndef SEEKABLE_H
+#define SEEKABLE_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include "zstd.h" /* ZSTDLIB_API */
+
+
+#define ZSTD_seekTableFooterSize 9
+
+#define ZSTD_SEEKABLE_MAGICNUMBER 0x8F92EAB1
+
+#define ZSTD_SEEKABLE_MAXFRAMES 0x8000000U
+
+/* Limit the maximum size to avoid any potential issues storing the compressed size */
+#define ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE 0x80000000U
+
+/*-****************************************************************************
+* Seekable Format
+*
+* The seekable format splits the compressed data into a series of "frames",
+* each compressed individually so that decompression of a section in the
+* middle of an archive only requires zstd to decompress at most a frame's
+* worth of extra data, instead of the entire archive.
+******************************************************************************/
+
+typedef struct ZSTD_seekable_CStream_s ZSTD_seekable_CStream;
+typedef struct ZSTD_seekable_s ZSTD_seekable;
+
+/*-****************************************************************************
+* Seekable compression - HowTo
+* A ZSTD_seekable_CStream object is required to tracking streaming operation.
+* Use ZSTD_seekable_createCStream() and ZSTD_seekable_freeCStream() to create/
+* release resources.
+*
+* Streaming objects are reusable to avoid allocation and deallocation,
+* to start a new compression operation call ZSTD_seekable_initCStream() on the
+* compressor.
+*
+* Data streamed to the seekable compressor will automatically be split into
+* frames of size `maxFrameSize` (provided in ZSTD_seekable_initCStream()),
+* or if none is provided, will be cut off whenever ZSTD_seekable_endFrame() is
+* called or when the default maximum frame size (2GB) is reached.
+*
+* Use ZSTD_seekable_initCStream() to initialize a ZSTD_seekable_CStream object
+* for a new compression operation.
+* `maxFrameSize` indicates the size at which to automatically start a new
+* seekable frame. `maxFrameSize == 0` implies the default maximum size.
+* `checksumFlag` indicates whether or not the seek table should include frame
+* checksums on the uncompressed data for verification.
+* @return : a size hint for input to provide for compression, or an error code
+* checkable with ZSTD_isError()
+*
+* Use ZSTD_seekable_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.
+* @return : a size hint, preferred nb of bytes to use as input for next
+* function call or an error code, which can be tested using
+* ZSTD_isError().
+* Note 1 : it's just a hint, to help latency a little, any other
+* value will work fine.
+*
+* At any time, call ZSTD_seekable_endFrame() to end the current frame and
+* start a new one.
+*
+* ZSTD_seekable_endStream() will end the current frame, and then write the seek
+* table so that decompressors can efficiently find compressed frames.
+* ZSTD_seekable_endStream() may return a number > 0 if it was unable to flush
+* all the necessary data to `output`. In this case, it should be called again
+* until all remaining data is flushed out and 0 is returned.
+******************************************************************************/
+
+/*===== Seekable compressor management =====*/
+ZSTDLIB_API ZSTD_seekable_CStream* ZSTD_seekable_createCStream(void);
+ZSTDLIB_API size_t ZSTD_seekable_freeCStream(ZSTD_seekable_CStream* zcs);
+
+/*===== Seekable compression functions =====*/
+ZSTDLIB_API size_t ZSTD_seekable_initCStream(ZSTD_seekable_CStream* zcs, int compressionLevel, int checksumFlag, unsigned maxFrameSize);
+ZSTDLIB_API size_t ZSTD_seekable_compressStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input);
+ZSTDLIB_API size_t ZSTD_seekable_endFrame(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output);
+ZSTDLIB_API size_t ZSTD_seekable_endStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output);
+
+/*= Raw seek table API
+ * These functions allow for the seek table to be constructed directly.
+ * This table can then be appended to a file of concatenated frames.
+ * This allows the frames to be compressed independently, even in parallel,
+ * and compiled together afterward into a seekable archive.
+ *
+ * Use ZSTD_seekable_createFrameLog() to allocate and initialize a tracking
+ * structure.
+ *
+ * Call ZSTD_seekable_logFrame() once for each frame in the archive.
+ * checksum is optional, and will not be used if checksumFlag was 0 when the
+ * frame log was created. If present, it should be the least significant 32
+ * bits of the XXH64 hash of the uncompressed data.
+ *
+ * Call ZSTD_seekable_writeSeekTable to serialize the data into a seek table.
+ * If the entire table was written, the return value will be 0. Otherwise,
+ * it will be equal to the number of bytes left to write. */
+typedef struct ZSTD_frameLog_s ZSTD_frameLog;
+ZSTDLIB_API ZSTD_frameLog* ZSTD_seekable_createFrameLog(int checksumFlag);
+ZSTDLIB_API size_t ZSTD_seekable_freeFrameLog(ZSTD_frameLog* fl);
+ZSTDLIB_API size_t ZSTD_seekable_logFrame(ZSTD_frameLog* fl, unsigned compressedSize, unsigned decompressedSize, unsigned checksum);
+ZSTDLIB_API size_t ZSTD_seekable_writeSeekTable(ZSTD_frameLog* fl, ZSTD_outBuffer* output);
+
+/*-****************************************************************************
+* Seekable decompression - HowTo
+* A ZSTD_seekable object is required to tracking the seekTable.
+*
+* Call ZSTD_seekable_init* to initialize a ZSTD_seekable object with the
+* the seek table provided in the input.
+* There are three modes for ZSTD_seekable_init:
+* - ZSTD_seekable_initBuff() : An in-memory API. The data contained in
+* `src` should be the entire seekable file, including the seek table.
+* `src` should be kept alive and unmodified until the ZSTD_seekable object
+* is freed or reset.
+* - ZSTD_seekable_initFile() : A simplified file API using stdio. fread and
+* fseek will be used to access the required data for building the seek
+* table and doing decompression operations. `src` should not be closed
+* or modified until the ZSTD_seekable object is freed or reset.
+* - ZSTD_seekable_initAdvanced() : A general API allowing the client to
+* provide its own read and seek callbacks.
+* + ZSTD_seekable_read() : read exactly `n` bytes into `buffer`.
+* Premature EOF should be treated as an error.
+* + ZSTD_seekable_seek() : seek the read head to `offset` from `origin`,
+* where origin is either SEEK_SET (beginning of
+* file), or SEEK_END (end of file).
+* Both functions should return a non-negative value in case of success, and a
+* negative value in case of failure. If implementing using this API and
+* stdio, be careful with files larger than 4GB and fseek. All of these
+* functions return an error code checkable with ZSTD_isError().
+*
+* Call ZSTD_seekable_decompress to decompress `dstSize` bytes at decompressed
+* offset `offset`. ZSTD_seekable_decompress may have to decompress the entire
+* prefix of the frame before the desired data if it has not already processed
+* this section. If ZSTD_seekable_decompress is called multiple times for a
+* consecutive range of data, it will efficiently retain the decompressor object
+* and avoid redecompressing frame prefixes. The return value is the number of
+* bytes decompressed, or an error code checkable with ZSTD_isError().
+*
+* The seek table access functions can be used to obtain the data contained
+* in the seek table. If frameIndex is larger than the value returned by
+* ZSTD_seekable_getNumFrames(), they will return error codes checkable with
+* ZSTD_isError(). Note that since the offset access functions return
+* unsigned long long instead of size_t, in this case they will instead return
+* the value ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE.
+******************************************************************************/
+
+/*===== Seekable decompressor management =====*/
+ZSTDLIB_API ZSTD_seekable* ZSTD_seekable_create(void);
+ZSTDLIB_API size_t ZSTD_seekable_free(ZSTD_seekable* zs);
+
+/*===== Seekable decompression functions =====*/
+ZSTDLIB_API size_t ZSTD_seekable_initBuff(ZSTD_seekable* zs, const void* src, size_t srcSize);
+ZSTDLIB_API size_t ZSTD_seekable_initFile(ZSTD_seekable* zs, FILE* src);
+ZSTDLIB_API size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t dstSize, unsigned long long offset);
+ZSTDLIB_API size_t ZSTD_seekable_decompressFrame(ZSTD_seekable* zs, void* dst, size_t dstSize, unsigned frameIndex);
+
+#define ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE (0ULL-2)
+/*===== Seek Table access functions =====*/
+ZSTDLIB_API unsigned ZSTD_seekable_getNumFrames(ZSTD_seekable* const zs);
+ZSTDLIB_API unsigned long long ZSTD_seekable_getFrameCompressedOffset(ZSTD_seekable* const zs, unsigned frameIndex);
+ZSTDLIB_API unsigned long long ZSTD_seekable_getFrameDecompressedOffset(ZSTD_seekable* const zs, unsigned frameIndex);
+ZSTDLIB_API size_t ZSTD_seekable_getFrameCompressedSize(ZSTD_seekable* const zs, unsigned frameIndex);
+ZSTDLIB_API size_t ZSTD_seekable_getFrameDecompressedSize(ZSTD_seekable* const zs, unsigned frameIndex);
+ZSTDLIB_API unsigned ZSTD_seekable_offsetToFrameIndex(ZSTD_seekable* const zs, unsigned long long offset);
+
+/*===== Seekable advanced I/O API =====*/
+typedef int(ZSTD_seekable_read)(void* opaque, void* buffer, size_t n);
+typedef int(ZSTD_seekable_seek)(void* opaque, long long offset, int origin);
+typedef struct {
+ void* opaque;
+ ZSTD_seekable_read* read;
+ ZSTD_seekable_seek* seek;
+} ZSTD_seekable_customFile;
+ZSTDLIB_API size_t ZSTD_seekable_initAdvanced(ZSTD_seekable* zs, ZSTD_seekable_customFile src);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
diff --git a/src/zstd/contrib/seekable_format/zstd_seekable_compression_format.md b/src/zstd/contrib/seekable_format/zstd_seekable_compression_format.md
new file mode 100644
index 000000000..bf3080f7b
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/zstd_seekable_compression_format.md
@@ -0,0 +1,116 @@
+# Zstandard Seekable Format
+
+### Notices
+
+Copyright (c) 2017-present Facebook, Inc.
+
+Permission is granted to copy and distribute this document
+for any purpose and without charge,
+including translations into other languages
+and incorporation into compilations,
+provided that the copyright notice and this notice are preserved,
+and that any substantive changes or deletions from the original
+are clearly marked.
+Distribution of this document is unlimited.
+
+### Version
+0.1.0 (11/04/17)
+
+## Introduction
+This document defines a format for compressed data to be stored so that subranges of the data can be efficiently decompressed without requiring the entire document to be decompressed.
+This is done by splitting up the input data into frames,
+each of which are compressed independently,
+and so can be decompressed independently.
+Decompression then takes advantage of a provided 'seek table', which allows the decompressor to immediately jump to the desired data. This is done in a way that is compatible with the original Zstandard format by placing the seek table in a Zstandard skippable frame.
+
+### Overall conventions
+In this document:
+- square brackets i.e. `[` and `]` are used to indicate optional fields or parameters.
+- the naming convention for identifiers is `Mixed_Case_With_Underscores`
+- All numeric fields are little-endian unless specified otherwise
+
+## Format
+
+The format consists of a number of frames (Zstandard compressed frames and skippable frames), followed by a final skippable frame at the end containing the seek table.
+
+### Seek Table Format
+The structure of the seek table frame is as follows:
+
+|`Skippable_Magic_Number`|`Frame_Size`|`[Seek_Table_Entries]`|`Seek_Table_Footer`|
+|------------------------|------------|----------------------|-------------------|
+| 4 bytes | 4 bytes | 8-12 bytes each | 9 bytes |
+
+__`Skippable_Magic_Number`__
+
+Value : 0x184D2A5E.
+This is for compatibility with [Zstandard skippable frames].
+Since it is legal for other Zstandard skippable frames to use the same
+magic number, it is not recommended for a decoder to recognize frames
+solely on this.
+
+__`Frame_Size`__
+
+The total size of the skippable frame, not including the `Skippable_Magic_Number` or `Frame_Size`.
+This is for compatibility with [Zstandard skippable frames].
+
+[Zstandard skippable frames]: https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#skippable-frames
+
+#### `Seek_Table_Footer`
+The seek table footer format is as follows:
+
+|`Number_Of_Frames`|`Seek_Table_Descriptor`|`Seekable_Magic_Number`|
+|------------------|-----------------------|-----------------------|
+| 4 bytes | 1 byte | 4 bytes |
+
+__`Seekable_Magic_Number`__
+
+Value : 0x8F92EAB1.
+This value must be the last bytes present in the compressed file so that decoders
+can efficiently find it and determine if there is an actual seek table present.
+
+__`Number_Of_Frames`__
+
+The number of stored frames in the data.
+
+__`Seek_Table_Descriptor`__
+
+A bitfield describing the format of the seek table.
+
+| Bit number | Field name |
+| ---------- | ---------- |
+| 7 | `Checksum_Flag` |
+| 6-2 | `Reserved_Bits` |
+| 1-0 | `Unused_Bits` |
+
+While only `Checksum_Flag` currently exists, there are 7 other bits in this field that can be used for future changes to the format,
+for example the addition of inline dictionaries.
+
+__`Checksum_Flag`__
+
+If the checksum flag is set, each of the seek table entries contains a 4 byte checksum of the uncompressed data contained in its frame.
+
+`Reserved_Bits` are not currently used but may be used in the future for breaking changes, so a compliant decoder should ensure they are set to 0. `Unused_Bits` may be used in the future for non-breaking changes, so a compliant decoder should not interpret these bits.
+
+#### __`Seek_Table_Entries`__
+
+`Seek_Table_Entries` consists of `Number_Of_Frames` (one for each frame in the data, not including the seek table frame) entries of the following form, in sequence:
+
+|`Compressed_Size`|`Decompressed_Size`|`[Checksum]`|
+|-----------------|-------------------|------------|
+| 4 bytes | 4 bytes | 4 bytes |
+
+__`Compressed_Size`__
+
+The compressed size of the frame.
+The cumulative sum of the `Compressed_Size` fields of frames `0` to `i` gives the offset in the compressed file of frame `i+1`.
+
+__`Decompressed_Size`__
+
+The size of the decompressed data contained in the frame. For skippable or otherwise empty frames, this value is 0.
+
+__`Checksum`__
+
+Only present if `Checksum_Flag` is set in the `Seek_Table_Descriptor`. Value : the least significant 32 bits of the XXH64 digest of the uncompressed data, stored in little-endian format.
+
+## Version Changes
+- 0.1.0: initial version
diff --git a/src/zstd/contrib/seekable_format/zstdseek_compress.c b/src/zstd/contrib/seekable_format/zstdseek_compress.c
new file mode 100644
index 000000000..5a75714fa
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/zstdseek_compress.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+#include <stdlib.h> /* malloc, free */
+#include <limits.h> /* UINT_MAX */
+#include <assert.h>
+
+#define XXH_STATIC_LINKING_ONLY
+#define XXH_NAMESPACE ZSTD_
+#include "xxhash.h"
+
+#define ZSTD_STATIC_LINKING_ONLY
+#include "zstd.h"
+#include "zstd_errors.h"
+#include "mem.h"
+#include "zstd_seekable.h"
+
+#define CHECK_Z(f) { size_t const ret = (f); if (ret != 0) return ret; }
+
+#undef ERROR
+#define ERROR(name) ((size_t)-ZSTD_error_##name)
+
+#undef MIN
+#undef MAX
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+typedef struct {
+ U32 cSize;
+ U32 dSize;
+ U32 checksum;
+} framelogEntry_t;
+
+struct ZSTD_frameLog_s {
+ framelogEntry_t* entries;
+ U32 size;
+ U32 capacity;
+
+ int checksumFlag;
+
+ /* for use when streaming out the seek table */
+ U32 seekTablePos;
+ U32 seekTableIndex;
+} framelog_t;
+
+struct ZSTD_seekable_CStream_s {
+ ZSTD_CStream* cstream;
+ ZSTD_frameLog framelog;
+
+ U32 frameCSize;
+ U32 frameDSize;
+
+ XXH64_state_t xxhState;
+
+ U32 maxFrameSize;
+
+ int writingSeekTable;
+};
+
+size_t ZSTD_seekable_frameLog_allocVec(ZSTD_frameLog* fl)
+{
+ /* allocate some initial space */
+ size_t const FRAMELOG_STARTING_CAPACITY = 16;
+ fl->entries = (framelogEntry_t*)malloc(
+ sizeof(framelogEntry_t) * FRAMELOG_STARTING_CAPACITY);
+ if (fl->entries == NULL) return ERROR(memory_allocation);
+ fl->capacity = FRAMELOG_STARTING_CAPACITY;
+
+ return 0;
+}
+
+size_t ZSTD_seekable_frameLog_freeVec(ZSTD_frameLog* fl)
+{
+ if (fl != NULL) free(fl->entries);
+ return 0;
+}
+
+ZSTD_frameLog* ZSTD_seekable_createFrameLog(int checksumFlag)
+{
+ ZSTD_frameLog* fl = malloc(sizeof(ZSTD_frameLog));
+ if (fl == NULL) return NULL;
+
+ if (ZSTD_isError(ZSTD_seekable_frameLog_allocVec(fl))) {
+ free(fl);
+ return NULL;
+ }
+
+ fl->checksumFlag = checksumFlag;
+ fl->seekTablePos = 0;
+ fl->seekTableIndex = 0;
+ fl->size = 0;
+
+ return fl;
+}
+
+size_t ZSTD_seekable_freeFrameLog(ZSTD_frameLog* fl)
+{
+ ZSTD_seekable_frameLog_freeVec(fl);
+ free(fl);
+ return 0;
+}
+
+ZSTD_seekable_CStream* ZSTD_seekable_createCStream()
+{
+ ZSTD_seekable_CStream* zcs = malloc(sizeof(ZSTD_seekable_CStream));
+
+ if (zcs == NULL) return NULL;
+
+ memset(zcs, 0, sizeof(*zcs));
+
+ zcs->cstream = ZSTD_createCStream();
+ if (zcs->cstream == NULL) goto failed1;
+
+ if (ZSTD_isError(ZSTD_seekable_frameLog_allocVec(&zcs->framelog))) goto failed2;
+
+ return zcs;
+
+failed2:
+ ZSTD_freeCStream(zcs->cstream);
+failed1:
+ free(zcs);
+ return NULL;
+}
+
+size_t ZSTD_seekable_freeCStream(ZSTD_seekable_CStream* zcs)
+{
+ if (zcs == NULL) return 0; /* support free on null */
+ ZSTD_freeCStream(zcs->cstream);
+ ZSTD_seekable_frameLog_freeVec(&zcs->framelog);
+ free(zcs);
+
+ return 0;
+}
+
+size_t ZSTD_seekable_initCStream(ZSTD_seekable_CStream* zcs,
+ int compressionLevel,
+ int checksumFlag,
+ unsigned maxFrameSize)
+{
+ zcs->framelog.size = 0;
+ zcs->frameCSize = 0;
+ zcs->frameDSize = 0;
+
+ /* make sure maxFrameSize has a reasonable value */
+ if (maxFrameSize > ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE) {
+ return ERROR(frameParameter_unsupported);
+ }
+
+ zcs->maxFrameSize = maxFrameSize
+ ? maxFrameSize
+ : ZSTD_SEEKABLE_MAX_FRAME_DECOMPRESSED_SIZE;
+
+ zcs->framelog.checksumFlag = checksumFlag;
+ if (zcs->framelog.checksumFlag) {
+ XXH64_reset(&zcs->xxhState, 0);
+ }
+
+ zcs->framelog.seekTablePos = 0;
+ zcs->framelog.seekTableIndex = 0;
+ zcs->writingSeekTable = 0;
+
+ return ZSTD_initCStream(zcs->cstream, compressionLevel);
+}
+
+size_t ZSTD_seekable_logFrame(ZSTD_frameLog* fl,
+ unsigned compressedSize,
+ unsigned decompressedSize,
+ unsigned checksum)
+{
+ if (fl->size == ZSTD_SEEKABLE_MAXFRAMES)
+ return ERROR(frameIndex_tooLarge);
+
+ /* grow the buffer if required */
+ if (fl->size == fl->capacity) {
+ /* exponential size increase for constant amortized runtime */
+ size_t const newCapacity = fl->capacity * 2;
+ framelogEntry_t* const newEntries = realloc(fl->entries,
+ sizeof(framelogEntry_t) * newCapacity);
+
+ if (newEntries == NULL) return ERROR(memory_allocation);
+
+ fl->entries = newEntries;
+ assert(newCapacity <= UINT_MAX);
+ fl->capacity = (U32)newCapacity;
+ }
+
+ fl->entries[fl->size] = (framelogEntry_t){
+ compressedSize, decompressedSize, checksum
+ };
+ fl->size++;
+
+ return 0;
+}
+
+size_t ZSTD_seekable_endFrame(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output)
+{
+ size_t const prevOutPos = output->pos;
+ /* end the frame */
+ size_t ret = ZSTD_endStream(zcs->cstream, output);
+
+ zcs->frameCSize += output->pos - prevOutPos;
+
+ /* need to flush before doing the rest */
+ if (ret) return ret;
+
+ /* frame done */
+
+ /* store the frame data for later */
+ ret = ZSTD_seekable_logFrame(
+ &zcs->framelog, zcs->frameCSize, zcs->frameDSize,
+ zcs->framelog.checksumFlag
+ ? XXH64_digest(&zcs->xxhState) & 0xFFFFFFFFU
+ : 0);
+ if (ret) return ret;
+
+ /* reset for the next frame */
+ zcs->frameCSize = 0;
+ zcs->frameDSize = 0;
+
+ ZSTD_resetCStream(zcs->cstream, 0);
+ if (zcs->framelog.checksumFlag)
+ XXH64_reset(&zcs->xxhState, 0);
+
+ return 0;
+}
+
+size_t ZSTD_seekable_compressStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
+{
+ const BYTE* const inBase = (const BYTE*) input->src + input->pos;
+ size_t inLen = input->size - input->pos;
+
+ inLen = MIN(inLen, (size_t)(zcs->maxFrameSize - zcs->frameDSize));
+
+ /* if we haven't finished flushing the last frame, don't start writing a new one */
+ if (inLen > 0) {
+ ZSTD_inBuffer inTmp = { inBase, inLen, 0 };
+ size_t const prevOutPos = output->pos;
+
+ size_t const ret = ZSTD_compressStream(zcs->cstream, output, &inTmp);
+
+ if (zcs->framelog.checksumFlag) {
+ XXH64_update(&zcs->xxhState, inBase, inTmp.pos);
+ }
+
+ zcs->frameCSize += output->pos - prevOutPos;
+ zcs->frameDSize += inTmp.pos;
+
+ input->pos += inTmp.pos;
+
+ if (ZSTD_isError(ret)) return ret;
+ }
+
+ if (zcs->maxFrameSize == zcs->frameDSize) {
+ /* log the frame and start over */
+ size_t const ret = ZSTD_seekable_endFrame(zcs, output);
+ if (ZSTD_isError(ret)) return ret;
+
+ /* get the client ready for the next frame */
+ return (size_t)zcs->maxFrameSize;
+ }
+
+ return (size_t)(zcs->maxFrameSize - zcs->frameDSize);
+}
+
+static inline size_t ZSTD_seekable_seekTableSize(const ZSTD_frameLog* fl)
+{
+ size_t const sizePerFrame = 8 + (fl->checksumFlag?4:0);
+ size_t const seekTableLen = ZSTD_SKIPPABLEHEADERSIZE +
+ sizePerFrame * fl->size +
+ ZSTD_seekTableFooterSize;
+
+ return seekTableLen;
+}
+
+static inline size_t ZSTD_stwrite32(ZSTD_frameLog* fl,
+ ZSTD_outBuffer* output, U32 const value,
+ U32 const offset)
+{
+ if (fl->seekTablePos < offset + 4) {
+ BYTE tmp[4]; /* so that we can work with buffers too small to write a whole word to */
+ size_t const lenWrite =
+ MIN(output->size - output->pos, offset + 4 - fl->seekTablePos);
+ MEM_writeLE32(tmp, value);
+ memcpy((BYTE*)output->dst + output->pos,
+ tmp + (fl->seekTablePos - offset), lenWrite);
+ output->pos += lenWrite;
+ fl->seekTablePos += lenWrite;
+
+ if (lenWrite < 4) return ZSTD_seekable_seekTableSize(fl) - fl->seekTablePos;
+ }
+ return 0;
+}
+
+size_t ZSTD_seekable_writeSeekTable(ZSTD_frameLog* fl, ZSTD_outBuffer* output)
+{
+ /* seekTableIndex: the current index in the table and
+ * seekTableSize: the amount of the table written so far
+ *
+ * This function is written this way so that if it has to return early
+ * because of a small buffer, it can keep going where it left off.
+ */
+
+ size_t const sizePerFrame = 8 + (fl->checksumFlag?4:0);
+ size_t const seekTableLen = ZSTD_seekable_seekTableSize(fl);
+
+ CHECK_Z(ZSTD_stwrite32(fl, output, ZSTD_MAGIC_SKIPPABLE_START | 0xE, 0));
+ assert(seekTableLen <= (size_t)UINT_MAX);
+ CHECK_Z(ZSTD_stwrite32(fl, output, (U32)seekTableLen - ZSTD_SKIPPABLEHEADERSIZE, 4));
+
+ while (fl->seekTableIndex < fl->size) {
+ unsigned long long const start = ZSTD_SKIPPABLEHEADERSIZE + sizePerFrame * fl->seekTableIndex;
+ assert(start + 8 <= UINT_MAX);
+ CHECK_Z(ZSTD_stwrite32(fl, output,
+ fl->entries[fl->seekTableIndex].cSize,
+ (U32)start + 0));
+
+ CHECK_Z(ZSTD_stwrite32(fl, output,
+ fl->entries[fl->seekTableIndex].dSize,
+ (U32)start + 4));
+
+ if (fl->checksumFlag) {
+ CHECK_Z(ZSTD_stwrite32(
+ fl, output, fl->entries[fl->seekTableIndex].checksum,
+ (U32)start + 8));
+ }
+
+ fl->seekTableIndex++;
+ }
+
+ assert(seekTableLen <= UINT_MAX);
+ CHECK_Z(ZSTD_stwrite32(fl, output, fl->size,
+ (U32)seekTableLen - ZSTD_seekTableFooterSize));
+
+ if (output->size - output->pos < 1) return seekTableLen - fl->seekTablePos;
+ if (fl->seekTablePos < seekTableLen - 4) {
+ BYTE sfd = 0;
+ sfd |= (fl->checksumFlag) << 7;
+
+ ((BYTE*)output->dst)[output->pos] = sfd;
+ output->pos++;
+ fl->seekTablePos++;
+ }
+
+ CHECK_Z(ZSTD_stwrite32(fl, output, ZSTD_SEEKABLE_MAGICNUMBER,
+ (U32)seekTableLen - 4));
+
+ if (fl->seekTablePos != seekTableLen) return ERROR(GENERIC);
+ return 0;
+}
+
+size_t ZSTD_seekable_endStream(ZSTD_seekable_CStream* zcs, ZSTD_outBuffer* output)
+{
+ if (!zcs->writingSeekTable && zcs->frameDSize) {
+ const size_t endFrame = ZSTD_seekable_endFrame(zcs, output);
+ if (ZSTD_isError(endFrame)) return endFrame;
+ /* return an accurate size hint */
+ if (endFrame) return endFrame + ZSTD_seekable_seekTableSize(&zcs->framelog);
+ }
+
+ zcs->writingSeekTable = 1;
+
+ return ZSTD_seekable_writeSeekTable(&zcs->framelog, output);
+}
diff --git a/src/zstd/contrib/seekable_format/zstdseek_decompress.c b/src/zstd/contrib/seekable_format/zstdseek_decompress.c
new file mode 100644
index 000000000..abfd1e902
--- /dev/null
+++ b/src/zstd/contrib/seekable_format/zstdseek_decompress.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/* *********************************************************
+* Turn on Large Files support (>4GB) for 32-bit Linux/Unix
+***********************************************************/
+#if !defined(__64BIT__) || defined(__MINGW32__) /* No point defining Large file for 64 bit but MinGW-w64 requires it */
+# if !defined(_FILE_OFFSET_BITS)
+# define _FILE_OFFSET_BITS 64 /* turn off_t into a 64-bit type for ftello, fseeko */
+# endif
+# if !defined(_LARGEFILE_SOURCE) /* obsolete macro, replaced with _FILE_OFFSET_BITS */
+# define _LARGEFILE_SOURCE 1 /* Large File Support extension (LFS) - fseeko, ftello */
+# endif
+# if defined(_AIX) || defined(__hpux)
+# define _LARGE_FILES /* Large file support on 32-bits AIX and HP-UX */
+# endif
+#endif
+
+/* ************************************************************
+* Avoid fseek()'s 2GiB barrier with MSVC, macOS, *BSD, MinGW
+***************************************************************/
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# define LONG_SEEK _fseeki64
+#elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */
+# define LONG_SEEK fseeko
+#elif defined(__MINGW32__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS) && defined(__MSVCRT__)
+# define LONG_SEEK fseeko64
+#elif defined(_WIN32) && !defined(__DJGPP__)
+# include <windows.h>
+ static int LONG_SEEK(FILE* file, __int64 offset, int origin) {
+ LARGE_INTEGER off;
+ DWORD method;
+ off.QuadPart = offset;
+ if (origin == SEEK_END)
+ method = FILE_END;
+ else if (origin == SEEK_CUR)
+ method = FILE_CURRENT;
+ else
+ method = FILE_BEGIN;
+
+ if (SetFilePointerEx((HANDLE) _get_osfhandle(_fileno(file)), off, NULL, method))
+ return 0;
+ else
+ return -1;
+ }
+#else
+# define LONG_SEEK fseek
+#endif
+
+#include <stdlib.h> /* malloc, free */
+#include <stdio.h> /* FILE* */
+#include <limits.h> /* UNIT_MAX */
+#include <assert.h>
+
+#define XXH_STATIC_LINKING_ONLY
+#define XXH_NAMESPACE ZSTD_
+#include "xxhash.h"
+
+#define ZSTD_STATIC_LINKING_ONLY
+#include "zstd.h"
+#include "zstd_errors.h"
+#include "mem.h"
+#include "zstd_seekable.h"
+
+#undef ERROR
+#define ERROR(name) ((size_t)-ZSTD_error_##name)
+
+#define CHECK_IO(f) { int const errcod = (f); if (errcod < 0) return ERROR(seekableIO); }
+
+#undef MIN
+#undef MAX
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+/* Special-case callbacks for FILE* and in-memory modes, so that we can treat
+ * them the same way as the advanced API */
+static int ZSTD_seekable_read_FILE(void* opaque, void* buffer, size_t n)
+{
+ size_t const result = fread(buffer, 1, n, (FILE*)opaque);
+ if (result != n) {
+ return -1;
+ }
+ return 0;
+}
+
+static int ZSTD_seekable_seek_FILE(void* opaque, long long offset, int origin)
+{
+ int const ret = LONG_SEEK((FILE*)opaque, offset, origin);
+ if (ret) return ret;
+ return fflush((FILE*)opaque);
+}
+
+typedef struct {
+ const void *ptr;
+ size_t size;
+ size_t pos;
+} buffWrapper_t;
+
+static int ZSTD_seekable_read_buff(void* opaque, void* buffer, size_t n)
+{
+ buffWrapper_t* buff = (buffWrapper_t*) opaque;
+ if (buff->pos + n > buff->size) return -1;
+ memcpy(buffer, (const BYTE*)buff->ptr + buff->pos, n);
+ buff->pos += n;
+ return 0;
+}
+
+static int ZSTD_seekable_seek_buff(void* opaque, long long offset, int origin)
+{
+ buffWrapper_t* const buff = (buffWrapper_t*) opaque;
+ unsigned long long newOffset;
+ switch (origin) {
+ case SEEK_SET:
+ newOffset = offset;
+ break;
+ case SEEK_CUR:
+ newOffset = (unsigned long long)buff->pos + offset;
+ break;
+ case SEEK_END:
+ newOffset = (unsigned long long)buff->size + offset;
+ break;
+ default:
+ assert(0); /* not possible */
+ }
+ if (newOffset > buff->size) {
+ return -1;
+ }
+ buff->pos = newOffset;
+ return 0;
+}
+
+typedef struct {
+ U64 cOffset;
+ U64 dOffset;
+ U32 checksum;
+} seekEntry_t;
+
+typedef struct {
+ seekEntry_t* entries;
+ size_t tableLen;
+
+ int checksumFlag;
+} seekTable_t;
+
+#define SEEKABLE_BUFF_SIZE ZSTD_BLOCKSIZE_MAX
+
+struct ZSTD_seekable_s {
+ ZSTD_DStream* dstream;
+ seekTable_t seekTable;
+ ZSTD_seekable_customFile src;
+
+ U64 decompressedOffset;
+ U32 curFrame;
+
+ BYTE inBuff[SEEKABLE_BUFF_SIZE]; /* need to do our own input buffering */
+ BYTE outBuff[SEEKABLE_BUFF_SIZE]; /* so we can efficiently decompress the
+ starts of chunks before we get to the
+ desired section */
+ ZSTD_inBuffer in; /* maintain continuity across ZSTD_seekable_decompress operations */
+ buffWrapper_t buffWrapper; /* for `src.opaque` in in-memory mode */
+
+ XXH64_state_t xxhState;
+};
+
+ZSTD_seekable* ZSTD_seekable_create(void)
+{
+ ZSTD_seekable* zs = malloc(sizeof(ZSTD_seekable));
+
+ if (zs == NULL) return NULL;
+
+ /* also initializes stage to zsds_init */
+ memset(zs, 0, sizeof(*zs));
+
+ zs->dstream = ZSTD_createDStream();
+ if (zs->dstream == NULL) {
+ free(zs);
+ return NULL;
+ }
+
+ return zs;
+}
+
+size_t ZSTD_seekable_free(ZSTD_seekable* zs)
+{
+ if (zs == NULL) return 0; /* support free on null */
+ ZSTD_freeDStream(zs->dstream);
+ free(zs->seekTable.entries);
+ free(zs);
+
+ return 0;
+}
+
+/** ZSTD_seekable_offsetToFrameIndex() :
+ * Performs a binary search to find the last frame with a decompressed offset
+ * <= pos
+ * @return : the frame's index */
+unsigned ZSTD_seekable_offsetToFrameIndex(ZSTD_seekable* const zs, unsigned long long pos)
+{
+ U32 lo = 0;
+ U32 hi = (U32)zs->seekTable.tableLen;
+ assert(zs->seekTable.tableLen <= UINT_MAX);
+
+ if (pos >= zs->seekTable.entries[zs->seekTable.tableLen].dOffset) {
+ return (U32)zs->seekTable.tableLen;
+ }
+
+ while (lo + 1 < hi) {
+ U32 const mid = lo + ((hi - lo) >> 1);
+ if (zs->seekTable.entries[mid].dOffset <= pos) {
+ lo = mid;
+ } else {
+ hi = mid;
+ }
+ }
+ return lo;
+}
+
+unsigned ZSTD_seekable_getNumFrames(ZSTD_seekable* const zs)
+{
+ assert(zs->seekTable.tableLen <= UINT_MAX);
+ return (unsigned)zs->seekTable.tableLen;
+}
+
+unsigned long long ZSTD_seekable_getFrameCompressedOffset(ZSTD_seekable* const zs, unsigned frameIndex)
+{
+ if (frameIndex >= zs->seekTable.tableLen) return ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE;
+ return zs->seekTable.entries[frameIndex].cOffset;
+}
+
+unsigned long long ZSTD_seekable_getFrameDecompressedOffset(ZSTD_seekable* const zs, unsigned frameIndex)
+{
+ if (frameIndex >= zs->seekTable.tableLen) return ZSTD_SEEKABLE_FRAMEINDEX_TOOLARGE;
+ return zs->seekTable.entries[frameIndex].dOffset;
+}
+
+size_t ZSTD_seekable_getFrameCompressedSize(ZSTD_seekable* const zs, unsigned frameIndex)
+{
+ if (frameIndex >= zs->seekTable.tableLen) return ERROR(frameIndex_tooLarge);
+ return zs->seekTable.entries[frameIndex + 1].cOffset -
+ zs->seekTable.entries[frameIndex].cOffset;
+}
+
+size_t ZSTD_seekable_getFrameDecompressedSize(ZSTD_seekable* const zs, unsigned frameIndex)
+{
+ if (frameIndex > zs->seekTable.tableLen) return ERROR(frameIndex_tooLarge);
+ return zs->seekTable.entries[frameIndex + 1].dOffset -
+ zs->seekTable.entries[frameIndex].dOffset;
+}
+
+static size_t ZSTD_seekable_loadSeekTable(ZSTD_seekable* zs)
+{
+ int checksumFlag;
+ ZSTD_seekable_customFile src = zs->src;
+ /* read the footer, fixed size */
+ CHECK_IO(src.seek(src.opaque, -(int)ZSTD_seekTableFooterSize, SEEK_END));
+ CHECK_IO(src.read(src.opaque, zs->inBuff, ZSTD_seekTableFooterSize));
+
+ if (MEM_readLE32(zs->inBuff + 5) != ZSTD_SEEKABLE_MAGICNUMBER) {
+ return ERROR(prefix_unknown);
+ }
+
+ { BYTE const sfd = zs->inBuff[4];
+ checksumFlag = sfd >> 7;
+
+ /* check reserved bits */
+ if ((checksumFlag >> 2) & 0x1f) {
+ return ERROR(corruption_detected);
+ }
+ }
+
+ { U32 const numFrames = MEM_readLE32(zs->inBuff);
+ U32 const sizePerEntry = 8 + (checksumFlag?4:0);
+ U32 const tableSize = sizePerEntry * numFrames;
+ U32 const frameSize = tableSize + ZSTD_seekTableFooterSize + ZSTD_SKIPPABLEHEADERSIZE;
+
+ U32 remaining = frameSize - ZSTD_seekTableFooterSize; /* don't need to re-read footer */
+ {
+ U32 const toRead = MIN(remaining, SEEKABLE_BUFF_SIZE);
+
+ CHECK_IO(src.seek(src.opaque, -(S64)frameSize, SEEK_END));
+ CHECK_IO(src.read(src.opaque, zs->inBuff, toRead));
+
+ remaining -= toRead;
+ }
+
+ if (MEM_readLE32(zs->inBuff) != (ZSTD_MAGIC_SKIPPABLE_START | 0xE)) {
+ return ERROR(prefix_unknown);
+ }
+ if (MEM_readLE32(zs->inBuff+4) + ZSTD_SKIPPABLEHEADERSIZE != frameSize) {
+ return ERROR(prefix_unknown);
+ }
+
+ { /* Allocate an extra entry at the end so that we can do size
+ * computations on the last element without special case */
+ seekEntry_t* entries = (seekEntry_t*)malloc(sizeof(seekEntry_t) * (numFrames + 1));
+
+ U32 idx = 0;
+ U32 pos = 8;
+
+
+ U64 cOffset = 0;
+ U64 dOffset = 0;
+
+ if (!entries) {
+ free(entries);
+ return ERROR(memory_allocation);
+ }
+
+ /* compute cumulative positions */
+ for (; idx < numFrames; idx++) {
+ if (pos + sizePerEntry > SEEKABLE_BUFF_SIZE) {
+ U32 const offset = SEEKABLE_BUFF_SIZE - pos;
+ U32 const toRead = MIN(remaining, SEEKABLE_BUFF_SIZE - offset);
+ memmove(zs->inBuff, zs->inBuff + pos, offset); /* move any data we haven't read yet */
+ CHECK_IO(src.read(src.opaque, zs->inBuff+offset, toRead));
+ remaining -= toRead;
+ pos = 0;
+ }
+ entries[idx].cOffset = cOffset;
+ entries[idx].dOffset = dOffset;
+
+ cOffset += MEM_readLE32(zs->inBuff + pos);
+ pos += 4;
+ dOffset += MEM_readLE32(zs->inBuff + pos);
+ pos += 4;
+ if (checksumFlag) {
+ entries[idx].checksum = MEM_readLE32(zs->inBuff + pos);
+ pos += 4;
+ }
+ }
+ entries[numFrames].cOffset = cOffset;
+ entries[numFrames].dOffset = dOffset;
+
+ zs->seekTable.entries = entries;
+ zs->seekTable.tableLen = numFrames;
+ zs->seekTable.checksumFlag = checksumFlag;
+ return 0;
+ }
+ }
+}
+
+size_t ZSTD_seekable_initBuff(ZSTD_seekable* zs, const void* src, size_t srcSize)
+{
+ zs->buffWrapper = (buffWrapper_t){src, srcSize, 0};
+ { ZSTD_seekable_customFile srcFile = {&zs->buffWrapper,
+ &ZSTD_seekable_read_buff,
+ &ZSTD_seekable_seek_buff};
+ return ZSTD_seekable_initAdvanced(zs, srcFile); }
+}
+
+size_t ZSTD_seekable_initFile(ZSTD_seekable* zs, FILE* src)
+{
+ ZSTD_seekable_customFile srcFile = {src, &ZSTD_seekable_read_FILE,
+ &ZSTD_seekable_seek_FILE};
+ return ZSTD_seekable_initAdvanced(zs, srcFile);
+}
+
+size_t ZSTD_seekable_initAdvanced(ZSTD_seekable* zs, ZSTD_seekable_customFile src)
+{
+ zs->src = src;
+
+ { const size_t seekTableInit = ZSTD_seekable_loadSeekTable(zs);
+ if (ZSTD_isError(seekTableInit)) return seekTableInit; }
+
+ zs->decompressedOffset = (U64)-1;
+ zs->curFrame = (U32)-1;
+
+ { const size_t dstreamInit = ZSTD_initDStream(zs->dstream);
+ if (ZSTD_isError(dstreamInit)) return dstreamInit; }
+ return 0;
+}
+
+size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsigned long long offset)
+{
+ U32 targetFrame = ZSTD_seekable_offsetToFrameIndex(zs, offset);
+ do {
+ /* check if we can continue from a previous decompress job */
+ if (targetFrame != zs->curFrame || offset != zs->decompressedOffset) {
+ zs->decompressedOffset = zs->seekTable.entries[targetFrame].dOffset;
+ zs->curFrame = targetFrame;
+
+ CHECK_IO(zs->src.seek(zs->src.opaque,
+ zs->seekTable.entries[targetFrame].cOffset,
+ SEEK_SET));
+ zs->in = (ZSTD_inBuffer){zs->inBuff, 0, 0};
+ XXH64_reset(&zs->xxhState, 0);
+ ZSTD_resetDStream(zs->dstream);
+ }
+
+ while (zs->decompressedOffset < offset + len) {
+ size_t toRead;
+ ZSTD_outBuffer outTmp;
+ size_t prevOutPos;
+ if (zs->decompressedOffset < offset) {
+ /* dummy decompressions until we get to the target offset */
+ outTmp = (ZSTD_outBuffer){zs->outBuff, MIN(SEEKABLE_BUFF_SIZE, offset - zs->decompressedOffset), 0};
+ } else {
+ outTmp = (ZSTD_outBuffer){dst, len, zs->decompressedOffset - offset};
+ }
+
+ prevOutPos = outTmp.pos;
+ toRead = ZSTD_decompressStream(zs->dstream, &outTmp, &zs->in);
+ if (ZSTD_isError(toRead)) {
+ return toRead;
+ }
+
+ if (zs->seekTable.checksumFlag) {
+ XXH64_update(&zs->xxhState, (BYTE*)outTmp.dst + prevOutPos,
+ outTmp.pos - prevOutPos);
+ }
+ zs->decompressedOffset += outTmp.pos - prevOutPos;
+
+ if (toRead == 0) {
+ /* frame complete */
+
+ /* verify checksum */
+ if (zs->seekTable.checksumFlag &&
+ (XXH64_digest(&zs->xxhState) & 0xFFFFFFFFU) !=
+ zs->seekTable.entries[targetFrame].checksum) {
+ return ERROR(corruption_detected);
+ }
+
+ if (zs->decompressedOffset < offset + len) {
+ /* go back to the start and force a reset of the stream */
+ targetFrame = ZSTD_seekable_offsetToFrameIndex(zs, zs->decompressedOffset);
+ }
+ break;
+ }
+
+ /* read in more data if we're done with this buffer */
+ if (zs->in.pos == zs->in.size) {
+ toRead = MIN(toRead, SEEKABLE_BUFF_SIZE);
+ CHECK_IO(zs->src.read(zs->src.opaque, zs->inBuff, toRead));
+ zs->in.size = toRead;
+ zs->in.pos = 0;
+ }
+ }
+ } while (zs->decompressedOffset != offset + len);
+
+ return len;
+}
+
+size_t ZSTD_seekable_decompressFrame(ZSTD_seekable* zs, void* dst, size_t dstSize, unsigned frameIndex)
+{
+ if (frameIndex >= zs->seekTable.tableLen) {
+ return ERROR(frameIndex_tooLarge);
+ }
+
+ {
+ size_t const decompressedSize =
+ zs->seekTable.entries[frameIndex + 1].dOffset -
+ zs->seekTable.entries[frameIndex].dOffset;
+ if (dstSize < decompressedSize) {
+ return ERROR(dstSize_tooSmall);
+ }
+ return ZSTD_seekable_decompress(
+ zs, dst, decompressedSize,
+ zs->seekTable.entries[frameIndex].dOffset);
+ }
+}
diff --git a/src/zstd/contrib/single_file_libs/.gitignore b/src/zstd/contrib/single_file_libs/.gitignore
new file mode 100644
index 000000000..054333f9b
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/.gitignore
@@ -0,0 +1,4 @@
+zstddeclib.c
+zstdenclib.c
+zstd.c
+zstd.h
diff --git a/src/zstd/contrib/single_file_libs/README.md b/src/zstd/contrib/single_file_libs/README.md
new file mode 100644
index 000000000..d88e8fc6b
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/README.md
@@ -0,0 +1,33 @@
+# Single File Zstandard Libraries
+
+The script `combine.sh` creates an _amalgamated_ source file that can be used with or without `zstd.h`. This isn't a _header-only_ file but it does offer a similar level of simplicity when integrating into a project.
+
+All it now takes to support Zstd in your own projects is the addition of a single file, two if using the header, with no configuration or further build steps.
+
+Decompressor
+------------
+
+This is the most common use case. The decompression library is small, adding, for example, 26kB to an Emscripten compiled WebAssembly project. Native implementations add a little more, 40-70kB depending on the compiler and platform.
+
+Create `zstddeclib.c` from the Zstd source using:
+```
+cd zstd/contrib/single_file_libs
+./combine.sh -r ../../lib -o zstddeclib.c zstddeclib-in.c
+```
+Then add the resulting file to your project (see the [example files](examples)).
+
+`create_single_file_decoder.sh` will run the above script, creating the file `zstddeclib.c` (`build_decoder_test.sh` will also create `zstddeclib.c`, then compile and test the result).
+
+Full Library
+------------
+
+The same tool can amalgamate the entire Zstd library for ease of adding both compression and decompression to a project. The [roundtrip example](examples/roundtrip.c) uses the original `zstd.h` with the remaining source files combined into `zstd.c` (currently just over 1.2MB) created from `zstd-in.c`. As with the standalone decoder the most useful compile flags have already been rolled-in and the resulting file can be added to a project as-is.
+
+Create `zstd.c` from the Zstd source using:
+```
+cd zstd/contrib/single_file_libs
+./combine.sh -r ../../lib -o zstd.c zstd-in.c
+```
+It's possible to create a compressor-only library but since the decompressor is so small in comparison this doesn't bring much of a gain (but for the curious, simply remove the files in the _decompress_ section at the end of `zstd-in.c`).
+
+`create_single_file_library.sh` will run the script to create `zstd.c` (`build_library_test.sh` will also create `zstd.c`, then compile and test the result).
diff --git a/src/zstd/contrib/single_file_libs/build_decoder_test.sh b/src/zstd/contrib/single_file_libs/build_decoder_test.sh
new file mode 100755
index 000000000..74e3f1c57
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/build_decoder_test.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# Temporary compiled binary
+OUT_FILE="tempbin"
+
+# Optional temporary compiled WebAssembly
+OUT_WASM="temp.wasm"
+
+# Amalgamate the sources
+./create_single_file_decoder.sh
+# Did combining work?
+if [ $? -ne 0 ]; then
+ echo "Single file decoder creation script: FAILED"
+ exit 1
+fi
+echo "Single file decoder creation script: PASSED"
+
+# Compile the generated output
+cc -Wall -Wextra -Werror -Os -g0 -o $OUT_FILE examples/simple.c
+# Did compilation work?
+if [ $? -ne 0 ]; then
+ echo "Compiling simple.c: FAILED"
+ exit 1
+fi
+echo "Compiling simple.c: PASSED"
+
+# Run then delete the compiled output
+./$OUT_FILE
+retVal=$?
+rm -f $OUT_FILE
+# Did the test work?
+if [ $retVal -ne 0 ]; then
+ echo "Running simple.c: FAILED"
+ exit 1
+fi
+echo "Running simple.c: PASSED"
+
+# Is Emscripten available?
+which emcc > /dev/null
+if [ $? -ne 0 ]; then
+ echo "(Skipping Emscripten test)"
+else
+ # Compile the Emscripten example
+ CC_FLAGS="-Wall -Wextra -Werror -Os -g0 -flto --llvm-lto 3 -lGL -DNDEBUG=1"
+ emcc $CC_FLAGS -s WASM=1 -o $OUT_WASM examples/emscripten.c
+ # Did compilation work?
+ if [ $? -ne 0 ]; then
+ echo "Compiling emscripten.c: FAILED"
+ exit 1
+ fi
+ echo "Compiling emscripten.c: PASSED"
+ rm -f $OUT_WASM
+fi
+
+exit 0
diff --git a/src/zstd/contrib/single_file_libs/build_library_test.sh b/src/zstd/contrib/single_file_libs/build_library_test.sh
new file mode 100755
index 000000000..3b8b16a05
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/build_library_test.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+# Where to find the sources (only used to copy zstd.h)
+ZSTD_SRC_ROOT="../../lib"
+
+# Temporary compiled binary
+OUT_FILE="tempbin"
+
+# Optional temporary compiled WebAssembly
+OUT_WASM="temp.wasm"
+
+# Amalgamate the sources
+./create_single_file_library.sh
+# Did combining work?
+if [ $? -ne 0 ]; then
+ echo "Single file library creation script: FAILED"
+ exit 1
+fi
+echo "Single file library creation script: PASSED"
+
+# Copy the header to here (for the tests)
+cp "$ZSTD_SRC_ROOT/zstd.h" zstd.h
+
+# Compile the generated output
+cc -Wall -Wextra -Werror -pthread -I. -Os -g0 -o $OUT_FILE zstd.c examples/roundtrip.c
+# Did compilation work?
+if [ $? -ne 0 ]; then
+ echo "Compiling roundtrip.c: FAILED"
+ exit 1
+fi
+echo "Compiling roundtrip.c: PASSED"
+
+# Run then delete the compiled output
+./$OUT_FILE
+retVal=$?
+rm -f $OUT_FILE
+# Did the test work?
+if [ $retVal -ne 0 ]; then
+ echo "Running roundtrip.c: FAILED"
+ exit 1
+fi
+echo "Running roundtrip.c: PASSED"
+
+# Is Emscripten available?
+which emcc > /dev/null
+if [ $? -ne 0 ]; then
+ echo "(Skipping Emscripten test)"
+else
+ # Compile the the same example as above
+ CC_FLAGS="-Wall -Wextra -Werror -Os -g0 -flto"
+ emcc $CC_FLAGS -s WASM=1 -I. -o $OUT_WASM zstd.c examples/roundtrip.c
+ # Did compilation work?
+ if [ $? -ne 0 ]; then
+ echo "Compiling emscripten.c: FAILED"
+ exit 1
+ fi
+ echo "Compiling emscripten.c: PASSED"
+ rm -f $OUT_WASM
+fi
+
+exit 0
diff --git a/src/zstd/contrib/single_file_libs/combine.sh b/src/zstd/contrib/single_file_libs/combine.sh
new file mode 100755
index 000000000..8eac4f9eb
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/combine.sh
@@ -0,0 +1,211 @@
+#!/bin/sh -e
+
+# Tool to bundle multiple C/C++ source files, inlining any includes.
+#
+# Note: this POSIX-compliant script is many times slower than the original bash
+# implementation (due to the grep calls) but it runs and works everywhere.
+#
+# TODO: ROOTS, FOUND, etc., as arrays (since they fail on paths with spaces)
+# TODO: revert to Bash-only regex (the grep ones being too slow)
+#
+# Author: Carl Woffenden, Numfum GmbH (this script is released under a CC0 license/Public Domain)
+
+# Common file roots
+ROOTS="."
+
+# -x option excluded includes
+XINCS=""
+
+# -k option includes to keep as include directives
+KINCS=""
+
+# Files previously visited
+FOUND=""
+
+# Optional destination file (empty string to write to stdout)
+DESTN=""
+
+# Whether the "#pragma once" directives should be written to the output
+PONCE=0
+
+# Prints the script usage then exits
+usage() {
+ echo "Usage: $0 [-r <path>] [-x <header>] [-k <header>] [-o <outfile>] infile"
+ echo " -r file root search path"
+ echo " -x file to completely exclude from inlining"
+ echo " -k file to exclude from inlining but keep the include directive"
+ echo " -p keep any '#pragma once' directives (removed by default)"
+ echo " -o output file (otherwise stdout)"
+ echo "Example: $0 -r ../my/path - r ../other/path -o out.c in.c"
+ exit 1
+}
+
+# Tests that the grep implementation works as expected (older OSX grep fails)
+test_deps() {
+ if ! echo '#include "foo"' | grep -Eq '^\s*#\s*include\s*".+"'; then
+ echo "Aborting: the grep implementation fails to parse include lines"
+ exit 1
+ fi
+ if ! echo '"foo.h"' | sed -E 's/"([^"]+)"/\1/' | grep -Eq '^foo\.h$'; then
+ echo "Aborting: sed is unavailable or non-functional"
+ exit 1
+ fi
+}
+
+# Tests if list $1 has item $2 (returning zero on a match)
+list_has_item() {
+ if echo "$1" | grep -Eq "(^|\s*)$2(\$|\s*)"; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Adds a new line with the supplied arguments to $DESTN (or stdout)
+write_line() {
+ if [ -n "$DESTN" ]; then
+ printf '%s\n' "$@" >> "$DESTN"
+ else
+ printf '%s\n' "$@"
+ fi
+}
+
+log_line() {
+ echo $@ >&2
+}
+
+# Find this file!
+resolve_include() {
+ local srcdir=$1
+ local inc=$2
+ for root in $srcdir $ROOTS; do
+ if [ -f "$root/$inc" ]; then
+ # Try to reduce the file path into a canonical form (so that multiple)
+ # includes of the same file are successfully deduplicated, even if they
+ # are expressed differently.
+ local relpath="$(realpath --relative-to . "$root/$inc" 2>/dev/null)"
+ if [ "$relpath" != "" ]; then # not all realpaths support --relative-to
+ echo "$relpath"
+ return 0
+ fi
+ local relpath="$(realpath "$root/$inc" 2>/dev/null)"
+ if [ "$relpath" != "" ]; then # not all distros have realpath...
+ echo "$relpath"
+ return 0
+ fi
+ # Fallback on Python to reduce the path if the above fails.
+ local relpath=$(python -c "import os,sys; print os.path.relpath(sys.argv[1])" "$root/$inc" 2>/dev/null)
+ if [ "$relpath" != "" ]; then # not all distros have realpath...
+ echo "$relpath"
+ return 0
+ fi
+ # Worst case, fall back to just the root + relative include path. The
+ # problem with this is that it is possible to emit multiple different
+ # resolved paths to the same file, depending on exactly how its included.
+ # Since the main loop below keeps a list of the resolved paths it's
+ # already included, in order to avoid repeated includes, this failure to
+ # produce a canonical/reduced path can lead to multiple inclusions of the
+ # same file. But it seems like the resulting single file library still
+ # works (hurray include guards!), so I guess it's ok.
+ echo "$root/$inc"
+ return 0
+ fi
+ done
+ return 1
+}
+
+# Adds the contents of $1 with any of its includes inlined
+add_file() {
+ local file=$1
+ if [ -n "$file" ]; then
+ log_line "Processing: $file"
+ # Get directory of the current so we can resolve relative includes
+ local srcdir="$(dirname "$file")"
+ # Read the file
+ local line=
+ while IFS= read -r line; do
+ if echo "$line" | grep -Eq '^\s*#\s*include\s*".+"'; then
+ # We have an include directive so strip the (first) file
+ local inc=$(echo "$line" | grep -Eo '".*"' | sed -E 's/"([^"]+)"/\1/' | head -1)
+ local res_inc="$(resolve_include "$srcdir" "$inc")"
+ if list_has_item "$XINCS" "$inc"; then
+ # The file was excluded so error if the source attempts to use it
+ write_line "#error Using excluded file: $inc"
+ log_line "Excluding: $inc"
+ else
+ if ! list_has_item "$FOUND" "$res_inc"; then
+ # The file was not previously encountered
+ FOUND="$FOUND $res_inc"
+ if list_has_item "$KINCS" "$inc"; then
+ # But the include was flagged to keep as included
+ write_line "/**** *NOT* inlining $inc ****/"
+ write_line "$line"
+ log_line "Not Inlining: $inc"
+ else
+ # The file was neither excluded nor seen before so inline it
+ write_line "/**** start inlining $inc ****/"
+ add_file "$res_inc"
+ write_line "/**** ended inlining $inc ****/"
+ fi
+ else
+ write_line "/**** skipping file: $inc ****/"
+ fi
+ fi
+ else
+ # Skip any 'pragma once' directives, otherwise write the source line
+ local write=$PONCE
+ if [ $write -eq 0 ]; then
+ if echo "$line" | grep -Eqv '^\s*#\s*pragma\s*once\s*'; then
+ write=1
+ fi
+ fi
+ if [ $write -ne 0 ]; then
+ write_line "$line"
+ fi
+ fi
+ done < "$file"
+ else
+ write_line "#error Unable to find \"$1\""
+ log_line "Error: Unable to find: \"$1\""
+ fi
+}
+
+while getopts ":r:x:k:po:" opts; do
+ case $opts in
+ r)
+ ROOTS="$ROOTS $OPTARG"
+ ;;
+ x)
+ XINCS="$XINCS $OPTARG"
+ ;;
+ k)
+ KINCS="$KINCS $OPTARG"
+ ;;
+ p)
+ PONCE=1
+ ;;
+ o)
+ DESTN="$OPTARG"
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+shift $((OPTIND-1))
+
+if [ -n "$1" ]; then
+ if [ -f "$1" ]; then
+ if [ -n "$DESTN" ]; then
+ printf "" > "$DESTN"
+ fi
+ test_deps
+ add_file "$1"
+ else
+ echo "Input file not found: \"$1\""
+ exit 1
+ fi
+else
+ usage
+fi
+exit 0
diff --git a/src/zstd/contrib/single_file_libs/create_single_file_decoder.sh b/src/zstd/contrib/single_file_libs/create_single_file_decoder.sh
new file mode 100755
index 000000000..b5f5613ae
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/create_single_file_decoder.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Where to find the sources
+ZSTD_SRC_ROOT="../../lib"
+
+# Amalgamate the sources
+echo "Amalgamating files... this can take a while"
+./combine.sh -r "$ZSTD_SRC_ROOT" -o zstddeclib.c zstddeclib-in.c
+# Did combining work?
+if [ $? -ne 0 ]; then
+ echo "Combine script: FAILED"
+ exit 1
+fi
+echo "Combine script: PASSED"
diff --git a/src/zstd/contrib/single_file_libs/create_single_file_library.sh b/src/zstd/contrib/single_file_libs/create_single_file_library.sh
new file mode 100755
index 000000000..6f38526d5
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/create_single_file_library.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Where to find the sources
+ZSTD_SRC_ROOT="../../lib"
+
+# Amalgamate the sources
+echo "Amalgamating files... this can take a while"
+./combine.sh -r "$ZSTD_SRC_ROOT" -o zstd.c zstd-in.c
+# Did combining work?
+if [ $? -ne 0 ]; then
+ echo "Combine script: FAILED"
+ exit 1
+fi
+echo "Combine script: PASSED"
diff --git a/src/zstd/contrib/single_file_libs/examples/README.md b/src/zstd/contrib/single_file_libs/examples/README.md
new file mode 100644
index 000000000..e93bee35f
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/examples/README.md
@@ -0,0 +1,11 @@
+# Single File ZStandard Examples
+
+The examples `#include` the generated `zstddeclib.c` directly but work equally as well when including `zstd.h` and compiling the amalgamated source separately.
+
+`simple.c` is the most basic example of decompressing content and verifying the result.
+
+`emscripten.c` is a bare-bones [Emscripten](https://github.com/emscripten-core/emscripten) compiled WebGL demo using Zstd to further compress a DXT1 texture (see the [original PNG image](testcard.png)). The 256x256 texture would normally be 32kB, but even when bundled with the Zstd decompressor the resulting WebAssembly weighs in at 41kB (`shell.html` is a support file to run the Wasm).
+
+`roundtrip.c` is an example to use with the optional [amalgamated library](../create_single_file_library.sh) showing compression the decompression.
+
+The example files in this directory are released under a [Creative Commons Zero license](https://creativecommons.org/publicdomain/zero/1.0/) (or Public Domain, whichever is applicable in your jurisdiction).
diff --git a/src/zstd/contrib/single_file_libs/examples/emscripten.c b/src/zstd/contrib/single_file_libs/examples/emscripten.c
new file mode 100644
index 000000000..10dae8689
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/examples/emscripten.c
@@ -0,0 +1,340 @@
+/**
+ * \file emscripten.c
+ * Emscripten example of using the single-file \c zstddeclib. Draws a rotating
+ * textured quad with data from the in-line Zstd compressed DXT1 texture (DXT1
+ * being hardware compression, further compressed with Zstd).
+ * \n
+ * Compile using:
+ * \code
+ * export CC_FLAGS="-Wall -Wextra -Werror -Os -g0 -flto --llvm-lto 3 -lGL -DNDEBUG=1"
+ * export EM_FLAGS="-s WASM=1 -s ENVIRONMENT=web --shell-file shell.html --closure 1"
+ * emcc $CC_FLAGS $EM_FLAGS -o out.html emscripten.c
+ * \endcode
+ *
+ * \author Carl Woffenden, Numfum GmbH (released under a CC0 license)
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <emscripten/emscripten.h>
+#include <emscripten/html5.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "../zstddeclib.c"
+
+//************************* Test Data (DXT texture) **************************/
+
+/**
+ * Zstd compressed DXT1 256x256 texture source.
+ * \n
+ * See \c testcard.png for the original.
+ */
+static uint8_t const srcZstd[] = {
+#include "testcard-zstd.inl"
+};
+
+/**
+ * Uncompressed size of \c #srcZstd.
+ */
+#define DXT1_256x256 32768
+
+/**
+ * Destination for decoding \c #srcZstd.
+ */
+static uint8_t dstDxt1[DXT1_256x256] = {};
+
+#ifndef ZSTD_VERSION_MAJOR
+/**
+ * For the case where the decompression library hasn't been included we add a
+ * dummy function to fake the process and stop the buffers being optimised out.
+ */
+size_t ZSTD_decompress(void* dst, size_t dstLen, const void* src, size_t srcLen) {
+ return (memcmp(dst, src, (srcLen < dstLen) ? srcLen : dstLen)) ? dstLen : 0;
+}
+#endif
+
+//*************************** Program and Shaders ***************************/
+
+/**
+ * Program object ID.
+ */
+static GLuint progId = 0;
+
+/**
+ * Vertex shader ID.
+ */
+static GLuint vertId = 0;
+
+/**
+ * Fragment shader ID.
+ */
+static GLuint fragId = 0;
+
+//********************************* Uniforms *********************************/
+
+/**
+ * Quad rotation angle ID.
+ */
+static GLint uRotId = -1;
+
+/**
+ * Draw colour ID.
+ */
+static GLint uTx0Id = -1;
+
+//******************************* Shader Source ******************************/
+
+/**
+ * Vertex shader to draw texture mapped polys with an applied rotation.
+ */
+static GLchar const vertShader2D[] =
+#if GL_ES_VERSION_2_0
+ "#version 100\n"
+ "precision mediump float;\n"
+#else
+ "#version 120\n"
+#endif
+ "uniform float uRot;" // rotation
+ "attribute vec2 aPos;" // vertex position coords
+ "attribute vec2 aUV0;" // vertex texture UV0
+ "varying vec2 vUV0;" // (passed to fragment shader)
+ "void main() {"
+ " float cosA = cos(radians(uRot));"
+ " float sinA = sin(radians(uRot));"
+ " mat3 rot = mat3(cosA, -sinA, 0.0,"
+ " sinA, cosA, 0.0,"
+ " 0.0, 0.0, 1.0);"
+ " gl_Position = vec4(rot * vec3(aPos, 1.0), 1.0);"
+ " vUV0 = aUV0;"
+ "}";
+
+/**
+ * Fragment shader for the above polys.
+ */
+static GLchar const fragShader2D[] =
+#if GL_ES_VERSION_2_0
+ "#version 100\n"
+ "precision mediump float;\n"
+#else
+ "#version 120\n"
+#endif
+ "uniform sampler2D uTx0;"
+ "varying vec2 vUV0;" // (passed from fragment shader)
+ "void main() {"
+ " gl_FragColor = texture2D(uTx0, vUV0);"
+ "}";
+
+/**
+ * Helper to compile a shader.
+ *
+ * \param type shader type
+ * \param text shader source
+ * \return the shader ID (or zero if compilation failed)
+ */
+static GLuint compileShader(GLenum const type, const GLchar* text) {
+ GLuint shader = glCreateShader(type);
+ if (shader) {
+ glShaderSource (shader, 1, &text, NULL);
+ glCompileShader(shader);
+ GLint compiled;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (compiled) {
+ return shader;
+ } else {
+ GLint logLen;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen);
+ if (logLen > 1) {
+ GLchar* logStr = malloc(logLen);
+ glGetShaderInfoLog(shader, logLen, NULL, logStr);
+ #ifndef NDEBUG
+ printf("Shader compilation error: %s\n", logStr);
+ #endif
+ free(logStr);
+ }
+ glDeleteShader(shader);
+ }
+ }
+ return 0;
+}
+
+//********************************** Helpers *********************************/
+
+/**
+ * Vertex position index.
+ */
+#define GL_VERT_POSXY_ID 0
+
+/**
+ * Vertex UV0 index.
+ */
+#define GL_VERT_TXUV0_ID 1
+
+ /**
+ * \c GL vec2 storage type.
+ */
+struct vec2 {
+ float x;
+ float y;
+};
+
+/**
+ * Combined 2D vertex and 2D texture coordinates.
+ */
+struct posTex2d {
+ struct vec2 pos;
+ struct vec2 uv0;
+};
+
+//****************************************************************************/
+
+/**
+ * Current quad rotation angle (in degrees, updated per frame).
+ */
+static float rotDeg = 0.0f;
+
+/**
+ * Emscripten (single) GL context.
+ */
+static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE glCtx = 0;
+
+/**
+ * Emscripten resize handler.
+ */
+static EM_BOOL resize(int type, const EmscriptenUiEvent* e, void* data) {
+ double surfaceW;
+ double surfaceH;
+ if (emscripten_get_element_css_size ("#canvas", &surfaceW, &surfaceH) == EMSCRIPTEN_RESULT_SUCCESS) {
+ emscripten_set_canvas_element_size("#canvas", surfaceW, surfaceH);
+ if (glCtx) {
+ glViewport(0, 0, (int) surfaceW, (int) surfaceH);
+ }
+ }
+ (void) type;
+ (void) data;
+ (void) e;
+ return EM_FALSE;
+}
+
+/**
+ * Boilerplate to create a WebGL context.
+ */
+static EM_BOOL initContext() {
+ // Default attributes
+ EmscriptenWebGLContextAttributes attr;
+ emscripten_webgl_init_context_attributes(&attr);
+ if ((glCtx = emscripten_webgl_create_context("#canvas", &attr))) {
+ // Bind the context and fire a resize to get the initial size
+ emscripten_webgl_make_context_current(glCtx);
+ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, resize);
+ resize(0, NULL, NULL);
+ return EM_TRUE;
+ }
+ return EM_FALSE;
+}
+
+/**
+ * Called once per frame (clears the screen and draws the rotating quad).
+ */
+static void tick() {
+ glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (uRotId >= 0) {
+ glUniform1f(uRotId, rotDeg);
+ rotDeg += 0.1f;
+ if (rotDeg >= 360.0f) {
+ rotDeg -= 360.0f;
+ }
+ }
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
+ glFlush();
+}
+
+/**
+ * Creates the GL context, shaders and quad data, decompresses the Zstd data
+ * and 'uploads' the resulting texture.
+ *
+ * As a (naive) comparison, removing Zstd and building with "-Os -g0 s WASM=1
+ * -lGL emscripten.c" results in a 15kB WebAssembly file; re-adding Zstd
+ * increases the Wasm by 26kB.
+ */
+int main() {
+ if (initContext()) {
+ // Compile shaders and set the initial GL state
+ if ((progId = glCreateProgram())) {
+ vertId = compileShader(GL_VERTEX_SHADER, vertShader2D);
+ fragId = compileShader(GL_FRAGMENT_SHADER, fragShader2D);
+
+ glBindAttribLocation(progId, GL_VERT_POSXY_ID, "aPos");
+ glBindAttribLocation(progId, GL_VERT_TXUV0_ID, "aUV0");
+
+ glAttachShader(progId, vertId);
+ glAttachShader(progId, fragId);
+ glLinkProgram (progId);
+ glUseProgram (progId);
+ uRotId = glGetUniformLocation(progId, "uRot");
+ uTx0Id = glGetUniformLocation(progId, "uTx0");
+ if (uTx0Id >= 0) {
+ glUniform1i(uTx0Id, 0);
+ }
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glDisable(GL_DITHER);
+
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ }
+
+ GLuint vertsBuf = 0;
+ GLuint indexBuf = 0;
+ GLuint txName = 0;
+ // Create the textured quad (vert positions then UVs)
+ struct posTex2d verts2d[] = {
+ {{-0.85f, -0.85f}, {0.0f, 0.0f}}, // BL
+ {{ 0.85f, -0.85f}, {1.0f, 0.0f}}, // BR
+ {{-0.85f, 0.85f}, {0.0f, 1.0f}}, // TL
+ {{ 0.85f, 0.85f}, {1.0f, 1.0f}}, // TR
+ };
+ uint16_t index2d[] = {
+ 0, 1, 2,
+ 2, 1, 3,
+ };
+ glGenBuffers(1, &vertsBuf);
+ glBindBuffer(GL_ARRAY_BUFFER, vertsBuf);
+ glBufferData(GL_ARRAY_BUFFER,
+ sizeof(verts2d), verts2d, GL_STATIC_DRAW);
+ glVertexAttribPointer(GL_VERT_POSXY_ID, 2,
+ GL_FLOAT, GL_FALSE, sizeof(struct posTex2d), 0);
+ glVertexAttribPointer(GL_VERT_TXUV0_ID, 2,
+ GL_FLOAT, GL_FALSE, sizeof(struct posTex2d),
+ (void*) offsetof(struct posTex2d, uv0));
+ glGenBuffers(1, &indexBuf);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ sizeof(index2d), index2d, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(GL_VERT_POSXY_ID);
+ glEnableVertexAttribArray(GL_VERT_TXUV0_ID);
+
+ // Decode the Zstd data and create the texture
+ if (ZSTD_decompress(dstDxt1, DXT1_256x256, srcZstd, sizeof srcZstd) == DXT1_256x256) {
+ glGenTextures(1, &txName);
+ glBindTexture(GL_TEXTURE_2D, txName);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+ 256, 256, 0, DXT1_256x256, dstDxt1);
+ } else {
+ printf("Failed to decode Zstd data\n");
+ }
+ emscripten_set_main_loop(tick, 0, EM_FALSE);
+ emscripten_exit_with_live_runtime();
+ }
+ return EXIT_FAILURE;
+}
diff --git a/src/zstd/contrib/single_file_libs/examples/roundtrip.c b/src/zstd/contrib/single_file_libs/examples/roundtrip.c
new file mode 100644
index 000000000..b228de88e
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/examples/roundtrip.c
@@ -0,0 +1,83 @@
+/*
+ * \file roundtrip.c
+ * In this example we include \c zstd.h and compile separately the amalgamated
+ * \c zstd.c:
+ * \code
+ * cc -Wall -Wextra -Werror -I. -Os -g0 zstd.c examples/roundtrip.c
+ * \endcode
+ *
+ * \author Carl Woffenden, Numfum GmbH (released under a CC0 license)
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zstd.h"
+
+//************************** Test Data (DXT texture) **************************/
+
+/**
+ * Raw test data (borrowed from the Emscripten example).
+ * \n
+ * See \c testcard.png for the original.
+ */
+static uint8_t const rawData[] = {
+#include "testcard-dxt1.inl"
+};
+
+#ifndef ZSTD_VERSION_MAJOR
+/*
+ * For the case where the decompression library hasn't been included we add
+ * dummy functions to fake the process and stop the buffers being optimised out.
+ */
+size_t ZSTD_compressBound(size_t maxSrc) {
+ return maxSrc + 32;
+}
+int ZSTD_maxCLevel(void) {
+ return 20;
+}
+size_t ZSTD_compress(void* dst, size_t dstLen, const void* src, size_t srcLen, int level) {
+ return (memcmp(dst, src, (srcLen < dstLen) ? srcLen : dstLen)) ? level : dstLen;
+}
+unsigned ZSTD_isError(size_t code) {
+ return ((int) code) < 0;
+}
+size_t ZSTD_decompress(void* dst, size_t dstLen, const void* src, size_t srcLen) {
+ return (memcmp(dst, src, (srcLen < dstLen) ? srcLen : dstLen)) ? 0 : dstLen;
+}
+#endif
+
+//*****************************************************************************/
+
+/**
+ * Simple single-file test to compress \c rawData, decompress the result, then
+ * compare the decompressed version with the original.
+ */
+int main() {
+ size_t bounds = ZSTD_compressBound(sizeof rawData);
+ void* compBuf = malloc(bounds);
+ void* testBuf = malloc(sizeof rawData);
+ int compare = -1;
+ if (compBuf && testBuf) {
+ size_t compSize = ZSTD_compress(compBuf, bounds, rawData, sizeof rawData, ZSTD_maxCLevel());
+ if (!ZSTD_isError(compSize)) {
+ printf("Compression: PASSED (size: %lu, uncompressed: %lu)\n", (unsigned long) compSize, (unsigned long) (sizeof rawData));
+ size_t decSize = ZSTD_decompress(testBuf, sizeof rawData, compBuf, compSize);
+ if (!ZSTD_isError(decSize)) {
+ printf("Decompression: PASSED\n");
+ compare = memcmp(rawData, testBuf, decSize);
+ printf("Byte comparison: %s\n", (compare == 0) ? "PASSED" : "FAILED");
+ } else {
+ printf("Decompression: FAILED\n");
+ }
+ } else {
+ printf("Compression: FAILED\n");
+ }
+ free(compBuf);
+ free(testBuf);
+ }
+ return (compare == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/zstd/contrib/single_file_libs/examples/shell.html b/src/zstd/contrib/single_file_libs/examples/shell.html
new file mode 100644
index 000000000..5beb0e6d5
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/examples/shell.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
+ <meta name="apple-mobile-web-app-capable" content="yes" />
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
+ <title>Emscripten Shell</title>
+ <style>
+body {background:#333; font-family:"Verdana","Helvetica Neue","Helvetica","Arial",sans-serif; margin:1em 0;}
+#canvas{position:absolute; top:0px; left:0px; border:none; margin:0; width: 100%; height: 100%; overflow: hidden; display: block;}
+ </style>
+</head>
+<body>
+ <canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+ <script>
+function trace(msg) {
+ console.log(msg);
+}
+
+var Module = {
+ print: trace, printErr: trace, setStatus: trace, monitorRunDependencies: trace,
+ canvas: (function() {
+ return document.getElementById("canvas");
+ })(),
+ preRun: [], postRun: [],
+};
+</script>
+{{{ SCRIPT }}}
+</body>
+</html>
diff --git a/src/zstd/contrib/single_file_libs/examples/simple.c b/src/zstd/contrib/single_file_libs/examples/simple.c
new file mode 100644
index 000000000..ee63416a6
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/examples/simple.c
@@ -0,0 +1,75 @@
+/**
+ * \file simple.c
+ * Simple standalone example of using the single-file \c zstddeclib.
+ *
+ * \note In this simple example we include the amalgamated source and compile
+ * just this single file, but we could equally (and more conventionally)
+ * include \c zstd.h and compile both this file and \c zstddeclib.c (the
+ * resulting binaries differ slightly in size but perform the same).
+ *
+ * \author Carl Woffenden, Numfum GmbH (released under a CC0 license)
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../zstddeclib.c"
+
+//************************* Test Data (DXT texture) **************************/
+
+/**
+ * Raw 256x256 DXT1 data (used to compare the result).
+ * \n
+ * See \c testcard.png for the original.
+ */
+static uint8_t const rawDxt1[] = {
+#include "testcard-dxt1.inl"
+};
+
+/**
+ * Zstd compressed version of \c #rawDxt1.
+ * \n
+ * See \c testcard.png for the original.
+ */
+static uint8_t const srcZstd[] = {
+#include "testcard-zstd.inl"
+};
+
+/**
+ * Destination for decoding \c #srcZstd.
+ */
+static uint8_t dstDxt1[sizeof rawDxt1] = {};
+
+#ifndef ZSTD_VERSION_MAJOR
+/**
+ * For the case where the decompression library hasn't been included we add a
+ * dummy function to fake the process and stop the buffers being optimised out.
+ */
+size_t ZSTD_decompress(void* dst, size_t dstLen, const void* src, size_t srcLen) {
+ return (memcmp(dst, src, (srcLen < dstLen) ? srcLen : dstLen)) ? 0 : dstLen;
+}
+#endif
+
+//****************************************************************************/
+
+/**
+ * Simple single-file test to decompress \c #srcZstd into \c # dstDxt1 then
+ * compare the resulting bytes with \c #rawDxt1.
+ * \n
+ * As a (naive) comparison, removing Zstd and building with "-Os -g0 simple.c"
+ * results in a 44kB binary (macOS 10.14, Clang 10); re-adding Zstd increases
+ * the binary by 56kB (after calling \c strip).
+ */
+int main() {
+ size_t size = ZSTD_decompress(dstDxt1, sizeof dstDxt1, srcZstd, sizeof srcZstd);
+ int compare = memcmp(rawDxt1, dstDxt1, sizeof dstDxt1);
+ printf("Decompressed size: %s\n", (size == sizeof dstDxt1) ? "PASSED" : "FAILED");
+ printf("Byte comparison: %s\n", (compare == 0) ? "PASSED" : "FAILED");
+ if (size == sizeof dstDxt1 && compare == 0) {
+ return EXIT_SUCCESS;
+ }
+ return EXIT_FAILURE;
+}
diff --git a/src/zstd/contrib/single_file_libs/examples/testcard-dxt1.inl b/src/zstd/contrib/single_file_libs/examples/testcard-dxt1.inl
new file mode 100644
index 000000000..e099e66fc
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/examples/testcard-dxt1.inl
@@ -0,0 +1,2731 @@
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0x30, 0x84, 0x00, 0x55, 0x55, 0xb5,
+0xde, 0xf7, 0x30, 0x84, 0x00, 0x15, 0x35, 0x20, 0xdf, 0xff, 0x30, 0x84,
+0x00, 0xd4, 0x80, 0x54, 0xde, 0xf7, 0x30, 0x84, 0x00, 0x2b, 0x7e, 0x55,
+0xde, 0xf7, 0x10, 0x84, 0x00, 0xa0, 0x55, 0x55, 0xdf, 0xff, 0xe7, 0x39,
+0x00, 0x2a, 0x3f, 0x3f, 0x82, 0x10, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0xff, 0xff, 0x28, 0x42, 0x00, 0xff, 0xff, 0xff, 0x41, 0x08, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0x8a, 0x52, 0x00, 0x3f, 0x3f, 0x3f,
+0xff, 0xff, 0x08, 0x42, 0x00, 0xa8, 0xfc, 0xfc, 0xde, 0xf7, 0x30, 0x84,
+0x00, 0x02, 0x55, 0x55, 0xff, 0xff, 0x10, 0x84, 0x00, 0xfa, 0xaf, 0x55,
+0xdf, 0xff, 0x30, 0x84, 0x00, 0x15, 0x20, 0x35, 0xde, 0xf7, 0x30, 0x84,
+0x00, 0x54, 0x54, 0x80, 0xff, 0xff, 0x30, 0x84, 0x00, 0x55, 0x55, 0x57,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x10, 0x84, 0x15, 0x15, 0x15, 0x2d, 0xff, 0xff, 0x30, 0x84,
+0x54, 0xd4, 0x88, 0x5c, 0xff, 0xff, 0x10, 0x84, 0xb5, 0xe2, 0x57, 0x55,
+0x7d, 0xef, 0x30, 0x84, 0xe0, 0x55, 0x55, 0x55, 0x41, 0x08, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x30, 0x84, 0xd4, 0x54, 0x54, 0x54,
+0x9d, 0xef, 0x30, 0x84, 0x82, 0xd5, 0x55, 0x55, 0xff, 0xff, 0x10, 0x84,
+0x57, 0xe2, 0xb5, 0x55, 0xff, 0xff, 0x30, 0x84, 0x15, 0x15, 0x38, 0x2d,
+0xff, 0xff, 0x10, 0x84, 0x54, 0x54, 0x54, 0x5c, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x41, 0x08, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0x9e, 0xf7, 0x10, 0x84, 0x55, 0x55, 0x35, 0xe2,
+0x5c, 0xe7, 0x10, 0x84, 0xb5, 0x83, 0x5c, 0x55, 0xff, 0xff, 0x30, 0x84,
+0x38, 0x15, 0x15, 0x15, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xf7, 0x30, 0x84,
+0x88, 0x94, 0x54, 0x54, 0x5c, 0xe7, 0x10, 0x84, 0x57, 0x70, 0x0d, 0xd5,
+0xbe, 0xf7, 0x30, 0x84, 0x55, 0x55, 0x57, 0x62, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0xff, 0xff, 0x08, 0x42,
+0x3f, 0x3f, 0x2f, 0x00, 0x51, 0x8c, 0xdf, 0xff, 0x61, 0x25, 0x01, 0x55,
+0xff, 0xff, 0x49, 0x4a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0xff, 0xff, 0x69, 0x4a,
+0x2f, 0xff, 0xff, 0x00, 0x51, 0x8c, 0xff, 0xff, 0x42, 0x66, 0x60, 0x55,
+0xff, 0xff, 0x28, 0x42, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0x99, 0xff, 0x00, 0x5a,
+0xff, 0xff, 0xff, 0xff, 0x99, 0xff, 0x00, 0x5a, 0xff, 0xff, 0xff, 0xff,
+0x99, 0xff, 0x00, 0x5a, 0xff, 0xff, 0xff, 0xff, 0x99, 0xff, 0x00, 0x5a,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0xde, 0xf7, 0x10, 0x84, 0x00, 0x55, 0xd5, 0x25, 0xbe, 0xf7, 0x30, 0x84,
+0x00, 0xc9, 0x58, 0x57, 0xff, 0xff, 0x08, 0x42, 0x00, 0x3f, 0x3f, 0x3f,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x42,
+0x00, 0xbc, 0xfc, 0xfc, 0xbe, 0xf7, 0x10, 0x84, 0x00, 0x58, 0xc9, 0x35,
+0xff, 0xff, 0x10, 0x84, 0x00, 0x55, 0x55, 0x56, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xf6, 0xff, 0xc1, 0x59, 0xff, 0xff, 0xff, 0xff,
+0xf6, 0xff, 0xc1, 0x59, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xc1, 0x59,
+0xff, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xc1, 0x59, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x99, 0xff, 0x00, 0x5a, 0xff, 0xff, 0xff, 0xff,
+0x99, 0xff, 0x00, 0x5a, 0xff, 0xff, 0xff, 0xff, 0x99, 0xff, 0x00, 0x5a,
+0xff, 0xff, 0xff, 0xff, 0xe9, 0x93, 0xc7, 0x8b, 0xaa, 0xaa, 0xaa, 0x2a,
+0xbe, 0xf7, 0x10, 0x84, 0x54, 0x94, 0x8c, 0x70, 0x7d, 0xef, 0x10, 0x84,
+0x63, 0x5c, 0x55, 0x55, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0x71, 0x8c, 0xcf, 0x7b, 0xbf, 0xff, 0xff, 0xff, 0x9d, 0xef, 0x10, 0x84,
+0x72, 0x8d, 0x95, 0x55, 0xbe, 0xf7, 0x10, 0x84, 0x15, 0x15, 0x1c, 0x23,
+0xf6, 0xff, 0xc1, 0x59, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xc1, 0x59,
+0xff, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xc1, 0x59, 0xff, 0xff, 0xff, 0xff,
+0xf6, 0xff, 0xc1, 0x59, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0x99, 0xff, 0x00, 0x5a, 0xff, 0xff, 0xff, 0xff, 0x99, 0xff, 0x00, 0x5a,
+0xff, 0xff, 0xff, 0xff, 0x56, 0xd6, 0xa1, 0x72, 0xff, 0xff, 0xff, 0x3f,
+0x5c, 0xef, 0x2a, 0x94, 0x15, 0x8d, 0x73, 0x54, 0x41, 0x08, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x30, 0x84, 0x25, 0x15, 0x15, 0x15, 0x7c, 0xf7, 0x09, 0x94,
+0x55, 0x5c, 0x73, 0x85, 0x09, 0x94, 0xa7, 0x8b, 0xff, 0xff, 0xff, 0xfe,
+0xf6, 0xff, 0xc1, 0x59, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xc1, 0x59,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0x99, 0xff, 0x00, 0x5a,
+0xff, 0xff, 0xff, 0xff, 0x7c, 0xf7, 0xc8, 0x8b, 0x55, 0x55, 0xd5, 0x35,
+0x3b, 0xef, 0x09, 0x94, 0x05, 0x61, 0x58, 0x57, 0x2a, 0x9c, 0xc7, 0x8b,
+0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xf9, 0xe6, 0x60, 0x6a, 0x3f, 0xff, 0xff, 0xff,
+0x9d, 0xf7, 0x09, 0x94, 0x56, 0x52, 0x49, 0x35, 0xc2, 0x72, 0xce, 0xac,
+0xaa, 0xaa, 0xaa, 0xa9, 0xf6, 0xff, 0xc1, 0x59, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x10, 0x84, 0x00, 0x54, 0xd4, 0x34,
+0xde, 0xf7, 0xef, 0x7b, 0x00, 0x73, 0x5c, 0x57, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0xde, 0xf7, 0xef, 0x7b, 0x00, 0x73, 0xcd, 0x35,
+0xff, 0xff, 0x10, 0x84, 0x00, 0x15, 0x15, 0x17, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x5d, 0xf7, 0xef, 0xaa, 0x55, 0x55, 0xd5, 0x35,
+0xde, 0xf7, 0xef, 0x7b, 0xcc, 0x70, 0x5c, 0x54, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x2c, 0x63, 0xd3, 0x9c, 0x6a, 0xaa, 0xaa, 0xaa, 0xde, 0xf7, 0xef, 0x7b,
+0x1c, 0x33, 0x0d, 0x35, 0xd4, 0x62, 0x57, 0x94, 0xaa, 0xaa, 0xaa, 0xa9,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xd8, 0xdd, 0xcb, 0x99, 0xff, 0xff, 0xff, 0x3f,
+0xdb, 0xee, 0x30, 0xb3, 0x85, 0x61, 0x50, 0x54, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x1d, 0xe7, 0xb6, 0x83, 0x54, 0x52, 0x41, 0x85, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x30, 0xb3, 0x0f, 0xb3, 0xff, 0xff, 0xff, 0xbf,
+0x9e, 0xf7, 0x30, 0xb3, 0x35, 0xcd, 0x71, 0x5a, 0xf2, 0xbb, 0xae, 0xaa,
+0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff,
+0x76, 0xfe, 0x01, 0xd8, 0xff, 0xff, 0xff, 0xff, 0x76, 0xfe, 0x01, 0xd8,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xf7, 0x81, 0xf7, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x5e, 0xef, 0x96, 0x7b,
+0x15, 0xd5, 0x55, 0x55, 0x9e, 0xf7, 0xb6, 0x7b, 0x57, 0x5c, 0x53, 0x69,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0x7d, 0xf7, 0x2f, 0xb3, 0x95, 0x35, 0xc5, 0x69, 0xdb, 0xee, 0x0f, 0xb3,
+0x54, 0x57, 0x55, 0x55, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0x5e, 0xef, 0xf2, 0x49, 0x8f, 0x3f, 0xbf, 0xff, 0x7e, 0xef, 0x96, 0x7b,
+0x55, 0x57, 0x54, 0x5a, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x7d, 0xf7, 0x2f, 0xb3, 0x55, 0x55, 0x95, 0x35, 0x7d, 0xf7, 0x30, 0xb3,
+0x53, 0x5c, 0x56, 0x55, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x7e, 0xef, 0xb6, 0x83, 0x71, 0x4d, 0xa5, 0x15,
+0x73, 0x5a, 0xb8, 0x9c, 0xaa, 0xaa, 0xaa, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xfc, 0xee, 0x70, 0xb3,
+0xc5, 0x49, 0x51, 0x58, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0x19, 0xa5, 0xaf, 0x28, 0x2a, 0xaa, 0xaa, 0xaa, 0x1d, 0xe7, 0xd6, 0x83,
+0x54, 0x58, 0x51, 0x49, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0xff, 0xff, 0x10, 0x84,
+0x15, 0x15, 0x35, 0x00, 0x9e, 0xf7, 0x30, 0xb3, 0x54, 0x57, 0x55, 0x55,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x41, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x41, 0x08, 0x00, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x3d, 0xe7, 0xb6, 0x7b, 0xc5, 0x35, 0x15, 0xd5,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0x08, 0x42,
+0x00, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x71, 0x8c, 0x00, 0x11, 0x1b, 0x14,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x1f, 0x62, 0x1e, 0x5a, 0xea, 0xaa, 0xaa, 0xea,
+0x1f, 0x62, 0xfd, 0x59, 0xfe, 0xfa, 0xfe, 0xfe, 0x1e, 0x5a, 0xfd, 0x59,
+0x5f, 0x57, 0x57, 0x57, 0xfd, 0x59, 0xdb, 0x51, 0xfa, 0xfa, 0xfa, 0xfa,
+0xfc, 0x51, 0xba, 0x51, 0xfe, 0xfe, 0xfa, 0xfe, 0xda, 0x51, 0x99, 0x49,
+0xea, 0xea, 0xe8, 0xea, 0xb9, 0x51, 0x98, 0x49, 0x7e, 0x7e, 0x7e, 0x7e,
+0x97, 0x49, 0x76, 0x41, 0xe8, 0xe8, 0xe8, 0xe8, 0x97, 0x49, 0x75, 0x41,
+0x5f, 0x5f, 0x5f, 0x5f, 0x75, 0x41, 0x32, 0x39, 0xea, 0xea, 0xea, 0xea,
+0x53, 0x39, 0x32, 0x39, 0x7e, 0x7e, 0x5e, 0x7e, 0x31, 0x39, 0x10, 0x31,
+0xfa, 0xfa, 0x78, 0x7a, 0x0f, 0x31, 0xcd, 0x28, 0xa0, 0x80, 0x80, 0x80,
+0xee, 0x30, 0xed, 0x28, 0x5e, 0x7e, 0x5e, 0x5e, 0xcc, 0x28, 0xaa, 0x20,
+0xa0, 0xa0, 0xa0, 0xa0, 0xcc, 0x28, 0xaa, 0x20, 0x5f, 0x5f, 0x5f, 0x5f,
+0xaa, 0x20, 0x88, 0x18, 0xfa, 0xfa, 0xfa, 0xfa, 0x88, 0x18, 0x66, 0x18,
+0xe8, 0xe8, 0xe8, 0xe8, 0x87, 0x18, 0x45, 0x10, 0xfa, 0xfa, 0xfa, 0xfa,
+0x66, 0x10, 0x44, 0x10, 0x7e, 0x7e, 0x7e, 0x7e, 0x44, 0x10, 0x22, 0x08,
+0xa8, 0xe8, 0xa8, 0xe8, 0x44, 0x10, 0x22, 0x08, 0x5f, 0x7f, 0x7f, 0x7f,
+0x22, 0x08, 0x01, 0x08, 0xea, 0xfa, 0xfa, 0xea, 0x01, 0x08, 0x00, 0x00,
+0xaa, 0xea, 0xaa, 0xaa, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x51, 0x8c,
+0x00, 0x50, 0x78, 0x44, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x3c, 0xe7, 0x69, 0x4a, 0xbf, 0x3f, 0x2f, 0x8f,
+0xff, 0xff, 0xef, 0x7b, 0x16, 0x17, 0x15, 0x15, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x1f, 0x62, 0x1e, 0x5a, 0xaa, 0xea, 0xaa, 0xea, 0x1f, 0x62, 0xfd, 0x59,
+0xfe, 0xfe, 0xfe, 0xfe, 0x1e, 0x5a, 0xfd, 0x59, 0x57, 0x57, 0x57, 0x57,
+0xfd, 0x59, 0xdb, 0x51, 0xfa, 0xfa, 0xfa, 0xfa, 0xdb, 0x51, 0xb9, 0x51,
+0xa0, 0xa0, 0xa0, 0x80, 0xba, 0x51, 0xb9, 0x49, 0xe8, 0xe8, 0xe8, 0xe8,
+0xda, 0x51, 0x98, 0x49, 0x5f, 0x7f, 0x7f, 0x5f, 0x97, 0x49, 0x76, 0x41,
+0xe8, 0xe8, 0xe8, 0xe0, 0x97, 0x49, 0x75, 0x41, 0x57, 0x57, 0x5f, 0x5f,
+0x75, 0x41, 0x32, 0x39, 0xea, 0xea, 0xea, 0xea, 0x53, 0x39, 0x32, 0x39,
+0x5c, 0x5e, 0x7e, 0x5e, 0x32, 0x39, 0x0f, 0x31, 0xfa, 0xfa, 0xfa, 0xfa,
+0x0f, 0x31, 0xee, 0x28, 0xe0, 0xe0, 0xa0, 0xa0, 0x10, 0x31, 0xed, 0x28,
+0x5f, 0x5f, 0x5f, 0x5f, 0xcc, 0x28, 0xcb, 0x20, 0xe0, 0xe8, 0xe8, 0xe0,
+0xcc, 0x28, 0xaa, 0x20, 0x5f, 0x5f, 0x5f, 0x5f, 0xa9, 0x20, 0x88, 0x18,
+0xe8, 0xe8, 0xe8, 0xe8, 0x88, 0x18, 0x66, 0x18, 0xe8, 0xe8, 0xe8, 0xe8,
+0x67, 0x18, 0x65, 0x10, 0xfe, 0xfa, 0xfe, 0xfa, 0x66, 0x10, 0x44, 0x10,
+0x7e, 0x7e, 0x7e, 0x7e, 0x44, 0x10, 0x22, 0x08, 0xa8, 0xa8, 0xa8, 0xa8,
+0x44, 0x10, 0x22, 0x08, 0x5f, 0x7f, 0x7f, 0x7f, 0x22, 0x08, 0x01, 0x08,
+0xf8, 0xe8, 0xea, 0xea, 0x01, 0x08, 0x00, 0x00, 0xaa, 0xe8, 0xea, 0xe8,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0x84, 0xe4, 0x34, 0x94, 0xd4,
+0x3c, 0xe7, 0x69, 0x4a, 0xff, 0xff, 0xfe, 0xfc, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x9d, 0xef, 0x30, 0x84, 0x4d, 0x79, 0x51, 0x5a, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x1f, 0x62, 0x1e, 0x5a,
+0xea, 0xea, 0xea, 0xea, 0x1f, 0x62, 0xfd, 0x59, 0xfe, 0xfe, 0xfa, 0xfe,
+0x1e, 0x5a, 0xfd, 0x59, 0x57, 0x5f, 0x57, 0x57, 0xfd, 0x59, 0xdb, 0x51,
+0xfa, 0xfa, 0xfa, 0xfa, 0xdb, 0x51, 0xba, 0x51, 0xe0, 0xe0, 0xe0, 0xe0,
+0xba, 0x51, 0xb9, 0x49, 0xe8, 0xe8, 0xe8, 0xe8, 0xda, 0x51, 0x98, 0x49,
+0x5f, 0x5f, 0x5f, 0x5f, 0x97, 0x49, 0x76, 0x41, 0xe8, 0xe0, 0xe8, 0xe0,
+0x97, 0x49, 0x75, 0x41, 0x5f, 0x5f, 0x5f, 0x5f, 0x75, 0x41, 0x32, 0x39,
+0xea, 0xea, 0xea, 0xea, 0x53, 0x39, 0x32, 0x39, 0x7e, 0x7a, 0x7a, 0x7e,
+0x31, 0x39, 0x10, 0x31, 0x78, 0xf8, 0xf8, 0x78, 0x0f, 0x31, 0xee, 0x28,
+0xa0, 0xe0, 0xa0, 0xe0, 0x10, 0x31, 0xed, 0x28, 0x5f, 0x5f, 0x5f, 0x5f,
+0xed, 0x28, 0xaa, 0x20, 0xea, 0xea, 0xea, 0xea, 0xcc, 0x28, 0xaa, 0x20,
+0x5f, 0x5f, 0x5f, 0x5f, 0xaa, 0x20, 0x88, 0x18, 0xfa, 0xfa, 0xfa, 0xfa,
+0x88, 0x18, 0x66, 0x18, 0xe8, 0xe8, 0xe8, 0xe8, 0x67, 0x18, 0x65, 0x10,
+0xfa, 0xfa, 0xf8, 0xfa, 0x66, 0x10, 0x44, 0x10, 0x7e, 0x7e, 0x7e, 0x7e,
+0x44, 0x10, 0x22, 0x08, 0xa8, 0xa8, 0xa8, 0xa8, 0x44, 0x10, 0x22, 0x08,
+0x5f, 0x5f, 0x7f, 0x5f, 0x22, 0x08, 0x01, 0x08, 0xea, 0xea, 0xea, 0xe8,
+0x01, 0x08, 0x00, 0x00, 0xea, 0xea, 0xe8, 0xea, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x08, 0x42, 0xfc, 0xfc, 0xfc, 0xfc, 0x9e, 0xf7, 0x30, 0x84,
+0x5c, 0x5b, 0x51, 0x69, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0xff, 0xff, 0xef, 0x7b, 0x55, 0xd5, 0x95, 0x00, 0xbe, 0xf7, 0x10, 0x84,
+0x5c, 0x54, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x1f, 0x62, 0x1e, 0x5a, 0xea, 0xaa, 0xea, 0xea,
+0x1f, 0x62, 0xfd, 0x59, 0xfe, 0xfe, 0xfe, 0xfe, 0x1e, 0x5a, 0xfd, 0x59,
+0x57, 0x57, 0x57, 0x57, 0xfd, 0x59, 0xdb, 0x51, 0xea, 0xfa, 0xfa, 0xea,
+0xdb, 0x51, 0xb9, 0x51, 0x80, 0x80, 0xa0, 0x80, 0xba, 0x51, 0xb8, 0x49,
+0xa8, 0xa8, 0xa8, 0xa0, 0xb9, 0x51, 0x98, 0x49, 0x7e, 0x7e, 0x7e, 0x7e,
+0x97, 0x49, 0x76, 0x41, 0xa8, 0xe8, 0xe8, 0xe0, 0x97, 0x49, 0x75, 0x41,
+0x5f, 0x5f, 0x57, 0x5f, 0x75, 0x41, 0x32, 0x39, 0xea, 0xea, 0xea, 0xea,
+0x53, 0x39, 0x32, 0x39, 0x58, 0x7e, 0x7a, 0x7a, 0x32, 0x39, 0x0f, 0x31,
+0xfa, 0xfa, 0xfa, 0xfa, 0x0f, 0x31, 0xee, 0x28, 0xa0, 0xe0, 0xe0, 0xe0,
+0xef, 0x30, 0xed, 0x28, 0x5e, 0x7f, 0x5e, 0x7f, 0xed, 0x28, 0xaa, 0x20,
+0xea, 0xea, 0xea, 0xea, 0xcc, 0x28, 0xaa, 0x20, 0x5f, 0x5f, 0x5f, 0x5f,
+0xa9, 0x20, 0x88, 0x18, 0xf8, 0xe8, 0xe8, 0xe8, 0x88, 0x18, 0x66, 0x18,
+0xe8, 0xe8, 0xe8, 0xe8, 0x67, 0x18, 0x65, 0x10, 0xfa, 0xfa, 0xfa, 0xfa,
+0x66, 0x10, 0x44, 0x10, 0x7e, 0x7e, 0x7e, 0x7e, 0x44, 0x10, 0x22, 0x08,
+0xa8, 0xa8, 0xa8, 0xe0, 0x44, 0x10, 0x22, 0x08, 0x7f, 0x7f, 0x5f, 0x5f,
+0x22, 0x08, 0x01, 0x08, 0xfa, 0xf8, 0xfa, 0xf8, 0x01, 0x08, 0x00, 0x00,
+0xa8, 0xa8, 0xa8, 0xa8, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0xbe, 0xf7, 0x10, 0x84, 0x4d, 0xc5, 0xb5, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0xff, 0xff, 0x30, 0x84,
+0x00, 0xe5, 0x45, 0x6d, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x8c, 0xf8, 0x6b, 0xf0, 0xaa, 0xaa, 0xaa, 0xea, 0x8c, 0xf0, 0x6b, 0xf0,
+0xff, 0xdf, 0xff, 0xff, 0x8b, 0xf0, 0x6b, 0xe8, 0x5f, 0x5f, 0x7f, 0x5f,
+0x6b, 0xe8, 0x6a, 0xd8, 0xfa, 0xfa, 0xfa, 0xfa, 0x6a, 0xd8, 0x6a, 0xd0,
+0xe0, 0xa0, 0xe0, 0xe0, 0x6a, 0xd0, 0x69, 0xc8, 0xf8, 0xf8, 0x78, 0xf8,
+0x69, 0xc8, 0x49, 0xb8, 0xa8, 0xe8, 0xe8, 0xe8, 0x69, 0xc0, 0x48, 0xb0,
+0xfa, 0xfa, 0xfa, 0xfe, 0x69, 0xb8, 0x48, 0xa8, 0x5f, 0x5f, 0x5f, 0x5f,
+0x48, 0xa8, 0x47, 0x98, 0x7a, 0xfa, 0xfa, 0xfa, 0x47, 0x98, 0x47, 0x90,
+0x7c, 0x5c, 0x58, 0x5c, 0x47, 0x90, 0x46, 0x80, 0x7a, 0x7e, 0x7a, 0x7e,
+0x46, 0x80, 0x45, 0x70, 0xf8, 0xf8, 0xf8, 0xf8, 0x45, 0x70, 0x25, 0x68,
+0x78, 0x78, 0x78, 0x78, 0x25, 0x68, 0x24, 0x58, 0xfa, 0xfa, 0xfa, 0xfa,
+0x24, 0x58, 0x24, 0x50, 0x78, 0x78, 0x78, 0x78, 0x24, 0x50, 0x23, 0x40,
+0xfa, 0xfa, 0xfa, 0xfa, 0x23, 0x40, 0x23, 0x38, 0x78, 0x78, 0x78, 0x78,
+0x23, 0x38, 0x02, 0x28, 0xea, 0xea, 0xea, 0xea, 0x22, 0x30, 0x02, 0x20,
+0xfa, 0xfe, 0xfa, 0xfa, 0x02, 0x20, 0x01, 0x18, 0xe8, 0xe8, 0xe8, 0xf8,
+0x01, 0x18, 0x01, 0x10, 0xf8, 0xf8, 0xf8, 0xe8, 0x01, 0x10, 0x00, 0x08,
+0xe8, 0xe8, 0xe8, 0xe0, 0x01, 0x10, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0xff, 0xff, 0x10, 0x84, 0x00, 0xd5, 0x55, 0x55, 0xff, 0xff, 0x10, 0x84,
+0x00, 0x56, 0x54, 0x5e, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0x7d, 0xef, 0x10, 0x84, 0x79, 0x51, 0x53, 0x5a,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x6c, 0xf8, 0x6b, 0xf0,
+0xe8, 0xa8, 0xe8, 0xa8, 0x8b, 0xf8, 0x6b, 0xe8, 0xea, 0xfa, 0xfa, 0xea,
+0x8b, 0xf0, 0x6b, 0xe8, 0x57, 0x57, 0x57, 0x57, 0x6b, 0xe8, 0x6a, 0xd8,
+0xfa, 0xfa, 0xfa, 0xfa, 0x6a, 0xd8, 0x6a, 0xd0, 0xa0, 0xa0, 0xa0, 0xe0,
+0x6a, 0xd0, 0x69, 0xc8, 0x60, 0x68, 0xf8, 0xe8, 0x6a, 0xd0, 0x69, 0xc0,
+0x5f, 0x5f, 0x5f, 0x5f, 0x69, 0xc0, 0x48, 0xb0, 0xfa, 0xfa, 0xfa, 0xfa,
+0x68, 0xb0, 0x48, 0xa8, 0x7e, 0x7a, 0x7e, 0x7a, 0x48, 0xa8, 0x47, 0x98,
+0x7a, 0xfa, 0x7a, 0xfa, 0x47, 0x90, 0x47, 0x98, 0x09, 0x09, 0x09, 0x09,
+0x47, 0x90, 0x46, 0x80, 0x7e, 0x7e, 0x7e, 0x7e, 0x46, 0x80, 0x25, 0x70,
+0xe8, 0xe8, 0xe8, 0xf8, 0x46, 0x78, 0x25, 0x68, 0x7e, 0x7e, 0x7e, 0x7e,
+0x45, 0x68, 0x24, 0x58, 0xfa, 0xfe, 0xfa, 0xfa, 0x24, 0x58, 0x24, 0x50,
+0x78, 0x78, 0x78, 0x78, 0x24, 0x50, 0x23, 0x40, 0xfa, 0xfa, 0xfa, 0xfa,
+0x23, 0x40, 0x23, 0x38, 0x78, 0x78, 0x78, 0x78, 0x23, 0x38, 0x02, 0x28,
+0xea, 0xea, 0xfa, 0xea, 0x02, 0x30, 0x22, 0x20, 0xfe, 0xfe, 0xfa, 0xfa,
+0x22, 0x28, 0x01, 0x18, 0x7e, 0x7e, 0xfe, 0xfe, 0x01, 0x18, 0x01, 0x10,
+0xe8, 0xe8, 0xe8, 0xe8, 0x01, 0x10, 0x00, 0x08, 0xe8, 0xe8, 0xe8, 0xe0,
+0x01, 0x08, 0x00, 0x08, 0xff, 0xff, 0xfb, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x7d, 0xef, 0x10, 0x84, 0x5b, 0x51, 0x71, 0x69,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xdf, 0xff, 0x10, 0x84, 0x54, 0x54, 0xd4, 0x94,
+0x1c, 0xe7, 0xef, 0x7b, 0x5c, 0x54, 0x54, 0x56, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x8c, 0xf8, 0x6b, 0xf0, 0xfa, 0xea, 0xea, 0xea,
+0x8c, 0xf0, 0x6b, 0xf0, 0xfa, 0xfe, 0xfa, 0xff, 0x8b, 0xf0, 0x6b, 0xe8,
+0x5f, 0x5f, 0x5e, 0x5f, 0x6b, 0xe8, 0x6a, 0xd8, 0xfa, 0xfa, 0xfa, 0xfa,
+0x6a, 0xd8, 0x6a, 0xd0, 0xe0, 0xa0, 0xa0, 0xe0, 0x6a, 0xd0, 0x69, 0xc8,
+0xf8, 0xe8, 0xf8, 0xf8, 0x6a, 0xc8, 0x69, 0xc0, 0x7e, 0x7e, 0x5e, 0x5e,
+0x69, 0xc0, 0x48, 0xb0, 0xfa, 0xfa, 0xfa, 0xfa, 0x68, 0xb0, 0x48, 0xa8,
+0x7e, 0x5e, 0x7a, 0x7e, 0x48, 0xa8, 0x47, 0x98, 0x7a, 0x7a, 0x7a, 0xfa,
+0x47, 0x90, 0x47, 0x98, 0x09, 0x09, 0x09, 0x09, 0x47, 0x90, 0x46, 0x80,
+0x7e, 0x7e, 0x7a, 0x7e, 0x46, 0x80, 0x25, 0x70, 0xfa, 0xea, 0xea, 0xea,
+0x46, 0x78, 0x25, 0x68, 0x7e, 0x7e, 0x7e, 0x7e, 0x45, 0x68, 0x24, 0x58,
+0xfe, 0xfa, 0xfe, 0xfe, 0x24, 0x58, 0x24, 0x50, 0x78, 0x78, 0x78, 0x78,
+0x24, 0x50, 0x23, 0x40, 0xfa, 0xfa, 0xfa, 0xfa, 0x23, 0x40, 0x23, 0x38,
+0x78, 0x78, 0x78, 0x78, 0x23, 0x38, 0x22, 0x28, 0xea, 0xfa, 0xfa, 0xfa,
+0x22, 0x30, 0x02, 0x20, 0xfa, 0xfe, 0xfa, 0xfa, 0x22, 0x28, 0x01, 0x18,
+0xfe, 0xfe, 0xfe, 0xfe, 0x01, 0x18, 0x01, 0x10, 0xe8, 0xe8, 0xe8, 0xf8,
+0x01, 0x10, 0x00, 0x08, 0xe8, 0xe8, 0xe0, 0xe8, 0x01, 0x10, 0x00, 0x00,
+0xfe, 0xfa, 0xfa, 0xfe, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x7d, 0xef, 0x10, 0x84, 0x4d, 0x45, 0xe5, 0xa5, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xff, 0xff, 0x10, 0x84, 0x94, 0x14, 0xb4, 0x00, 0xdf, 0xff, 0xef, 0x7b,
+0x57, 0x55, 0x55, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x8c, 0xf8, 0x6b, 0xf0, 0xea, 0xea, 0xea, 0xea, 0x8c, 0xf0, 0x6b, 0xf0,
+0xff, 0xff, 0xff, 0xfb, 0x6b, 0xf0, 0x6b, 0xe0, 0xea, 0xfa, 0xea, 0xfa,
+0x6b, 0xe8, 0x6a, 0xd8, 0xfa, 0xfa, 0xfa, 0xfa, 0x6a, 0xd8, 0x6a, 0xd0,
+0xe0, 0xe0, 0xa0, 0xe0, 0x6a, 0xd0, 0x69, 0xc8, 0x70, 0xe8, 0x78, 0xe8,
+0x6a, 0xd0, 0x69, 0xc0, 0x5f, 0x5f, 0x5f, 0x5f, 0x69, 0xc0, 0x48, 0xb0,
+0xfe, 0xfe, 0xfa, 0x7a, 0x68, 0xb0, 0x48, 0xa8, 0x7a, 0x7a, 0x7e, 0x7a,
+0x48, 0xa8, 0x47, 0x98, 0xfa, 0xfa, 0xfa, 0xfa, 0x47, 0x90, 0x47, 0x98,
+0x09, 0x09, 0x09, 0x09, 0x47, 0x90, 0x46, 0x80, 0x7a, 0x7a, 0x7e, 0x7e,
+0x46, 0x80, 0x25, 0x70, 0xe8, 0xe8, 0xe8, 0xe8, 0x45, 0x70, 0x25, 0x68,
+0x78, 0x78, 0x78, 0x78, 0x25, 0x68, 0x24, 0x58, 0xfa, 0xfa, 0xfa, 0xfa,
+0x24, 0x58, 0x24, 0x50, 0x78, 0x78, 0x78, 0x78, 0x24, 0x50, 0x23, 0x40,
+0xfa, 0xfa, 0xfa, 0xfa, 0x23, 0x40, 0x23, 0x38, 0x78, 0x78, 0x78, 0x78,
+0x23, 0x38, 0x02, 0x28, 0xea, 0xfa, 0xea, 0xea, 0x22, 0x30, 0x02, 0x20,
+0xfa, 0xfa, 0xfa, 0xfe, 0x22, 0x28, 0x01, 0x18, 0xfe, 0xfe, 0xfe, 0x7e,
+0x01, 0x18, 0x01, 0x10, 0xe8, 0xe8, 0xf8, 0xe8, 0x01, 0x10, 0x00, 0x08,
+0xa8, 0xe8, 0xa0, 0xa8, 0x01, 0x10, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0xff, 0xff, 0x10, 0x84,
+0xb5, 0x15, 0x95, 0x00, 0xff, 0xff, 0x10, 0x84, 0x15, 0x15, 0x17, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xf7, 0x30, 0x84,
+0x00, 0x44, 0x44, 0x6c, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x41, 0x08, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0xbe, 0xf7, 0x10, 0x84, 0x00, 0x14, 0x14, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xde, 0xf7, 0x30, 0x84, 0x6c, 0x78, 0x78, 0x50,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf7, 0x30, 0x84,
+0x1e, 0x1b, 0x1b, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xdf, 0xff, 0x10, 0x84, 0x50, 0x50, 0x58, 0x58, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x30, 0x84, 0x11, 0x11, 0x39, 0x39,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x42,
+0xf8, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0xff, 0xff, 0x08, 0x42, 0x2b, 0x2b, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xa2, 0x10, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x04, 0x21, 0xbe, 0xf7,
+0x55, 0x5a, 0x5a, 0x5a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xff, 0xff, 0x28, 0x42, 0xfc, 0xfc, 0xfc, 0xfc, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xff, 0xc8, 0x88, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xc8, 0x88,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x71, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x71, 0x39,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf7, 0x49, 0x4a, 0x0f, 0x0f, 0x0f, 0x0f,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0x28, 0x42,
+0xfc, 0xfc, 0xfc, 0xfc, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x10, 0x84, 0xdf, 0xff, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xa2, 0x10, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xd3, 0x9d, 0x02, 0x10,
+0xff, 0xff, 0xff, 0xff, 0xd3, 0x9d, 0x02, 0x10, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0xbe, 0xf7, 0xaa, 0x52,
+0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xff, 0xff, 0x08, 0x42, 0x00, 0xf8, 0xf8, 0xf8, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0x08, 0x42, 0x00, 0x2b, 0x2b, 0x2b,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0x10, 0x84,
+0x58, 0x58, 0x50, 0x50, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xdf, 0xff, 0x30, 0x84, 0x39, 0x39, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xde, 0xf7, 0x30, 0x84, 0x50, 0x78, 0x78, 0x6c,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf7, 0x30, 0x84,
+0x11, 0x1b, 0x1b, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xbe, 0xf7, 0x30, 0x84, 0x4c, 0x44, 0x44, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x41, 0x08, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0xbe, 0xf7, 0x10, 0x84, 0x1c, 0x14, 0x14, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0x10, 0x84,
+0x00, 0xb4, 0x14, 0x94, 0xdf, 0xff, 0xef, 0x7b, 0x00, 0x55, 0x55, 0x57,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0x10, 0x84, 0x00, 0x95, 0x15, 0xb5,
+0xff, 0xff, 0x10, 0x84, 0x00, 0x17, 0x15, 0x15, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xdf, 0xff, 0x10, 0x84, 0x94, 0xd4, 0x54, 0x54,
+0x3c, 0xe7, 0xef, 0x7b, 0x56, 0x54, 0x54, 0x5c, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x7d, 0xef, 0x10, 0x84, 0xa5, 0xe5, 0x45, 0x4d, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0x5d, 0xef, 0x10, 0x84,
+0x5a, 0x53, 0x51, 0x79, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x7d, 0xef, 0x10, 0x84,
+0x69, 0x71, 0x51, 0x5b, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0xff, 0xff, 0x30, 0x84, 0x6d, 0x45, 0xe5, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff,
+0xd6, 0xb5, 0x21, 0x08, 0xff, 0xff, 0xff, 0xff, 0xd6, 0xb5, 0x21, 0x08,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0xff, 0xff, 0x10, 0x84,
+0x55, 0x55, 0xd5, 0x00, 0xff, 0xff, 0x10, 0x84, 0x5e, 0x54, 0x56, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0xff, 0xff, 0xef, 0x7b, 0x00, 0x95, 0xd5, 0x55, 0xbe, 0xf7, 0x10, 0x84,
+0x00, 0x57, 0x54, 0x5c, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0xbe, 0xf7, 0x10, 0x84, 0x00, 0xb5, 0xc5, 0x4d,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x9e, 0xf7, 0x30, 0x84, 0x5a, 0x51, 0x79, 0x4d,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x42, 0xfc, 0xfc, 0xfc, 0xfc,
+0x9e, 0xf7, 0x30, 0x84, 0x69, 0x51, 0x5b, 0x5c, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x3c, 0xe7, 0x69, 0x4a, 0x8f, 0x2f, 0x3f, 0xbf, 0xff, 0xff, 0xef, 0x7b,
+0x15, 0x15, 0x17, 0x16, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x10, 0x84, 0xd4, 0x94, 0x34, 0xe4, 0x1c, 0xe7, 0x69, 0x4a,
+0xfc, 0xfe, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0xff, 0xff, 0x08, 0x42,
+0xff, 0xff, 0xff, 0x00, 0xdf, 0xff, 0x71, 0x8c, 0x14, 0x1b, 0x11, 0x00,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x51, 0x8c,
+0x44, 0x78, 0x50, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0xff, 0xff, 0x10, 0x84, 0x00, 0x35, 0x15, 0x15, 0xbe, 0xef, 0xb0, 0x4c,
+0x55, 0x55, 0x57, 0x54, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0x5b, 0xe7, 0x29, 0x7c,
+0xd5, 0x15, 0x35, 0xc5, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x9d, 0xe7, 0xd0, 0x54, 0x5a, 0x51, 0x69, 0xc5,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xe1, 0x52, 0x70, 0xa5,
+0xaa, 0xaa, 0xaa, 0x6a, 0x3a, 0xe7, 0x6a, 0x84, 0x49, 0x51, 0x58, 0x54,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x9d, 0xef, 0xb0, 0x4c, 0x35, 0x95, 0x55, 0x55, 0x9d, 0xef, 0xd0, 0x4c,
+0x55, 0x56, 0x5c, 0x53, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0x9d, 0xef, 0x49, 0x84, 0x15, 0xa5, 0x4d, 0x71,
+0x2e, 0x9d, 0xa6, 0x6b, 0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x9d, 0xe7, 0xb0, 0x4c, 0x69, 0xc5, 0x35, 0x95,
+0x3c, 0xd7, 0xaf, 0x4c, 0x55, 0x55, 0x57, 0x54, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0x7c, 0xef, 0xc0, 0x4a, 0xff, 0xbf, 0x3f, 0x8f,
+0x9c, 0xef, 0x29, 0x7c, 0x5a, 0x54, 0x57, 0x55, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xb0, 0x4c, 0xb0, 0x44, 0x2a, 0xaa, 0xaa, 0xaa, 0xbe, 0xef, 0xb0, 0x4c,
+0x5a, 0x71, 0xcd, 0x35, 0x6e, 0x3c, 0xf1, 0x5c, 0xaa, 0xaa, 0xaa, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x7c, 0xef, 0x29, 0x7c, 0x55, 0x55, 0xd5, 0x15,
+0xbd, 0xf7, 0x49, 0x7c, 0x69, 0x53, 0x5c, 0x57, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x7d, 0xe7, 0xb0, 0x4c, 0x95, 0x55, 0x55, 0x55,
+0x3b, 0xd7, 0xd0, 0x4c, 0x54, 0x50, 0x61, 0x85, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x3a, 0xe7, 0x49, 0x84, 0x85, 0x41, 0x52, 0x54, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x9d, 0xe7, 0x8f, 0x44,
+0x35, 0xd5, 0x55, 0x55, 0xde, 0xf7, 0xef, 0x7b, 0x54, 0x5c, 0x70, 0xcc,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x2c, 0x63, 0xd3, 0x9c, 0xaa, 0xaa, 0xaa, 0x6a,
+0xde, 0xf7, 0xef, 0x7b, 0x35, 0x0d, 0x33, 0x1c, 0x70, 0xad, 0x85, 0x63,
+0xfe, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xdf, 0xff, 0x10, 0x84, 0x34, 0xd4, 0x54, 0x00, 0xde, 0xf7, 0xef, 0x7b,
+0x57, 0x5c, 0x73, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xde, 0xf5, 0x14, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6,
+0xff, 0xff, 0xff, 0xff, 0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff,
+0xc0, 0xf5, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x14, 0x06, 0xde, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x14, 0x06, 0xde, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05,
+0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x06, 0xc0, 0x05, 0xaa, 0xaa, 0xaa, 0xaa,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0xf0, 0x14, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff,
+0x00, 0xf0, 0x00, 0xa0, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0xa0,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00,
+0xff, 0xff, 0xff, 0xff, 0x1e, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0xde, 0xf7, 0xef, 0x7b, 0x35, 0xcd, 0x73, 0x00, 0xff, 0xff, 0x10, 0x84,
+0x17, 0x15, 0x15, 0x00, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf6, 0x63,
+0x55, 0x55, 0x55, 0x55, 0x7e, 0xef, 0xd6, 0x63, 0x35, 0xd5, 0x55, 0x55,
+0x3d, 0xe7, 0x17, 0x6c, 0x57, 0x58, 0x61, 0x05, 0xd8, 0x8c, 0xf6, 0x63,
+0x55, 0x55, 0x55, 0x57, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0xfd, 0xde, 0x93, 0x32, 0xff, 0xff, 0xff, 0x3f,
+0x9e, 0xef, 0x37, 0x6c, 0x35, 0x49, 0x52, 0x56, 0xf6, 0x63, 0xfb, 0xb5,
+0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55, 0x9e, 0xef, 0xf6, 0x63,
+0x95, 0x55, 0x55, 0x55, 0x5e, 0xe7, 0x16, 0x6c, 0x5c, 0x73, 0x8d, 0x15,
+0x41, 0x08, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x84, 0x15, 0x15, 0x15, 0x25,
+0x9e, 0xef, 0x36, 0x6c, 0x85, 0x73, 0x5c, 0x55, 0x16, 0x6c, 0xf6, 0x63,
+0x57, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55,
+0x16, 0x6c, 0xf6, 0x63, 0xd5, 0x55, 0x55, 0x55, 0xbe, 0xf7, 0x10, 0x84,
+0x70, 0x8c, 0x94, 0x54, 0x7d, 0xef, 0x10, 0x84, 0x55, 0x55, 0x5c, 0x63,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0x71, 0x8c, 0xcf, 0x7b,
+0xff, 0xff, 0xff, 0xbf, 0x9d, 0xef, 0x10, 0x84, 0x55, 0x95, 0x8d, 0x72,
+0xbe, 0xf7, 0x10, 0x84, 0x23, 0x1c, 0x15, 0x15, 0x00, 0x00, 0xf6, 0x63,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63,
+0x55, 0x55, 0x55, 0x55, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xd5, 0x0a, 0x04, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf6, 0x63,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0xde, 0xf7, 0x10, 0x84, 0x25, 0xd5, 0x55, 0x00, 0xbe, 0xf7, 0x30, 0x84,
+0x57, 0x58, 0xc9, 0x00, 0xff, 0xff, 0x08, 0x42, 0x3f, 0x3f, 0x3f, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0xff, 0xff, 0x08, 0x42,
+0xfc, 0xfc, 0xbc, 0x00, 0xbe, 0xf7, 0x10, 0x84, 0x35, 0xc9, 0x58, 0x00,
+0xff, 0xff, 0x10, 0x84, 0x56, 0x55, 0x55, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xf6, 0x63, 0x55, 0x55, 0x55, 0x55,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b,
+0xff, 0xff, 0xff, 0xff, 0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff,
+0xda, 0xfd, 0x60, 0x3b, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0xff, 0xff, 0x08, 0x42, 0x00, 0x2f, 0x3f, 0x3f, 0xff, 0xff, 0x8a, 0x52,
+0x00, 0xfc, 0xe0, 0x2c, 0xdf, 0xff, 0x30, 0x84, 0x00, 0x55, 0x55, 0x56,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0xdf, 0xff, 0x30, 0x84, 0x00, 0x55, 0x55, 0x25, 0xff, 0xff, 0x8a, 0x52,
+0x00, 0x2f, 0x22, 0x3e, 0xff, 0xff, 0x08, 0x42, 0x00, 0xfc, 0xfc, 0xfc,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xa9, 0xa9, 0xa9, 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0x55, 0xa9, 0xa9, 0xa9,
+0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff,
+0x55, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xff, 0xff, 0x55, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x41, 0x08, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0x9e, 0xf7, 0x10, 0x84, 0xe2, 0x35, 0x55, 0x55, 0x3c, 0xe7, 0x10, 0x84,
+0x55, 0x5c, 0x83, 0xb5, 0xff, 0xff, 0x30, 0x84, 0x15, 0x15, 0x15, 0x38,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xde, 0xf7, 0x30, 0x84, 0x54, 0x54, 0x94, 0x88,
+0x5c, 0xe7, 0x10, 0x84, 0xd5, 0x0d, 0x70, 0x57, 0xbe, 0xf7, 0x30, 0x84,
+0x62, 0x57, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x10, 0x84, 0x2d, 0x15, 0x15, 0x15, 0xff, 0xff, 0x30, 0x84,
+0x5c, 0x88, 0xd4, 0x54, 0xff, 0xff, 0x10, 0x84, 0x55, 0x57, 0xe2, 0xb5,
+0x9d, 0xef, 0x30, 0x84, 0x55, 0x55, 0x55, 0xe0, 0x41, 0x08, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0xff, 0xff, 0x30, 0x84, 0x54, 0x54, 0x54, 0xd4,
+0x9d, 0xef, 0x30, 0x84, 0x55, 0x55, 0xd5, 0x82, 0xff, 0xff, 0x10, 0x84,
+0x55, 0xb5, 0xe2, 0x57, 0xff, 0xff, 0x30, 0x84, 0x2d, 0x38, 0x15, 0x15,
+0xff, 0xff, 0x10, 0x84, 0x5c, 0x54, 0x54, 0x54, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52,
+0xff, 0xff, 0xff, 0xff, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0xa9, 0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff,
+0xfb, 0xdf, 0x0a, 0x52, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0xff, 0xff, 0x30, 0x84,
+0xb5, 0x55, 0x55, 0x00, 0xde, 0xf7, 0x30, 0x84, 0x20, 0x35, 0x15, 0x00,
+0xdf, 0xff, 0x30, 0x84, 0x54, 0x80, 0xd4, 0x00, 0xde, 0xf7, 0x30, 0x84,
+0x55, 0x7e, 0x2b, 0x00, 0xdf, 0xff, 0x10, 0x84, 0x55, 0x55, 0xa0, 0x00,
+0xef, 0x7b, 0xdf, 0xff, 0x40, 0x40, 0x6a, 0x55, 0x82, 0x10, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0xff, 0xff, 0x28, 0x42, 0xff, 0xff, 0xff, 0x00,
+0x21, 0x08, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0xc3, 0x18, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0xff, 0xff, 0x08, 0x42, 0xfc, 0xfc, 0xa8, 0x00,
+0xde, 0xf7, 0x30, 0x84, 0x55, 0x55, 0x02, 0x00, 0xff, 0xff, 0x10, 0x84,
+0x55, 0xaf, 0xfa, 0x00, 0xdf, 0xff, 0x30, 0x84, 0x35, 0x20, 0x15, 0x00,
+0xde, 0xf7, 0x30, 0x84, 0x80, 0x54, 0x54, 0x00, 0xff, 0xff, 0x30, 0x84,
+0x57, 0x55, 0x55, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xa9, 0xa9, 0xa9, 0x55, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x6a, 0x6a, 0x6a, 0x55, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xa9, 0xa9, 0x55,
+0x00, 0x00, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff,
+0xaa, 0xaa, 0xaa, 0x55, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x6a, 0x6a, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff,
+0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
+0x00, 0x00, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55 \ No newline at end of file
diff --git a/src/zstd/contrib/single_file_libs/examples/testcard-zstd.inl b/src/zstd/contrib/single_file_libs/examples/testcard-zstd.inl
new file mode 100644
index 000000000..9e4388365
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/examples/testcard-zstd.inl
@@ -0,0 +1,261 @@
+0x28, 0xb5, 0x2f, 0xfd, 0x60, 0x00, 0x7f, 0x6d, 0x61, 0x00, 0x0a, 0x66,
+0xec, 0x17, 0x48, 0x60, 0x1c, 0x5a, 0xc9, 0x5d, 0x1a, 0x38, 0x07, 0xe8,
+0xc5, 0x82, 0x99, 0x68, 0xe6, 0x95, 0x45, 0x58, 0x0d, 0x0c, 0xf3, 0x36,
+0xc8, 0xd9, 0x0f, 0x46, 0x2d, 0x68, 0x11, 0xf8, 0x31, 0x10, 0xa1, 0x1a,
+0x2f, 0x99, 0x5c, 0x84, 0xfd, 0x92, 0x02, 0xe6, 0x3b, 0x44, 0x9b, 0x01,
+0x5d, 0x92, 0xff, 0x38, 0x26, 0x00, 0x6a, 0x6b, 0xc3, 0x53, 0xb2, 0x0c,
+0x25, 0xf3, 0xd8, 0x59, 0x68, 0x9b, 0x14, 0x8a, 0x89, 0x75, 0x18, 0x03,
+0x1d, 0xc9, 0x0f, 0x63, 0x01, 0x73, 0x01, 0x72, 0x01, 0x4f, 0x66, 0x31,
+0x58, 0x0f, 0x97, 0x4b, 0x0c, 0x4c, 0x06, 0xac, 0x07, 0x0b, 0x68, 0xd4,
+0xad, 0x80, 0x64, 0x13, 0x74, 0xa1, 0x12, 0x16, 0x58, 0xcf, 0x1a, 0x95,
+0x5f, 0x0d, 0x26, 0x55, 0xd0, 0x9c, 0xf4, 0x52, 0x35, 0x2e, 0x20, 0xc1,
+0x06, 0x69, 0x03, 0x0a, 0x93, 0x83, 0x5e, 0x27, 0x9b, 0x4c, 0x6d, 0xee,
+0x87, 0x03, 0x30, 0x6c, 0x46, 0xd7, 0x50, 0x5c, 0xca, 0xe6, 0xa6, 0x4d,
+0xa8, 0xf6, 0xab, 0xd7, 0x0e, 0x27, 0x27, 0x90, 0xc4, 0xb2, 0xd1, 0x10,
+0xfa, 0x43, 0x82, 0xc8, 0xf2, 0xe5, 0xff, 0xff, 0xd5, 0x52, 0x62, 0x43,
+0x87, 0x26, 0x2a, 0x05, 0x70, 0x0e, 0xb0, 0x2f, 0xc4, 0x56, 0xef, 0xb5,
+0xca, 0xb8, 0x53, 0xb7, 0x96, 0x0e, 0xe7, 0x00, 0x2c, 0xa8, 0xda, 0x3b,
+0x07, 0x70, 0xa7, 0x78, 0x38, 0x60, 0x87, 0x7a, 0x01, 0x3b, 0x75, 0xec,
+0xfa, 0x77, 0xe2, 0x46, 0x94, 0x61, 0x8e, 0x0d, 0x0c, 0xfb, 0xe7, 0x8b,
+0x13, 0x50, 0x31, 0xa9, 0x27, 0xcd, 0x27, 0xef, 0x6b, 0xa6, 0xab, 0x9c,
+0x4d, 0x95, 0x6c, 0x3a, 0xbb, 0x8e, 0x96, 0x92, 0x18, 0x5a, 0x7c, 0x4f,
+0xff, 0x7b, 0x38, 0xf2, 0xdb, 0x86, 0xde, 0xff, 0x1f, 0x2f, 0x21, 0x86,
+0x7d, 0xbf, 0x45, 0xd0, 0x6e, 0x77, 0x0a, 0xee, 0x0a, 0xee, 0x14, 0x9a,
+0xb8, 0x84, 0xf3, 0xac, 0xbe, 0xc8, 0x7f, 0x8d, 0xff, 0xff, 0xcf, 0x2a,
+0xfb, 0x69, 0xfc, 0xfb, 0xfd, 0x7a, 0x10, 0x22, 0x36, 0xfc, 0xff, 0x3f,
+0xcf, 0xd0, 0xf1, 0x7f, 0xfe, 0xff, 0x3d, 0x24, 0xdf, 0x78, 0x4a, 0xff,
+0xda, 0x9c, 0x39, 0xcf, 0xef, 0xe7, 0xfd, 0x52, 0x98, 0xb5, 0x40, 0x92,
+0xee, 0xdd, 0x99, 0xf5, 0x53, 0x5b, 0x65, 0x6b, 0xb5, 0xd8, 0x7b, 0xae,
+0xfa, 0xc1, 0x0f, 0x0c, 0x7f, 0x4f, 0x55, 0xa3, 0xad, 0x2c, 0xa0, 0xbd,
+0xf7, 0x2a, 0x0e, 0xe8, 0xbd, 0xc7, 0x5e, 0xf5, 0xd8, 0x54, 0x9e, 0x56,
+0xa3, 0xd6, 0x59, 0xd5, 0xfe, 0x1f, 0xc0, 0x30, 0x8c, 0xfc, 0x46, 0x04,
+0xae, 0x60, 0xbc, 0xe8, 0xcf, 0xec, 0x3d, 0xde, 0xf9, 0xf0, 0xfe, 0xef,
+0x7d, 0xcc, 0xf7, 0x2b, 0xe5, 0x1b, 0x70, 0xff, 0xff, 0x7e, 0x3f, 0x6e,
+0xe4, 0x02, 0x07, 0xfc, 0x1b, 0x7a, 0xff, 0xe7, 0x58, 0xfc, 0x7e, 0x3a,
+0xdc, 0x97, 0xfd, 0x57, 0xef, 0xa3, 0xfc, 0x2a, 0xc7, 0x4d, 0xf3, 0xcb,
+0x9d, 0xce, 0xac, 0xfe, 0xeb, 0x2e, 0x86, 0xb9, 0x69, 0x54, 0xef, 0xf9,
+0x55, 0xcf, 0xff, 0x48, 0x24, 0x72, 0x3a, 0x9d, 0x72, 0x2f, 0x2f, 0x2f,
+0xff, 0x3f, 0xe7, 0x01, 0x6c, 0x4d, 0x6c, 0xcd, 0x2d, 0x5b, 0x53, 0xb7,
+0x59, 0x22, 0x08, 0x0b, 0xa7, 0x92, 0x15, 0x75, 0x93, 0xb0, 0x5d, 0xaf,
+0x2a, 0x63, 0x95, 0x1d, 0x25, 0xd2, 0xd2, 0xa8, 0x1c, 0x84, 0xc9, 0xdc,
+0x72, 0xba, 0xd7, 0xfc, 0x69, 0xf5, 0xc7, 0x19, 0xa9, 0xbe, 0xfa, 0x26,
+0x55, 0x25, 0x75, 0xb7, 0x60, 0xa3, 0xd8, 0x68, 0x54, 0xb7, 0x1b, 0xa5,
+0x54, 0x62, 0xb1, 0x49, 0xde, 0xe2, 0xac, 0xa2, 0xe8, 0x7b, 0xff, 0x5f,
+0x75, 0x4e, 0xb8, 0xa2, 0xdd, 0x6a, 0xb7, 0xda, 0x6e, 0x2e, 0x04, 0xcd,
+0x08, 0x2f, 0xec, 0x8e, 0x49, 0xaf, 0x49, 0x6f, 0x8b, 0x4f, 0x2e, 0x1a,
+0xc5, 0x62, 0x7b, 0x6b, 0x3e, 0x32, 0x3e, 0x32, 0xbe, 0x08, 0x35, 0x4d,
+0x63, 0x93, 0xa6, 0xc8, 0x42, 0xe6, 0x21, 0xcc, 0x59, 0xc8, 0x4c, 0xe5,
+0x86, 0xe1, 0x03, 0x06, 0xa4, 0xec, 0xff, 0xb7, 0x78, 0x7e, 0x62, 0x43,
+0xc7, 0x2c, 0x50, 0x30, 0x4a, 0xc8, 0x9b, 0xf3, 0xbf, 0xe6, 0x62, 0xa0,
+0x50, 0xa6, 0x9c, 0xe3, 0x6e, 0x5b, 0xaf, 0x77, 0x8b, 0xbb, 0xe1, 0x70,
+0xaa, 0xaa, 0xaa, 0x92, 0xb4, 0x52, 0xad, 0x14, 0x87, 0x93, 0x0b, 0xe6,
+0x82, 0x39, 0x11, 0xb9, 0x20, 0x9a, 0x16, 0x34, 0x22, 0x68, 0xb2, 0x68,
+0xb2, 0x76, 0xd3, 0xe8, 0x6e, 0xda, 0x6b, 0x62, 0x34, 0x2e, 0x8d, 0xbd,
+0x2d, 0x3d, 0x6b, 0x4c, 0x26, 0x33, 0xda, 0x33, 0xf3, 0x91, 0x51, 0x46,
+0x79, 0xbd, 0x3e, 0x39, 0x9f, 0xcf, 0xd2, 0xb8, 0x5c, 0xfa, 0x22, 0xf8,
+0x8e, 0xb6, 0xbe, 0x08, 0x40, 0x14, 0x49, 0x40, 0x14, 0xf2, 0x0c, 0x2d,
+0x30, 0x85, 0x3c, 0x63, 0x29, 0xd3, 0x98, 0x85, 0x6c, 0xb5, 0xdb, 0xad,
+0x5c, 0x63, 0x9e, 0x72, 0xcf, 0x43, 0xe6, 0xaf, 0x77, 0xa6, 0xe2, 0x21,
+0x0c, 0x4d, 0xd3, 0x49, 0x1e, 0xc2, 0x14, 0x6f, 0xee, 0xdb, 0x7b, 0x7b,
+0x08, 0xb3, 0xa4, 0x60, 0x3b, 0x9d, 0x6e, 0x8b, 0x37, 0x4b, 0x0a, 0x74,
+0x35, 0x33, 0xbc, 0xf9, 0x64, 0x85, 0x63, 0x32, 0x29, 0x20, 0x59, 0x0c,
+0x3c, 0x96, 0x67, 0x62, 0xb7, 0x8a, 0x92, 0x4d, 0xa0, 0xd3, 0xf3, 0xd1,
+0x85, 0x80, 0x38, 0xcb, 0x64, 0x60, 0xc9, 0xb5, 0xaf, 0x97, 0x8d, 0x20,
+0x45, 0x28, 0xb8, 0xab, 0xe8, 0xc9, 0x0a, 0x88, 0x1f, 0xd6, 0x47, 0x54,
+0xf1, 0xd3, 0xfb, 0x62, 0xa7, 0xfd, 0xf2, 0x8b, 0xfd, 0xb6, 0xe4, 0x2e,
+0xb6, 0x91, 0x73, 0x1c, 0xd0, 0x7b, 0xba, 0x83, 0xc9, 0xac, 0x51, 0x39,
+0x92, 0xc5, 0x4f, 0x30, 0x1e, 0x2e, 0xd5, 0xf1, 0xa8, 0xa6, 0xa5, 0x80,
+0x70, 0xb9, 0xbc, 0xb7, 0xc2, 0x52, 0x32, 0x6c, 0xe3, 0x3d, 0xed, 0x41,
+0xa4, 0x4b, 0x31, 0x2a, 0xe6, 0x62, 0x11, 0x19, 0x95, 0x73, 0x1d, 0xbf,
+0xe1, 0x6c, 0xfc, 0x47, 0x75, 0x6c, 0x37, 0x63, 0x02, 0xf8, 0x34, 0x40,
+0x9a, 0x00, 0x1d, 0xf7, 0x32, 0x56, 0x77, 0xda, 0x5b, 0x9f, 0x9f, 0x0f,
+0xbb, 0x91, 0x5b, 0xbd, 0xe7, 0x58, 0x82, 0x4a, 0x20, 0xcd, 0x4f, 0x47,
+0x15, 0xf3, 0x51, 0xf1, 0x43, 0x51, 0x10, 0x96, 0xae, 0xba, 0xf7, 0x21,
+0x50, 0xef, 0x55, 0x27, 0x0c, 0x1f, 0xe0, 0x54, 0xf8, 0xc9, 0x69, 0xef,
+0xb9, 0x53, 0xf7, 0x83, 0x73, 0x9d, 0xce, 0x86, 0x07, 0x83, 0x44, 0x61,
+0x37, 0x35, 0x35, 0x33, 0x4e, 0x33, 0x33, 0x3e, 0x9f, 0x50, 0x48, 0x24,
+0xe6, 0xd0, 0x79, 0x49, 0xc3, 0x2d, 0xa0, 0x46, 0x31, 0x9a, 0x72, 0xc3,
+0x84, 0xff, 0x7a, 0x95, 0xbb, 0x00, 0x22, 0xcc, 0x14, 0x00, 0x04, 0xac,
+0x60, 0x64, 0x86, 0xe4, 0x6f, 0xb1, 0x58, 0xf4, 0xdc, 0xb0, 0x05, 0x00,
+0x72, 0x38, 0xf8, 0xce, 0xce, 0x8e, 0xcf, 0x37, 0x33, 0x43, 0x24, 0x0a,
+0x85, 0x33, 0x35, 0x35, 0x37, 0xc2, 0xa8, 0x28, 0x27, 0x1b, 0x9d, 0xce,
+0x29, 0x18, 0xe4, 0xfc, 0x09, 0x53, 0xa5, 0x51, 0xad, 0x74, 0x79, 0x7b,
+0xb5, 0x4a, 0x65, 0x94, 0x36, 0x89, 0xf5, 0x62, 0x9b, 0xd8, 0x9a, 0xe8,
+0x2b, 0xff, 0xa1, 0x73, 0xfe, 0x2e, 0x2c, 0x41, 0x45, 0x37, 0xef, 0x6e,
+0x7b, 0x38, 0xca, 0xa5, 0xd2, 0xb8, 0x1c, 0x3b, 0x96, 0x21, 0xbb, 0x5d,
+0xad, 0xd1, 0xdb, 0x1c, 0xf6, 0x5e, 0x4b, 0xd9, 0x59, 0x1b, 0x67, 0xf5,
+0x7a, 0x7c, 0x9a, 0x91, 0x3e, 0x8e, 0xe3, 0xee, 0x7b, 0xb9, 0xa4, 0xb9,
+0xf5, 0x70, 0xee, 0x1d, 0x4e, 0x4f, 0xcc, 0xd6, 0x7b, 0x07, 0x71, 0x48,
+0xf2, 0x06, 0xd0, 0x10, 0x82, 0x21, 0xe4, 0x55, 0x2e, 0xa5, 0x1d, 0xbe,
+0x48, 0x8c, 0x69, 0xbb, 0x24, 0x40, 0x68, 0x9b, 0xba, 0x5a, 0x5a, 0xa7,
+0xe2, 0xd1, 0xac, 0xc2, 0xd8, 0x87, 0x9c, 0xe3, 0x78, 0xee, 0xa6, 0xcd,
+0xdd, 0x68, 0x6e, 0xdd, 0xdb, 0x2e, 0xc6, 0xbb, 0x8b, 0xe9, 0xc1, 0xd9,
+0xf6, 0x62, 0x7e, 0x72, 0x7e, 0x72, 0x34, 0xe4, 0x68, 0xc8, 0x11, 0x32,
+0x10, 0x32, 0x20, 0x32, 0xf0, 0x12, 0x19, 0x90, 0xe0, 0x45, 0x91, 0xe0,
+0x25, 0x83, 0xba, 0xc9, 0x20, 0x26, 0x87, 0xa5, 0x72, 0xa9, 0x64, 0x72,
+0x80, 0x21, 0x54, 0x13, 0xeb, 0x29, 0x18, 0x42, 0x34, 0x84, 0x94, 0x34,
+0x84, 0xa4, 0x1d, 0xa4, 0x1d, 0x82, 0x1c, 0xef, 0xaf, 0x0e, 0x63, 0x47,
+0x6d, 0x10, 0xb9, 0xec, 0xd8, 0x2d, 0x3b, 0x9e, 0x21, 0xb1, 0x67, 0x48,
+0x34, 0x24, 0x1a, 0x52, 0xdb, 0xa4, 0x6d, 0x62, 0xd3, 0xfa, 0xff, 0xfa,
+0x03, 0x34, 0xef, 0x9d, 0xc9, 0xe1, 0x5d, 0xec, 0xf5, 0xf1, 0x79, 0x8c,
+0x97, 0xd2, 0x24, 0xc1, 0x2d, 0xe0, 0x39, 0x16, 0x1e, 0xa9, 0x41, 0xc3,
+0xbf, 0x4a, 0xd9, 0x3c, 0xea, 0x77, 0x96, 0x55, 0xe6, 0x95, 0xc3, 0xf1,
+0x8e, 0x7b, 0x4f, 0xad, 0x61, 0xf8, 0xe7, 0x01, 0xad, 0x46, 0xf5, 0x2c,
+0xac, 0x55, 0x2c, 0x94, 0xaa, 0x46, 0xfb, 0x5e, 0xcd, 0xaa, 0x1f, 0x78,
+0x4f, 0x2f, 0xd1, 0xc9, 0x02, 0xd6, 0x2c, 0x67, 0xef, 0x3f, 0x54, 0xab,
+0xda, 0x03, 0x79, 0x1f, 0xab, 0xfd, 0x0c, 0x38, 0x3c, 0xbc, 0xe1, 0xd5,
+0x01, 0xf6, 0xfb, 0xfb, 0xf1, 0x70, 0xee, 0xfd, 0x90, 0x13, 0x97, 0xc4,
+0xbc, 0x08, 0xe7, 0x4b, 0x88, 0x34, 0xf7, 0x56, 0x1e, 0x0c, 0xdb, 0xe4,
+0x9c, 0x78, 0xf1, 0xf4, 0x62, 0x4c, 0xb5, 0xf7, 0xdd, 0xd9, 0x4c, 0x5a,
+0x69, 0xa6, 0x36, 0x27, 0x03, 0xbe, 0x86, 0xc2, 0x72, 0xa2, 0x60, 0x73,
+0xf1, 0xe0, 0x17, 0x50, 0xb5, 0x93, 0x81, 0xac, 0xf1, 0xc9, 0xd4, 0x66,
+0x73, 0x71, 0xce, 0x63, 0xa8, 0x60, 0x98, 0xda, 0x86, 0x46, 0x72, 0xec,
+0x54, 0xc1, 0xe6, 0x8a, 0x10, 0x23, 0x2d, 0x0c, 0xdd, 0x44, 0x0b, 0xa0,
+0x44, 0xa4, 0x9d, 0x0e, 0x64, 0x31, 0x30, 0x45, 0xb1, 0x97, 0x4c, 0x6d,
+0x9f, 0x43, 0x99, 0x71, 0xa8, 0x9a, 0xe6, 0xbd, 0x3a, 0xe1, 0xff, 0x7f,
+0x33, 0x61, 0xf1, 0x48, 0xda, 0x48, 0x28, 0x10, 0x23, 0x9b, 0x24, 0xeb,
+0xee, 0xbd, 0x35, 0x0e, 0x6e, 0x75, 0x23, 0x20, 0xd6, 0x95, 0x8c, 0xa5,
+0x24, 0xec, 0x44, 0x67, 0x52, 0x2e, 0x78, 0x2a, 0xba, 0x3e, 0x3a, 0x4e,
+0xc9, 0x5c, 0x23, 0xb0, 0xd5, 0xfb, 0x29, 0xaf, 0x9a, 0x0b, 0x90, 0x89,
+0xd8, 0xec, 0xa9, 0xa8, 0x13, 0xfc, 0x22, 0xfa, 0xf2, 0x74, 0x2f, 0x4e,
+0x35, 0xb0, 0x6d, 0x6c, 0xfd, 0xc4, 0xfe, 0xd0, 0x98, 0x3d, 0xe5, 0x43,
+0x0a, 0xd0, 0x33, 0x26, 0x3b, 0x12, 0x7d, 0x65, 0xa1, 0xff, 0xff, 0x6f,
+0x53, 0x0e, 0x28, 0x84, 0xa7, 0xa2, 0x2e, 0xf8, 0x4a, 0xb6, 0xa1, 0x47,
+0xf5, 0xd0, 0x13, 0x9d, 0xd9, 0x50, 0xef, 0x9f, 0x31, 0xb4, 0x13, 0x67,
+0xf9, 0x0a, 0x99, 0xb5, 0x80, 0xec, 0x4a, 0x1a, 0x59, 0x21, 0x3b, 0xce,
+0xc5, 0x7e, 0x96, 0x85, 0x92, 0xc5, 0xb0, 0x75, 0xaa, 0x41, 0x16, 0xa9,
+0xd3, 0xde, 0x13, 0x7d, 0xd9, 0x61, 0x30, 0x1c, 0x73, 0x61, 0x54, 0x90,
+0xcf, 0xd4, 0xe8, 0xfe, 0xbf, 0xbf, 0x36, 0x57, 0x26, 0x38, 0xab, 0x06,
+0xc4, 0x7e, 0x3c, 0x5b, 0x35, 0xd2, 0x7c, 0x2c, 0x0a, 0x82, 0xf2, 0xa8,
+0xf2, 0x8b, 0x48, 0xa9, 0x90, 0x00, 0x01, 0x10, 0x10, 0x14, 0x04, 0x00,
+0x32, 0xa2, 0x06, 0x82, 0x28, 0x90, 0xc2, 0xb4, 0x85, 0xda, 0x01, 0x52,
+0xe9, 0x18, 0x85, 0x60, 0x00, 0x00, 0x20, 0x0c, 0x00, 0x14, 0x41, 0x00,
+0x40, 0xa0, 0x04, 0x40, 0x00, 0x80, 0x50, 0x03, 0x01, 0x10, 0x18, 0x01,
+0x80, 0xd4, 0x14, 0x99, 0x01, 0xfd, 0x07, 0xf8, 0x16, 0x0e, 0xd9, 0x5d,
+0xa3, 0x70, 0xfe, 0xda, 0x17, 0xfa, 0xce, 0x46, 0x9a, 0x99, 0x81, 0x1a,
+0x39, 0xba, 0x63, 0xb1, 0x18, 0x11, 0x58, 0xd7, 0xc7, 0xba, 0x03, 0x3e,
+0x01, 0xf2, 0xf9, 0x4e, 0x12, 0xa3, 0x50, 0x7b, 0xaf, 0x7b, 0x60, 0x5c,
+0x83, 0x23, 0xd2, 0x60, 0x27, 0x84, 0xad, 0xb8, 0x02, 0xed, 0xfe, 0xb4,
+0x9c, 0x08, 0x9f, 0x49, 0xae, 0x55, 0x02, 0x94, 0xc0, 0x1b, 0x90, 0x75,
+0x0b, 0x90, 0xc4, 0xc7, 0x43, 0x9e, 0x67, 0x25, 0x70, 0x61, 0x0d, 0xb8,
+0x7a, 0x97, 0x43, 0xfc, 0xd1, 0x7e, 0x68, 0xed, 0x03, 0xb7, 0x1e, 0x75,
+0xe9, 0x4d, 0x7a, 0x23, 0x18, 0x37, 0x63, 0x6f, 0xab, 0x5f, 0x7c, 0x5b,
+0x1c, 0x05, 0xdf, 0x3f, 0x00, 0x86, 0x37, 0xa0, 0xfa, 0x0c, 0xe0, 0xed,
+0x35, 0x35, 0x2f, 0xd8, 0xd1, 0x75, 0xba, 0x37, 0x34, 0x7e, 0xb0, 0x84,
+0x2a, 0x01, 0x0c, 0x98, 0xed, 0x47, 0xf9, 0x86, 0x81, 0x74, 0x00, 0x5d,
+0x8b, 0x4c, 0x18, 0x8a, 0x31, 0xcd, 0xae, 0x07, 0x44, 0xb5, 0xd5, 0x07,
+0xa0, 0xdf, 0xf4, 0xfa, 0xa6, 0x42, 0xd0, 0x4f, 0x17, 0xd8, 0xdf, 0xb6,
+0x34, 0x44, 0xe3, 0x01, 0xc4, 0xb6, 0x2d, 0xb5, 0x56, 0xc6, 0x2a, 0x1f,
+0x05, 0x6c, 0x35, 0xe0, 0x09, 0x31, 0xef, 0x60, 0xfe, 0xaf, 0x07, 0x80,
+0x32, 0xa0, 0xe9, 0xd3, 0x96, 0x45, 0xa7, 0xaa, 0xb6, 0xfb, 0x03, 0x10,
+0xe3, 0x97, 0x96, 0x8d, 0x3a, 0x01, 0xdd, 0x58, 0x58, 0x78, 0x00, 0xab,
+0xff, 0x06, 0xa0, 0xd6, 0x01, 0x58, 0x08, 0xb7, 0xdc, 0x2d, 0xa7, 0xfb,
+0x22, 0xa8, 0x67, 0x00, 0xe3, 0xcf, 0x82, 0x43, 0xfc, 0x96, 0x1b, 0x40,
+0x63, 0xcf, 0x9d, 0x42, 0x5d, 0x66, 0x40, 0xaa, 0xaf, 0x28, 0x94, 0xd3,
+0x2a, 0xd4, 0x02, 0x13, 0xd2, 0xdf, 0x03, 0x9c, 0x60, 0x6b, 0x16, 0x94,
+0xb4, 0xbe, 0x62, 0xc2, 0x35, 0x60, 0x45, 0x09, 0x23, 0x5a, 0xe0, 0x85,
+0xb3, 0x03, 0x50, 0x68, 0x0c, 0x20, 0xa5, 0xf9, 0x94, 0xd2, 0x35, 0x80,
+0xad, 0x4c, 0x4e, 0x40, 0x41, 0x97, 0x92, 0x75, 0xbe, 0x0c, 0x03, 0x50,
+0x85, 0x08, 0xaf, 0x36, 0x00, 0x68, 0xaf, 0x09, 0xb3, 0x0c, 0x20, 0x4f,
+0x81, 0x6a, 0x6a, 0xf5, 0x0d, 0x70, 0x69, 0x00, 0x4c, 0xb4, 0x0f, 0x59,
+0xe7, 0x31, 0x0a, 0x45, 0x9f, 0xde, 0x90, 0xd6, 0x38, 0x80, 0x6b, 0x2c,
+0xb9, 0x2f, 0xd4, 0x01, 0x40, 0x14, 0xd5, 0xed, 0x8e, 0x01, 0x53, 0xbf,
+0x03, 0x18, 0x1e, 0xb0, 0xc1, 0x85, 0x32, 0xec, 0x78, 0x2b, 0xf0, 0xbb,
+0xbb, 0x6c, 0xf3, 0x4d, 0xdc, 0x73, 0x40, 0xfd, 0x10, 0x09, 0x9e, 0x20,
+0xe2, 0x12, 0x8c, 0xe0, 0xd2, 0xed, 0x80, 0x6b, 0xcc, 0x78, 0x20, 0x03,
+0xd0, 0x5e, 0x06, 0xf4, 0xb0, 0xc4, 0x0e, 0x15, 0x1d, 0x80, 0xb4, 0x76,
+0xdf, 0x49, 0x03, 0x50, 0x82, 0xad, 0xda, 0x8b, 0x5a, 0x61, 0xc2, 0x5e,
+0xb5, 0x1e, 0x46, 0xc0, 0xde, 0xaa, 0x0e, 0x15, 0x06, 0xd2, 0xf4, 0xb2,
+0xd1, 0xed, 0x38, 0x0a, 0x03, 0x18, 0x33, 0x1a, 0x80, 0x61, 0x3e, 0xec,
+0x7c, 0x74, 0xa8, 0x1d, 0x80, 0x1a, 0xce, 0x25, 0x1d, 0x41, 0xd1, 0xc1,
+0x03, 0x28, 0xb5, 0xaf, 0x72, 0x9c, 0x59, 0x7a, 0xe1, 0x7d, 0xc0, 0xa5,
+0x08, 0x1e, 0x18, 0x24, 0xfa, 0xbd, 0x99, 0x4a, 0x31, 0xa0, 0xea, 0xee,
+0xf8, 0x36, 0x60, 0x98, 0xc9, 0x10, 0xd1, 0xa7, 0x35, 0x00, 0x8d, 0x40,
+0x8e, 0x5a, 0x35, 0x0f, 0x80, 0xb1, 0xd4, 0x32, 0x79, 0x40, 0x34, 0x05,
+0x7e, 0x98, 0xc6, 0x80, 0x3e, 0x90, 0x01, 0x65, 0xf4, 0x80, 0x73, 0x08,
+0x64, 0xd7, 0x36, 0xc1, 0x7c, 0xc0, 0x5c, 0x75, 0x00, 0xc5, 0x09, 0x58,
+0x9c, 0x13, 0x01, 0x72, 0x37, 0x9b, 0x79, 0xe4, 0x05, 0xd1, 0x01, 0x04,
+0x98, 0x08, 0x74, 0xfd, 0xfc, 0x3f, 0x1c, 0x00, 0x73, 0x01, 0xfc, 0x1c,
+0xcc, 0x16, 0x43, 0x19, 0x1d, 0xac, 0x61, 0x4b, 0x11, 0xc2, 0xa0, 0xf2,
+0x01, 0x0b, 0x7b, 0x3b, 0xf4, 0xfc, 0x58, 0x5d, 0x2d, 0x5c, 0x01, 0x8c,
+0x62, 0x17, 0x78, 0xbe, 0x60, 0x8c, 0x01, 0x6f, 0x91, 0x49, 0x65, 0x54,
+0x92, 0xe9, 0x01, 0x1e, 0x10, 0x77, 0x35, 0x00, 0xa8, 0xd4, 0xc7, 0x71,
+0x07, 0xd8, 0xcd, 0xa3, 0x7d, 0x69, 0x20, 0xac, 0x07, 0x00, 0x35, 0xc7,
+0x62, 0xee, 0x8c, 0x7d, 0x0c, 0xb8, 0x43, 0x0e, 0x00, 0x08, 0xfb, 0xe7,
+0xec, 0x33, 0x37, 0x04, 0x80, 0x2d, 0x1d, 0xa6, 0x13, 0x34, 0x1b, 0x1d,
+0xc0, 0xca, 0x00, 0x92, 0xed, 0x2e, 0x56, 0xbe, 0x91, 0x80, 0x0c, 0x88,
+0xa6, 0x01, 0xdf, 0x7f, 0x90, 0x49, 0xed, 0x0c, 0xe0, 0x08, 0x73, 0x28,
+0x74, 0xc7, 0xe1, 0xb1, 0x03, 0x5d, 0xc5, 0xab, 0x61, 0x42, 0xdf, 0x03,
+0x43, 0xf3, 0x35, 0x04, 0xcf, 0xc6, 0x1d, 0x79, 0x07, 0x40, 0x22, 0xe4,
+0x68, 0x0d, 0x01, 0x95, 0xad, 0x72, 0x69, 0x00, 0x39, 0x9d, 0x53, 0x8f,
+0x13, 0x0d, 0xb0, 0x29, 0x79, 0x1a, 0x39, 0x20, 0x12, 0x28, 0x9b, 0x02,
+0x8f, 0x74, 0x90, 0x4c, 0xe8, 0xd1, 0x57, 0xf4, 0x01, 0x44, 0x04, 0xe0,
+0x0c, 0x82, 0x91, 0xc5, 0x4f, 0x8f, 0xc6, 0x00, 0x43, 0x85, 0x65, 0xc8,
+0xe6, 0x34, 0x1d, 0x80, 0xc0, 0xca, 0xdb, 0x57, 0x6c, 0x00, 0x72, 0x42,
+0x5f, 0xd0, 0x49, 0x57, 0x47, 0xd4, 0x97, 0x18, 0x18, 0x80, 0x68, 0x8e,
+0x0a, 0xf1, 0x6b, 0x34, 0xf1, 0x60, 0x2c, 0x41, 0x29, 0xd3, 0x3d, 0x55,
+0x95, 0xb1, 0x3c, 0xd4, 0x95, 0x42, 0xef, 0xe7, 0xca, 0x00, 0x2e, 0xce,
+0x25, 0xc2, 0xca, 0xf5, 0x00, 0x17, 0x3b, 0x8c, 0x42, 0x88, 0x03, 0xde,
+0x97, 0xe1, 0x3a, 0x74, 0xb0, 0x33, 0xe0, 0x8f, 0x47, 0xeb, 0x2a, 0x5f,
+0x36, 0x3e, 0x5a, 0xff, 0xc5, 0x80, 0xb9, 0x13, 0xa9, 0x1f, 0xf8, 0x86,
+0xc9, 0x51, 0xf8, 0x4c, 0xaa, 0xe1, 0x65, 0x80, 0xb0, 0x8b, 0x91, 0xec,
+0xcc, 0xbf, 0x70, 0x19, 0x98, 0x03, 0x10, 0xf0, 0x38, 0x40, 0xc4, 0x65,
+0xbe, 0x41, 0xb2, 0x58, 0x3f, 0xe0, 0xcc, 0x0e, 0x08, 0x2b, 0x73, 0xf4,
+0xdd, 0x86, 0x06, 0xa0, 0xc6, 0x8f, 0x1a, 0x32, 0x66, 0x50, 0x8e, 0xe1,
+0x59, 0x67, 0x00, 0xed, 0x66, 0x1d, 0xdd, 0xfa, 0x7b, 0xe2, 0x56, 0x89,
+0xd9, 0xa0, 0x4f, 0x41, 0x94, 0x28, 0xb8, 0xc6, 0xc7, 0x64, 0xde, 0x9b,
+0x64, 0x44, 0x33, 0x39, 0xb5, 0x6c, 0xb9, 0x42, 0xe7, 0x7e, 0x16, 0xd2,
+0x01, 0x12, 0x03, 0xb3, 0x48, 0x47, 0x6b, 0x75, 0x26, 0x19, 0x8c, 0xac,
+0x6f, 0xb1, 0x6f, 0xdc, 0x04, 0x27, 0x3a, 0x00, 0xd6, 0xae, 0xfa, 0xe1,
+0xf7, 0x30, 0xa4, 0xdb, 0xd5, 0x86, 0x5a, 0x07, 0x11, 0xde, 0xea, 0xf4,
+0xb0, 0x83, 0x16, 0xbb, 0xc6, 0x00, 0x6e, 0xf2, 0x6b, 0x40, 0x81, 0x01,
+0x67, 0x0e, 0xa9, 0x82, 0x23, 0x04, 0x34, 0xed, 0x02, 0xf5, 0xe4, 0x0e,
+0x58, 0xe8, 0x8a, 0x58, 0x57, 0xb0, 0x56, 0x65, 0x3d, 0x40, 0x64, 0x03,
+0x6e, 0x7b, 0x07, 0x20, 0x99, 0x90, 0x36, 0x95, 0x9f, 0xdf, 0x3d, 0xe8,
+0x00, 0xa0, 0x57, 0x8f, 0x6d, 0xa4, 0xb3, 0x1d, 0x7a, 0x06, 0xa8, 0x26,
+0x41, 0xb0, 0x8c, 0x9c, 0x10, 0x85, 0x6c, 0xb4, 0x31, 0xa6, 0x5b, 0x7a,
+0x10, 0x51, 0x15, 0x3c, 0xa2, 0x42, 0xd3, 0x23, 0x02, 0xc0, 0x17, 0x7e,
+0x03, 0x28, 0xba, 0xce, 0x9b, 0xae, 0xdd, 0x1a, 0x19, 0xd0, 0x15, 0xac,
+0xeb, 0x20, 0x3c, 0x3a, 0x00, 0xc6, 0xbb, 0x8a, 0xd5, 0x64, 0xc2, 0x21,
+0x1d, 0x6c, 0x15, 0x5a, 0xd3, 0x44, 0x98, 0x14, 0x95, 0xb3, 0xb7, 0xdd,
+0xa6, 0xea, 0x06, 0x54, 0x78, 0xc3, 0xe8, 0x79, 0x9b, 0x86, 0x29, 0x76,
+0x8b, 0x6b, 0xaa, 0x0d, 0xa8, 0x2f, 0x22, 0x2a, 0xeb, 0x68, 0x81, 0x6c,
+0x56, 0xfd, 0x79, 0xac, 0x79, 0x4b, 0xa0, 0x01, 0x3f, 0x17, 0x43, 0x82,
+0xb4, 0xd5, 0x00, 0x14, 0xb7, 0xf5, 0x00, 0xf4, 0x15, 0xa8, 0xd7, 0x4b,
+0xb1, 0xbc, 0xa8, 0x36, 0x98, 0xf0, 0x8c, 0xe7, 0xf4, 0x7b, 0x35, 0xd8,
+0xad, 0x0d, 0x5f, 0x9d, 0x96, 0xab, 0xed, 0x48, 0xe2, 0xdc, 0x1c, 0xbe,
+0x12, 0xfa, 0x41, 0x6f, 0xf5, 0x1e, 0xb6, 0x9f, 0xee, 0xac, 0x21, 0xf4,
+0xf6, 0x00, 0x38, 0xb1, 0x1f, 0xfd, 0xd0, 0x0e, 0xc7, 0xdd, 0xa0, 0x39,
+0x07, 0x8c, 0x35, 0x1f, 0x7e, 0xcc, 0xbf, 0xf6, 0xe0, 0x06, 0x66, 0x7d,
+0x10, 0x3f, 0xc5, 0x3e, 0xde, 0x42, 0xf9, 0x3d, 0x00, 0x54, 0x81, 0x67,
+0x8a, 0xe6, 0x63, 0x0d, 0x01, 0xd0, 0x31, 0xe0, 0x6e, 0xd0, 0xe1, 0x59,
+0xf6, 0x1b, 0xf7, 0x0d, 0x52, 0x06, 0x80, 0x61, 0x4f, 0xe8, 0x77, 0xdd,
+0x6f, 0x48, 0x20, 0x1d, 0xbb, 0x2a, 0x16, 0x8b, 0x54, 0x87, 0x92, 0x83,
+0xe6, 0x8f, 0x55, 0x59, 0x06, 0x00, 0xe9, 0xc5, 0xce, 0x21, 0x63, 0x87,
+0xaf, 0x86, 0xcc, 0xba, 0xd6, 0xe7, 0x00, 0xf6, 0x91, 0x92, 0x92, 0xea,
+0xe8, 0x42, 0x06, 0x69, 0x13, 0xf5, 0x00, 0xd0, 0xb0, 0xa7, 0xcb, 0x4c,
+0xb0, 0xd2, 0x2d, 0x28, 0x63, 0xf0, 0x6a, 0xc7, 0x80, 0x6a, 0x19, 0xb2,
+0x66, 0x51, 0xf3, 0xb1, 0x21, 0xa0, 0x48, 0xad, 0x1e, 0x80, 0x62, 0xaf,
+0x00, 0xf4, 0xa5, 0x4e, 0x83, 0x75, 0x1b, 0xfe, 0x00, 0xc4, 0xcf, 0x55,
+0xb2, 0x50, 0xa6, 0xeb, 0x38, 0xed, 0x8f, 0xd3, 0x1d, 0x00, 0xf6, 0xe3,
+0x90, 0x1c, 0x60, 0x9e, 0x8e, 0xeb, 0x0b, 0xba, 0x44, 0x06, 0x68, 0xbb,
+0xd3, 0x10, 0x63, 0x35, 0xe1, 0x86, 0x5c, 0x5c, 0x2b, 0x85, 0xa6, 0xe7,
+0x38, 0x2c, 0x18, 0x83, 0x1f, 0x8f, 0x9b, 0x8e, 0x4d, 0x26, 0xcd, 0x34,
+0x0c, 0x66, 0x1d, 0x70, 0xb7, 0x01, 0xe6, 0x02, 0xa8, 0x51, 0x63, 0xcf,
+0xbb, 0x03, 0xca, 0x85, 0xc6, 0x9c, 0xf6, 0xf1, 0x51, 0xe0, 0x60, 0x07,
+0x40, 0x86, 0xf0, 0x1e, 0x6e, 0xef, 0x61, 0x10, 0xd9, 0x36, 0xcc, 0xfc,
+0x58, 0xe2, 0x37, 0x0d, 0x58, 0xb7, 0xbe, 0xca, 0xc9, 0xd8, 0xcd, 0xaa,
+0xd5, 0x5b, 0x77, 0x83, 0xcb, 0x0e, 0x30, 0xce, 0xc8, 0xb8, 0xcd, 0xbf,
+0x1e, 0x63, 0x04, 0xad, 0xb7, 0xcd, 0x43, 0x62, 0x4c, 0xe0, 0x1a, 0xd4,
+0x21, 0xe2, 0xdd, 0x33, 0xdf, 0xb1, 0xdd, 0xdc, 0x01, 0x22, 0x18, 0xce,
+0xa1, 0xd8, 0xcb, 0x67, 0xd5, 0x38, 0x4a, 0xbc, 0xd5, 0x81, 0x3d, 0x03,
+0x98, 0x35, 0x60, 0x41, 0x85, 0x0c, 0x1d, 0xe7, 0x76, 0xf8, 0x11, 0x52,
+0x76, 0xf6, 0x06, 0x16, 0x02, 0x45, 0xc8, 0xd8, 0x2f, 0x5e, 0x57, 0xbc,
+0x3b, 0x89, 0x97, 0x09, 0x3e, 0x03, 0x34, 0x1a, 0x9d, 0x37, 0x87, 0x48,
+0x0a, 0xe0, 0xa7, 0x4f, 0x8c, 0x3a, 0xa2, 0xaf, 0xfd, 0x7b, 0x80, 0xcf,
+0xe5, 0x18, 0x61, 0x68, 0xba, 0x61, 0x8b, 0x09, 0xaa, 0xa3, 0x0c, 0x47,
+0x3c, 0x43, 0x03, 0xac, 0xa3, 0x2e, 0x5e, 0x72, 0x0c, 0x80, 0x19, 0x61,
+0xe6, 0x6e, 0x0e, 0xd9, 0xe8, 0xe8, 0xaf, 0x11, 0x9b, 0x4a, 0x73, 0x7a,
+0x61, 0x66, 0xf0, 0x54, 0x1d, 0x18, 0xc8, 0x23, 0x36, 0xbf, 0xb5, 0xf4,
+0x86, 0x54, 0xed, 0xb5, 0x91, 0xee, 0xb8, 0xbc, 0xde, 0xc3, 0x87, 0x9b,
+0x2f, 0x81, 0xf2, 0xee, 0xa3, 0xec, 0x02 \ No newline at end of file
diff --git a/src/zstd/contrib/single_file_libs/examples/testcard.png b/src/zstd/contrib/single_file_libs/examples/testcard.png
new file mode 100755
index 000000000..43088bb16
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/examples/testcard.png
Binary files differ
diff --git a/src/zstd/contrib/single_file_libs/zstd-in.c b/src/zstd/contrib/single_file_libs/zstd-in.c
new file mode 100644
index 000000000..cac805549
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/zstd-in.c
@@ -0,0 +1,76 @@
+/**
+ * \file zstd.c
+ * Single-file Zstandard library.
+ *
+ * Generate using:
+ * \code
+ * combine.sh -r ../../lib -o zstd.c zstd-in.c
+ * \endcode
+ */
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+/*
+ * Settings to bake for the single library file.
+ *
+ * Note: It's important that none of these affects 'zstd.h' (only the
+ * implementation files we're amalgamating).
+ *
+ * Note: MEM_MODULE stops xxhash redefining BYTE, U16, etc., which are also
+ * defined in mem.h (breaking C99 compatibility).
+ *
+ * Note: the undefs for xxHash allow Zstd's implementation to coinside with with
+ * standalone xxHash usage (with global defines).
+ *
+ * Note: multithreading is enabled for all platforms apart from Emscripten.
+ */
+#define DEBUGLEVEL 0
+#define MEM_MODULE
+#undef XXH_NAMESPACE
+#define XXH_NAMESPACE ZSTD_
+#undef XXH_PRIVATE_API
+#define XXH_PRIVATE_API
+#undef XXH_INLINE_ALL
+#define XXH_INLINE_ALL
+#define ZSTD_LEGACY_SUPPORT 0
+#define ZSTD_LIB_DICTBUILDER 0
+#define ZSTD_LIB_DEPRECATED 0
+#define ZSTD_NOBENCH
+#ifndef __EMSCRIPTEN__
+#define ZSTD_MULTITHREAD
+#endif
+
+#include "common/debug.c"
+#include "common/entropy_common.c"
+#include "common/error_private.c"
+#include "common/fse_decompress.c"
+#include "common/threading.c"
+#include "common/pool.c"
+#include "common/zstd_common.c"
+
+#include "compress/fse_compress.c"
+#include "compress/hist.c"
+#include "compress/huf_compress.c"
+#include "compress/zstd_compress_literals.c"
+#include "compress/zstd_compress_sequences.c"
+#include "compress/zstd_compress_superblock.c"
+#include "compress/zstd_compress.c"
+#include "compress/zstd_double_fast.c"
+#include "compress/zstd_fast.c"
+#include "compress/zstd_lazy.c"
+#include "compress/zstd_ldm.c"
+#include "compress/zstd_opt.c"
+#ifdef ZSTD_MULTITHREAD
+#include "compress/zstdmt_compress.c"
+#endif
+
+#include "decompress/huf_decompress.c"
+#include "decompress/zstd_ddict.c"
+#include "decompress/zstd_decompress.c"
+#include "decompress/zstd_decompress_block.c"
diff --git a/src/zstd/contrib/single_file_libs/zstddeclib-in.c b/src/zstd/contrib/single_file_libs/zstddeclib-in.c
new file mode 100644
index 000000000..a9083dd34
--- /dev/null
+++ b/src/zstd/contrib/single_file_libs/zstddeclib-in.c
@@ -0,0 +1,54 @@
+/**
+ * \file zstddeclib.c
+ * Single-file Zstandard decompressor.
+ *
+ * Generate using:
+ * \code
+ * combine.sh -r ../../lib -o zstddeclib.c zstddeclib-in.c
+ * \endcode
+ */
+/*
+ * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+/*
+ * Settings to bake for the standalone decompressor.
+ *
+ * Note: It's important that none of these affects 'zstd.h' (only the
+ * implementation files we're amalgamating).
+ *
+ * Note: MEM_MODULE stops xxhash redefining BYTE, U16, etc., which are also
+ * defined in mem.h (breaking C99 compatibility).
+ *
+ * Note: the undefs for xxHash allow Zstd's implementation to coinside with with
+ * standalone xxHash usage (with global defines).
+ */
+#define DEBUGLEVEL 0
+#define MEM_MODULE
+#undef XXH_NAMESPACE
+#define XXH_NAMESPACE ZSTD_
+#undef XXH_PRIVATE_API
+#define XXH_PRIVATE_API
+#undef XXH_INLINE_ALL
+#define XXH_INLINE_ALL
+#define ZSTD_LEGACY_SUPPORT 0
+#define ZSTD_LIB_COMPRESSION 0
+#define ZSTD_LIB_DEPRECATED 0
+#define ZSTD_NOBENCH
+#define ZSTD_STRIP_ERROR_STRINGS
+
+#include "common/debug.c"
+#include "common/entropy_common.c"
+#include "common/error_private.c"
+#include "common/fse_decompress.c"
+#include "common/zstd_common.c"
+
+#include "decompress/huf_decompress.c"
+#include "decompress/zstd_ddict.c"
+#include "decompress/zstd_decompress.c"
+#include "decompress/zstd_decompress_block.c"
diff --git a/src/zstd/contrib/snap/snapcraft.yaml b/src/zstd/contrib/snap/snapcraft.yaml
new file mode 100644
index 000000000..0a77946ae
--- /dev/null
+++ b/src/zstd/contrib/snap/snapcraft.yaml
@@ -0,0 +1,28 @@
+name: zstd
+version: git
+summary: Zstandard - Fast real-time compression algorithm
+description: |
+ Zstandard, or zstd as short version, is a fast lossless compression
+ algorithm, targeting real-time compression scenarios at zlib-level and better
+ compression ratios. It's backed by a very fast entropy stage, provided by
+ Huff0 and FSE library
+
+grade: devel # must be 'stable' to release into candidate/stable channels
+confinement: devmode # use 'strict' once you have the right plugs and slots
+
+apps:
+ zstd:
+ command: usr/local/bin/zstd
+ plugs: [home, removable-media]
+ zstdgrep:
+ command: usr/local/bin/zstdgrep
+ plugs: [home, removable-media]
+ zstdless:
+ command: usr/local/bin/zstdless
+ plugs: [home, removable-media]
+
+parts:
+ zstd:
+ source: .
+ plugin: make
+ build-packages: [g++]