packages feed

zstd (empty) → 0.1.0.0

raw patch · 55 files changed

+20590/−0 lines, 55 filesdep +QuickCheckdep +basedep +bytestringsetup-changed

Dependencies added: QuickCheck, base, bytestring, criterion, deepseq, ghc-prim, test-framework, test-framework-quickcheck2, zlib, zstd

Files

+ CONTRIBUTING.md view
@@ -0,0 +1,63 @@+# Contributing to `hs-zstd`++We want to make contributing to this project as easy and transparent as+possible.++## Our development process++This library is developed in the open on GitHub.  We publish+occasional releases to Hackage, either to fix bugs or add new+functionality.++If you run into problems with either the code, documentation, or+examples, please+[file a GitHub issue](https://github.com/facebookexperimental/hs-zstd/issues).++(Note: if you'd like to file an issue requesting new functionality,+rather than bugfixes, please plan to implement that functionality+yourself and submit a pull request. We regret that we are very+unlikely to have time to extend the library for you.)++## Pull Requests++We very much welcome your pull requests! To respect our time, we+request that you follow the conventions below.++1. Fork the repo and create your branch from `master`.+2. If you're adding code or functionality, please add tests (and, if+   necessary) examples.+3. If you're changing APIs, please update the appropriate+   documentation and examples, and the [changelog](changelog.md).+   (Breaking API changes have a high bar for approval.)+4. Ensure that the test suite passes (`cabal test`).+5. Make sure your code conforms to the existing style you see in the+   code base.+6. Tidy up your commit history before submitting a pull request.  This+   means one commit per logical change, please.+7. If you haven't yet done so, please complete our Contributor License+   Agreement ("CLA").++## Contributor License Agreement ("CLA")++In order to accept your pull request, we need you to submit a CLA. You+only need to do this once, after which you can work on any of+Facebook's open source projects.++Complete your CLA here: <https://code.facebook.com/cla>++## Issues++We use GitHub issues to track public bugs.  Please ensure that your+description is clear and has sufficient instructions for us be able to+reproduce the issue.++Facebook has a [bounty program](https://www.facebook.com/whitehat/)+for the safe disclosure of security bugs. In those cases, please go+through the process outlined on that page and do not file a public+issue.++## License++By contributing to `hs-zstd`, you agree that your contributions will+be licensed under the [`LICENSE`](LICENSE) file in the root directory+of this source tree.
+ Codec/Compression/Zstd.hs view
@@ -0,0 +1,97 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++-- |+-- Module      : Codec.Compression.Zstd+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- A fast lossless compression algorithm, targeting real-time+-- compression scenarios at zlib-level and better compression ratios.++module Codec.Compression.Zstd+    (+    -- * Basic pure API+      compress+    , Decompress(..)+    , decompressedSize+    , decompress+    , C.maxCLevel++    -- * Dictionary-based compression+    , Dict+    , mkDict+    , fromDict+    , trainFromSamples+    , getDictID++    -- ** Basic pure API+    , compressUsingDict+    , decompressUsingDict+    ) where++import Codec.Compression.Zstd.Internal+import Codec.Compression.Zstd.Types (Decompress(..), Dict(..), mkDict)+import Data.ByteString.Internal (ByteString(..))+import System.IO.Unsafe (unsafePerformIO)+import qualified Codec.Compression.Zstd.FFI as C++-- | Compress the given data as a single zstd compressed frame.+compress :: Int+         -- ^ Compression level. Must be >= 1 and <= 'C.maxCLevel'.+         -> ByteString+         -- ^ Payload to compress.+         -> ByteString+compress level bs = unsafePerformIO $+  compressWith "compress" C.compress level bs++-- | Decompress a single-frame payload of known size.  Typically this+-- will be a payload that was compressed with 'compress'.+--+-- /Note:/ This function is not capable of decompressing a payload+-- generated by the streaming or lazy compression APIs.+decompress :: ByteString -> Decompress+decompress bs = unsafePerformIO $ decompressWith C.decompress bs++-- | Compress the given data as a single zstd compressed frame, using+-- a prebuilt dictionary.+compressUsingDict :: Dict+                  -- ^ Compression dictionary.+                  -> Int+                  -- ^ Compression level. Must be >= 1 and <= 'C.maxCLevel'.+                  -> ByteString+                  -- ^ Payload to compress.+                  -> ByteString+compressUsingDict dict level bs =+  unsafePerformIO . withCCtx $ \(CCtx ctx) ->+    withDict dict $ \dictPtr dictLen ->+      let compressor dp dl sp sl l =+            C.compressUsingDict ctx dp dl sp sl dictPtr dictLen l+      in compressWith "compressUsingDict" compressor level bs++-- | Decompress a single-frame payload of known size, using a prebuilt+-- dictionary.  Typically this will be a payload that was compressed+-- with 'compressUsingDict'.+--+-- /Note:/ This function is not capable of decompressing a payload+-- generated by the streaming or lazy compression APIs.+decompressUsingDict :: Dict+                    -- ^ Dictionary.+                    -> ByteString+                    -- ^ Payload to decompress.+                    -> Decompress+decompressUsingDict dict bs =+  unsafePerformIO . withDCtx $ \(DCtx ctx) ->+    withDict dict $ \dictPtr dictLen ->+      let decompressor dp dl sp sl =+            C.decompressUsingDict ctx dp dl sp sl dictPtr dictLen+      in decompressWith decompressor bs
+ Codec/Compression/Zstd/Base.hs view
@@ -0,0 +1,402 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++-- |+-- Module      : Codec.Compression.Zstd.Base+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- Mid-level bindings to the native zstd compression library.  These+-- bindings provide a little more safety and ease of use than the+-- lowest-level FFI bindings.  Unless you have highly specialized+-- needs, you should use the streaming or other higher-level APIs+-- instead.++module Codec.Compression.Zstd.Base+    (+    -- * One-shot functions+      compress+    , compressBound+    , maxCLevel+    , decompress+    , getDecompressedSize++    -- ** Cheaper operations using contexts+    -- *** Compression+    , CCtx+    , withCCtx+    , compressCCtx++    -- *** Decompression+    , DCtx+    , withDCtx+    , decompressDCtx++    -- * Streaming operations+    -- ** Streaming types+    , CStream+    , DStream+    , FFI.Buffer(..)+    , FFI.In+    , FFI.Out++    -- ** Streaming compression+    , cstreamInSize+    , cstreamOutSize+    , createCStream+    , initCStream+    , compressStream+    , endStream++    -- ** Streaming decompression+    , dstreamInSize+    , dstreamOutSize+    , createDStream+    , initDStream+    , decompressStream++    -- * Dictionary compression+    , trainFromBuffer+    , getDictID++    , compressUsingDict+    , decompressUsingDict++    -- ** Pre-digested dictionaries+    -- *** Compression+    , CDict+    , createCDict+    , compressUsingCDict++    -- *** Decompression+    , DDict+    , createDDict+    , decompressUsingDDict+    ) where++import Codec.Compression.Zstd.Base.Types (CDict(..), DDict(..))+import Codec.Compression.Zstd.FFI.Types (CCtx, DCtx)+import Control.Exception.Base (bracket)+import Data.Word (Word, Word64)+import Foreign.C.Types (CSize)+import Foreign.ForeignPtr (ForeignPtr, newForeignPtr, withForeignPtr)+import Foreign.Ptr (Ptr, castPtr)+import qualified Codec.Compression.Zstd.FFI as FFI++-- | Compress bytes from source buffer into destination buffer.+-- The destination buffer must be already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error description if it fails.+compress :: Ptr dst         -- ^ Destination buffer.+         -> Int             -- ^ Capacity of destination buffer.+         -> Ptr src         -- ^ Source buffer.+         -> Int             -- ^ Size of source buffer.+         -> Int             -- ^ Compression level.+         -> IO (Either String Int)+compress dst dstSize src srcSize level = checkError $+  FFI.compress dst (fromIntegral dstSize) src (fromIntegral srcSize)+               (fromIntegral level)++-- | The maximum compression level supported by the library.+maxCLevel :: Int+maxCLevel = fromIntegral FFI.maxCLevel++-- | Compute the maximum compressed size of given source buffer.+compressBound :: Ptr src         -- ^ Source buffer.+              -> IO Int+compressBound src = fromIntegral `fmap` FFI.compressBound src++-- | Decompress a buffer.  The destination buffer must be already+-- allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error description if it fails.+decompress :: Ptr dst         -- ^ Destination buffer.+           -> Int             -- ^ Capacity of destination buffer.+           -> Ptr src         -- ^ Source buffer.+           -> Int+           -- ^ Size of compressed input.  This must be exact, so+           -- for example supplying the size of a buffer that is+           -- larger than the compressed input will cause a failure.+           -> IO (Either String Int)+decompress dst dstSize src srcSize = checkError $+  FFI.decompress dst (fromIntegral dstSize) src (fromIntegral srcSize)++-- | Returns the decompressed size of a compressed payload if known.+--+-- To discover precisely why a result is not known, follow up with+-- 'FFI.getFrameParams'.+getDecompressedSize :: Ptr src+                    -> Int+                    -> IO (Maybe Word64)+getDecompressedSize src srcSize = do+  ret <- FFI.getDecompressedSize src (fromIntegral srcSize)+  return $! if ret == 0+            then Nothing+            else Just (fromIntegral ret)++-- | Allocate a compression context, run an action that may reuse the+-- context as many times as it needs, then free the context.+withCCtx :: (Ptr CCtx -> IO a) -> IO a+withCCtx act =+  bracket (FFI.checkAlloc "withCCtx" FFI.createCCtx) FFI.freeCCtx act++-- | Compress bytes from source buffer into destination buffer.+-- The destination buffer must be already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error description if it fails.+compressCCtx :: Ptr CCtx    -- ^ Compression context.+             -> Ptr dst     -- ^ Destination buffer.+             -> Int         -- ^ Capacity of destination buffer.+             -> Ptr src     -- ^ Source buffer.+             -> CSize       -- ^ Size of source buffer.+             -> Int         -- ^ Compression level.+             -> IO (Either String Int)+compressCCtx cctx dstPtr dstSize srcPtr srcSize level = checkError $+  FFI.compressCCtx cctx dstPtr (fromIntegral dstSize)+                        srcPtr (fromIntegral srcSize)+                        (fromIntegral level)++-- | Allocate a decompression context, run an action that may reuse+-- the context as many times as it needs, then free the context.+withDCtx :: (Ptr DCtx -> IO a) -> IO a+withDCtx act =+  bracket (FFI.checkAlloc "withDCtx" FFI.createDCtx) FFI.freeDCtx act++-- | Decompress a buffer.  The destination buffer must be already+-- allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error description if it fails.+decompressDCtx :: Ptr DCtx        -- ^ Decompression context.+               -> Ptr dst         -- ^ Destination buffer.+               -> Int             -- ^ Capacity of destination buffer.+               -> Ptr src         -- ^ Source buffer.+               -> Int+               -- ^ Size of compressed input.  This must be exact, so+               -- for example supplying the size of a buffer that is+               -- larger than the compressed input will cause a failure.+               -> IO (Either String Int)+decompressDCtx dctx dst dstSize src srcSize = checkError $+  FFI.decompressDCtx dctx dst (fromIntegral dstSize) src (fromIntegral srcSize)++-- | Recommended size for input buffer.+cstreamInSize :: Int+cstreamInSize = fromIntegral FFI.cstreamInSize++-- | Recommended size for output buffer.+cstreamOutSize :: Int+cstreamOutSize = fromIntegral FFI.cstreamOutSize++-- | A context for streaming compression.+newtype CStream = CS (ForeignPtr FFI.CStream)++-- | Create a 'CStream' value.  After use, this will eventually be+-- freed via a finalizer.+createCStream :: IO CStream+createCStream = do+  cs <- FFI.checkAlloc "createCStream" FFI.createCStream+  cfp <- newForeignPtr FFI.p_freeCStream cs+  return (CS cfp)++-- | Begin a new streaming compression operation.+initCStream :: CStream+            -> Int              -- ^ Compression level.+            -> IO (Either String ())+initCStream (CS cfp) level =+  fmap (fmap (const ())) $ checkError $ withForeignPtr cfp $ \cs ->+    FFI.initCStream cs (fromIntegral level)++-- | Consume part or all of an input.+compressStream :: CStream -> Ptr (FFI.Buffer FFI.Out) -> Ptr (FFI.Buffer FFI.In)+               -> IO (Either String Int)+compressStream (CS cfp) bi bo = checkError $+  withForeignPtr cfp $ \cs ->+    FFI.compressStream cs bi bo++-- | End a compression stream. This performs a flush and writes a+-- frame epilogue.+endStream :: CStream -> Ptr (FFI.Buffer FFI.Out) -> IO (Either String Int)+endStream (CS cfp) bo = checkError $+  withForeignPtr cfp $ \cs ->+    FFI.endStream cs bo++-- | Recommended size for input buffer.+dstreamInSize :: Int+dstreamInSize = fromIntegral FFI.dstreamInSize++-- | Recommended size for output buffer.+dstreamOutSize :: Int+dstreamOutSize = fromIntegral FFI.dstreamOutSize++-- | A context for streaming decompression.+newtype DStream = DS (ForeignPtr FFI.DStream)++-- | Create a streaming decompression context.  After use, this will+-- eventually be freed via a finalizer.+createDStream :: IO DStream+createDStream = do+  ds <- FFI.checkAlloc "createDStream" FFI.createDStream+  dfp <- newForeignPtr FFI.p_freeDStream ds+  return (DS dfp)++-- | Begin a new streaming decompression operation.+initDStream :: DStream+            -> IO (Either String ())+initDStream (DS dfp) =+  fmap (fmap (const ())) $ checkError $ withForeignPtr dfp FFI.initDStream++-- | Consume part or all of an input.+decompressStream :: DStream -> Ptr (FFI.Buffer FFI.Out)+                 -> Ptr (FFI.Buffer FFI.In) -> IO (Either String Int)+decompressStream (DS dfp) bi bo = checkError $+  withForeignPtr dfp $ \ds ->+    FFI.decompressStream ds bi bo++-- | Train a dictionary from a collection of samples.+-- Returns the number size of the resulting dictionary.+trainFromBuffer :: Ptr dict+                -- ^ Preallocated dictionary buffer.+                -> Int+                -- ^ Capacity of dictionary buffer.+                -> Ptr samples+                -- ^ Concatenated samples.+                -> Ptr Int+                -- ^ Array of sizes of samples.+                -> Int+                -- ^ Number of samples.+                -> IO (Either String Int)+trainFromBuffer dictPtr dictSize sampPtr sampSizes sampCount = checkError $+  FFI.trainFromBuffer dictPtr (fromIntegral dictSize)+                      sampPtr (castPtr sampSizes) (fromIntegral sampCount)++-- | Return the identifier for the given dictionary, or 'Nothing' if+-- not a valid dictionary.+getDictID :: Ptr dict -> Int -> IO (Maybe Word)+getDictID ptr size = do+  n <- FFI.getDictID ptr (fromIntegral size)+  return $! if n == 0+            then Nothing+            else Just (fromIntegral n)++-- | Compress bytes from source buffer into destination buffer.+-- The destination buffer must be already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error description if it fails.+compressUsingDict :: Ptr CCtx+                  -> Ptr dst         -- ^ Destination buffer.+                  -> Int             -- ^ Capacity of destination buffer.+                  -> Ptr src         -- ^ Source buffer.+                  -> Int             -- ^ Size of source buffer.+                  -> Ptr dict        -- ^ Dictionary.+                  -> Int             -- ^ Size of dictionary.+                  -> Int             -- ^ Compression level.+                  -> IO (Either String Int)+compressUsingDict ctx dst dstSize src srcSize dict dictSize level = checkError $+  FFI.compressUsingDict ctx dst (fromIntegral dstSize)+    src (fromIntegral srcSize) dict (fromIntegral dictSize) (fromIntegral level)++-- | Decompress a buffer.  The destination buffer must be already+-- allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error description if it fails.+decompressUsingDict :: Ptr DCtx+                    -> Ptr dst         -- ^ Destination buffer.+                    -> Int             -- ^ Capacity of destination buffer.+                    -> Ptr src         -- ^ Source buffer.+                    -> Int+                    -- ^ Size of compressed input.  This must be exact, so+                    -- for example supplying the size of a buffer that is+                    -- larger than the compressed input will cause a failure.+                    -> Ptr dict        -- ^ Dictionary.+                    -> Int             -- ^ Size of dictionary.+                    -> IO (Either String Int)+decompressUsingDict ctx dst dstSize src srcSize dict dictSize = checkError $+  FFI.decompressUsingDict ctx dst (fromIntegral dstSize)+    src (fromIntegral srcSize) dict (fromIntegral dictSize)++-- | Create a pre-digested compression dictionary.  After use, this+-- will eventually be freed via a finalizer.+createCDict :: Ptr dict+            -- ^ Dictionary.+            -> Int+            -- ^ Size of dictionary.+            -> Int+            -- ^ Compression level.+            -> IO CDict+createCDict dict size level = do+  cd <- FFI.checkAlloc "createCDict" $+        FFI.createCDict dict (fromIntegral size) (fromIntegral level)+  fp <- newForeignPtr FFI.p_freeCDict cd+  return (CD fp)++-- | Compress bytes from source buffer into destination buffer, using+-- a pre-digested dictionary.  The destination buffer must be already+-- allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error description if it fails.+compressUsingCDict+    :: Ptr CCtx    -- ^ Compression context.+    -> Ptr dst     -- ^ Destination buffer.+    -> Int         -- ^ Capacity of destination buffer.+    -> Ptr src     -- ^ Source buffer.+    -> Int         -- ^ Size of source buffer.+    -> CDict       -- ^ Dictionary.+    -> IO (Either String Int)+compressUsingCDict ctx dst dstSize src srcSize (CD fp) =+  checkError . withForeignPtr fp $ \ dict ->+  FFI.compressUsingCDict ctx dst (fromIntegral dstSize)+    src (fromIntegral srcSize) dict++-- | Create a pre-digested decompression dictionary.  After use, this+-- will eventually be freed via a finalizer.+createDDict :: Ptr dict+            -- ^ Dictionary.+            -> Int+            -- ^ Size of dictionary.+            -> IO DDict+createDDict dict size = do+  cd <- FFI.checkAlloc "createDDict" $+        FFI.createDDict dict (fromIntegral size)+  fp <- newForeignPtr FFI.p_freeDDict cd+  return (DD fp)++-- | Decompress bytes from source buffer into destination buffer,+-- using a pre-digested dictionary.  The destination buffer must be+-- already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error description if it fails.+decompressUsingDDict+    :: Ptr DCtx    -- ^ Compression context.+    -> Ptr dst     -- ^ Destination buffer.+    -> Int         -- ^ Capacity of destination buffer.+    -> Ptr src     -- ^ Source buffer.+    -> Int         -- ^ Size of source buffer.+    -> DDict       -- ^ Dictionary.+    -> IO (Either String Int)+decompressUsingDDict ctx dst dstSize src srcSize (DD fp) =+  checkError . withForeignPtr fp $ \ dict ->+  FFI.decompressUsingDDict ctx dst (fromIntegral dstSize)+    src (fromIntegral srcSize) dict++checkError :: IO CSize -> IO (Either String Int)+checkError act = do+  ret <- act+  return $! if FFI.isError ret+            then Left (FFI.getErrorName ret)+            else Right (fromIntegral ret)
+ Codec/Compression/Zstd/Base/Types.hs view
@@ -0,0 +1,28 @@+-- |+-- Module      : Codec.Compression.Zstd.Base.Types+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- Mid-level bindings to the native zstd compression library.  These+-- bindings provide a little more safety and ease of use than the+-- lowest-level FFI bindings.  Unless you have highly specialized+-- needs, you should use the streaming API instead.++module Codec.Compression.Zstd.Base.Types+    (+      CDict(..)+    , DDict(..)+    ) where++import Foreign.ForeignPtr (ForeignPtr)+import qualified Codec.Compression.Zstd.FFI.Types as FFI++-- | A pre-digested compression dictionary.+newtype CDict = CD (ForeignPtr FFI.CDict)++-- | A pre-digested decompression dictionary.+newtype DDict = DD (ForeignPtr FFI.DDict)
+ Codec/Compression/Zstd/Efficient.hs view
@@ -0,0 +1,175 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++-- |+-- Module      : Codec.Compression.Zstd.Efficient+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- These functions allow for pre-allocation and reuse of relatively+-- expensive data structures, such as compression and decompression+-- contexts and dictionaries.+--+-- If your application mostly deals with small payloads and is+-- particularly sensitive to latency or throughput, using these+-- pre-allocated structures may make a noticeable difference to+-- performance.++module Codec.Compression.Zstd.Efficient+    (+    -- * Basic entry points+      Decompress(..)+    , decompressedSize+    , C.maxCLevel++    -- ** Cheaper operations using contexts+    -- *** Compression+    , CCtx+    , withCCtx+    , compressCCtx++    -- *** Decompression+    , DCtx+    , withDCtx+    , decompressDCtx++    -- * Dictionary-based compression+    , Dict+    , mkDict+    , fromDict+    , trainFromSamples+    , getDictID++    -- ** Basic pure API+    , compressUsingDict+    , decompressUsingDict++    -- ** Pre-digested dictionaries+    , Base.CDict+    , createCDict+    , compressUsingCDict++    , Base.DDict+    , createDDict+    , decompressUsingDDict+    ) where++import Codec.Compression.Zstd.Internal+import Codec.Compression.Zstd.Types (Decompress(..), Dict(..), mkDict)+import Codec.Compression.Zstd.Base.Types (CDict(..), DDict(..))+import Data.ByteString.Internal (ByteString(..))+import Foreign.ForeignPtr (withForeignPtr)+import System.IO.Unsafe (unsafePerformIO)+import qualified Codec.Compression.Zstd.FFI as C+import qualified Codec.Compression.Zstd.Base as Base++-- | Compress the given data as a single zstd compressed frame.+compressCCtx :: CCtx+             -- ^ Compression context.+             -> Int+             -- ^ Compression level. Must be >= 1 and <= 'C.maxCLevel'.+             -> ByteString+             -- ^ Payload to compress.+             -> IO ByteString+compressCCtx (CCtx cc) level bs =+  compressWith "compressCCtx" (C.compressCCtx cc) level bs++-- | Decompress a single-frame payload of known size.  Typically this+-- will be a payload that was compressed with 'compress'.+--+-- /Note:/ This function is not capable of decompressing a payload+-- generated by the streaming or lazy compression APIs.+decompressDCtx :: DCtx+               -- ^ Decompression context.+               -> ByteString+               -- ^ Compressed payload.+               -> IO Decompress+decompressDCtx (DCtx cc) bs = decompressWith (C.decompressDCtx cc) bs++-- | Compress the given data as a single zstd compressed frame, using+-- a prebuilt dictionary.+compressUsingDict :: Dict+                  -- ^ Compression dictionary.+                  -> Int+                  -- ^ Compression level. Must be >= 1 and <= 'C.maxCLevel'.+                  -> ByteString+                  -- ^ Payload to compress.+                  -> ByteString+compressUsingDict dict level bs =+  unsafePerformIO . withCCtx $ \(CCtx ctx) ->+    withDict dict $ \dictPtr dictLen ->+      let compressor dp dl sp sl l =+            C.compressUsingDict ctx dp dl sp sl dictPtr dictLen l+      in compressWith "compressUsingDict" compressor level bs++-- | Decompress a single-frame payload of known size, using a prebuilt+-- dictionary.  Typically this will be a payload that was compressed+-- with 'compressUsingDict'.+--+-- /Note:/ This function is not capable of decompressing a payload+-- generated by the streaming or lazy compression APIs.+decompressUsingDict :: Dict+                    -- ^ Dictionary.+                    -> ByteString+                    -- ^ Payload to decompress.+                    -> Decompress+decompressUsingDict dict bs =+  unsafePerformIO . withDCtx $ \(DCtx ctx) ->+    withDict dict $ \dictPtr dictLen ->+      let decompressor dp dl sp sl =+            C.decompressUsingDict ctx dp dl sp sl dictPtr dictLen+      in decompressWith decompressor bs++-- | Create a pre-digested compression dictionary.+createCDict :: Int              -- ^ Compression level.+            -> Dict             -- ^ Dictionary.+            -> CDict+createCDict level d = unsafePerformIO $+  withDict d $ \dict size -> Base.createCDict dict (fromIntegral size) level++-- | Compress the given data as a single zstd compressed frame, using+-- a pre-built, pre-digested dictionary.+compressUsingCDict :: CCtx+                   -- ^ Compression context.+                   -> CDict+                   -- ^ Compression dictionary.+                   -> ByteString+                   -- ^ Payload to compress.+                   -> IO ByteString+compressUsingCDict (CCtx ctx) (CD fp) bs =+  withForeignPtr fp $ \dict -> do+    let compressor dp dl sp sl _ = C.compressUsingCDict ctx dp dl sp sl dict+    compressWith "compressUsingCDict" compressor 0 bs++-- | Create a pre-digested compression dictionary.+createDDict :: Dict             -- ^ Dictionary.+            -> DDict+createDDict d = unsafePerformIO $+  withDict d $ \dict size -> Base.createDDict dict (fromIntegral size)++-- | Decompress a single-frame payload of known size, using a+-- pre-built, pre-digested dictionary.  Typically this will be a+-- payload that was compressed with 'compressUsingCDict'.+--+-- /Note:/ This function is not capable of decompressing a payload+-- generated by the streaming or lazy compression APIs.+decompressUsingDDict :: DCtx+                     -- ^ Decompression context.+                     -> DDict+                     -- ^ Decompression dictionary.+                     -> ByteString+                     -- ^ Payload to compress.+                     -> IO Decompress+decompressUsingDDict (DCtx ctx) (DD fp) bs =+  withForeignPtr fp $ \dict -> do+    let decompressor dp dl sp sl = C.decompressUsingDDict ctx dp dl sp sl dict+    decompressWith decompressor bs
+ Codec/Compression/Zstd/FFI.hs view
@@ -0,0 +1,461 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++{-# LANGUAGE MagicHash #-}++-- |+-- Module      : Codec.Compression.Zstd.FFI+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- Low-level bindings to the native zstd compression library.  These+-- bindings make almost no effort to provide any additional safety or+-- ease of use above that of the C library.  Unless you have highly+-- specialized needs, you should use the streaming or base APIs+-- instead.+--+-- To correctly use the functions in this module, you must read the+-- API documentation in the zstd library's @zstd.h@ include file.  It+-- would also be wise to search elsewhere in this package for uses of+-- the functions you are interested in.++module Codec.Compression.Zstd.FFI+    (+    -- * One-shot functions+      compress+    , compressBound+    , maxCLevel+    , decompress+    , getDecompressedSize++    -- ** Cheaper operations using contexts+    -- *** Compression+    , CCtx+    , createCCtx+    , freeCCtx+    , p_freeCCtx+    , compressCCtx++    -- *** Decompression+    , DCtx+    , createDCtx+    , freeDCtx+    , p_freeDCtx+    , decompressDCtx++    -- * Result and error checks+    , isError+    , getErrorName+    , checkError+    , checkAlloc++    -- * Streaming operations+    -- ** Streaming types+    , CStream+    , DStream+    , Buffer(..)+    , In+    , Out++    -- ** Streaming compression+    , cstreamInSize+    , cstreamOutSize+    , createCStream+    , freeCStream+    , p_freeCStream+    , initCStream+    , compressStream+    , endStream++    -- ** Streaming decompression+    , dstreamInSize+    , dstreamOutSize+    , createDStream+    , initDStream+    , decompressStream+    , freeDStream+    , p_freeDStream++    -- * Dictionary-based compression+    , trainFromBuffer+    , getDictID+    , compressUsingDict+    , decompressUsingDict++    -- ** Pre-digested dictionaries+    -- *** Compression+    , CDict+    , createCDict+    , freeCDict+    , p_freeCDict+    , compressUsingCDict++    -- *** Decompression+    , DDict+    , createDDict+    , freeDDict+    , p_freeDDict+    , decompressUsingDDict++    -- * Low-level code+    , c_maxCLevel+    ) where++import Codec.Compression.Zstd.FFI.Types+import Foreign.C.Types (CInt(..), CSize(..), CUInt(..), CULLong(..))+import Foreign.Ptr (FunPtr, nullPtr)+import GHC.CString (unpackCString#)+import GHC.IO.Exception+import GHC.Ptr (Ptr(..))++-- | Compress bytes from source buffer into destination buffer.+-- The destination buffer must be already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error code if it fails (which can be tested using 'isError').+foreign import ccall unsafe "ZSTD_compress"+    compress :: Ptr dst         -- ^ Destination buffer.+             -> CSize           -- ^ Capacity of destination buffer.+             -> Ptr src         -- ^ Source buffer.+             -> CSize           -- ^ Size of source buffer.+             -> CInt            -- ^ Compression level.+             -> IO CSize++-- | Returns the maximum compression level supported by the library.+foreign import ccall unsafe "ZSTD_maxCLevel"+    c_maxCLevel :: CInt++-- | The maximum compression level supported by the library.+maxCLevel :: Int+maxCLevel = fromIntegral c_maxCLevel++-- | Compute the maximum compressed size of given source buffer.+foreign import ccall unsafe "ZSTD_compressBound"+    compressBound :: Ptr src         -- ^ Source buffer.+                  -> IO CSize++foreign import ccall unsafe "ZSTD_isError"+    c_isError :: CSize -> CUInt++-- | Indicates whether a return value is an error code.+isError :: CSize -> Bool+isError sizeOrError = c_isError sizeOrError /= 0++-- | Gives the description associated with an error code.+--+-- Always returns a valid pointer to a constant string.+foreign import ccall unsafe "ZSTD_getErrorName"+    c_getErrorName :: CSize -> Ptr a++-- | Gives the description associated with an error code.+getErrorName :: CSize -> String+getErrorName cs = unpackCString# (case c_getErrorName cs of Ptr a -> a)++-- | Decompress a buffer.  The destination buffer must be already+-- allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error code if it fails (which can be tested using 'isError').+foreign import ccall unsafe "ZSTD_decompress"+    decompress :: Ptr dst         -- ^ Destination buffer.+               -> CSize           -- ^ Capacity of destination buffer.+               -> Ptr src         -- ^ Source buffer.+               -> CSize+               -- ^ Size of compressed input.  This must be exact, so+               -- for example supplying the size of a buffer that is+               -- larger than the compressed input will cause a failure.+               -> IO CSize++-- | Returns the decompressed size of a compressed payload if known, 0+-- otherwise.+--+-- To discover precisely why a result is 0, follow up with+-- 'getFrameParams'.+foreign import ccall unsafe "ZSTD_getDecompressedSize"+    getDecompressedSize :: Ptr src+                        -> CSize+                        -> IO CULLong++-- | Allocate a compression context.+foreign import ccall unsafe "ZSTD_createCCtx"+    createCCtx :: IO (Ptr CCtx)++-- | Free a compression context.+foreign import ccall unsafe "ZSTD_freeCCtx"+    freeCCtx :: Ptr CCtx -> IO ()++-- | Free a compression context.  For use by a finalizer.+foreign import ccall unsafe "zstd.h &ZSTD_freeCCtx"+    p_freeCCtx :: FunPtr (Ptr CCtx -> IO ())++-- | Compress bytes from source buffer into destination buffer.+-- The destination buffer must be already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error code if it fails (which can be tested using 'isError').+foreign import ccall unsafe "ZSTD_compressCCtx"+    compressCCtx :: Ptr CCtx    -- ^ Compression context.+                 -> Ptr dst     -- ^ Destination buffer.+                 -> CSize       -- ^ Capacity of destination buffer.+                 -> Ptr src     -- ^ Source buffer.+                 -> CSize       -- ^ Size of source buffer.+                 -> CInt        -- ^ Compression level.+                 -> IO CSize++-- | Compress bytes from source buffer into destination buffer, using+-- a prebuilt dictionary.  The destination buffer must be already+-- allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error code if it fails (which can be tested using 'isError').+foreign import ccall unsafe "ZSTD_compress_usingDict"+    compressUsingDict+        :: Ptr CCtx    -- ^ Compression context.+        -> Ptr dst     -- ^ Destination buffer.+        -> CSize       -- ^ Capacity of destination buffer.+        -> Ptr src     -- ^ Source buffer.+        -> CSize       -- ^ Size of source buffer.+        -> Ptr dict     -- ^ Dictionary.+        -> CSize       -- ^ Size of dictionary.+        -> CInt        -- ^ Compression level.+        -> IO CSize++-- | Compress bytes from source buffer into destination buffer, using+-- a pre-built, pre-digested dictionary.  The destination buffer must+-- be already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error code if it fails (which can be tested using 'isError').+foreign import ccall unsafe "ZSTD_compress_usingCDict"+    compressUsingCDict+        :: Ptr CCtx    -- ^ Compression context.+        -> Ptr dst     -- ^ Destination buffer.+        -> CSize       -- ^ Capacity of destination buffer.+        -> Ptr src     -- ^ Source buffer.+        -> CSize       -- ^ Size of source buffer.+        -> Ptr CDict   -- ^ Dictionary.+        -> IO CSize++-- | Decompress a buffer, using a prebuilt dictionary.  The+-- destination buffer must be already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error code if it fails (which can be tested using 'isError').+foreign import ccall unsafe "ZSTD_decompress_usingDict"+    decompressUsingDict+        :: Ptr DCtx        -- ^ Decompression context.+        -> Ptr dst         -- ^ Destination buffer.+        -> CSize           -- ^ Capacity of destination buffer.+        -> Ptr src         -- ^ Source buffer.+        -> CSize+        -- ^ Size of compressed input.  This must be exact, so+        -- for example supplying the size of a buffer that is+        -- larger than the compressed input will cause a failure.+        -> Ptr dict        -- ^ Dictionary.+        -> CSize           -- ^ Size of dictionary.+        -> IO CSize++-- | Decompress a buffer, using a pre-built, pre-digested dictionary.+-- The destination buffer must be already allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error code if it fails (which can be tested using 'isError').+foreign import ccall unsafe "ZSTD_decompress_usingDDict"+    decompressUsingDDict+        :: Ptr DCtx        -- ^ Decompression context.+        -> Ptr dst         -- ^ Destination buffer.+        -> CSize           -- ^ Capacity of destination buffer.+        -> Ptr src         -- ^ Source buffer.+        -> CSize+        -- ^ Size of compressed input.  This must be exact, so+        -- for example supplying the size of a buffer that is+        -- larger than the compressed input will cause a failure.+        -> Ptr DDict       -- ^ Dictionary.+        -> IO CSize++-- | Allocate a decompression context.+foreign import ccall unsafe "ZSTD_createDCtx"+    createDCtx :: IO (Ptr DCtx)++-- | Free a decompression context.+foreign import ccall unsafe "ZSTD_freeDCtx"+    freeDCtx :: Ptr DCtx -> IO ()++-- | Free a decompression context.  For use by a finalizer.+foreign import ccall unsafe "zstd.h &ZSTD_freeDCtx"+    p_freeDCtx :: FunPtr (Ptr DCtx -> IO ())++-- | Decompress a buffer.  The destination buffer must be already+-- allocated.+--+-- Returns the number of bytes written into destination buffer, or an+-- error code if it fails (which can be tested using 'isError').+foreign import ccall unsafe "ZSTD_decompressDCtx"+    decompressDCtx :: Ptr DCtx  -- ^ Decompression context.+                   -> Ptr dst   -- ^ Destination buffer.+                   -> CSize     -- ^ Capacity of destination buffer.+                   -> Ptr src   -- ^ Source buffer.+                   -> CSize+                   -- ^ Size of compressed input.  This must be exact, so+                   -- for example supplying the size of a buffer that is+                   -- larger than the compressed input will cause a failure.+                   -> IO CSize++-- | Recommended size for input buffer.+foreign import ccall unsafe "ZSTD_CStreamInSize"+    cstreamInSize :: CSize++-- | Recommended size for output buffer.+foreign import ccall unsafe "ZSTD_CStreamOutSize"+    cstreamOutSize :: CSize++-- | A context for streaming compression.+data CStream++-- | Create a streaming compression context.  This must be freed using+-- 'freeCStream', or if using a finalizer, with 'p_freeCStream'.+foreign import ccall unsafe "ZSTD_createCStream"+    createCStream :: IO (Ptr CStream)++-- | Free a 'CStream' value.+foreign import ccall unsafe "ZSTD_freeCStream"+    freeCStream :: Ptr CStream -> IO ()++-- | Free a 'CStream' value.  For use by a finalizer.+foreign import ccall unsafe "zstd.h &ZSTD_freeCStream"+    p_freeCStream :: FunPtr (Ptr CStream -> IO ())++-- | Begin a new compression operation.+foreign import ccall unsafe "ZSTD_initCStream"+    initCStream :: Ptr CStream+                -> CInt         -- ^ Compression level.+                -> IO CSize++-- | Consume part or all of an input.+foreign import ccall unsafe "ZSTD_compressStream"+    compressStream :: Ptr CStream -> Ptr (Buffer Out) -> Ptr (Buffer In)+                   -> IO CSize++-- | End a compression stream. This performs a flush and writes a+-- frame epilogue.+foreign import ccall unsafe "ZSTD_endStream"+    endStream :: Ptr CStream -> Ptr (Buffer Out) -> IO CSize++-- | Recommended size for input buffer.+foreign import ccall unsafe "ZSTD_DStreamInSize"+    dstreamInSize :: CSize++-- | Recommended size for output buffer.+foreign import ccall unsafe "ZSTD_DStreamOutSize"+    dstreamOutSize :: CSize++-- | A context for streaming decompression.+data DStream++-- | Create a streaming decompression context.  This must be freed using+-- 'freeDStream', or if using a finalizer, with 'p_freeDStream'.+foreign import ccall unsafe "ZSTD_createDStream"+    createDStream :: IO (Ptr DStream)++-- | Begin a new streaming decompression operation.+foreign import ccall unsafe "ZSTD_initDStream"+    initDStream :: Ptr DStream -> IO CSize++-- | Consume part or all of an input.+foreign import ccall unsafe "ZSTD_decompressStream"+    decompressStream :: Ptr DStream -> Ptr (Buffer Out) -> Ptr (Buffer In)+                     -> IO CSize++-- | Free a 'CStream' value.+foreign import ccall unsafe "ZSTD_freeDStream"+    freeDStream :: Ptr DStream -> IO ()++-- | Free a 'CStream' value.  For use by a finalizer.+foreign import ccall unsafe "zstd.h &ZSTD_freeDStream"+    p_freeDStream :: FunPtr (Ptr DStream -> IO ())++-- | Train a dictionary from a collection of samples.+-- Returns the number size of the resulting dictionary.+foreign import ccall unsafe "ZDICT_trainFromBuffer"+    trainFromBuffer :: Ptr dict+                    -- ^ Preallocated dictionary buffer.+                    -> CSize+                    -- ^ Capacity of dictionary buffer.+                    -> Ptr samples+                    -- ^ Concatenated samples.+                    -> Ptr CSize+                    -- ^ Array of sizes of samples.+                    -> CUInt+                    -- ^ Number of samples.+                    -> IO CSize++-- | Return the identifier for the given dictionary, or zero if+-- not a valid dictionary.+foreign import ccall unsafe "ZDICT_getDictID"+    getDictID :: Ptr dict+              -- ^ Dictionary.+              -> CSize+              -- ^ Size of dictionary.+              -> IO CUInt++-- | Allocate a pre-digested dictionary.+foreign import ccall unsafe "ZSTD_createCDict"+    createCDict :: Ptr dict+                -- ^ Dictionary.+                -> CSize+                -- ^ Size of dictionary.+                -> CInt+                -- ^ Compression level.+                -> IO (Ptr CDict)++-- | Free a pre-digested dictionary.+foreign import ccall unsafe "ZSTD_freeCDict"+    freeCDict :: Ptr CDict -> IO ()++-- | Free a pre-digested dictionary.+foreign import ccall unsafe "zstd.h &ZSTD_freeCDict"+    p_freeCDict :: FunPtr (Ptr CDict -> IO ())++-- | Allocate a pre-digested dictionary.+foreign import ccall unsafe "ZSTD_createDDict"+    createDDict :: Ptr dict+                -- ^ Dictionary.+                -> CSize+                -- ^ Size of dictionary.+                -> IO (Ptr DDict)++-- | Free a pre-digested dictionary.+foreign import ccall unsafe "ZSTD_freeDDict"+    freeDDict :: Ptr DDict -> IO ()++-- | Free a pre-digested dictionary.+foreign import ccall unsafe "zstd.h &ZSTD_freeDDict"+    p_freeDDict :: FunPtr (Ptr DDict -> IO ())++-- | Check that an allocating operation is successful.  If it fails,+-- throw an 'IOError'.+checkAlloc :: String -> IO (Ptr a) -> IO (Ptr a)+checkAlloc name act = do+  addr <- act+  if addr == nullPtr+    then ioError (IOError Nothing ResourceExhausted name+                  "out of memory" Nothing Nothing)+    else return addr++-- | Check whether a 'CSize' has an error encoded in it (yuck!), and+-- report success or failure more safely.+checkError :: IO CSize -> IO (Either String CSize)+checkError act = do+  ret <- act+  return $! if isError ret+            then Left (getErrorName ret)+            else Right ret
+ Codec/Compression/Zstd/FFI/Types.hsc view
@@ -0,0 +1,113 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++{-# LANGUAGE ExistentialQuantification #-}++-- |+-- Module      : Codec.Compression.Zstd.FFI+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- Types and functions that support the low-level FFI bindings.++module Codec.Compression.Zstd.FFI.Types+    (+      Buffer(..)+    , In+    , Out+    , CCtx+    , DCtx+    , CDict+    , DDict+    , peekPtr+    , pokePtr+    , peekSize+    , pokeSize+    , peekPos+    , pokePos+    ) where++#define ZSTD_STATIC_LINKING_ONLY+#include <zstd.h>++import Foreign.C.Types (CInt(..), CSize(..))+import Foreign.Storable+import GHC.Ptr (Ptr(..))++-- | An opaque compression context structure.+data CCtx+-- | An opaque decompression context structure.+data DCtx++-- | An opaque pre-digested compression dictionary structure.+data CDict+-- | An opaque pre-digested decompression dictionary structure.+data DDict++-- | A tag type to indicate that a 'Buffer' is used for tracking input.+data In+-- | A tag type to indicate that a 'Buffer' is used for tracking output.+data Out++-- | A streaming buffer type. The type parameter statically indicates+-- whether the buffer is used to track an input or output buffer.+data Buffer io = forall a. Buffer {+      -- | Pointer to the start of the buffer.  This can be set once+      -- by the caller, and read by the streaming function.+      bufPtr  :: {-# UNPACK #-} !(Ptr a)+      -- | Size of the buffer (in bytes).  This can be set once by the+      -- caller, and is read by the streaming function.+    , bufSize :: {-# UNPACK #-} !CSize+      -- | Current offset into the buffer (in bytes).  This must be+      -- initially set to zero by the caller, and is updated by the+      -- streaming function.+    , bufPos  :: {-# UNPACK #-} !CSize+    }++instance Storable (Buffer io) where+    sizeOf _     = #const sizeof(ZSTD_inBuffer)+    alignment _  = alignment (undefined :: CInt)++    peek p = do+      ptr <- (#peek ZSTD_inBuffer, src) p+      size <- (#peek ZSTD_inBuffer, size) p+      pos <- (#peek ZSTD_inBuffer, pos) p+      return (Buffer ptr size pos)++    poke p (Buffer ptr size pos) = do+      (#poke ZSTD_inBuffer, src) p ptr+      (#poke ZSTD_inBuffer, size) p size+      (#poke ZSTD_inBuffer, pos) p pos++-- | Read the 'bufPtr' value from a 'Buffer'.+peekPtr :: Ptr (Buffer io) -> IO CSize+peekPtr p = (#peek ZSTD_inBuffer, src) p++-- | Write to the 'bufPtr' value in a 'Buffer'.+pokePtr :: Ptr (Buffer io) -> Ptr a -> IO ()+pokePtr dst p = (#poke ZSTD_inBuffer, src) dst p++-- | Read the 'bufSize' value from a 'Buffer'.+peekSize :: Ptr (Buffer io) -> IO CSize+peekSize p = (#peek ZSTD_inBuffer, size) p++-- | Write to the 'bufSize' value in a 'Buffer'.+pokeSize :: Ptr (Buffer io) -> CSize -> IO ()+pokeSize dst s = (#poke ZSTD_inBuffer, size) dst s++-- | Read the 'bufPos' value from a 'Buffer'.+peekPos :: Ptr (Buffer io) -> IO CSize+peekPos p = (#peek ZSTD_inBuffer, pos) p++-- | Write to the 'bufPos' value in a 'Buffer'.+pokePos :: Ptr (Buffer io) -> CSize -> IO ()+pokePos dst s = (#poke ZSTD_inBuffer, pos) dst s
+ Codec/Compression/Zstd/Internal.hs view
@@ -0,0 +1,185 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++-- |+-- Module      : Codec.Compression.Zstd.Internal+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- A fast lossless compression algorithm, targeting real-time+-- compression scenarios at zlib-level and better compression ratios.++module Codec.Compression.Zstd.Internal+    (+      CCtx(..)+    , DCtx(..)+    , compressWith+    , decompressWith+    , decompressedSize+    , withCCtx+    , withDCtx+    , withDict+    , trainFromSamples+    , getDictID+    ) where++import Codec.Compression.Zstd.Types (Decompress(..), Dict(..))+import Control.Exception.Base (bracket)+import Data.ByteString.Internal (ByteString(..))+import Data.Word (Word, Word8)+import Foreign.C.Types (CInt, CSize)+import Foreign.Marshal.Array (withArray)+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Ptr (Ptr, castPtr, plusPtr)+import System.IO.Unsafe (unsafePerformIO)+import qualified Codec.Compression.Zstd.FFI as C+import qualified Data.ByteString as B+import qualified Data.ByteString.Internal as B++compressWith+    :: String+    -> (Ptr Word8 -> CSize -> Ptr Word8 -> CSize -> CInt -> IO CSize)+    -> Int+    -> ByteString+    -> IO ByteString+compressWith name compressor level (PS sfp off len)+  | level < 1 || level > C.maxCLevel+              = bail name "unsupported compression level"+  | otherwise =+  withForeignPtr sfp $ \sp -> do+    let src = sp `plusPtr` off+    maxSize <- C.compressBound src+    dfp <- B.mallocByteString (fromIntegral maxSize)+    withForeignPtr dfp $ \dst -> do+      csz <- compressor dst maxSize src (fromIntegral len) (fromIntegral level)+      handleError csz name $ do+        let size = fromIntegral csz+        if csz < 128 || csz >= maxSize `div` 2+        then return (PS dfp 0 size)+        else B.create size $ \p -> B.memcpy p dst size++-- | Return the decompressed size of a compressed payload, as stored+-- in the payload's header.+--+-- The returned value will be `Nothing` if it is either not known+-- (probably because the payload was compressed using a streaming+-- API), empty, or too large to fit in an 'Int'.+--+-- /Note:/ this value should not be trusted, as it can be controlled+-- by an attacker.+decompressedSize :: ByteString -> Maybe Int+decompressedSize (PS fp off len) =+  unsafePerformIO . withForeignPtr fp $ \ptr -> do+    sz <- C.getDecompressedSize (ptr `plusPtr` off) (fromIntegral len)+    return $ if sz == 0 || sz > fromIntegral (maxBound :: Int)+             then Nothing+             else Just (fromIntegral sz)++decompressWith :: (Ptr Word8 -> CSize -> Ptr Word8 -> CSize -> IO CSize)+               -> ByteString+               -> IO Decompress+decompressWith decompressor (PS sfp off len) = do+  withForeignPtr sfp $ \sp -> do+    let src = sp `plusPtr` off+    dstSize <- C.getDecompressedSize src (fromIntegral len)+    if dstSize == 0+      then return Skip+      else if dstSize > fromIntegral (maxBound :: Int)+           then return (Error "invalid compressed payload size")+           else do+      dfp <- B.mallocByteString (fromIntegral dstSize)+      size <- withForeignPtr dfp $ \dst ->+        decompressor dst (fromIntegral dstSize) src (fromIntegral len)+      return $ if C.isError size+               then Error (C.getErrorName size)+               else Decompress (PS dfp 0 (fromIntegral size))++-- | Compression context.+newtype CCtx = CCtx { getCCtx :: Ptr C.CCtx }++-- | Allocate a compression context, run an action that may reuse the+-- context as many times as it needs, then free the context.+withCCtx :: (CCtx -> IO a) -> IO a+withCCtx act =+  bracket (fmap CCtx (C.checkAlloc "withCCtx" C.createCCtx))+          (C.freeCCtx . getCCtx) act++-- | Decompression context.+newtype DCtx = DCtx { getDCtx :: Ptr C.DCtx }++-- | Allocate a decompression context, run an action that may reuse the+-- context as many times as it needs, then free the context.+withDCtx :: (DCtx -> IO a) -> IO a+withDCtx act =+  bracket (fmap DCtx (C.checkAlloc "withDCtx" C.createDCtx))+          (C.freeDCtx . getDCtx) act++withDict :: Dict -> (Ptr dict -> CSize -> IO a) -> IO a+withDict (Dict (PS fp off len)) act =+  withForeignPtr fp $ \ptr -> act (ptr `plusPtr` off) (fromIntegral len)++-- | Create and train a compression dictionary from a collection of+-- samples.+--+-- To create a well-trained dictionary, here are some useful+-- guidelines to keep in mind:+--+-- * A reasonable dictionary size is in the region of 100 KB.  (Trying+--   to specify a dictionary size of less than a few hundred bytes will+--   probably fail.)+--+-- * To train the dictionary well, it is best to supply a few thousand+--   training samples.+--+-- * The combined size of all training samples should be 100 or more+--   times larger than the size of the dictionary.+trainFromSamples :: Int+                 -- ^ Maximum size of the compression dictionary to+                 -- create. The actual dictionary returned may be+                 -- smaller.+                 -> [ByteString]+                 -- ^ Samples to train with.+                 -> Either String Dict+trainFromSamples capacity samples = unsafePerformIO $+  withArray (map B.length samples) $ \sizes -> do+    dfp <- B.mallocByteString capacity+    let PS sfp _ _ = B.concat samples+    withForeignPtr dfp $ \dict ->+      withForeignPtr sfp $ \sampPtr -> do+        dsz <- C.trainFromBuffer+               dict (fromIntegral capacity)+               sampPtr (castPtr sizes) (fromIntegral (length samples))+        if C.isError dsz+          then return (Left (C.getErrorName dsz))+          else fmap (Right . Dict) $ do+            let size = fromIntegral dsz+            if size < 128 || size >= capacity `div` 2+            then return (PS dfp 0 size)+            else B.create size $ \p -> B.memcpy p dict size++-- | Return the identifier for the given dictionary, or 'Nothing' if+-- not a valid dictionary.+getDictID :: Dict -> Maybe Word+getDictID dict = unsafePerformIO $ do+  n <- withDict dict C.getDictID+  return $! if n == 0+            then Nothing+            else Just (fromIntegral n)++handleError :: CSize -> String -> IO a -> IO a+handleError sizeOrError func act+  | C.isError sizeOrError+              = bail func (C.getErrorName sizeOrError)+  | otherwise = act++bail :: String -> String -> a+bail func str = error $ "Codec.Compression.Zstd." ++ func ++ ": " ++ str
+ Codec/Compression/Zstd/Lazy.hs view
@@ -0,0 +1,69 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++{-# LANGUAGE MultiWayIf #-}++-- |+-- Module      : Codec.Compression.Zstd.Lazy+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- Lazy compression and decompression support for zstd.  Under the+-- hood, these are implemented using the streaming APIs.++module Codec.Compression.Zstd.Lazy+    (+      compress+    , decompress+    , S.maxCLevel+    ) where++import Data.ByteString.Lazy.Internal as L+import System.IO.Unsafe (unsafeInterleaveIO, unsafePerformIO)+import qualified Codec.Compression.Zstd.Streaming as S+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L++-- | Compress a payload.  The input will be consumed lazily, and the+-- compressed result generated lazily.+--+-- /Note:/ if any error occurs, compression will fail part-way through+-- with a call to 'error'.+compress :: Int+         -- ^ Compression level. Must be >= 1 and <= 'S.maxCLevel'.+         -> ByteString+         -- ^ Payload to compress.  This will be consumed lazily.+         -> ByteString+compress level bs = lazy (S.compress level) bs++-- | Decompress a payload.  The input will be consumed lazily, and the+-- decompressed result generated lazily.+--+-- /Note:/ if any error occurs, decompression will fail part-way+-- through with a call to 'error'.+decompress :: ByteString -> ByteString+decompress bs = lazy S.decompress bs++lazy :: IO S.Result -> ByteString -> ByteString+lazy start b0 = unsafePerformIO (go b0 =<< start)+ where+  go _            (S.Error who what) = error (who ++ ": " ++ what)+  go bs           (S.Produce o k)    = do+    os <- unsafeInterleaveIO (go bs =<< k)+    return (L.chunk o os)+  go (Chunk c cs) (S.Consume f) = go cs =<< f c+  go empty        (S.Consume f) = go empty =<< f B.empty+  go Empty        (S.Done o)    = return (chunk o Empty)+  go input        state = error $+                          "unpossible! " +++                          show (L.length input) ++ " bytes of input left, " +++                          show state ++ " stream state"
+ Codec/Compression/Zstd/Streaming.hs view
@@ -0,0 +1,196 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++{-# LANGUAGE MultiWayIf #-}++-- |+-- Module      : Codec.Compression.Zstd.Streaming+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- Streaming compression and decompression support for zstd.++module Codec.Compression.Zstd.Streaming+    (+      Result(..)+    , compress+    , decompress+    , maxCLevel+    ) where++import Codec.Compression.Zstd.FFI hiding (compress, decompress)+import Codec.Compression.Zstd.FFI.Types (peekPos)+import qualified Data.ByteString as B+import Data.ByteString.Internal (ByteString(..), mallocByteString)+import Foreign.Marshal.Alloc (finalizerFree, malloc)+import Foreign.C.Types (CSize)+import Foreign.ForeignPtr+import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)+import Foreign.Storable (poke)+import Foreign.Ptr (Ptr, plusPtr)+import Data.Word (Word8)++-- | The result of a streaming compression or decompression step.+data Result+  = Produce ByteString (IO Result)+    -- ^ A single frame of transformed data, and an action that when+    -- executed will yield the next step in the streaming operation.+    -- The action is ephemeral; you should discard it as soon as you+    -- use it.+  | Consume (ByteString -> IO Result)+    -- ^ Provide the function with more input for the streaming+    -- operation to continue.  This function is ephemeral. You should+    -- call it exactly once, and discard it immediately after you call+    -- it.+    --+    -- To signal the end of a stream of data, supply an 'B.empty'+    -- input.+  | Error String String+    -- ^ An error has occurred. If an error occurs, the streaming+    -- operation cannot continue.+  | Done ByteString+    -- ^ The streaming operation has ended.  This payload may be+    -- empty. If it is not, it must be written out.+    --+    -- A non-empty payload consists of a frame epilogue, possibly+    -- preceded by any data left over from the final streaming step.++instance Show Result where+    show (Produce bs _) = "Produce " ++ show bs ++ " _"+    show (Consume _)    = "Consume _"+    show (Error n d)    = "Error " ++ show n ++ " " ++ show d+    show (Done bs)      = "Done " ++ show bs++-- | Begin a streaming compression operation.+--+-- The initial result will be either an 'Error' or a 'Consume'.+compress :: Int+         -- ^ Compression level. Must be >= 1 and <= 'maxCLevel'.+         -> IO Result+compress level+  | level < 1 || level > maxCLevel =+    return (Error "compress" "unsupported compression level")+  | otherwise =+  streaming+  createCStream+  p_freeCStream+  outSize+  (\cs -> initCStream cs (fromIntegral level))+  compressStream+  finish+ where+  outSize = fromIntegral cstreamOutSize+  finish cfp obfp opos dfp = do+    let cptr = unsafeForeignPtrToPtr cfp+        obuf = unsafeForeignPtrToPtr obfp+    check "endStream" (endStream cptr obuf) $ \leftover -> do+      touchForeignPtr cfp+      touchForeignPtr obfp+      if | leftover == 0 -> do+             opos1 <- fromIntegral `fmap` peekPos obuf+             Done `fmap` shrink outSize dfp opos1+         | leftover > 0 -> do+             dfp1 <- mallocByteString (fromIntegral leftover)+             poke obuf (buffer (unsafeForeignPtrToPtr dfp1) leftover)+             touchForeignPtr obfp+             bs <- shrink outSize dfp opos+             return (Produce bs (finish cfp obfp 0 dfp1))++type ConsumeBlock ctx io = Ptr ctx -> Ptr (Buffer Out)+                         -> Ptr (Buffer In) -> IO CSize++type Finish ctx io = ForeignPtr ctx -> ForeignPtr (Buffer Out)+                   -> Int -> ForeignPtr Word8 -> IO Result++streaming :: IO (Ptr ctx)+          -> FinalizerPtr ctx+          -> Int+          -> (Ptr ctx -> IO CSize)+          -> ConsumeBlock ctx io+          -> Finish ctx io+          -> IO Result+streaming createStream freeStream outSize initStream consumeBlock finish = do+  cx <- checkAlloc "createStream" createStream+  cxfp <- newForeignPtr freeStream cx+  check "initStream" (initStream cx) $ \_ -> do+    ibfp <- newForeignPtr finalizerFree =<< malloc+    obfp <- newForeignPtr finalizerFree =<< malloc+    dfp <- newOutput obfp+    advanceInput cxfp ibfp obfp 0 dfp+ where+  advanceInput cxfp ibfp obfp opos dfp = do+    let prompt (PS fp off len)+          | len == 0 = finish cxfp obfp opos dfp+          | otherwise = do+              withForeignPtr fp $ \sp0 ->+                withForeignPtr ibfp $ \ibuf ->+                  poke ibuf (buffer (sp0 `plusPtr` off) (fromIntegral len))+              consume cxfp ibfp 0 len obfp 0 dfp fp+    return (Consume prompt)+  newOutput obfp = do+    dfp <- mallocByteString outSize+    withForeignPtr dfp $ \dp ->+      withForeignPtr obfp $ \obuf ->+        poke obuf (buffer dp (fromIntegral outSize))+    return dfp+  consume cxfp ibfp ipos ilen obfp opos dfp fp = do+    if | fromIntegral ipos == ilen -> advanceInput cxfp ibfp obfp opos dfp+       | opos == outSize -> do+           let go = do+                 ndfp <- newOutput obfp+                 consume cxfp ibfp ipos ilen obfp 0 ndfp fp+           return (Produce (PS dfp 0 opos) go)+       | otherwise -> do+           let obuf = unsafeForeignPtrToPtr obfp+               ibuf = unsafeForeignPtrToPtr ibfp+           check "consumeBlock"+             (withForeignPtr cxfp $ \cptr ->+               consumeBlock cptr obuf ibuf <* touchForeignPtr fp) $ \_ -> do+             opos1 <- fromIntegral `fmap` peekPos obuf+             ipos1 <- peekPos ibuf+             touchForeignPtr obfp+             touchForeignPtr ibfp+             consume cxfp ibfp ipos1 ilen obfp opos1 dfp fp++-- | Begin a streaming decompression operation.+--+-- The initial result will be either an 'Error' or a 'Consume'.+decompress :: IO Result+decompress =+  streaming+  createDStream+  p_freeDStream+  outSize+  initDStream+  decompressStream+  finish+ where+  outSize = fromIntegral dstreamOutSize+  finish _cxfp _obfp opos dfp = Done `fmap` shrink outSize dfp opos++shrink :: Int -> ForeignPtr Word8 -> Int -> IO B.ByteString+shrink capacity dfp opos+  | opos == 0  = return B.empty+  | let unused = capacity - opos+    in unused >= 1024 || unused > capacity `rem` 8+               = return (B.copy (PS dfp 0 opos))+  | otherwise  = return (PS dfp 0 opos)++buffer :: Ptr a -> CSize -> Buffer io+buffer ptr size = Buffer ptr size 0++check :: String -> IO CSize -> (CSize -> IO Result) -> IO Result+check name act onSuccess = do+  ret <- act+  if isError ret+    then return (Error name (getErrorName ret))+    else onSuccess ret
+ Codec/Compression/Zstd/Types.hs view
@@ -0,0 +1,59 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++{-# LANGUAGE BangPatterns #-}++-- |+-- Module      : Codec.Compression.Zstd.Types+-- Copyright   : (c) 2016-present, Facebook, Inc. All rights reserved.+--+-- License     : BSD3+-- Maintainer  : bryano@fb.com+-- Stability   : experimental+-- Portability : GHC+--+-- Types supporting zstd compression and decompression.++module Codec.Compression.Zstd.Types+    (+      Decompress(..)+    , Dict(..)+    , mkDict+    ) where++import Control.DeepSeq (NFData(..))+import Data.ByteString (ByteString)++-- | The result of a decompression operation.+data Decompress =+    Skip+  -- ^ Either the compressed frame was empty, or it was compressed in+  -- streaming mode and so its size is not known.+  | Error String+  -- ^ An error occurred.+  | Decompress ByteString+  -- ^ The payload was successfully decompressed.+  deriving (Eq, Read, Show)++-- | Compression dictionary.+newtype Dict = Dict {+    fromDict :: ByteString+  } deriving (Eq, Ord)++-- | Smart constructor.+mkDict :: ByteString -> Dict+mkDict d = Dict d++instance Show Dict where+    showsPrec n (Dict d) r = showsPrec n d r++instance Read Dict where+    readsPrec n s = map (\(a,b) -> (Dict a, b)) (readsPrec n s)++instance NFData Dict where+    rnf (Dict d) = rnf d
+ LICENSE view
@@ -0,0 +1,30 @@+BSD License++For Zstandard software++Copyright (c) 2016-present, Facebook, Inc. All rights reserved.++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.++ * Neither the name Facebook nor the names of its contributors may be used to+   endorse or promote products derived from this software without specific+   prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ PATENTS view
@@ -0,0 +1,33 @@+Additional Grant of Patent Rights Version 2++"Software" means the Zstandard software distributed by Facebook, Inc.++Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable+(subject to the termination provision below) license under any Necessary+Claims, to make, have made, use, sell, offer to sell, import, and otherwise+transfer the Software. For avoidance of doubt, no license is granted under+Facebook’s rights in any patent claims that are infringed by (i) modifications+to the Software made by you or any third party or (ii) the Software in+combination with any software or other technology.++The license granted hereunder will terminate, automatically and without notice,+if you (or any of your subsidiaries, corporate affiliates or agents) initiate+directly or indirectly, or take a direct financial interest in, any Patent+Assertion: (i) against Facebook or any of its subsidiaries or corporate+affiliates, (ii) against any party if such Patent Assertion arises in whole or+in part from any software, technology, product or service of Facebook or any of+its subsidiaries or corporate affiliates, or (iii) against any party relating+to the Software. Notwithstanding the foregoing, if Facebook or any of its+subsidiaries or corporate affiliates files a lawsuit alleging patent+infringement against you in the first instance, and you respond by filing a+patent infringement counterclaim in that lawsuit against that party that is+unrelated to the Software, the license granted hereunder will not terminate+under section (i) of this paragraph due to such counterclaim.++A "Necessary Claim" is a claim of a patent owned by Facebook that is+necessarily infringed by the Software standing alone.++A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,+or contributory infringement or inducement to infringe any patent, including a+cross-claim or counterclaim.
+ README.md view
@@ -0,0 +1,37 @@+# Zstandard bindings for Haskell++This library provides Haskell bindings to the+[Zstandard compression library](http://facebook.github.io/zstd/).++The library is structured to provide several layers of abstraction.++* For the simplest use cases, the top-level+  [`Zstd`](http://hackage.haskell.org/package/zstd/docs/Codec-Compression-Zstd.html)+  module is the best place to get started.++* If you need to stream a large amount of data with a constant memory+  footprint, use the+  [`Zstd.Streaming`](http://hackage.haskell.org/package/zstd/docs/Codec-Compression-Zstd-Streaming.html)+  module. This can also be used as a building block for adapting to+  streaming libraries such as `pipes` and `conduit`.  (If you need to+  use lazy bytestrings instead, see the+  [`Zstd.Lazy`](http://hackage.haskell.org/package/zstd/docs/Codec-Compression-Zstd-Lazy.html)+  module.  This is built using the abstractions from the+  `Zstd.Streaming` module.)++* When your usage is dominated by lots of small messages (presumably+  using pre-computed compression dictionaries), use the+  [`Zstd.Efficient`](http://hackage.haskell.org/package/zstd/docs/Codec-Compression-Zstd-Efficient.html)+  module to amortize the cost of allocating and initializing context+  and dictionary values.++## Join in++If you'd like to help improve the code, please+[read the contribution guidelines](CONTRIBUTING.md).  This discusses+how to file bugs and submit changes to the code itself.++## API documentation++The APIs should be easy to understand and work with, and you can find+[documentation on Hackage](http://hackage.haskell.org/package/zstd).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ benchmarks/Benchmarks.hs view
@@ -0,0 +1,45 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++{-# LANGUAGE BangPatterns, OverloadedStrings, ScopedTypeVariables #-}++module Main (main) where++import Criterion.Main+import Codec.Compression.Zstd as Zstd+import Codec.Compression.Zstd.Efficient as Zstd+import qualified Data.ByteString as B+import Data.ByteString.Char8 (ByteString)++compress_no_ctx :: Int -> ByteString -> Int+compress_no_ctx count input0 = go 0 0 input0+  where+    go i !acc input+      | i >= count = acc+      | otherwise  = go (i+1) (n+acc) input+        where    n = B.length (Zstd.compress 3 input)++compress_ctx :: Int -> ByteString -> IO Int+compress_ctx count input0 = Zstd.withCCtx $ \ctx -> go ctx 0 0 input0+  where+    go ctx i !acc input+      | i >= count = return acc+      | otherwise  = do+        n <- B.length `fmap` Zstd.compressCCtx ctx 3 input+        go ctx (i+1) (n+acc) input++main :: IO ()+main =+  defaultMain [+      env (B.take 200 `fmap` B.readFile "zstd.cabal") $ \ ~input ->+      let count = 1000 in+      bgroup "context" [+        bench "yes" $ nfIO (compress_ctx count input)+      , bench "no" $ nf (compress_no_ctx count) input+      ]+    ]
+ changelog.md view
@@ -0,0 +1,3 @@+# 0.1.0.0++* Initial release
+ examples/low-level/DictionaryCompression.hs view
@@ -0,0 +1,62 @@+module Main (main) where++import Codec.Compression.Zstd.Efficient+import Control.Monad (forM_)+import System.Environment (getArgs, getProgName)+import System.Exit (exitFailure)+import System.FilePath (addExtension, splitExtension)+import System.IO (hPutStrLn, stderr)+import qualified Data.ByteString as B++main :: IO ()+main = do+  args <- getArgs+  case args of+    "-c":dictName:files -> do+      dict <- (createCDict 3 . mkDict) <$> B.readFile dictName+      compress dict files+    "-d":dictName:files -> do+      dict <- (createDDict . mkDict) <$> B.readFile dictName+      decompress dict files+    "-t":dictSize:dictName:files ->+      case reads dictSize of+        [(size,['k'])] -> train (size * 1024) dictName files+        [(size,['m'])] -> train (size * 1048576) dictName files+        [(size,"")]    -> train size dictName files+        _           -> do+          program <- getProgName+          hPutStrLn stderr $ "usage: " ++ program ++ " -t SIZE DICT [FILES]"+          exitFailure+    _ -> do+      program <- getProgName+      hPutStrLn stderr $ "usage: " ++ program ++ " -[cdt] ARGS"+      exitFailure++compress :: CDict -> [FilePath] -> IO ()+compress dict files = do+  withCCtx $ \ctx ->+    forM_ files $ \file -> do+      content <- compressUsingCDict ctx dict =<< B.readFile file+      B.writeFile (addExtension file "zst") content++decompress :: DDict -> [FilePath] -> IO ()+decompress dict files = do+  withDCtx $ \ctx ->+    forM_ files $ \file -> do+      result <- decompressUsingDDict ctx dict =<< B.readFile file+      let newFile = case splitExtension file of+            (prefix,"zst") -> prefix+            _              -> addExtension file "dzst"+      case result of+        Skip          -> hPutStrLn stderr ("NOTE: skipping " ++ file)+        Error desc    -> hPutStrLn stderr ("ERROR (" ++ file ++ "): " ++ desc)+        Decompress bs -> B.writeFile newFile bs++train :: Int -> FilePath -> [FilePath] -> IO ()+train size dictName files = do+  md <- trainFromSamples size <$> mapM B.readFile files+  case md of+    Left err -> do+      hPutStrLn stderr ("ERROR: " ++ err)+      exitFailure+    Right dict -> B.writeFile dictName (fromDict dict)
+ examples/zstd-examples.cabal view
@@ -0,0 +1,23 @@+name:          zstd-examples+version:       0+synopsis:      Examples of how to use the zstd library+description:   Examples of how to use the zstd library+license:       OtherLicense+license-file:  ../LICENSE-examples+author:        Bryan O'Sullivan+maintainer:    bryano@fb.com+copyright:     (c) 2016-present, Facebook, Inc. All rights reserved.+build-type:    Simple+category:      Codec+cabal-version: >=1.10++executable low-level-dictionary-compression+  hs-source-dirs:   low-level+  ghc-options:      -Wall -fwarn-tabs+  main-is:          DictionaryCompression.hs+  default-language: Haskell2010+  build-depends:+    base >= 4.8 && < 5,+    bytestring,+    filepath,+    zstd
+ tests/Main.hs view
@@ -0,0 +1,16 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++module Main (main) where++import Test.Framework (defaultMain)++import qualified Properties++main :: IO ()+main = defaultMain [Properties.tests]
+ tests/Properties.hs view
@@ -0,0 +1,63 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++{-# LANGUAGE OverloadedStrings #-}++module Properties+    (+      tests+    ) where++import Codec.Compression.Zstd+import qualified Codec.Compression.Zstd.Lazy as L+import qualified Codec.Compression.Zstd.Streaming as S+import Codec.Compression.Zstd.Streaming (Result(..))+import Data.Bits (xor)+import Data.ByteString (ByteString, pack, unpack)+import Data.Monoid ((<>))+import System.IO.Unsafe (unsafePerformIO)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck+import qualified Control.Exception as E+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import QuickCheckUtils++Right dict = trainFromSamples 400 (replicate 100 "noooooooooo")++t_rechunk cs bs = L.toStrict (rechunk cs bs) == bs++t_roundtrip (CLevel n) (NE s) = decompress (compress n s) == Decompress s++t_dict_roundtrip (CLevel n) (NE s) =+  decompressUsingDict dict (compressUsingDict dict n s) == Decompress s++t_lazy_roundtrip (CLevel n) cs s =+  L.decompress (L.compress n (rechunk cs s)) == L.fromStrict s++-- Two lazy representations of an input compress to the same result.+t_lazy_compress_equiv (CLevel n) = unsquare $ \cs ds s ->+  L.compress n (rechunk cs s) == L.compress n (rechunk ds s)++t_stream_lazy_compress (CLevel n) = unsquare $ \cs ds s ->+  L.fromChunks (stream (S.compress n) cs s) == L.compress n (rechunk ds s)++t_stream_roundtrip (CLevel n) cs s =+  (B.concat . stream S.decompress cs . L.toStrict . L.compress n . L.fromStrict) s == s++tests :: Test+tests = testGroup "properties" [+    testProperty "rechunk" t_rechunk+  , testProperty "roundtrip" t_roundtrip+  , testProperty "dict_roundtrip" t_dict_roundtrip+  , testProperty "lazy_roundtrip" t_lazy_roundtrip+  , testProperty "lazy_compress_equiv" t_lazy_compress_equiv+  , testProperty "stream_lazy_compress" t_stream_lazy_compress+  , testProperty "stream_roundtrip" t_stream_roundtrip+  ]
+ tests/QuickCheckUtils.hs view
@@ -0,0 +1,99 @@+-- Copyright (c) 2016-present, Facebook, Inc.+-- All rights reserved.+--+-- This source code is licensed under the BSD-style license found in+-- the LICENSE file in the root directory of this source tree. An+-- additional grant of patent rights can be found in the PATENTS file+-- in the same directory.++{-# OPTIONS_GHC -fno-warn-orphans #-}++module QuickCheckUtils+    (+      CLevel(..)+    , NEBS(..)+    , rechunkList+    , rechunk+    , smallArbitrary+    , stream+    , throwsException+    , unsquare+    ) where++import Codec.Compression.Zstd+import qualified Codec.Compression.Zstd.Lazy as L+import qualified Codec.Compression.Zstd.Streaming as S+import Codec.Compression.Zstd.Streaming (Result(..))+import Data.Bits (xor)+import Data.ByteString (ByteString, pack, unpack)+import Data.Monoid ((<>))+import System.IO.Unsafe (unsafePerformIO)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck+import qualified Control.Exception as E+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L++newtype NEBS = NE { fromNE :: ByteString }+  deriving (Eq, Ord, Read, Show)++instance Arbitrary ByteString where+    arbitrary     = pack `fmap` arbitrary+    shrink        = map pack . shrink . unpack++instance Arbitrary NEBS where+    arbitrary     = (NE . pack . getNonEmpty) `fmap` arbitrary+    shrink        = map (NE . pack . getNonEmpty) . shrink .+                    NonEmpty . unpack . fromNE++newtype CLevel = CLevel { fromCLevel :: Int }+  deriving (Eq, Ord, Read, Show)++instance Arbitrary CLevel where+    arbitrary = fmap CLevel (choose (1, maxCLevel))+    shrink    = map CLevel . filter (>0) . shrink . fromCLevel++rechunkList :: [Int] -> ByteString -> [ByteString]+rechunkList cs0 bs0 = go cs0 bs0+  where+    go _      bs+      | B.null bs = []+    go []     bs  = [bs]+    go (c:cs) bs+      | c <= 0    = go cs bs+      | otherwise = let (h,t) = B.splitAt c bs+                    in h : go cs t++rechunk :: [Int] -> ByteString -> L.ByteString+rechunk cs bs = L.fromChunks (rechunkList cs bs)++stream :: IO S.Result -> [Int] -> ByteString -> [ByteString]+stream act cs s = unsafePerformIO $ go (rechunkList cs s) =<< act+  where+    go _      (S.Error w e) = error $ w ++ ": " ++ e+    go bs     (Produce p k) = (p:) <$> (go bs =<< k)+    go (b:bs) (Consume k)   = go bs =<< k b+    go []     (Consume k)   = done =<< k B.empty+    go _      wtf           = error $ "stream go: unexpected " ++ show wtf+    done (Produce p k) = (p:) <$> (done =<< k)+    done (Done p)      = return [p]+    done (S.Error w e) = error $ w ++ ": " ++ e+    done wtf           = error $ "stream done: unexpected " ++ show wtf++throwsException :: (a -> b) -> a -> Bool+throwsException f a =+  let ret = return :: b -> IO b+      try = E.try :: IO b -> IO (Either E.SomeException b)+  in case unsafePerformIO (try (E.evaluate (ret (f a)))) of+       Left _err -> True+       _         -> False++-- For tests that have O(n^2) running times or input sizes, resize+-- their inputs to the square root of the originals.+unsquare :: (Arbitrary a, Show a, Testable b) => (a -> b) -> Property+unsquare = forAll smallArbitrary++smallArbitrary :: (Arbitrary a, Show a) => Gen a+smallArbitrary = sized $ \n -> resize (smallish n) arbitrary+  where smallish = round . (sqrt :: Double -> Double) . fromIntegral . abs
+ zstd.cabal view
@@ -0,0 +1,125 @@+name:                zstd+version:             0.1.0.0+synopsis:            Haskell bindings to the Zstandard compression algorithm+description:+  A fast lossless compression algorithm, targeting real-time+  compression scenarios at zlib-level and better compression ratios.+homepage:            https://github.com/facebookexperimental/hs-zstd+bug-reports:         https://github.com/facebookexperimental/hs-zstd/issues+license:             BSD3+license-file:        LICENSE+author:              Bryan O'Sullivan+maintainer:          bryano@fb.com+copyright:           (c) 2016-present, Facebook, Inc. All rights reserved.+category:            Codec+build-type:          Simple+cabal-version:       >=1.10+extra-source-files:+  *.md+  PATENTS+  examples/*.cabal+  examples/low-level/*.hs+  zstd/*.md+  zstd/LICENSE+  zstd/LICENSE-examples+  zstd/NEWS+  zstd/PATENTS+  zstd/lib/*.h+  zstd/lib/README.md+  zstd/lib/common/*.c+  zstd/lib/common/*.h+  zstd/lib/compress/*.c+  zstd/lib/compress/*.h+  zstd/lib/decompress/*.c+  zstd/lib/dictBuilder/*.c+  zstd/lib/dictBuilder/*.h++flag standalone+  description: Use a built-in copy of the zstd library+  default:     True++library+  exposed-modules:+    Codec.Compression.Zstd.Base+    Codec.Compression.Zstd.Efficient+    Codec.Compression.Zstd.FFI+    Codec.Compression.Zstd.Streaming+    Codec.Compression.Zstd.Types+    Codec.Compression.Zstd+    Codec.Compression.Zstd.Lazy++  other-modules:+    Codec.Compression.Zstd.Base.Types+    Codec.Compression.Zstd.FFI.Types+    Codec.Compression.Zstd.Internal++  if flag(standalone)+    c-sources:+      zstd/lib/common/entropy_common.c+      zstd/lib/common/error_private.c+      zstd/lib/common/fse_decompress.c+      zstd/lib/common/xxhash.c+      zstd/lib/common/zstd_common.c+      zstd/lib/compress/fse_compress.c+      zstd/lib/compress/huf_compress.c+      zstd/lib/compress/zstd_compress.c+      zstd/lib/decompress/huf_decompress.c+      zstd/lib/decompress/zstd_decompress.c+      zstd/lib/dictBuilder/divsufsort.c+      zstd/lib/dictBuilder/zdict.c++  if flag(standalone)+    include-dirs:+      zstd/lib+      zstd/lib/common+      zstd/lib/compress++  ghc-options: -Wall+  default-language: Haskell2010+  if !flag(standalone)+    extra-libraries: zstd++  build-depends:+    base >= 4.8 && < 5,+    bytestring >= 0.9,+    deepseq,+    ghc-prim++test-suite tests+  type:           exitcode-stdio-1.0+  default-language: Haskell2010+  hs-source-dirs: tests+  main-is:        Main.hs+  ghc-options:    -Wall -threaded -rtsopts+  other-modules:+    Properties+    QuickCheckUtils++  build-depends:+    QuickCheck >= 2.7,+    base >= 4.8 && < 5,+    bytestring >= 0.9,+    test-framework >= 0.4,+    test-framework-quickcheck2 >= 0.2,+    zstd++benchmark benchmarks+  hs-source-dirs:   benchmarks+  main-is:          Benchmarks.hs++  default-language: Haskell2010+  type:             exitcode-stdio-1.0++  build-depends:+    base,+    bytestring,+    criterion,+    ghc-prim,+    zstd,+    zlib++  ghc-options: -Wall -O2++source-repository head+  type:     git+  location: https://github.com/facebookexperimental//hs-zstd
+ zstd/CONTRIBUTING.md view
@@ -0,0 +1,42 @@+# Contributing to Zstandard+We want to make contributing to this project as easy and transparent as+possible.++## Our Development Process+New versions are being developed in the "dev" branch,+or in their own feature branch.+When they are deemed ready for a release, they are merged into "master".++As a consequences, all contributions must stage first through "dev"+or their own feature branch.++## Pull Requests+We actively welcome your pull requests.++1. Fork the repo and create your branch from `dev`.+2. If you've added code that should be tested, add tests.+3. If you've changed APIs, update the documentation.+4. Ensure the test suite passes.+5. Make sure your code lints.+6. If you haven't already, complete the Contributor License Agreement ("CLA").++## Contributor License Agreement ("CLA")+In order to accept your pull request, we need you to submit a CLA. You only need+to do this once to work on any of Facebook's open source projects.++Complete your CLA here: <https://code.facebook.com/cla>++## Issues+We use GitHub issues to track public bugs. Please ensure your description is+clear and has sufficient instructions to be able to reproduce the issue.++Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe+disclosure of security bugs. In those cases, please go through the process+outlined on that page and do not file a public issue.++## Coding Style  +* 4 spaces for indentation rather than tabs++## License+By contributing to Zstandard, you agree that your contributions will be licensed+under the [LICENSE](LICENSE) file in the root directory of this source tree.
+ zstd/LICENSE view
@@ -0,0 +1,30 @@+BSD License++For Zstandard software++Copyright (c) 2016-present, Facebook, Inc. All rights reserved.++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.++ * Neither the name Facebook nor the names of its contributors may be used to+   endorse or promote products derived from this software without specific+   prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ zstd/LICENSE-examples view
@@ -0,0 +1,11 @@+Copyright (c) 2016-present, Facebook, Inc. All rights reserved.++The examples provided by Facebook are for non-commercial testing and evaluation+purposes only. Facebook reserves all rights not expressly granted.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ zstd/NEWS view
@@ -0,0 +1,236 @@+v1.1.3+cli : new : advanced commands for detailed parameters, by Przemyslaw Skibinski+cli : fix zstdless on Mac OS-X, by Andrew Janke+API : fix : all symbols properly exposed in libzstd, by Nick Terrell+API : new : ZSTD_create?Dict_byReference(), requested by Bartosz Taudul+API : new : ZDICT_finalizeDictionary()++v1.1.2+API : streaming : decompression : changed : automatic implicit reset when chain-decoding new frames without init+API : experimental : added : dictID retrieval functions, and ZSTD_initCStream_srcSize()+API : zbuff : changed : prototypes now generate deprecation warnings+lib : improved : faster decompression speed at ultra compression settings and 32-bits mode+lib : changed : only public ZSTD_ symbols are now exposed+lib : changed : reduced usage  of stack memory+lib : fixed : several corner case bugs, by Nick Terrell+cli : new : gzstd, experimental version able to decode .gz files, by Przemyslaw Skibinski+cli : new : preserve file attributes+cli : new : added zstdless and zstdgrep tools+cli : fixed : status displays total amount decoded, even for file consisting of multiple frames (like pzstd)+cli : fixed : zstdcat+zlib_wrapper : added support for gz* functions, by Przemyslaw Skibinski+install : better compatibility with FreeBSD, by Dimitry Andric+source tree : changed : zbuff source files moved to lib/deprecated++v1.1.1+New : command -M#, --memory=, --memlimit=, --memlimit-decompress= to limit allowed memory consumption+New : doc/zstd_manual.html, by Przemyslaw Skibinski+Improved : slightly better compression ratio at --ultra levels (>= 20)+Improved : better memory usage when using streaming compression API, thanks to @Rogier-5 report+Added : API : ZSTD_initCStream_usingCDict(), ZSTD_initDStream_usingDDict() (experimental section)+Added : example/multiple_streaming_compression.c+Changed : zstd_errors.h is now installed within /include (and replaces errors_public.h)+Updated man page+Fixed : zstd-small, zstd-compress and zstd-decompress compilation targets++v1.1.0+New : contrib/pzstd, parallel version of zstd, by Nick Terrell+added : NetBSD install target (#338)+Improved : speed for batches of small files+Improved : speed of zlib wrapper, by Przemyslaw Skibinski+Changed : libzstd on Windows supports legacy formats, by Christophe Chevalier+Fixed : CLI -d output to stdout by default when input is stdin (#322)+Fixed : CLI correctly detects console on Mac OS-X+Fixed : CLI supports recursive mode `-r` on Mac OS-X+Fixed : Legacy decoders use unified error codes, reported by benrg (#341), fixed by Przemyslaw Skibinski+Fixed : compatibility with OpenBSD, reported by Juan Francisco Cantero Hurtado (#319)+Fixed : compatibility with Hurd, by Przemyslaw Skibinski (#365)+Fixed : zstd-pgo, reported by octoploid (#329)++v1.0.0+Change Licensing, all project is now BSD, Copyright Facebook+Small decompression speed improvement+API : Streaming API supports legacy format+API : ZDICT_getDictID(), ZSTD_sizeof_{CCtx, DCtx, CStream, DStream}(), ZSTD_setDStreamParamter()+CLI supports legacy formats v0.4++Fixed : compression fails on certain huge files, reported by Jesse McGrew+Enhanced documentation, by Przemyslaw Skibinski++v0.8.1+New streaming API+Changed : --ultra now enables levels beyond 19+Changed : -i# now selects benchmark time in second+Fixed : ZSTD_compress* can now compress > 4 GB in a single pass, reported by Nick Terrell+Fixed : speed regression on specific patterns (#272)+Fixed : support for Z_SYNC_FLUSH, by Dmitry Krot (#291)+Fixed : ICC compilation, by Przemyslaw Skibinski++v0.8.0+Improved : better speed on clang and gcc -O2, thanks to Eric Biggers+New : Build on FreeBSD and DragonFly, thanks to JrMarino+Changed : modified API : ZSTD_compressEnd()+Fixed : legacy mode with ZSTD_HEAPMODE=0, by Christopher Bergqvist+Fixed : premature end of frame when zero-sized raw block, reported by Eric Biggers+Fixed : large dictionaries (> 384 KB), reported by Ilona Papava+Fixed : checksum correctly checked in single-pass mode+Fixed : combined --test amd --rm, reported by Andreas M. Nilsson+Modified : minor compression level adaptations+Updated : compression format specification to v0.2.0+changed : zstd.h moved to /lib directory++v0.7.5+Transition version, supporting decoding of v0.8.x++v0.7.4+Added : homebrew for Mac, by Daniel Cade+Added : more examples+Fixed : segfault when using small dictionaries, reported by Felix Handte+Modified : default compression level for CLI is now 3+Updated : specification, to v0.1.1++v0.7.3+New : compression format specification+New : `--` separator, stating that all following arguments are file names. Suggested by Chip Turner.+New : `ZSTD_getDecompressedSize()`+New : OpenBSD target, by Juan Francisco Cantero Hurtado+New : `examples` directory+fixed : dictBuilder using HC levels, reported by Bartosz Taudul+fixed : legacy support from ZSTD_decompress_usingDDict(), reported by Felix Handte+fixed : multi-blocks decoding with intermediate uncompressed blocks, reported by Greg Slazinski+modified : removed "mem.h" and "error_public.h" dependencies from "zstd.h" (experimental section)+modified : legacy functions no longer need magic number++v0.7.2+fixed : ZSTD_decompressBlock() using multiple consecutive blocks. Reported by Greg Slazinski.+fixed : potential segfault on very large files (many gigabytes). Reported by Chip Turner.+fixed : CLI displays system error message when destination file cannot be created (#231). Reported by Chip Turner.++v0.7.1+fixed : ZBUFF_compressEnd() called multiple times with too small `dst` buffer, reported by Christophe Chevalier+fixed : dictBuilder fails if first sample is too small, reported by Руслан Ковалёв+fixed : corruption issue, reported by cj+modified : checksum enabled by default in command line mode++v0.7.0+New : Support for directory compression, using `-r`, thanks to Przemyslaw Skibinski+New : Command `--rm`, to remove source file after successful de/compression+New : Visual build scripts, by Christophe Chevalier+New : Support for Sparse File-systems (do not use space for zero-filled sectors)+New : Frame checksum support+New : Support pass-through mode (when using `-df`)+API : more efficient Dictionary API : `ZSTD_compress_usingCDict()`, `ZSTD_decompress_usingDDict()`+API : create dictionary files from custom content, by Giuseppe Ottaviano+API : support for custom malloc/free functions+New : controllable Dictionary ID+New : Support for skippable frames++v0.6.1+New : zlib wrapper API, thanks to Przemyslaw Skibinski+New : Ability to compile compressor / decompressor separately+Changed : new lib directory structure+Fixed : Legacy codec v0.5 compatible with dictionary decompression+Fixed : Decoder corruption error (#173)+Fixed : null-string roundtrip (#176)+New : benchmark mode can select directory as input+Experimental : midipix support, VMS support++v0.6.0+Stronger high compression modes, thanks to Przemyslaw Skibinski+API : ZSTD_getFrameParams() provides size of decompressed content+New : highest compression modes require `--ultra` command to fully unleash their capacity+Fixed : zstd cli return error code > 0 and removes dst file artifact when decompression fails, thanks to Chip Turner++v0.5.1+New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski+Changed : Dictionary builder integrated into libzstd and zstd cli+Changed (!) : zstd cli now uses "multiple input files" as default mode. See `zstd -h`.+Fix : high compression modes for big-endian platforms+New : zstd cli : `-t` | `--test` command++v0.5.0+New : dictionary builder utility+Changed : streaming & dictionary API+Improved : better compression of small data++v0.4.7+Improved : small compression speed improvement in HC mode+Changed : `zstd_decompress.c` has ZSTD_LEGACY_SUPPORT to 0 by default+fix : bt search bug++v0.4.6+fix : fast compression mode on Windows+New : cmake configuration file, thanks to Artyom Dymchenko+Improved : high compression mode on repetitive data+New : block-level API+New : ZSTD_duplicateCCtx()++v0.4.5+new : -m/--multiple : compress/decompress multiple files++v0.4.4+Fixed : high compression modes for Windows 32 bits+new : external dictionary API extended to buffered mode and accessible through command line+new : windows DLL project, thanks to Christophe Chevalier++v0.4.3 :+new : external dictionary API+new : zstd-frugal++v0.4.2 :+Generic minor improvements for small blocks+Fixed : big-endian compatibility, by Peter Harris (#85)++v0.4.1+Fixed : ZSTD_LEGACY_SUPPORT=0 build mode (reported by Luben)+removed `zstd.c`++v0.4.0+Command line utility compatible with high compression levels+Removed zstdhc => merged into zstd+Added : ZBUFF API (see zstd_buffered.h)+Rolling buffer support++v0.3.6+small blocks params++v0.3.5+minor generic compression improvements++v0.3.4+Faster fast cLevels++v0.3.3+Small compression ratio improvement++v0.3.2+Fixed Visual Studio++v0.3.1 :+Small compression ratio improvement++v0.3+HC mode : compression levels 2-26++v0.2.2+Fix : Visual Studio 2013 & 2015 release compilation, by Christophe Chevalier++v0.2.1+Fix : Read errors, advanced fuzzer tests, by Hanno Böck++v0.2.0+**Breaking format change**+Faster decompression speed+Can still decode v0.1 format++v0.1.3+fix uninitialization warning, reported by Evan Nemerson++v0.1.2+frame concatenation support++v0.1.1+fix compression bug+detects write-flush errors++v0.1.0+first release
+ zstd/PATENTS view
@@ -0,0 +1,33 @@+Additional Grant of Patent Rights Version 2++"Software" means the Zstandard software distributed by Facebook, Inc.++Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable+(subject to the termination provision below) license under any Necessary+Claims, to make, have made, use, sell, offer to sell, import, and otherwise+transfer the Software. For avoidance of doubt, no license is granted under+Facebook’s rights in any patent claims that are infringed by (i) modifications+to the Software made by you or any third party or (ii) the Software in+combination with any software or other technology.++The license granted hereunder will terminate, automatically and without notice,+if you (or any of your subsidiaries, corporate affiliates or agents) initiate+directly or indirectly, or take a direct financial interest in, any Patent+Assertion: (i) against Facebook or any of its subsidiaries or corporate+affiliates, (ii) against any party if such Patent Assertion arises in whole or+in part from any software, technology, product or service of Facebook or any of+its subsidiaries or corporate affiliates, or (iii) against any party relating+to the Software. Notwithstanding the foregoing, if Facebook or any of its+subsidiaries or corporate affiliates files a lawsuit alleging patent+infringement against you in the first instance, and you respond by filing a+patent infringement counterclaim in that lawsuit against that party that is+unrelated to the Software, the license granted hereunder will not terminate+under section (i) of this paragraph due to such counterclaim.++A "Necessary Claim" is a claim of a patent owned by Facebook that is+necessarily infringed by the Software standing alone.++A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,+or contributory infringement or inducement to infringe any patent, including a+cross-claim or counterclaim.
+ zstd/README.md view
@@ -0,0 +1,124 @@+ __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 is provided as an open-source BSD-licensed **C** library,+and a command line utility producing and decoding `.zst` compressed files.+For other programming languages,+you can consult a list of known ports on [Zstandard homepage](http://www.zstd.net/#other-languages).++|Branch      |Status   |+|------------|---------|+|master      | [![Build Status](https://travis-ci.org/facebook/zstd.svg?branch=master)](https://travis-ci.org/facebook/zstd) |+|dev         | [![Build Status](https://travis-ci.org/facebook/zstd.svg?branch=dev)](https://travis-ci.org/facebook/zstd) |++As a reference, several fast compression algorithms were tested and compared on a Core i7-3930K CPU @ 4.5GHz, using [lzbench], an open-source in-memory benchmark by @inikep compiled with GCC 5.4.0, with the [Silesia compression corpus].++[lzbench]: https://github.com/inikep/lzbench+[Silesia compression corpus]: http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia+++| Name                    | Ratio | C.speed | D.speed |+|-------------------------|-------|--------:|--------:|+|                         |       |   MB/s  |  MB/s   |+| **zstd 0.8.2 -1**     |**2.877**| **330** | **940** |+| [zlib] 1.2.8 deflate -1 | 2.730 |    95   |   360   |+| brotli 0.4 -0           | 2.708 |   320   |   375   |+| QuickLZ 1.5             | 2.237 |   510   |   605   |+| LZO 2.09                | 2.106 |   610   |   870   |+| [LZ4] r131              | 2.101 |   620   |  3100   |+| Snappy 1.1.3            | 2.091 |   480   |  1600   |+| LZF 3.6                 | 2.077 |   375   |   790   |++[zlib]:http://www.zlib.net/+[LZ4]: http://www.lz4.org/++Zstd can also offer stronger compression ratios at the cost of compression speed.+Speed vs Compression trade-off is configurable by small increments. Decompression speed is preserved and remains roughly the same at all settings, a property shared by most LZ compression algorithms, such as [zlib] or lzma.++The following tests were run on a Core i7-3930K CPU @ 4.5GHz, using [lzbench], an open-source in-memory benchmark by @inikep compiled with GCC 5.2.1, on the [Silesia compression corpus].++Compression Speed vs Ratio | Decompression Speed+---------------------------|--------------------+![Compression Speed vs Ratio](doc/images/Cspeed4.png "Compression Speed vs Ratio") | ![Decompression Speed](doc/images/Dspeed4.png "Decompression Speed")++Several algorithms can produce higher compression ratios, but at slower speeds, falling outside of the graph.+For a larger picture including very slow modes, [click on this link](doc/images/DCspeed5.png) .+++### The case for Small Data compression++Previous charts provide results applicable to typical file and stream scenarios (several MB). Small data comes with different perspectives. The smaller the amount of data to compress, the more difficult it is to achieve any significant compression.++This problem is common to many compression algorithms. The reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new file, there is no "past" to build upon.++To solve this situation, Zstd offers a __training mode__, which can be used to tune the algorithm for a selected type of data, by providing it with a few samples. The result of the training is stored in a file called "dictionary", which can be loaded before compression and decompression. Using this dictionary, the compression ratio achievable on small data improves dramatically:++![Compressing Small Data](doc/images/smallData.png "Compressing Small Data")++These compression gains are achieved while simultaneously providing faster compression and decompression speeds.++Dictionary works if there is some correlation in a family of small data (there is no _universal dictionary_).+Hence, deploying one dictionary per type of data will provide the greatest benefits. Dictionary gains are mostly effective in the first few KB. Then, the compression algorithm will rely more and more on previously decoded content to compress the rest of the file.++#### Dictionary compression How To :++1) Create the dictionary++`zstd --train FullPathToTrainingSet/* -o dictionaryName`++2) Compress with dictionary++`zstd FILE -D dictionaryName`++3) Decompress with dictionary++`zstd --decompress FILE.zst -D dictionaryName`++### Build++Once you have the repository cloned, there are multiple ways provided to build Zstandard.++#### Makefile++If your system is compatible with a standard `make` (or `gmake`) binary generator,+you can simply run it at the root directory.+It will generate `zstd` within root directory.++Other available options include :+- `make install` : create and install zstd binary, library and man page+- `make test` : create and run `zstd` and test tools on local platform++#### cmake++A `cmake` project generator is provided within `build/cmake`.+It can generate Makefiles or other build scripts+to create `zstd` binary, and `libzstd` dynamic and static libraries.++#### Visual (Windows)++Going into `build` directory, you will find additional possibilities :+- Projects for Visual Studio 2005, 2008 and 2010+  + VS2010 project is compatible with VS2012, VS2013 and VS2015+- Automated build scripts for Visual compiler by @KrzysFR , in `build/VS_scripts`,+  which will build `zstd` cli and `libzstd` library without any need to open Visual Studio solution.+++### Status++Zstandard is currently deployed within Facebook. It is used daily to compress and decompress very large amounts of data in multiple formats and use cases.+Zstandard is considered safe for production environments.++### License++Zstandard is [BSD-licensed](LICENSE). We also provide an [additional patent grant](PATENTS).++### Contributing++The "dev" branch is the one where all contributions will be merged before reaching "master".+If you plan to propose a patch, please commit into the "dev" branch or its own feature branch.+Direct commit to "master" are not permitted.+For more information, please read [CONTRIBUTING](CONTRIBUTING.md).++### Miscellaneous++Zstd entropy stage is provided by [Huff0 and FSE, from Finite State Entropy library](https://github.com/Cyan4973/FiniteStateEntropy).
+ zstd/lib/README.md view
@@ -0,0 +1,77 @@+Zstandard library files+================================++The __lib__ directory contains several directories.+Depending on target use case, it's enough to include only files from relevant directories.+++#### API++Zstandard's stable API is exposed within [zstd.h](zstd.h),+at the root of `lib` directory.+++#### Advanced API++Some additional API may be useful if you're looking into advanced features :+- common/error_public.h : transforms `size_t` function results into an `enum`,+                          for precise error handling.+- ZSTD_STATIC_LINKING_ONLY : if you define this macro _before_ including `zstd.h`,+                          it will give access to advanced and experimental API.+                          These APIs shall ___never be used with dynamic library___ !+                          They are not "stable", their definition may change in the future.+                          Only static linking is allowed.+++#### Modular build++Directory `common/` is required in all circumstances.+You can select to support compression only, by just adding files from the `compress/` directory,+In a similar way, you can build a decompressor-only library with the `decompress/` directory.++Other optional functionalities provided are :++- `dictBuilder/`  : source files to create dictionaries.+                    The API can be consulted in `dictBuilder/zdict.h`.+                    This module also depends on `common/` and `compress/` .++- `legacy/` : source code to decompress previous versions of zstd, starting from `v0.1`.+              This module also depends on `common/` and `decompress/` .+              Library compilation must include directive `ZSTD_LEGACY_SUPPORT = 1` .+              The main API can be consulted in `legacy/zstd_legacy.h`.+              Advanced API from each version can be found in their relevant header file.+              For example, advanced API for version `v0.4` is in `legacy/zstd_v04.h` .+++#### Using MinGW+MSYS to create DLL++DLL can be created using MinGW+MSYS with the `make libzstd` command.+This command creates `dll\libzstd.dll` and the import library `dll\libzstd.lib`.+The import library is only required with Visual C++.+The header file `zstd.h` and the dynamic library `dll\libzstd.dll` are required to+compile a project using gcc/MinGW.+The dynamic library has to be added to linking options.+It means that if a project that uses ZSTD consists of a single `test-dll.c`+file it should be linked with `dll\libzstd.dll`. For example:+```+    gcc $(CFLAGS) -Iinclude/ test-dll.c -o test-dll dll\libzstd.dll+```+The compiled executable will require ZSTD DLL which is available at `dll\libzstd.dll`.+++#### Obsolete streaming API++Streaming is now provided within `zstd.h`.+Older streaming API is still available within `deprecated/zbuff.h`.+It will be removed in a future version.+Consider migrating code towards newer streaming API in `zstd.h`.+++#### Miscellaneous++The other files are not source code. There are :++ - LICENSE : contains the BSD license text+ - Makefile : script to compile or install zstd library (static and dynamic)+ - libzstd.pc.in : for pkg-config (`make install`)+ - README.md : this file
+ zstd/lib/common/bitstream.h view
@@ -0,0 +1,414 @@+/* ******************************************************************+   bitstream+   Part of FSE library+   header file (to include)+   Copyright (C) 2013-2016, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++   You can contact the author at :+   - Source repository : https://github.com/Cyan4973/FiniteStateEntropy+****************************************************************** */+#ifndef BITSTREAM_H_MODULE+#define BITSTREAM_H_MODULE++#if defined (__cplusplus)+extern "C" {+#endif+++/*+*  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 "mem.h"            /* unaligned access routines */+#include "error_private.h"  /* error codes and messages */+++/*=========================================+*  Target specific+=========================================*/+#if defined(__BMI__) && defined(__GNUC__)+#  include <immintrin.h>   /* support for bextr (experimental) */+#endif+++/*-******************************************+*  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;++MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);+MEM_STATIC void   BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);+MEM_STATIC void   BIT_flushBits(BIT_CStream_t* bitC);+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);++/* 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 ... :( */++MEM_STATIC size_t   BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);+MEM_STATIC size_t   BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);+MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);+++/* 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+******************************************/+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);+/* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */++MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);+/* unsafe version; does not check buffer overflow */++MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);+/* faster, but works only if nbBits >= 1 */++++/*-**************************************************************+*  Internal functions+****************************************************************/+MEM_STATIC unsigned BIT_highbit32 (register U32 val)+{+#   if defined(_MSC_VER)   /* Visual */+    unsigned long r=0;+    _BitScanReverse ( &r, val );+    return (unsigned) r;+#   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* Use GCC Intrinsic */+    return 31 - __builtin_clz (val);+#   else   /* Software version */+    static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };+    U32 v = val;+    v |= v >> 1;+    v |= v >> 2;+    v |= v >> 4;+    v |= v >> 8;+    v |= v >> 16;+    return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];+#   endif+}++/*=====    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() ) */+MEM_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 ! */+MEM_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 */+MEM_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 */+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)+{+    size_t const nbBytes = bitC->bitPos >> 3;+    MEM_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() */+MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)+{+    size_t const nbBytes = bitC->bitPos >> 3;+    MEM_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 */+MEM_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+*/+MEM_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 = MEM_readLEST(bitD->ptr);+        { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];+          bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;  /* ensures bitsConsumed is always set */+          if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }+    } else {+        bitD->start = (const char*)srcBuffer;+        bitD->ptr   = bitD->start;+        bitD->bitContainer = *(const BYTE*)(bitD->start);+        switch(srcSize)+        {+            case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);+            case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);+            case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);+            case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;+            case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;+            case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) <<  8;+            default:;+        }+        { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];+          bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;+          if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }+        bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;+    }++    return srcSize;+}++MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)+{+    return bitContainer >> start;+}++MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)+{+#if defined(__BMI__) && defined(__GNUC__) && __GNUC__*1000+__GNUC_MINOR__ >= 4008  /* experimental */+#  if defined(__x86_64__)+    if (sizeof(bitContainer)==8)+        return _bextr_u64(bitContainer, start, nbBits);+    else+#  endif+        return _bextr_u32(bitContainer, start, nbBits);+#else+    return (bitContainer >> start) & BIT_mask[nbBits];+#endif+}++MEM_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+ */+ MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)+{+#if defined(__BMI__) && defined(__GNUC__)   /* experimental; fails if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8 */+    return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);+#else+    U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;+    return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask);+#endif+}++/*! BIT_lookBitsFast() :+*   unsafe version; only works only if nbBits >= 1 */+MEM_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);+}++MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)+{+    bitD->bitsConsumed += nbBits;+}++/*! BIT_readBits() :+ *  Read (consume) next n bits from local register and update.+ *  Pay attention to not read more than nbBits contained into local register.+ *  @return : extracted value.+ */+MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)+{+    size_t const value = BIT_lookBits(bitD, nbBits);+    BIT_skipBits(bitD, nbBits);+    return value;+}++/*! BIT_readBitsFast() :+*   unsafe version; only works only if nbBits >= 1 */+MEM_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 */+MEM_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 = MEM_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 = MEM_readLEST(bitD->ptr);   /* reminder : srcSize > sizeof(bitD) */+        return result;+    }+}++/*! BIT_endOfDStream() :+*   @return Tells if DStream has exactly reached its end (all bits consumed).+*/+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)+{+    return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));+}++#if defined (__cplusplus)+}+#endif++#endif /* BITSTREAM_H_MODULE */
+ zstd/lib/common/entropy_common.c view
@@ -0,0 +1,227 @@+/*+   Common functions of New Generation Entropy library+   Copyright (C) 2016, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++    You can contact the author at :+    - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy+    - Public forum : https://groups.google.com/forum/#!forum/lz4c+*************************************************************************** */++/* *************************************+*  Dependencies+***************************************/+#include "mem.h"+#include "error_private.h"       /* ERR_*, ERROR */+#define FSE_STATIC_LINKING_ONLY  /* FSE_MIN_TABLELOG */+#include "fse.h"+#define HUF_STATIC_LINKING_ONLY  /* HUF_TABLELOG_ABSOLUTEMAX */+#include "huf.h"+++/*-****************************************+*  FSE Error Management+******************************************/+unsigned FSE_isError(size_t code) { return ERR_isError(code); }++const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }+++/* **************************************************************+*  HUF Error Management+****************************************************************/+unsigned HUF_isError(size_t code) { return ERR_isError(code); }++const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }+++/*-**************************************************************+*  FSE NCount encoding-decoding+****************************************************************/+static short FSE_abs(short a) { return (short)(a<0 ? -a : a); }++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 = MEM_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 = MEM_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 = MEM_readLE32(ip) >> bitCount;+            } else {+                bitStream >>= 2;+        }   }+        {   short const max = (short)((2*threshold-1)-remaining);+            short count;++            if ((bitStream & (threshold-1)) < (U32)max) {+                count = (short)(bitStream & (threshold-1));+                bitCount   += nbBits-1;+            } else {+                count = (short)(bitStream & (2*threshold-1));+                if (count >= threshold) count -= max;+                bitCount   += nbBits;+            }++            count--;   /* extra accuracy */+            remaining -= FSE_abs(count);+            normalizedCounter[charnum++] = 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 = MEM_readLE32(ip) >> (bitCount & 31);+    }   }   /* while ((remaining>1) & (charnum<=*maxSVPtr)) */+    if (remaining != 1) return ERROR(corruption_detected);+    if (bitCount > 32) return ERROR(corruption_detected);+    *maxSVPtr = charnum-1;++    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(BYTE* huffWeight, size_t hwSize, U32* rankStats,+                     U32* nbSymbolsPtr, U32* tableLogPtr,+                     const void* src, size_t srcSize)+{+    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) */+        FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)];  /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */+        if (iSize+1 > srcSize) return ERROR(srcSize_wrong);+        oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6);   /* max (hwSize-1) values decoded, as last one is implied */+        if (FSE_isError(oSize)) return oSize;+    }++    /* 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;+}
+ zstd/lib/common/error_private.c view
@@ -0,0 +1,43 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++/* The purpose of this file is to have a single list of error strings embedded in binary */++#include "error_private.h"++const char* ERR_getErrorString(ERR_enum code)+{+    static const char* const notErrorCode = "Unspecified error code";+    switch( code )+    {+    case PREFIX(no_error): return "No error detected";+    case PREFIX(GENERIC):  return "Error (generic)";+    case PREFIX(prefix_unknown): return "Unknown frame descriptor";+    case PREFIX(version_unsupported): return "Version not supported";+    case PREFIX(parameter_unknown): return "Unknown parameter type";+    case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter";+    case PREFIX(frameParameter_unsupportedBy32bits): return "Frame parameter unsupported in 32-bits mode";+    case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding";+    case PREFIX(compressionParameter_unsupported): return "Compression parameter is out of bound";+    case PREFIX(init_missing): return "Context should be init first";+    case PREFIX(memory_allocation): return "Allocation error : not enough memory";+    case PREFIX(stage_wrong): return "Operation not authorized at current processing stage";+    case PREFIX(dstSize_tooSmall): return "Destination buffer is too small";+    case PREFIX(srcSize_wrong): return "Src size incorrect";+    case PREFIX(corruption_detected): return "Corrupted block detected";+    case PREFIX(checksum_wrong): return "Restored data doesn't match checksum";+    case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported";+    case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large";+    case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small";+    case PREFIX(dictionary_corrupted): return "Dictionary is corrupted";+    case PREFIX(dictionary_wrong): return "Dictionary mismatch";+    case PREFIX(maxCode):+    default: return notErrorCode;+    }+}
+ zstd/lib/common/error_private.h view
@@ -0,0 +1,76 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++/* Note : this module is expected to remain private, do not expose it */++#ifndef ERROR_H_MODULE+#define ERROR_H_MODULE++#if defined (__cplusplus)+extern "C" {+#endif+++/* ****************************************+*  Dependencies+******************************************/+#include <stddef.h>        /* size_t */+#include "zstd_errors.h"  /* enum list */+++/* ****************************************+*  Compiler-specific+******************************************/+#if defined(__GNUC__)+#  define ERR_STATIC static __attribute__((unused))+#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)+#  define ERR_STATIC static inline+#elif defined(_MSC_VER)+#  define ERR_STATIC static __inline+#else+#  define ERR_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */+#endif+++/*-****************************************+*  Customization (error_public.h)+******************************************/+typedef ZSTD_ErrorCode ERR_enum;+#define PREFIX(name) ZSTD_error_##name+++/*-****************************************+*  Error codes handling+******************************************/+#ifdef ERROR+#  undef ERROR   /* reported already defined on VS 2015 (Rich Geldreich) */+#endif+#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); }+++/*-****************************************+*  Error Strings+******************************************/++const char* ERR_getErrorString(ERR_enum code);   /* error_private.c */++ERR_STATIC const char* ERR_getErrorName(size_t code)+{+    return ERR_getErrorString(ERR_getErrorCode(code));+}++#if defined (__cplusplus)+}+#endif++#endif /* ERROR_H_MODULE */
+ zstd/lib/common/fse.h view
@@ -0,0 +1,668 @@+/* ******************************************************************+   FSE : Finite State Entropy codec+   Public Prototypes declaration+   Copyright (C) 2013-2016, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++   You can contact the author at :+   - Source repository : https://github.com/Cyan4973/FiniteStateEntropy+****************************************************************** */+#ifndef FSE_H+#define FSE_H++#if defined (__cplusplus)+extern "C" {+#endif+++/*-*****************************************+*  Dependencies+******************************************/+#include <stddef.h>    /* size_t, ptrdiff_t */+++/*-****************************************+*  FSE simple functions+******************************************/+/*! FSE_compress() :+    Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.+    'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).+    @return : size of compressed data (<= dstCapacity).+    Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!+                     if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.+                     if FSE_isError(return), compression failed (more details using FSE_getErrorName())+*/+size_t FSE_compress(void* dst, size_t dstCapacity,+              const void* src, size_t srcSize);++/*! FSE_decompress():+    Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',+    into already allocated destination buffer 'dst', of size 'dstCapacity'.+    @return : size of regenerated data (<= maxDstSize),+              or an error code, which can be tested using FSE_isError() .++    ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!+    Why ? : making this distinction requires a header.+    Header management is intentionally delegated to the user layer, which can better manage special cases.+*/+size_t FSE_decompress(void* dst,  size_t dstCapacity,+                const void* cSrc, size_t cSrcSize);+++/*-*****************************************+*  Tool functions+******************************************/+size_t FSE_compressBound(size_t size);       /* maximum compressed size */++/* Error Management */+unsigned    FSE_isError(size_t code);        /* tells if a return value is an error code */+const char* FSE_getErrorName(size_t code);   /* provides error code string (useful for debugging) */+++/*-*****************************************+*  FSE advanced functions+******************************************/+/*! FSE_compress2() :+    Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'+    Both parameters can be defined as '0' to mean : use default value+    @return : size of compressed data+    Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!+                     if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.+                     if FSE_isError(return), it's an error code.+*/+size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);+++/*-*****************************************+*  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_count():+    Provides the precise count of each byte within a table 'count'.+    'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1).+    *maxSymbolValuePtr will be updated if detected smaller than initial value.+    @return : the count of the most frequent symbol (which is not identified).+              if return == srcSize, there is only one symbol.+              Can also return an error code, which can be tested with FSE_isError(). */+size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);++/*! 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') */+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() */+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. */+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(). */+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_CTable* FSE_createCTable (unsigned tableLog, unsigned maxSymbolValue);+void        FSE_freeCTable (FSE_CTable* ct);++/*! FSE_buildCTable():+    Builds `ct`, which must be already allocated, using FSE_createCTable().+    @return : 0, or an errorCode, which can be tested using FSE_isError() */+size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);++/*! 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() */+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 */+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_DTable* FSE_createDTable(unsigned tableLog);+void        FSE_freeDTable(FSE_DTable* dt);++/*! FSE_buildDTable():+    Builds 'dt', which must be already allocated, using FSE_createDTable().+    return : 0, or an errorCode, which can be tested using FSE_isError() */+size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);++/*! 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() */+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)+*/+++#ifdef FSE_STATIC_LINKING_ONLY++/* *** 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() :+ *  same as FSE_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr+ */+size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);++/* 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` */++/* FSE_compress_wksp() :+ * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).+ * FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.+ */+#define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue)   ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + (1<<((maxTableLog>2)?(maxTableLog-2):0)) )+size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);++size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);+/**< 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, FSE_DTable* workSpace, unsigned maxLog);+/**< 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 */++MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)+{+    const void* ptr = ct;+    const U16* u16ptr = (const U16*) ptr;+    const U32 tableLog = MEM_read16(ptr);+    statePtr->value = (ptrdiff_t)1<<tableLog;+    statePtr->stateTable = u16ptr+2;+    statePtr->symbolTT = ((const U32*)ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1));+    statePtr->stateLog = tableLog;+}+++/*! FSE_initCState2() :+*   Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)+*   uses the smallest state value possible, saving the cost of this symbol */+MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)+{+    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];+    }+}++MEM_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];+}++MEM_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 */++MEM_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;+}++MEM_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;+}++MEM_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;+}++MEM_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% */+MEM_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;+}++MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)+{+    return DStatePtr->state == 0;+}++++#ifndef FSE_COMMONDEFS_ONLY++/* **************************************************************+*  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+++#endif   /* !FSE_COMMONDEFS_ONLY */+++/* ***************************************************************+*  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_STATIC_LINKING_ONLY */+++#if defined (__cplusplus)+}+#endif++#endif  /* FSE_H */
+ zstd/lib/common/fse_decompress.c view
@@ -0,0 +1,329 @@+/* ******************************************************************+   FSE : Finite State Entropy decoder+   Copyright (C) 2013-2015, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++    You can contact the author at :+    - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy+    - Public forum : https://groups.google.com/forum/#!forum/lz4c+****************************************************************** */+++/* **************************************************************+*  Compiler specifics+****************************************************************/+#ifdef _MSC_VER    /* Visual Studio */+#  define FORCE_INLINE static __forceinline+#  include <intrin.h>                    /* For Visual 2005 */+#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */+#  pragma warning(disable : 4214)        /* disable: C4214: non-int bitfields */+#else+#  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */+#    ifdef __GNUC__+#      define FORCE_INLINE static inline __attribute__((always_inline))+#    else+#      define FORCE_INLINE static inline+#    endif+#  else+#    define FORCE_INLINE static+#  endif /* __STDC_VERSION__ */+#endif+++/* **************************************************************+*  Includes+****************************************************************/+#include <stdlib.h>     /* malloc, free, qsort */+#include <string.h>     /* memcpy, memset */+#include <stdio.h>      /* printf (debug) */+#include "bitstream.h"+#define FSE_STATIC_LINKING_ONLY+#include "fse.h"+++/* **************************************************************+*  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 */+FSE_DTable* FSE_createDTable (unsigned tableLog)+{+    if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;+    return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );+}++void FSE_freeDTable (FSE_DTable* dt)+{+    free(dt);+}++size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)+{+    void* const tdPtr = dt+1;   /* because *dt is unsigned, 32-bits aligned on 32-bits */+    FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);+    U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];++    U32 const maxSV1 = maxSymbolValue + 1;+    U32 const tableSize = 1 << tableLog;+    U32 highThreshold = tableSize-1;++    /* Sanity Checks */+    if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);+    if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);++    /* 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;+}+++#ifndef FSE_COMMONDEFS_ONLY++/*-*******************************************************+*  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, FSE_DTable* workSpace, unsigned maxLog)+{+    const BYTE* const istart = (const BYTE*)cSrc;+    const BYTE* ip = istart;+    short counting[FSE_MAX_SYMBOL_VALUE+1];+    unsigned tableLog;+    unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;++    /* normal FSE decoding mode */+    size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);+    if (FSE_isError(NCountLength)) return NCountLength;+    //if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong);   /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */+    if (tableLog > maxLog) return ERROR(tableLog_tooLarge);+    ip += NCountLength;+    cSrcSize -= NCountLength;++    CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );++    return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace);   /* always return, even if it is an error code */+}+++typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];++size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize)+{+    DTable_max_t dt;   /* Static analyzer seems unable to understand this table will be properly initialized later */+    return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG);+}++++#endif   /* FSE_COMMONDEFS_ONLY */
+ zstd/lib/common/huf.h view
@@ -0,0 +1,238 @@+/* ******************************************************************+   Huffman coder, part of New Generation Entropy library+   header file+   Copyright (C) 2013-2016, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++   You can contact the author at :+   - Source repository : https://github.com/Cyan4973/FiniteStateEntropy+****************************************************************** */+#ifndef HUF_H_298734234+#define HUF_H_298734234++#if defined (__cplusplus)+extern "C" {+#endif+++/* *** Dependencies *** */+#include <stddef.h>    /* size_t */+++/* *** simple functions *** */+/**+HUF_compress() :+    Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.+    'dst' buffer must be already allocated.+    Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).+    `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.+    @return : size of compressed data (<= `dstCapacity`).+    Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!+                     if return == 1, srcData is a single repeated byte symbol (RLE compression).+                     if HUF_isError(return), compression failed (more details using HUF_getErrorName())+*/+size_t HUF_compress(void* dst, size_t dstCapacity,+              const void* src, size_t srcSize);++/**+HUF_decompress() :+    Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',+    into already allocated buffer 'dst', of minimum size 'dstSize'.+    `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.+    Note : in contrast with FSE, HUF_decompress can regenerate+           RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,+           because it knows size to regenerate.+    @return : size of regenerated data (== originalSize),+              or an error code, which can be tested using HUF_isError()+*/+size_t HUF_decompress(void* dst,  size_t originalSize,+                const void* cSrc, size_t cSrcSize);+++/* ***   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 */+const char* HUF_getErrorName(size_t code);   /**< provides error code string (useful for debugging) */+++/* ***   Advanced function   *** */++/** HUF_compress2() :+ *   Same as HUF_compress(), but offers direct control over `maxSymbolValue` and `tableLog` .+ *   `tableLog` must be `<= HUF_TABLELOG_MAX` . */+size_t HUF_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);++/** 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 1024 unsigned */++++#ifdef HUF_STATIC_LINKING_ONLY++/* *** Dependencies *** */+#include "mem.h"   /* U32 */+++/* *** Constants *** */+#define HUF_TABLELOG_ABSOLUTEMAX  15   /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */+#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+#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) }+++/* ****************************************+*  Advanced decompression functions+******************************************/+size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */+size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */++size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< decodes RLE and uncompressed */+size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */+size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */+size_t HUF_decompress4X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */+++/* ****************************************+*  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()+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_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits);+size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);+size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);+++/** 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(BYTE* huffWeight, size_t hwSize, U32* rankStats,+                     U32* nbSymbolsPtr, U32* tableLogPtr,+                     const void* src, size_t srcSize);++/** HUF_readCTable() :+*   Loading a CTable saved with HUF_writeCTable() */+size_t HUF_readCTable (HUF_CElt* CTable, unsigned maxSymbolValue, const void* src, size_t srcSize);+++/*+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 (HUF_DTable* DTable, const void* src, size_t srcSize);+size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize);++size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);+size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);+size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);+++/* single stream variants */++size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);+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 1024 unsigned */+size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);++size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* single-symbol decoder */+size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* double-symbol decoder */++size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);+size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< single-symbol decoder */+size_t HUF_decompress1X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /**< double-symbols decoder */++size_t HUF_decompress1X_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_STATIC_LINKING_ONLY */+++#if defined (__cplusplus)+}+#endif++#endif   /* HUF_H_298734234 */
+ zstd/lib/common/mem.h view
@@ -0,0 +1,372 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++#ifndef MEM_H_MODULE+#define MEM_H_MODULE++#if defined (__cplusplus)+extern "C" {+#endif++/*-****************************************+*  Dependencies+******************************************/+#include <stddef.h>     /* size_t, ptrdiff_t */+#include <string.h>     /* memcpy */+++/*-****************************************+*  Compiler specifics+******************************************/+#if defined(_MSC_VER)   /* Visual Studio */+#   include <stdlib.h>  /* _byteswap_ulong */+#   include <intrin.h>  /* _byteswap_* */+#endif+#if defined(__GNUC__)+#  define MEM_STATIC static __inline __attribute__((unused))+#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)+#  define MEM_STATIC static inline+#elif defined(_MSC_VER)+#  define MEM_STATIC static __inline+#else+#  define MEM_STATIC static  /* this version may generate warnings for unused static functions; disable the relevant warning */+#endif++/* code only tested on 32 and 64 bits systems */+#define MEM_STATIC_ASSERT(c)   { enum { MEM_static_assert = 1/(int)(!!(c)) }; }+MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }+++/*-**************************************************************+*  Basic Types+*****************************************************************/+#if  !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )+# include <stdint.h>+  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 intptr_t iPtrDiff;+#else+  typedef unsigned char      BYTE;+  typedef unsigned short      U16;+  typedef   signed short      S16;+  typedef unsigned int        U32;+  typedef   signed int        S32;+  typedef unsigned long long  U64;+  typedef   signed long long  S64;+  typedef ptrdiff_t      iPtrDiff;+#endif+++/*-**************************************************************+*  Memory I/O+*****************************************************************/+/* MEM_FORCE_MEMORY_ACCESS :+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.+ * The below switch allow to select different access method for improved performance.+ * Method 0 (default) : use `memcpy()`. Safe and portable.+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).+ *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.+ * Method 2 : direct access. This method is portable but violate C standard.+ *            It can generate buggy code on targets depending on alignment.+ *            In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)+ * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.+ * Prefer these methods in priority order (0 > 1 > 2)+ */+#ifndef MEM_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */+#  if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )+#    define MEM_FORCE_MEMORY_ACCESS 2+#  elif defined(__INTEL_COMPILER) /*|| defined(_MSC_VER)*/ || \+  (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))+#    define MEM_FORCE_MEMORY_ACCESS 1+#  endif+#endif++MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }+MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }++MEM_STATIC unsigned MEM_isLittleEndian(void)+{+    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */+    return one.c[0];+}++#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)++/* violates C standard, by lying on structure alignment.+Only use if no other choice to achieve best performance on target platform */+MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }+MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }+MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }+MEM_STATIC U64 MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }++MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }++#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)++/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */+/* currently only defined for gcc and icc */+#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))+	__pragma( pack(push, 1) )+    typedef union { U16 u16; U32 u32; U64 u64; size_t st; } unalign;+    __pragma( pack(pop) )+#else+    typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;+#endif++MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }+MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }+MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }+MEM_STATIC U64 MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; }++MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }+MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }+MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }++#else++/* default method, safe and standard.+   can sometimes prove slower */++MEM_STATIC U16 MEM_read16(const void* memPtr)+{+    U16 val; memcpy(&val, memPtr, sizeof(val)); return val;+}++MEM_STATIC U32 MEM_read32(const void* memPtr)+{+    U32 val; memcpy(&val, memPtr, sizeof(val)); return val;+}++MEM_STATIC U64 MEM_read64(const void* memPtr)+{+    U64 val; memcpy(&val, memPtr, sizeof(val)); return val;+}++MEM_STATIC size_t MEM_readST(const void* memPtr)+{+    size_t val; memcpy(&val, memPtr, sizeof(val)); return val;+}++MEM_STATIC void MEM_write16(void* memPtr, U16 value)+{+    memcpy(memPtr, &value, sizeof(value));+}++MEM_STATIC void MEM_write32(void* memPtr, U32 value)+{+    memcpy(memPtr, &value, sizeof(value));+}++MEM_STATIC void MEM_write64(void* memPtr, U64 value)+{+    memcpy(memPtr, &value, sizeof(value));+}++#endif /* MEM_FORCE_MEMORY_ACCESS */++MEM_STATIC U32 MEM_swap32(U32 in)+{+#if defined(_MSC_VER)     /* Visual Studio */+    return _byteswap_ulong(in);+#elif defined (__GNUC__)+    return __builtin_bswap32(in);+#else+    return  ((in << 24) & 0xff000000 ) |+            ((in <<  8) & 0x00ff0000 ) |+            ((in >>  8) & 0x0000ff00 ) |+            ((in >> 24) & 0x000000ff );+#endif+}++MEM_STATIC U64 MEM_swap64(U64 in)+{+#if defined(_MSC_VER)     /* Visual Studio */+    return _byteswap_uint64(in);+#elif defined (__GNUC__)+    return __builtin_bswap64(in);+#else+    return  ((in << 56) & 0xff00000000000000ULL) |+            ((in << 40) & 0x00ff000000000000ULL) |+            ((in << 24) & 0x0000ff0000000000ULL) |+            ((in << 8)  & 0x000000ff00000000ULL) |+            ((in >> 8)  & 0x00000000ff000000ULL) |+            ((in >> 24) & 0x0000000000ff0000ULL) |+            ((in >> 40) & 0x000000000000ff00ULL) |+            ((in >> 56) & 0x00000000000000ffULL);+#endif+}++MEM_STATIC size_t MEM_swapST(size_t in)+{+    if (MEM_32bits())+        return (size_t)MEM_swap32((U32)in);+    else+        return (size_t)MEM_swap64((U64)in);+}++/*=== Little endian r/w ===*/++MEM_STATIC U16 MEM_readLE16(const void* memPtr)+{+    if (MEM_isLittleEndian())+        return MEM_read16(memPtr);+    else {+        const BYTE* p = (const BYTE*)memPtr;+        return (U16)(p[0] + (p[1]<<8));+    }+}++MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)+{+    if (MEM_isLittleEndian()) {+        MEM_write16(memPtr, val);+    } else {+        BYTE* p = (BYTE*)memPtr;+        p[0] = (BYTE)val;+        p[1] = (BYTE)(val>>8);+    }+}++MEM_STATIC U32 MEM_readLE24(const void* memPtr)+{+    return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);+}++MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)+{+    MEM_writeLE16(memPtr, (U16)val);+    ((BYTE*)memPtr)[2] = (BYTE)(val>>16);+}++MEM_STATIC U32 MEM_readLE32(const void* memPtr)+{+    if (MEM_isLittleEndian())+        return MEM_read32(memPtr);+    else+        return MEM_swap32(MEM_read32(memPtr));+}++MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)+{+    if (MEM_isLittleEndian())+        MEM_write32(memPtr, val32);+    else+        MEM_write32(memPtr, MEM_swap32(val32));+}++MEM_STATIC U64 MEM_readLE64(const void* memPtr)+{+    if (MEM_isLittleEndian())+        return MEM_read64(memPtr);+    else+        return MEM_swap64(MEM_read64(memPtr));+}++MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)+{+    if (MEM_isLittleEndian())+        MEM_write64(memPtr, val64);+    else+        MEM_write64(memPtr, MEM_swap64(val64));+}++MEM_STATIC size_t MEM_readLEST(const void* memPtr)+{+    if (MEM_32bits())+        return (size_t)MEM_readLE32(memPtr);+    else+        return (size_t)MEM_readLE64(memPtr);+}++MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)+{+    if (MEM_32bits())+        MEM_writeLE32(memPtr, (U32)val);+    else+        MEM_writeLE64(memPtr, (U64)val);+}++/*=== Big endian r/w ===*/++MEM_STATIC U32 MEM_readBE32(const void* memPtr)+{+    if (MEM_isLittleEndian())+        return MEM_swap32(MEM_read32(memPtr));+    else+        return MEM_read32(memPtr);+}++MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)+{+    if (MEM_isLittleEndian())+        MEM_write32(memPtr, MEM_swap32(val32));+    else+        MEM_write32(memPtr, val32);+}++MEM_STATIC U64 MEM_readBE64(const void* memPtr)+{+    if (MEM_isLittleEndian())+        return MEM_swap64(MEM_read64(memPtr));+    else+        return MEM_read64(memPtr);+}++MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)+{+    if (MEM_isLittleEndian())+        MEM_write64(memPtr, MEM_swap64(val64));+    else+        MEM_write64(memPtr, val64);+}++MEM_STATIC size_t MEM_readBEST(const void* memPtr)+{+    if (MEM_32bits())+        return (size_t)MEM_readBE32(memPtr);+    else+        return (size_t)MEM_readBE64(memPtr);+}++MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)+{+    if (MEM_32bits())+        MEM_writeBE32(memPtr, (U32)val);+    else+        MEM_writeBE64(memPtr, (U64)val);+}+++/* function safe only for comparisons */+MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length)+{+    switch (length)+    {+    default :+    case 4 : return MEM_read32(memPtr);+    case 3 : if (MEM_isLittleEndian())+                return MEM_read32(memPtr)<<8;+             else+                return MEM_read32(memPtr)>>8;+    }+}++#if defined (__cplusplus)+}+#endif++#endif /* MEM_H_MODULE */
+ zstd/lib/common/xxhash.c view
@@ -0,0 +1,867 @@+/*+*  xxHash - Fast Hash algorithm+*  Copyright (C) 2012-2016, Yann Collet+*+*  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)+*+*  Redistribution and use in source and binary forms, with or without+*  modification, are permitted provided that the following conditions are+*  met:+*+*  * Redistributions of source code must retain the above copyright+*  notice, this list of conditions and the following disclaimer.+*  * Redistributions in binary form must reproduce the above+*  copyright notice, this list of conditions and the following disclaimer+*  in the documentation and/or other materials provided with the+*  distribution.+*+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+*+*  You can contact the author at :+*  - xxHash homepage: http://www.xxhash.com+*  - xxHash source repository : https://github.com/Cyan4973/xxHash+*/+++/* *************************************+*  Tuning parameters+***************************************/+/*!XXH_FORCE_MEMORY_ACCESS :+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.+ * The below switch allow to select different access method for improved performance.+ * Method 0 (default) : use `memcpy()`. Safe and portable.+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).+ *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.+ * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.+ *            It can generate buggy code on targets which do not support unaligned memory accesses.+ *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)+ * See http://stackoverflow.com/a/32095106/646947 for details.+ * Prefer these methods in priority order (0 > 1 > 2)+ */+#ifndef XXH_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */+#  if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )+#    define XXH_FORCE_MEMORY_ACCESS 2+#  elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \+  (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))+#    define XXH_FORCE_MEMORY_ACCESS 1+#  endif+#endif++/*!XXH_ACCEPT_NULL_INPUT_POINTER :+ * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.+ * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.+ * By default, this option is disabled. To enable it, uncomment below define :+ */+/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */++/*!XXH_FORCE_NATIVE_FORMAT :+ * By default, xxHash library provides endian-independant Hash values, based on little-endian convention.+ * Results are therefore identical for little-endian and big-endian CPU.+ * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.+ * Should endian-independance be of no importance for your application, you may set the #define below to 1,+ * to improve speed for Big-endian CPU.+ * This option has no impact on Little_Endian CPU.+ */+#ifndef XXH_FORCE_NATIVE_FORMAT   /* can be defined externally */+#  define XXH_FORCE_NATIVE_FORMAT 0+#endif++/*!XXH_FORCE_ALIGN_CHECK :+ * This is a minor performance trick, only useful with lots of very small keys.+ * It means : check for aligned/unaligned input.+ * The check costs one initial branch per hash; set to 0 when the input data+ * is guaranteed to be aligned.+ */+#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */+#  if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)+#    define XXH_FORCE_ALIGN_CHECK 0+#  else+#    define XXH_FORCE_ALIGN_CHECK 1+#  endif+#endif+++/* *************************************+*  Includes & Memory related functions+***************************************/+/* Modify the local functions below should you wish to use some other memory routines */+/* for malloc(), free() */+#include <stdlib.h>+static void* XXH_malloc(size_t s) { return malloc(s); }+static void  XXH_free  (void* p)  { free(p); }+/* for memcpy() */+#include <string.h>+static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }++#define XXH_STATIC_LINKING_ONLY+#include "xxhash.h"+++/* *************************************+*  Compiler Specific Options+***************************************/+#ifdef _MSC_VER    /* Visual Studio */+#  pragma warning(disable : 4127)      /* disable: C4127: conditional expression is constant */+#  define FORCE_INLINE static __forceinline+#else+#  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */+#    ifdef __GNUC__+#      define FORCE_INLINE static inline __attribute__((always_inline))+#    else+#      define FORCE_INLINE static inline+#    endif+#  else+#    define FORCE_INLINE static+#  endif /* __STDC_VERSION__ */+#endif+++/* *************************************+*  Basic Types+***************************************/+#ifndef MEM_MODULE+# define MEM_MODULE+# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )+#   include <stdint.h>+    typedef uint8_t  BYTE;+    typedef uint16_t U16;+    typedef uint32_t U32;+    typedef  int32_t S32;+    typedef uint64_t U64;+#  else+    typedef unsigned char      BYTE;+    typedef unsigned short     U16;+    typedef unsigned int       U32;+    typedef   signed int       S32;+    typedef unsigned long long U64;   /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */+#  endif+#endif+++#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))++/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */+static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }+static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }++#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))++/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */+/* currently only defined for gcc and icc */+typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign;++static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }+static U64 XXH_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }++#else++/* portable and safe solution. Generally efficient.+ * see : http://stackoverflow.com/a/32095106/646947+ */++static U32 XXH_read32(const void* memPtr)+{+    U32 val;+    memcpy(&val, memPtr, sizeof(val));+    return val;+}++static U64 XXH_read64(const void* memPtr)+{+    U64 val;+    memcpy(&val, memPtr, sizeof(val));+    return val;+}++#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */+++/* ****************************************+*  Compiler-specific Functions and Macros+******************************************/+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)++/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */+#if defined(_MSC_VER)+#  define XXH_rotl32(x,r) _rotl(x,r)+#  define XXH_rotl64(x,r) _rotl64(x,r)+#else+#  define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))+#  define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))+#endif++#if defined(_MSC_VER)     /* Visual Studio */+#  define XXH_swap32 _byteswap_ulong+#  define XXH_swap64 _byteswap_uint64+#elif GCC_VERSION >= 403+#  define XXH_swap32 __builtin_bswap32+#  define XXH_swap64 __builtin_bswap64+#else+static U32 XXH_swap32 (U32 x)+{+    return  ((x << 24) & 0xff000000 ) |+            ((x <<  8) & 0x00ff0000 ) |+            ((x >>  8) & 0x0000ff00 ) |+            ((x >> 24) & 0x000000ff );+}+static U64 XXH_swap64 (U64 x)+{+    return  ((x << 56) & 0xff00000000000000ULL) |+            ((x << 40) & 0x00ff000000000000ULL) |+            ((x << 24) & 0x0000ff0000000000ULL) |+            ((x << 8)  & 0x000000ff00000000ULL) |+            ((x >> 8)  & 0x00000000ff000000ULL) |+            ((x >> 24) & 0x0000000000ff0000ULL) |+            ((x >> 40) & 0x000000000000ff00ULL) |+            ((x >> 56) & 0x00000000000000ffULL);+}+#endif+++/* *************************************+*  Architecture Macros+***************************************/+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;++/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */+#ifndef XXH_CPU_LITTLE_ENDIAN+    static const int g_one = 1;+#   define XXH_CPU_LITTLE_ENDIAN   (*(const char*)(&g_one))+#endif+++/* ***************************+*  Memory reads+*****************************/+typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;++FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)+{+    if (align==XXH_unaligned)+        return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));+    else+        return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);+}++FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)+{+    return XXH_readLE32_align(ptr, endian, XXH_unaligned);+}++static U32 XXH_readBE32(const void* ptr)+{+    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);+}++FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)+{+    if (align==XXH_unaligned)+        return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));+    else+        return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);+}++FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)+{+    return XXH_readLE64_align(ptr, endian, XXH_unaligned);+}++static U64 XXH_readBE64(const void* ptr)+{+    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);+}+++/* *************************************+*  Macros+***************************************/+#define XXH_STATIC_ASSERT(c)   { enum { XXH_static_assert = 1/(int)(!!(c)) }; }    /* use only *after* variable declarations */+++/* *************************************+*  Constants+***************************************/+static const U32 PRIME32_1 = 2654435761U;+static const U32 PRIME32_2 = 2246822519U;+static const U32 PRIME32_3 = 3266489917U;+static const U32 PRIME32_4 =  668265263U;+static const U32 PRIME32_5 =  374761393U;++static const U64 PRIME64_1 = 11400714785074694791ULL;+static const U64 PRIME64_2 = 14029467366897019727ULL;+static const U64 PRIME64_3 =  1609587929392839161ULL;+static const U64 PRIME64_4 =  9650029242287828579ULL;+static const U64 PRIME64_5 =  2870177450012600261ULL;++XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }+++/* **************************+*  Utils+****************************/+XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dstState, const XXH32_state_t* restrict srcState)+{+    memcpy(dstState, srcState, sizeof(*dstState));+}++XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dstState, const XXH64_state_t* restrict srcState)+{+    memcpy(dstState, srcState, sizeof(*dstState));+}+++/* ***************************+*  Simple Hash Functions+*****************************/++static U32 XXH32_round(U32 seed, U32 input)+{+    seed += input * PRIME32_2;+    seed  = XXH_rotl32(seed, 13);+    seed *= PRIME32_1;+    return seed;+}++FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)+{+    const BYTE* p = (const BYTE*)input;+    const BYTE* bEnd = p + len;+    U32 h32;+#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)++#ifdef XXH_ACCEPT_NULL_INPUT_POINTER+    if (p==NULL) {+        len=0;+        bEnd=p=(const BYTE*)(size_t)16;+    }+#endif++    if (len>=16) {+        const BYTE* const limit = bEnd - 16;+        U32 v1 = seed + PRIME32_1 + PRIME32_2;+        U32 v2 = seed + PRIME32_2;+        U32 v3 = seed + 0;+        U32 v4 = seed - PRIME32_1;++        do {+            v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;+            v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;+            v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;+            v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;+        } while (p<=limit);++        h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);+    } else {+        h32  = seed + PRIME32_5;+    }++    h32 += (U32) len;++    while (p+4<=bEnd) {+        h32 += XXH_get32bits(p) * PRIME32_3;+        h32  = XXH_rotl32(h32, 17) * PRIME32_4 ;+        p+=4;+    }++    while (p<bEnd) {+        h32 += (*p) * PRIME32_5;+        h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;+        p++;+    }++    h32 ^= h32 >> 15;+    h32 *= PRIME32_2;+    h32 ^= h32 >> 13;+    h32 *= PRIME32_3;+    h32 ^= h32 >> 16;++    return h32;+}+++XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)+{+#if 0+    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */+    XXH32_CREATESTATE_STATIC(state);+    XXH32_reset(state, seed);+    XXH32_update(state, input, len);+    return XXH32_digest(state);+#else+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if (XXH_FORCE_ALIGN_CHECK) {+        if ((((size_t)input) & 3) == 0) {   /* Input is 4-bytes aligned, leverage the speed benefit */+            if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+                return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);+            else+                return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);+    }   }++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);+    else+        return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);+#endif+}+++static U64 XXH64_round(U64 acc, U64 input)+{+    acc += input * PRIME64_2;+    acc  = XXH_rotl64(acc, 31);+    acc *= PRIME64_1;+    return acc;+}++static U64 XXH64_mergeRound(U64 acc, U64 val)+{+    val  = XXH64_round(0, val);+    acc ^= val;+    acc  = acc * PRIME64_1 + PRIME64_4;+    return acc;+}++FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)+{+    const BYTE* p = (const BYTE*)input;+    const BYTE* const bEnd = p + len;+    U64 h64;+#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)++#ifdef XXH_ACCEPT_NULL_INPUT_POINTER+    if (p==NULL) {+        len=0;+        bEnd=p=(const BYTE*)(size_t)32;+    }+#endif++    if (len>=32) {+        const BYTE* const limit = bEnd - 32;+        U64 v1 = seed + PRIME64_1 + PRIME64_2;+        U64 v2 = seed + PRIME64_2;+        U64 v3 = seed + 0;+        U64 v4 = seed - PRIME64_1;++        do {+            v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;+            v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;+            v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;+            v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;+        } while (p<=limit);++        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);+        h64 = XXH64_mergeRound(h64, v1);+        h64 = XXH64_mergeRound(h64, v2);+        h64 = XXH64_mergeRound(h64, v3);+        h64 = XXH64_mergeRound(h64, v4);++    } else {+        h64  = seed + PRIME64_5;+    }++    h64 += (U64) len;++    while (p+8<=bEnd) {+        U64 const k1 = XXH64_round(0, XXH_get64bits(p));+        h64 ^= k1;+        h64  = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;+        p+=8;+    }++    if (p+4<=bEnd) {+        h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;+        h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;+        p+=4;+    }++    while (p<bEnd) {+        h64 ^= (*p) * PRIME64_5;+        h64 = XXH_rotl64(h64, 11) * PRIME64_1;+        p++;+    }++    h64 ^= h64 >> 33;+    h64 *= PRIME64_2;+    h64 ^= h64 >> 29;+    h64 *= PRIME64_3;+    h64 ^= h64 >> 32;++    return h64;+}+++XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)+{+#if 0+    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */+    XXH64_CREATESTATE_STATIC(state);+    XXH64_reset(state, seed);+    XXH64_update(state, input, len);+    return XXH64_digest(state);+#else+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if (XXH_FORCE_ALIGN_CHECK) {+        if ((((size_t)input) & 7)==0) {  /* Input is aligned, let's leverage the speed advantage */+            if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+                return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);+            else+                return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);+    }   }++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);+    else+        return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);+#endif+}+++/* **************************************************+*  Advanced Hash Functions+****************************************************/++XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)+{+    return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));+}+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)+{+    XXH_free(statePtr);+    return XXH_OK;+}++XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)+{+    return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));+}+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)+{+    XXH_free(statePtr);+    return XXH_OK;+}+++/*** Hash feed ***/++XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)+{+    XXH32_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */+    memset(&state, 0, sizeof(state)-4);   /* do not write into reserved, for future removal */+    state.v1 = seed + PRIME32_1 + PRIME32_2;+    state.v2 = seed + PRIME32_2;+    state.v3 = seed + 0;+    state.v4 = seed - PRIME32_1;+    memcpy(statePtr, &state, sizeof(state));+    return XXH_OK;+}+++XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)+{+    XXH64_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */+    memset(&state, 0, sizeof(state)-8);   /* do not write into reserved, for future removal */+    state.v1 = seed + PRIME64_1 + PRIME64_2;+    state.v2 = seed + PRIME64_2;+    state.v3 = seed + 0;+    state.v4 = seed - PRIME64_1;+    memcpy(statePtr, &state, sizeof(state));+    return XXH_OK;+}+++FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)+{+    const BYTE* p = (const BYTE*)input;+    const BYTE* const bEnd = p + len;++#ifdef XXH_ACCEPT_NULL_INPUT_POINTER+    if (input==NULL) return XXH_ERROR;+#endif++    state->total_len_32 += (unsigned)len;+    state->large_len |= (len>=16) | (state->total_len_32>=16);++    if (state->memsize + len < 16)  {   /* fill in tmp buffer */+        XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);+        state->memsize += (unsigned)len;+        return XXH_OK;+    }++    if (state->memsize) {   /* some data left from previous update */+        XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);+        {   const U32* p32 = state->mem32;+            state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;+            state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;+            state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;+            state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;+        }+        p += 16-state->memsize;+        state->memsize = 0;+    }++    if (p <= bEnd-16) {+        const BYTE* const limit = bEnd - 16;+        U32 v1 = state->v1;+        U32 v2 = state->v2;+        U32 v3 = state->v3;+        U32 v4 = state->v4;++        do {+            v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;+            v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;+            v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;+            v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;+        } while (p<=limit);++        state->v1 = v1;+        state->v2 = v2;+        state->v3 = v3;+        state->v4 = v4;+    }++    if (p < bEnd) {+        XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));+        state->memsize = (unsigned)(bEnd-p);+    }++    return XXH_OK;+}++XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)+{+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH32_update_endian(state_in, input, len, XXH_littleEndian);+    else+        return XXH32_update_endian(state_in, input, len, XXH_bigEndian);+}++++FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)+{+    const BYTE * p = (const BYTE*)state->mem32;+    const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;+    U32 h32;++    if (state->large_len) {+        h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);+    } else {+        h32 = state->v3 /* == seed */ + PRIME32_5;+    }++    h32 += state->total_len_32;++    while (p+4<=bEnd) {+        h32 += XXH_readLE32(p, endian) * PRIME32_3;+        h32  = XXH_rotl32(h32, 17) * PRIME32_4;+        p+=4;+    }++    while (p<bEnd) {+        h32 += (*p) * PRIME32_5;+        h32  = XXH_rotl32(h32, 11) * PRIME32_1;+        p++;+    }++    h32 ^= h32 >> 15;+    h32 *= PRIME32_2;+    h32 ^= h32 >> 13;+    h32 *= PRIME32_3;+    h32 ^= h32 >> 16;++    return h32;+}+++XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)+{+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH32_digest_endian(state_in, XXH_littleEndian);+    else+        return XXH32_digest_endian(state_in, XXH_bigEndian);+}++++/* **** XXH64 **** */++FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)+{+    const BYTE* p = (const BYTE*)input;+    const BYTE* const bEnd = p + len;++#ifdef XXH_ACCEPT_NULL_INPUT_POINTER+    if (input==NULL) return XXH_ERROR;+#endif++    state->total_len += len;++    if (state->memsize + len < 32) {  /* fill in tmp buffer */+        XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);+        state->memsize += (U32)len;+        return XXH_OK;+    }++    if (state->memsize) {   /* tmp buffer is full */+        XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);+        state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));+        state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));+        state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));+        state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));+        p += 32-state->memsize;+        state->memsize = 0;+    }++    if (p+32 <= bEnd) {+        const BYTE* const limit = bEnd - 32;+        U64 v1 = state->v1;+        U64 v2 = state->v2;+        U64 v3 = state->v3;+        U64 v4 = state->v4;++        do {+            v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;+            v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;+            v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;+            v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;+        } while (p<=limit);++        state->v1 = v1;+        state->v2 = v2;+        state->v3 = v3;+        state->v4 = v4;+    }++    if (p < bEnd) {+        XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));+        state->memsize = (unsigned)(bEnd-p);+    }++    return XXH_OK;+}++XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)+{+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH64_update_endian(state_in, input, len, XXH_littleEndian);+    else+        return XXH64_update_endian(state_in, input, len, XXH_bigEndian);+}++++FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)+{+    const BYTE * p = (const BYTE*)state->mem64;+    const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;+    U64 h64;++    if (state->total_len >= 32) {+        U64 const v1 = state->v1;+        U64 const v2 = state->v2;+        U64 const v3 = state->v3;+        U64 const v4 = state->v4;++        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);+        h64 = XXH64_mergeRound(h64, v1);+        h64 = XXH64_mergeRound(h64, v2);+        h64 = XXH64_mergeRound(h64, v3);+        h64 = XXH64_mergeRound(h64, v4);+    } else {+        h64  = state->v3 + PRIME64_5;+    }++    h64 += (U64) state->total_len;++    while (p+8<=bEnd) {+        U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));+        h64 ^= k1;+        h64  = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;+        p+=8;+    }++    if (p+4<=bEnd) {+        h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;+        h64  = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;+        p+=4;+    }++    while (p<bEnd) {+        h64 ^= (*p) * PRIME64_5;+        h64  = XXH_rotl64(h64, 11) * PRIME64_1;+        p++;+    }++    h64 ^= h64 >> 33;+    h64 *= PRIME64_2;+    h64 ^= h64 >> 29;+    h64 *= PRIME64_3;+    h64 ^= h64 >> 32;++    return h64;+}+++XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)+{+    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+        return XXH64_digest_endian(state_in, XXH_littleEndian);+    else+        return XXH64_digest_endian(state_in, XXH_bigEndian);+}+++/* **************************+*  Canonical representation+****************************/++/*! Default XXH result types are basic unsigned 32 and 64 bits.+*   The canonical representation follows human-readable write convention, aka big-endian (large digits first).+*   These functions allow transformation of hash result into and from its canonical format.+*   This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.+*/++XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)+{+    XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));+    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);+    memcpy(dst, &hash, sizeof(*dst));+}++XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)+{+    XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));+    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);+    memcpy(dst, &hash, sizeof(*dst));+}++XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)+{+    return XXH_readBE32(src);+}++XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)+{+    return XXH_readBE64(src);+}
+ zstd/lib/common/xxhash.h view
@@ -0,0 +1,309 @@+/*+   xxHash - Extremely Fast Hash algorithm+   Header File+   Copyright (C) 2012-2016, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++   You can contact the author at :+   - xxHash source repository : https://github.com/Cyan4973/xxHash+*/++/* Notice extracted from xxHash homepage :++xxHash is an extremely fast Hash algorithm, running at RAM speed limits.+It also successfully passes all tests from the SMHasher suite.++Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)++Name            Speed       Q.Score   Author+xxHash          5.4 GB/s     10+CrapWow         3.2 GB/s      2       Andrew+MumurHash 3a    2.7 GB/s     10       Austin Appleby+SpookyHash      2.0 GB/s     10       Bob Jenkins+SBox            1.4 GB/s      9       Bret Mulvey+Lookup3         1.2 GB/s      9       Bob Jenkins+SuperFastHash   1.2 GB/s      1       Paul Hsieh+CityHash64      1.05 GB/s    10       Pike & Alakuijala+FNV             0.55 GB/s     5       Fowler, Noll, Vo+CRC32           0.43 GB/s     9+MD5-32          0.33 GB/s    10       Ronald L. Rivest+SHA1-32         0.28 GB/s    10++Q.Score is a measure of quality of the hash function.+It depends on successfully passing SMHasher test set.+10 is a perfect score.++A 64-bits version, named XXH64, is available since r35.+It offers much better speed, but for 64-bits applications only.+Name     Speed on 64 bits    Speed on 32 bits+XXH64       13.8 GB/s            1.9 GB/s+XXH32        6.8 GB/s            6.0 GB/s+*/++#ifndef XXHASH_H_5627135585666179+#define XXHASH_H_5627135585666179 1++#if defined (__cplusplus)+extern "C" {+#endif++#ifndef XXH_NAMESPACE+#  define XXH_NAMESPACE ZSTD_  /* Zstandard specific */+#endif+++/* ****************************+*  Definitions+******************************/+#include <stddef.h>   /* size_t */+typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;+++/* ****************************+*  API modifier+******************************/+/** XXH_PRIVATE_API+*   This is useful if you want to include xxhash functions in `static` mode+*   in order to inline them, and remove their symbol from the public list.+*   Methodology :+*     #define XXH_PRIVATE_API+*     #include "xxhash.h"+*   `xxhash.c` is automatically included.+*   It's not useful to compile and link it as a separate module anymore.+*/+#ifdef XXH_PRIVATE_API+#  ifndef XXH_STATIC_LINKING_ONLY+#    define XXH_STATIC_LINKING_ONLY+#  endif+#  if defined(__GNUC__)+#    define XXH_PUBLIC_API static __inline __attribute__((unused))+#  elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)+#    define XXH_PUBLIC_API static inline+#  elif defined(_MSC_VER)+#    define XXH_PUBLIC_API static __inline+#  else+#    define XXH_PUBLIC_API static   /* this version may generate warnings for unused static functions; disable the relevant warning */+#  endif+#else+#  define XXH_PUBLIC_API   /* do nothing */+#endif /* XXH_PRIVATE_API */++/*!XXH_NAMESPACE, aka Namespace Emulation :++If you want to include _and expose_ xxHash functions from within your own library,+but also want to avoid symbol collisions with another library which also includes xxHash,++you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library+with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values).++Note that no change is required within the calling program as long as it includes `xxhash.h` :+regular symbol name will be automatically translated by this header.+*/+#ifdef XXH_NAMESPACE+#  define XXH_CAT(A,B) A##B+#  define XXH_NAME2(A,B) XXH_CAT(A,B)+#  define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)+#  define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)+#  define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)+#  define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)+#  define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)+#  define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)+#  define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)+#  define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)+#  define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)+#  define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)+#  define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)+#  define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)+#  define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)+#  define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)+#  define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)+#  define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)+#  define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)+#  define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)+#  define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)+#endif+++/* *************************************+*  Version+***************************************/+#define XXH_VERSION_MAJOR    0+#define XXH_VERSION_MINOR    6+#define XXH_VERSION_RELEASE  2+#define XXH_VERSION_NUMBER  (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)+XXH_PUBLIC_API unsigned XXH_versionNumber (void);+++/* ****************************+*  Simple Hash Functions+******************************/+typedef unsigned int       XXH32_hash_t;+typedef unsigned long long XXH64_hash_t;++XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);+XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);++/*!+XXH32() :+    Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".+    The memory between input & input+length must be valid (allocated and read-accessible).+    "seed" can be used to alter the result predictably.+    Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s+XXH64() :+    Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".+    "seed" can be used to alter the result predictably.+    This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark).+*/+++/* ****************************+*  Streaming Hash Functions+******************************/+typedef struct XXH32_state_s XXH32_state_t;   /* incomplete type */+typedef struct XXH64_state_s XXH64_state_t;   /* incomplete type */++/*! State allocation, compatible with dynamic libraries */++XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);+XXH_PUBLIC_API XXH_errorcode  XXH32_freeState(XXH32_state_t* statePtr);++XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);+XXH_PUBLIC_API XXH_errorcode  XXH64_freeState(XXH64_state_t* statePtr);+++/* hash streaming */++XXH_PUBLIC_API XXH_errorcode XXH32_reset  (XXH32_state_t* statePtr, unsigned int seed);+XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);+XXH_PUBLIC_API XXH32_hash_t  XXH32_digest (const XXH32_state_t* statePtr);++XXH_PUBLIC_API XXH_errorcode XXH64_reset  (XXH64_state_t* statePtr, unsigned long long seed);+XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);+XXH_PUBLIC_API XXH64_hash_t  XXH64_digest (const XXH64_state_t* statePtr);++/*+These functions generate the xxHash of an input provided in multiple segments.+Note that, for small input, they are slower than single-call functions, due to state management.+For small input, prefer `XXH32()` and `XXH64()` .++XXH state must first be allocated, using XXH*_createState() .++Start a new hash by initializing state with a seed, using XXH*_reset().++Then, feed the hash state by calling XXH*_update() as many times as necessary.+Obviously, input must be allocated and read accessible.+The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.++Finally, a hash value can be produced anytime, by using XXH*_digest().+This function returns the nn-bits hash as an int or long long.++It's still possible to continue inserting input into the hash state after a digest,+and generate some new hashes later on, by calling again XXH*_digest().++When done, free XXH state space if it was allocated dynamically.+*/+++/* **************************+*  Utils+****************************/+#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))   /* ! C99 */+#  define restrict   /* disable restrict */+#endif++XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* restrict dst_state, const XXH32_state_t* restrict src_state);+XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* restrict dst_state, const XXH64_state_t* restrict src_state);+++/* **************************+*  Canonical representation+****************************/+typedef struct { unsigned char digest[4]; } XXH32_canonical_t;+typedef struct { unsigned char digest[8]; } XXH64_canonical_t;++XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);+XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);++XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);+XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);++/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.+*  The canonical representation uses human-readable write convention, aka big-endian (large digits first).+*  These functions allow transformation of hash result into and from its canonical format.+*  This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.+*/+++#ifdef XXH_STATIC_LINKING_ONLY++/* ================================================================================================+   This section contains definitions which are not guaranteed to remain stable.+   They may change in future versions, becoming incompatible with a different version of the library.+   They shall only be used with static linking.+   Never use these definitions in association with dynamic linking !+=================================================================================================== */++/* These definitions are only meant to allow allocation of XXH state+   statically, on stack, or in a struct for example.+   Do not use members directly. */++   struct XXH32_state_s {+       unsigned total_len_32;+       unsigned large_len;+       unsigned v1;+       unsigned v2;+       unsigned v3;+       unsigned v4;+       unsigned mem32[4];   /* buffer defined as U32 for alignment */+       unsigned memsize;+       unsigned reserved;   /* never read nor write, will be removed in a future version */+   };   /* typedef'd to XXH32_state_t */++   struct XXH64_state_s {+       unsigned long long total_len;+       unsigned long long v1;+       unsigned long long v2;+       unsigned long long v3;+       unsigned long long v4;+       unsigned long long mem64[4];   /* buffer defined as U64 for alignment */+       unsigned memsize;+       unsigned reserved[2];          /* never read nor write, will be removed in a future version */+   };   /* typedef'd to XXH64_state_t */+++#  ifdef XXH_PRIVATE_API+#    include "xxhash.c"   /* include xxhash functions as `static`, for inlining */+#  endif++#endif /* XXH_STATIC_LINKING_ONLY */+++#if defined (__cplusplus)+}+#endif++#endif /* XXHASH_H_5627135585666179 */
+ zstd/lib/common/zstd_common.c view
@@ -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 this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++++/*-*************************************+*  Dependencies+***************************************/+#include <stdlib.h>         /* malloc */+#include "error_private.h"+#define ZSTD_STATIC_LINKING_ONLY+#include "zstd.h"           /* declaration of ZSTD_isError, ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber */+++/*-****************************************+*  Version+******************************************/+unsigned ZSTD_versionNumber (void) { return ZSTD_VERSION_NUMBER; }+++/*-****************************************+*  ZSTD Error Management+******************************************/+/*! ZSTD_isError() :+*   tells if a return value is an error code */+unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }++/*! ZSTD_getErrorName() :+*   provides error code string from function result (useful for debugging) */+const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }++/*! ZSTD_getError() :+*   convert a `size_t` function result into a proper ZSTD_errorCode enum */+ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }++/*! ZSTD_getErrorString() :+*   provides error code string from enum */+const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorName(code); }+++/*=**************************************************************+*  Custom allocator+****************************************************************/+/* default uses stdlib */+void* ZSTD_defaultAllocFunction(void* opaque, size_t size)+{+    void* address = malloc(size);+    (void)opaque;+    return address;+}++void ZSTD_defaultFreeFunction(void* opaque, void* address)+{+    (void)opaque;+    free(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);+}
+ zstd/lib/common/zstd_errors.h view
@@ -0,0 +1,74 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++#ifndef ZSTD_ERRORS_H_398273423+#define ZSTD_ERRORS_H_398273423++#if defined (__cplusplus)+extern "C" {+#endif++/*===== dependency =====*/+#include <stddef.h>   /* size_t */+++/* =====   ZSTDERRORLIB_API : control library symbols visibility   ===== */+#if defined(__GNUC__) && (__GNUC__ >= 4)+#  define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default")))+#else+#  define ZSTDERRORLIB_VISIBILITY+#endif+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)+#  define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)+#  define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/+#else+#  define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY+#endif++/*-****************************************+*  error codes list+******************************************/+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_maxCode+} ZSTD_ErrorCode;++/*! ZSTD_getErrorCode() :+    convert a `size_t` function result into a `ZSTD_ErrorCode` enum type,+    which can be used to compare directly with enum list published into "error_public.h" */+ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult);+ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code);+++#if defined (__cplusplus)+}+#endif++#endif /* ZSTD_ERRORS_H_398273423 */
+ zstd/lib/common/zstd_internal.h view
@@ -0,0 +1,270 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++#ifndef ZSTD_CCOMMON_H_MODULE+#define ZSTD_CCOMMON_H_MODULE++/*-*******************************************************+*  Compiler specifics+*********************************************************/+#ifdef _MSC_VER    /* Visual Studio */+#  define FORCE_INLINE static __forceinline+#  include <intrin.h>                    /* For Visual 2005 */+#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */+#  pragma warning(disable : 4324)        /* disable: C4324: padded structure */+#  pragma warning(disable : 4100)        /* disable: C4100: unreferenced formal parameter */+#else+#  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */+#    ifdef __GNUC__+#      define FORCE_INLINE static inline __attribute__((always_inline))+#    else+#      define FORCE_INLINE static inline+#    endif+#  else+#    define FORCE_INLINE static+#  endif /* __STDC_VERSION__ */+#endif++#ifdef _MSC_VER+#  define FORCE_NOINLINE static __declspec(noinline)+#else+#  ifdef __GNUC__+#    define FORCE_NOINLINE static __attribute__((__noinline__))+#  else+#    define FORCE_NOINLINE static+#  endif+#endif+++/*-*************************************+*  Dependencies+***************************************/+#include "mem.h"+#include "error_private.h"+#define ZSTD_STATIC_LINKING_ONLY+#include "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 */+++/*-*************************************+*  Common constants+***************************************/+#define ZSTD_OPT_NUM    (1<<12)+#define ZSTD_DICT_MAGIC  0xEC30A437   /* v0.7+ */++#define ZSTD_REP_NUM      3                 /* number of repcodes */+#define ZSTD_REP_CHECK    (ZSTD_REP_NUM)    /* number of repcodes to check by the optimal parser */+#define ZSTD_REP_MOVE     (ZSTD_REP_NUM-1)+#define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM)+static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };++#define KB *(1 <<10)+#define MB *(1 <<20)+#define GB *(1U<<30)++#define BIT7 128+#define BIT6  64+#define BIT5  32+#define BIT4  16+#define BIT1   2+#define BIT0   1++#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10+static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };+static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };++#define ZSTD_BLOCKHEADERSIZE 3   /* C standard doesn't allow `static const` variable to be init using another `static const` variable */+static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;+typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;++#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */+#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */)   /* for a non-null block */++#define HufLog 12+typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;++#define LONGNBSEQ 0x7F00++#define MINMATCH 3+#define EQUAL_READ32 4++#define Litbits  8+#define MaxLit ((1<<Litbits) - 1)+#define MaxML  52+#define MaxLL  35+#define MaxOff 28+#define MaxSeq MAX(MaxLL, MaxML)   /* Assumption : MaxOff < MaxLL,MaxML */+#define MLFSELog    9+#define LLFSELog    9+#define OffFSELog   8++static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+                                      1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9,10,11,12,+                                     13,14,15,16 };+static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,+                                             2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,+                                            -1,-1,-1,-1 };+#define LL_DEFAULTNORMLOG 6  /* for static allocation */+static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;++static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+                                      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+                                      1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9,10,11,+                                     12,13,14,15,16 };+static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,+                                             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,+                                             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,+                                            -1,-1,-1,-1,-1 };+#define ML_DEFAULTNORMLOG 6  /* for static allocation */+static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;++static const S16 OF_defaultNorm[MaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,+                                              1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 };+#define OF_DEFAULTNORMLOG 5  /* for static allocation */+static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;+++/*-*******************************************+*  Shared functions to include for inlining+*********************************************/+static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }+#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }++/*! ZSTD_wildcopy() :+*   custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */+#define WILDCOPY_OVERLENGTH 8+MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)+{+    const BYTE* ip = (const BYTE*)src;+    BYTE* op = (BYTE*)dst;+    BYTE* const oend = op + length;+    do+        COPY8(op, ip)+    while (op < oend);+}++MEM_STATIC void ZSTD_wildcopy_e(void* dst, const void* src, void* dstEnd)   /* should be faster for decoding, but strangely, not verified on all platform */+{+    const BYTE* ip = (const BYTE*)src;+    BYTE* op = (BYTE*)dst;+    BYTE* const oend = (BYTE*)dstEnd;+    do+        COPY8(op, ip)+    while (op < oend);+}+++/*-*******************************************+*  Private interfaces+*********************************************/+typedef struct ZSTD_stats_s ZSTD_stats_t;++typedef struct {+    U32 off;+    U32 len;+} ZSTD_match_t;++typedef struct {+    U32 price;+    U32 off;+    U32 mlen;+    U32 litlen;+    U32 rep[ZSTD_REP_NUM];+} ZSTD_optimal_t;+++typedef struct seqDef_s {+    U32 offset;+    U16 litLength;+    U16 matchLength;+} seqDef;+++typedef struct {+    seqDef* sequencesStart;+    seqDef* sequences;+    BYTE* litStart;+    BYTE* lit;+    BYTE* llCode;+    BYTE* mlCode;+    BYTE* ofCode;+    U32   longLengthID;   /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */+    U32   longLengthPos;+    /* opt */+    ZSTD_optimal_t* priceTable;+    ZSTD_match_t* matchTable;+    U32* matchLengthFreq;+    U32* litLengthFreq;+    U32* litFreq;+    U32* offCodeFreq;+    U32  matchLengthSum;+    U32  matchSum;+    U32  litLengthSum;+    U32  litSum;+    U32  offCodeSum;+    U32  log2matchLengthSum;+    U32  log2matchSum;+    U32  log2litLengthSum;+    U32  log2litSum;+    U32  log2offCodeSum;+    U32  factor;+    U32  staticPrices;+    U32  cachedPrice;+    U32  cachedLitLength;+    const BYTE* cachedLiterals;+} seqStore_t;++const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx);+void ZSTD_seqToCodes(const seqStore_t* seqStorePtr);+int ZSTD_isSkipFrame(ZSTD_DCtx* dctx);++/* custom memory allocation functions */+void* ZSTD_defaultAllocFunction(void* opaque, size_t size);+void ZSTD_defaultFreeFunction(void* opaque, void* address);+#ifndef ZSTD_DLL_IMPORT+static const ZSTD_customMem defaultCustomMem = { ZSTD_defaultAllocFunction, ZSTD_defaultFreeFunction, NULL };+#endif+void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);+void ZSTD_free(void* ptr, ZSTD_customMem customMem);+++/*======  common function  ======*/++MEM_STATIC U32 ZSTD_highbit32(U32 val)+{+#   if defined(_MSC_VER)   /* Visual */+    unsigned long r=0;+    _BitScanReverse(&r, val);+    return (unsigned)r;+#   elif defined(__GNUC__) && (__GNUC__ >= 3)   /* GCC Intrinsic */+    return 31 - __builtin_clz(val);+#   else   /* Software version */+    static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };+    U32 v = val;+    int r;+    v |= v >> 1;+    v |= v >> 2;+    v |= v >> 4;+    v |= v >> 8;+    v |= v >> 16;+    r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];+    return r;+#   endif+}+++#endif   /* ZSTD_CCOMMON_H_MODULE */
+ zstd/lib/compress/fse_compress.c view
@@ -0,0 +1,850 @@+/* ******************************************************************+   FSE : Finite State Entropy encoder+   Copyright (C) 2013-2015, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++    You can contact the author at :+    - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy+    - Public forum : https://groups.google.com/forum/#!forum/lz4c+****************************************************************** */++/* **************************************************************+*  Compiler specifics+****************************************************************/+#ifdef _MSC_VER    /* Visual Studio */+#  define FORCE_INLINE static __forceinline+#  include <intrin.h>                    /* For Visual 2005 */+#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */+#  pragma warning(disable : 4214)        /* disable: C4214: non-int bitfields */+#else+#  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */+#    ifdef __GNUC__+#      define FORCE_INLINE static inline __attribute__((always_inline))+#    else+#      define FORCE_INLINE static inline+#    endif+#  else+#    define FORCE_INLINE static+#  endif /* __STDC_VERSION__ */+#endif+++/* **************************************************************+*  Includes+****************************************************************/+#include <stdlib.h>     /* malloc, free, qsort */+#include <string.h>     /* memcpy, memset */+#include <stdio.h>      /* printf (debug) */+#include "bitstream.h"+#define FSE_STATIC_LINKING_ONLY+#include "fse.h"+++/* **************************************************************+*  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 wkspSize)+{+    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 cumul[FSE_MAX_SYMBOL_VALUE+2];++    FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;+    U32 highThreshold = tableSize-1;++    /* CTable header */+    if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);+    tableU16[-2] = (U16) tableLog;+    tableU16[-1] = (U16) maxSymbolValue;++    /* For explanations on how to distribute symbol values over the table :+    *  http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */++    /* symbol start positions */+    {   U32 u;+        cumul[0] = 0;+        for (u=1; u<=maxSymbolValue+1; u++) {+            if (normalizedCounter[u-1]==-1) {  /* Low proba symbol */+                cumul[u] = cumul[u-1] + 1;+                tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);+            } else {+                cumul[u] = cumul[u-1] + normalizedCounter[u-1];+        }   }+        cumul[maxSymbolValue+1] = tableSize+1;+    }++    /* Spread symbols */+    {   U32 position = 0;+        U32 symbol;+        for (symbol=0; symbol<=maxSymbolValue; symbol++) {+            int nbOccurences;+            for (nbOccurences=0; nbOccurences<normalizedCounter[symbol]; nbOccurences++) {+                tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;+                position = (position + step) & tableMask;+                while (position > highThreshold) position = (position + step) & tableMask;   /* Low proba area */+        }   }++        if (position!=0) return ERROR(GENERIC);   /* Must have gone through all positions */+    }++    /* Build table */+    {   U32 u; for (u=0; u<tableSize; u++) {+        FSE_FUNCTION_TYPE s = tableSymbol[u];   /* note : static analyzer may not understand tableSymbol is properly initialized */+        tableU16[cumul[s]++] = (U16) (tableSize+u);   /* TableU16 : sorted by symbol order; gives next state value */+    }   }++    /* Build Symbol Transformation Table */+    {   unsigned total = 0;+        unsigned s;+        for (s=0; s<=maxSymbolValue; s++) {+            switch (normalizedCounter[s])+            {+            case  0: break;++            case -1:+            case  1:+                symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);+                symbolTT[s].deltaFindState = total - 1;+                total ++;+                break;+            default :+                {+                    U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);+                    U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;+                    symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;+                    symbolTT[s].deltaFindState = total - normalizedCounter[s];+                    total +=  normalizedCounter[s];+    }   }   }   }++    return 0;+}+++size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)+{+    FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE];   /* memset() is not necessary, even if static analyzer complain about it */+    return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));+}++++#ifndef FSE_COMMONDEFS_ONLY++/*-**************************************************************+*  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 short FSE_abs(short a) { return (short)(a<0 ? -a : a); }++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;+        }   }+        {   short count = normalizedCounter[charnum++];+            const short max = (short)((2*threshold-1)-remaining);+            remaining -= FSE_abs(count);+            if (remaining<1) return ERROR(GENERIC);+            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);+            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(GENERIC);   /* 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 = MEM_read32(ip); ip += 4;+        while (ip < iend-15) {+            U32 c = cached; cached = MEM_read32(ip); ip += 4;+            Counting1[(BYTE) c     ]++;+            Counting2[(BYTE)(c>>8) ]++;+            Counting3[(BYTE)(c>>16)]++;+            Counting4[       c>>24 ]++;+            c = cached; cached = MEM_read32(ip); ip += 4;+            Counting1[(BYTE) c     ]++;+            Counting2[(BYTE)(c>>8) ]++;+            Counting3[(BYTE)(c>>16)]++;+            Counting4[       c>>24 ]++;+            c = cached; cached = MEM_read32(ip); ip += 4;+            Counting1[(BYTE) c     ]++;+            Counting2[(BYTE)(c>>8) ]++;+            Counting3[(BYTE)(c>>16)]++;+            Counting4[       c>>24 ]++;+            c = cached; cached = MEM_read32(ip); ip += 4;+            Counting1[(BYTE) c     ]++;+            Counting2[(BYTE)(c>>8) ]++;+            Counting3[(BYTE)(c>>16)]++;+            Counting4[       c>>24 ]++;+        }+        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);+}++/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */+size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr,+                     const void* source, size_t sourceSize)+{+    unsigned tmpCounters[1024];+    return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters);+}++/* 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);+}++size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr,+                 const void* src, size_t srcSize)+{+    unsigned tmpCounters[1024];+    return FSE_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters);+}++++/*-**************************************************************+*  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);+}++FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)+{+    size_t size;+    if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;+    size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);+    return (FSE_CTable*)malloc(size);+}++void FSE_freeCTable (FSE_CTable* ct) { free(ct); }++/* 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)+{+    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]=-2;+    }+    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] == -2) && (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;+    }++    {   U64 const vStepLog = 62 - tableLog;+        U64 const mid = (1ULL << (vStepLog-1)) - 1;+        U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total;   /* scale on remaining */+        U64 tmpTotal = mid;+        for (s=0; s<=maxSymbolValue; s++) {+            if (norm[s]==-2) {+                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 = ((U64)1<<62) / 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;+    }++#if 0+    {   /* Print Table (debug) */+        U32 s;+        U32 nTotal = 0;+        for (s=0; s<=maxSymbolValue; s++)+            printf("%3i: %4i \n", s, normalizedCounter[s]);+        for (s=0; s<=maxSymbolValue; s++)+            nTotal += abs(normalizedCounter[s]);+        if (nTotal != (1U<<tableLog))+            printf("Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);+        getchar();+    }+#endif++    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); }++#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return f+#define CHECK_F(f)   { CHECK_V_F(_var_err__, f); }++/* FSE_compress_wksp() :+ * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).+ * `wkspSize` size must be `(1<<tableLog)`.+ */+size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)+{+    BYTE* const ostart = (BYTE*) dst;+    BYTE* op = ostart;+    BYTE* const oend = ostart + dstSize;++    U32   count[FSE_MAX_SYMBOL_VALUE+1];+    S16   norm[FSE_MAX_SYMBOL_VALUE+1];+    FSE_CTable* CTable = (FSE_CTable*)workSpace;+    size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);+    void* scratchBuffer = (void*)(CTable + CTableSize);+    size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));++    /* init conditions */+    if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);+    if (srcSize <= 1) return 0;  /* Not compressible */+    if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;+    if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;++    /* Scan input and build symbol stats */+    {   CHECK_V_F(maxCount, FSE_count(count, &maxSymbolValue, src, srcSize) );+        if (maxCount == srcSize) return 1;   /* only a single symbol in src : rle */+        if (maxCount == 1) return 0;         /* each symbol present maximum once => not compressible */+        if (maxCount < (srcSize >> 7)) return 0;   /* Heuristic : not compressible enough */+    }++    tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);+    CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );++    /* Write table description header */+    {   CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );+        op += nc_err;+    }++    /* Compress */+    CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );+    {   CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );+        if (cSize == 0) return 0;   /* not enough space for compressed data */+        op += cSize;+    }++    /* check compressibility */+    if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;++    return op-ostart;+}++typedef struct {+    FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];+    BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];+} fseWkspMax_t;++size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)+{+    fseWkspMax_t scratchBuffer;+    FSE_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE));   /* compilation failures here means scratchBuffer is not large enough */+    if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);+    return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));+}++size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize)+{+    return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);+}+++#endif   /* FSE_COMMONDEFS_ONLY */
+ zstd/lib/compress/huf_compress.c view
@@ -0,0 +1,609 @@+/* ******************************************************************+   Huffman encoder, part of New Generation Entropy library+   Copyright (C) 2013-2016, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++    You can contact the author at :+    - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy+    - Public forum : https://groups.google.com/forum/#!forum/lz4c+****************************************************************** */++/* **************************************************************+*  Compiler specifics+****************************************************************/+#ifdef _MSC_VER    /* Visual Studio */+#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */+#endif+++/* **************************************************************+*  Includes+****************************************************************/+#include <string.h>     /* memcpy, memset */+#include <stdio.h>      /* printf (debug) */+#include "bitstream.h"+#define FSE_STATIC_LINKING_ONLY   /* FSE_optimalTableLog_internal */+#include "fse.h"        /* header compression */+#define HUF_STATIC_LINKING_ONLY+#include "huf.h"+++/* **************************************************************+*  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 (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)+{+    BYTE* const ostart = (BYTE*) dst;+    BYTE* op = ostart;+    BYTE* const oend = ostart + dstSize;++    U32 maxSymbolValue = HUF_TABLELOG_MAX;+    U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;++    FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];+    BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER];++    U32 count[HUF_TABLELOG_MAX+1];+    S16 norm[HUF_TABLELOG_MAX+1];++    /* 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, scratchBuffer, sizeof(scratchBuffer)) );+    {   CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) );+        if (cSize == 0) return 0;   /* not enough space for compressed data */+        op += cSize;+    }++    return op-ostart;+}+++struct HUF_CElt_s {+  U16  val;+  BYTE nbBits;+};   /* typedef'd to HUF_CElt within "huf.h" */++/*! HUF_writeCTable() :+    `CTable` : huffman tree to save, using huf representation.+    @return : size of saved CTable */+size_t HUF_writeCTable (void* dst, size_t maxDstSize,+                        const HUF_CElt* CTable, U32 maxSymbolValue, U32 huffLog)+{+    BYTE bitsToWeight[HUF_TABLELOG_MAX + 1];   /* precomputed conversion table */+    BYTE huffWeight[HUF_SYMBOLVALUE_MAX];+    BYTE* op = (BYTE*)dst;+    U32 n;++     /* 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(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );+        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 (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, size_t srcSize)+{+    BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1];   /* init not required, even though some static analyzer may complain */+    U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1];   /* large enough for values from 0 to 16 */+    U32 tableLog = 0;+    U32 nbSymbols = 0;++    /* get symbol weights */+    CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));++    /* 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 current = nextRankStart;+            nextRankStart += (rankVal[n] << (n-1));+            rankVal[n] = current;+    }   }++    /* 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 currentNbBits = maxNbBits;+                for (pos=n ; pos >= 0; pos--) {+                    if (huffNode[pos].nbBits >= currentNbBits) continue;+                    currentNbBits = huffNode[pos].nbBits;   /* < maxNbBits */+                    rankLast[maxNbBits-currentNbBits] = 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 !) */+                while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol))  /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */+                    nBitsToDecrease ++;+                totalCost -= 1 << (nBitsToDecrease-1);+                if (rankLast[nBitsToDecrease-1] == noSymbol)+                    rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease];   /* this rank is no longer empty */+                huffNode[rankLast[nBitsToDecrease]].nbBits ++;+                if (rankLast[nBitsToDecrease] == 0)    /* special case, reached largest symbol */+                    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 current;+} 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].current = rank[n].base;+    for (n=0; n<=maxSymbolValue; n++) {+        U32 const c = count[n];+        U32 const r = BIT_highbit32(c+1) + 1;+        U32 pos = rank[r].current++;+        while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) huffNode[pos]=huffNode[pos-1], pos--;+        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;+}++/** HUF_buildCTable() :+ *  Note : count is used before tree is written, so they can safely overlap+ */+size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits)+{+    huffNodeTable nodeTable;+    return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, nodeTable, sizeof(nodeTable));+}++static void HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)+{+    BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);+}++size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }++#define HUF_FLUSHBITS(s)  (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))++#define HUF_FLUSHBITS_1(stream) \+    if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream)++#define HUF_FLUSHBITS_2(stream) \+    if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)++size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)+{+    const BYTE* ip = (const BYTE*) src;+    BYTE* const ostart = (BYTE*)dst;+    BYTE* const oend = ostart + dstSize;+    BYTE* op = ostart;+    size_t n;+    const unsigned fast = (dstSize >= HUF_BLOCKBOUND(srcSize));+    BIT_CStream_t bitC;++    /* init */+    if (dstSize < 8) return 0;   /* not enough space to compress */+    { size_t const initErr = BIT_initCStream(&bitC, op, oend-op);+      if (HUF_isError(initErr)) return 0; }++    n = srcSize & ~3;  /* join to mod 4 */+    switch (srcSize & 3)+    {+        case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable);+                 HUF_FLUSHBITS_2(&bitC);+        case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable);+                 HUF_FLUSHBITS_1(&bitC);+        case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable);+                 HUF_FLUSHBITS(&bitC);+        case 0 :+        default: ;+    }++    for (; n>0; n-=4) {  /* note : n&3==0 at this stage */+        HUF_encodeSymbol(&bitC, ip[n- 1], CTable);+        HUF_FLUSHBITS_1(&bitC);+        HUF_encodeSymbol(&bitC, ip[n- 2], CTable);+        HUF_FLUSHBITS_2(&bitC);+        HUF_encodeSymbol(&bitC, ip[n- 3], CTable);+        HUF_FLUSHBITS_1(&bitC);+        HUF_encodeSymbol(&bitC, ip[n- 4], CTable);+        HUF_FLUSHBITS(&bitC);+    }++    return BIT_closeCStream(&bitC);+}+++size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)+{+    size_t const segmentSize = (srcSize+3)/4;   /* first 3 segments */+    const BYTE* ip = (const BYTE*) src;+    const BYTE* const iend = ip + srcSize;+    BYTE* const ostart = (BYTE*) dst;+    BYTE* const oend = ostart + dstSize;+    BYTE* op = ostart;++    if (dstSize < 6 + 1 + 1 + 1 + 8) return 0;   /* minimum space to compress successfully */+    if (srcSize < 12) return 0;   /* no saving possible : too small input */+    op += 6;   /* jumpTable */++    {   CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );+        if (cSize==0) return 0;+        MEM_writeLE16(ostart, (U16)cSize);+        op += cSize;+    }++    ip += segmentSize;+    {   CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );+        if (cSize==0) return 0;+        MEM_writeLE16(ostart+2, (U16)cSize);+        op += cSize;+    }++    ip += segmentSize;+    {   CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );+        if (cSize==0) return 0;+        MEM_writeLE16(ostart+4, (U16)cSize);+        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;+}+++/* `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)+{+    BYTE* const ostart = (BYTE*)dst;+    BYTE* const oend = ostart + dstSize;+    BYTE* op = ostart;++    union {+        U32 count[HUF_SYMBOLVALUE_MAX+1];+        HUF_CElt CTable[HUF_SYMBOLVALUE_MAX+1];+    } table;   /* `count` can overlap with `CTable`; saves 1 KB */++    /* checks & inits */+    if (wkspSize < sizeof(huffNodeTable)) return ERROR(GENERIC);+    if (!srcSize) return 0;  /* Uncompressed (note : 1 means rle, so first byte must be correct) */+    if (!dstSize) return 0;  /* cannot fit within dst budget */+    if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);   /* current block size limit */+    if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);+    if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;+    if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;++    /* Scan input and build symbol stats */+    {   CHECK_V_F(largest, FSE_count_wksp (table.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 */+    }++    /* Build Huffman Tree */+    huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);+    {   CHECK_V_F(maxBits, HUF_buildCTable_wksp (table.CTable, table.count, maxSymbolValue, huffLog, workSpace, wkspSize) );+        huffLog = (U32)maxBits;+    }++    /* Write table description header */+    {   CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table.CTable, maxSymbolValue, huffLog) );+        if (hSize + 12 >= srcSize) return 0;   /* not useful to try compression */+        op += hSize;+    }++    /* Compress */+    {   size_t const cSize = (singleStream) ?+                            HUF_compress1X_usingCTable(op, oend - op, src, srcSize, table.CTable) :   /* single segment */+                            HUF_compress4X_usingCTable(op, oend - op, src, srcSize, table.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;+}+++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);+}++size_t HUF_compress1X (void* dst, size_t dstSize,+                 const void* src, size_t srcSize,+                 unsigned maxSymbolValue, unsigned huffLog)+{+    unsigned workSpace[1024];+    return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));+}++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);+}++size_t HUF_compress2 (void* dst, size_t dstSize,+                const void* src, size_t srcSize,+                unsigned maxSymbolValue, unsigned huffLog)+{+    unsigned workSpace[1024];+    return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));+}++size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize)+{+    return HUF_compress2(dst, maxDstSize, src, (U32)srcSize, 255, HUF_TABLELOG_DEFAULT);+}
+ zstd/lib/compress/zstd_compress.c view
@@ -0,0 +1,3306 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */+++/*-*************************************+*  Dependencies+***************************************/+#include <string.h>         /* memset */+#include "mem.h"+#define XXH_STATIC_LINKING_ONLY   /* XXH64_state_t */+#include "xxhash.h"               /* XXH_reset, update, digest */+#define FSE_STATIC_LINKING_ONLY   /* FSE_encodeSymbol */+#include "fse.h"+#define HUF_STATIC_LINKING_ONLY+#include "huf.h"+#include "zstd_internal.h"  /* includes zstd.h */+++/*-*************************************+*  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+***************************************/+#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }+size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }+++/*-*************************************+*  Sequence storage+***************************************/+static void ZSTD_resetSeqStore(seqStore_t* ssPtr)+{+    ssPtr->lit = ssPtr->litStart;+    ssPtr->sequences = ssPtr->sequencesStart;+    ssPtr->longLengthID = 0;+}+++/*-*************************************+*  Context memory management+***************************************/+struct ZSTD_CCtx_s {+    const BYTE* nextSrc;    /* next block here to continue on current prefix */+    const BYTE* base;       /* All regular indexes relative to this position */+    const BYTE* dictBase;   /* extDict indexes relative to this position */+    U32   dictLimit;        /* below that point, need extDict */+    U32   lowLimit;         /* below that point, no more data */+    U32   nextToUpdate;     /* index from which to continue dictionary update */+    U32   nextToUpdate3;    /* index from which to continue dictionary update */+    U32   hashLog3;         /* dispatch table : larger == faster, more memory */+    U32   loadedDictEnd;+    ZSTD_compressionStage_e stage;+    U32   rep[ZSTD_REP_NUM];+    U32   savedRep[ZSTD_REP_NUM];+    U32   dictID;+    ZSTD_parameters params;+    void* workSpace;+    size_t workSpaceSize;+    size_t blockSize;+    U64 frameContentSize;+    XXH64_state_t xxhState;+    ZSTD_customMem customMem;++    seqStore_t seqStore;    /* sequences storage ptrs */+    U32* hashTable;+    U32* hashTable3;+    U32* chainTable;+    HUF_CElt* hufTable;+    U32 flagStaticTables;+    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[1024];+};++ZSTD_CCtx* ZSTD_createCCtx(void)+{+    return ZSTD_createCCtx_advanced(defaultCustomMem);+}++ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)+{+    ZSTD_CCtx* cctx;++    if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;+    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));+    memcpy(&(cctx->customMem), &customMem, sizeof(customMem));+    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 */+}++size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)+{+    if (cctx==NULL) return 0;   /* support sizeof on NULL */+    return sizeof(*cctx) + cctx->workSpaceSize;+}++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);+    { U32 const searchLengthMin = ((cParams.strategy == ZSTD_fast) | (cParams.strategy == ZSTD_greedy)) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN;+      U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;+      CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }+    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;+}+++size_t ZSTD_estimateCCtxSize(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 neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace+                             + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);++    return sizeof(ZSTD_CCtx) + neededSpace;+}+++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))+            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;+        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_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_resetCCtx_advanced(dstCCtx, srcCCtx->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;+    if (srcCCtx->flagStaticTables) {+        memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);+        memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));+        memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));+        memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));+    }++    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);+    MEM_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 */+            MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));+            break;+        default:   /*note : should not be necessary : flSize is within {1,2,3} */+        case 3: /* 2 - 2 - 20 */+            MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));+            break;+    }++    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 */+            MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));+            break;+        default:   /*note : should not be necessary : flSize is necessarily within {1,2,3} */+        case 3: /* 2 - 2 - 20 */+            MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));+            break;+    }++    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->flagStaticTables ? 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 */+    if (zc->flagStaticTables && (lhSize==3)) {+        hType = set_repeat;+        singleStream = 1;+        cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);+    } else {+        cLitSize = singleStream ? HUF_compress1X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters))+                                : HUF_compress4X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters));+    }++    if ((cLitSize==0) | (cLitSize >= srcSize - minGain))+        return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);+    if (cLitSize==1)+        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);+            MEM_writeLE24(ostart, lhc);+            break;+        }+    case 4: /* 2 - 2 - 14 - 14 */+        {   U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);+            MEM_writeLE32(ostart, lhc);+            break;+        }+    default:   /* should not be necessary, lhSize is only {3,4,5} */+    case 5: /* 2 - 2 - 18 - 18 */+        {   U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);+            MEM_writeLE32(ostart, lhc);+            ostart[4] = (BYTE)(cLitSize >> 10);+            break;+        }+    }+    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;+}+++size_t ZSTD_compressSequences(ZSTD_CCtx* zc,+                              void* dst, size_t dstCapacity,+                              size_t srcSize)+{+    const seqStore_t* seqStorePtr = &(zc->seqStore);+    U32 count[MaxSeq+1];+    S16 norm[MaxSeq+1];+    FSE_CTable* CTable_LitLength = zc->litlengthCTable;+    FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;+    FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;+    U32 LLtype, Offtype, MLtype;   /* compressed, raw or rle */+    const seqDef* const sequences = seqStorePtr->sequencesStart;+    const BYTE* const ofCodeTable = seqStorePtr->ofCode;+    const BYTE* const llCodeTable = seqStorePtr->llCode;+    const BYTE* const mlCodeTable = seqStorePtr->mlCode;+    BYTE* const ostart = (BYTE*)dst;+    BYTE* const oend = ostart + dstCapacity;+    BYTE* op = ostart;+    size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;+    BYTE* seqHead;+    BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];++    /* 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, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;+    if (nbSeq==0) goto _check_compressibility;++    /* seqHead : flags for FSE encoding type */+    seqHead = op++;++#define MIN_SEQ_FOR_DYNAMIC_FSE   64+#define MAX_SEQ_FOR_STATIC_FSE  1000++    /* convert length/distances into codes */+    ZSTD_seqToCodes(seqStorePtr);++    /* CTable for Literal Lengths */+    {   U32 max = MaxLL;+        size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);+        if ((mostFrequent == nbSeq) && (nbSeq > 2)) {+            *op++ = llCodeTable[0];+            FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);+            LLtype = set_rle;+        } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {+            LLtype = set_repeat;+        } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {+            FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));+            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 ERROR(GENERIC);+              op += NCountSize; }+            FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));+            LLtype = set_compressed;+    }   }++    /* CTable for Offsets */+    {   U32 max = MaxOff;+        size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);+        if ((mostFrequent == nbSeq) && (nbSeq > 2)) {+            *op++ = ofCodeTable[0];+            FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);+            Offtype = set_rle;+        } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {+            Offtype = set_repeat;+        } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {+            FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));+            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 ERROR(GENERIC);+              op += NCountSize; }+            FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));+            Offtype = set_compressed;+    }   }++    /* CTable for MatchLengths */+    {   U32 max = MaxML;+        size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);+        if ((mostFrequent == nbSeq) && (nbSeq > 2)) {+            *op++ = *mlCodeTable;+            FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);+            MLtype = set_rle;+        } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {+            MLtype = set_repeat;+        } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {+            FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));+            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 ERROR(GENERIC);+              op += NCountSize; }+            FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));+            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 (MEM_32bits()) BIT_flushBits(&blockStream);+        BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);+        if (MEM_32bits()) BIT_flushBits(&blockStream);+        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 (MEM_32bits()) BIT_flushBits(&blockStream);                  /* (7)*/+                FSE_encodeSymbol(&blockStream, &stateLitLength, llCode);        /* 16 */  /* 33 */+                if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))+                    BIT_flushBits(&blockStream);                                /* (7)*/+                BIT_addBits(&blockStream, sequences[n].litLength, llBits);+                if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);+                BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);+                if (MEM_32bits()) BIT_flushBits(&blockStream);                  /* (7)*/+                BIT_addBits(&blockStream, sequences[n].offset, ofBits);         /* 31 */+                BIT_flushBits(&blockStream);                                    /* (7)*/+        }   }++        FSE_flushCState(&blockStream, &stateMatchLength);+        FSE_flushCState(&blockStream, &stateOffsetBits);+        FSE_flushCState(&blockStream, &stateLitLength);++        {   size_t const streamSize = BIT_closeCStream(&blockStream);+            if (streamSize==0) return ERROR(dstSize_tooSmall);   /* not enough space */+            op += streamSize;+    }   }++    /* check compressibility */+_check_compressibility:+    { size_t const minGain = ZSTD_minGain(srcSize);+      size_t const maxCSize = srcSize - minGain;+      if ((size_t)(op-ostart) >= maxCSize) return 0; }++    /* confirm repcodes */+    { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->savedRep[i]; }++    return op - ostart;+}+++/*! ZSTD_storeSeq() :+    Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.+    `offsetCode` : distance to match, or 0 == repCode.+    `matchCode` : matchLength - MINMATCH+*/+MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)+{+#if 0  /* for debug */+    static const BYTE* g_start = NULL;+    const U32 pos = (U32)((const BYTE*)literals - g_start);+    if (g_start==NULL) g_start = (const BYTE*)literals;+    //if ((pos > 1) && (pos < 50000))+        printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",+               pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);+#endif+    /* copy Literals */+    ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);+    seqStorePtr->lit += litLength;++    /* literal Length */+    if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }+    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 (MEM_isLittleEndian()) {+        if (MEM_64bits()) {+#       if defined(_MSC_VER) && defined(_WIN64)+            unsigned long r = 0;+            _BitScanForward64( &r, (U64)val );+            return (unsigned)(r>>3);+#       elif defined(__GNUC__) && (__GNUC__ >= 3)+            return (__builtin_ctzll((U64)val) >> 3);+#       else+            static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };+            return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];+#       endif+        } else { /* 32 bits */+#       if defined(_MSC_VER)+            unsigned long r=0;+            _BitScanForward( &r, (U32)val );+            return (unsigned)(r>>3);+#       elif defined(__GNUC__) && (__GNUC__ >= 3)+            return (__builtin_ctz((U32)val) >> 3);+#       else+            static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };+            return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];+#       endif+        }+    } else {  /* Big Endian CPU */+        if (MEM_64bits()) {+#       if defined(_MSC_VER) && defined(_WIN64)+            unsigned long r = 0;+            _BitScanReverse64( &r, val );+            return (unsigned)(r>>3);+#       elif defined(__GNUC__) && (__GNUC__ >= 3)+            return (__builtin_clzll(val) >> 3);+#       else+            unsigned r;+            const unsigned n32 = sizeof(size_t)*4;   /* calculate this way due to compiler complaining in 32-bits mode */+            if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }+            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }+            r += (!val);+            return r;+#       endif+        } else { /* 32 bits */+#       if defined(_MSC_VER)+            unsigned long r = 0;+            _BitScanReverse( &r, (unsigned long)val );+            return (unsigned)(r>>3);+#       elif defined(__GNUC__) && (__GNUC__ >= 3)+            return (__builtin_clz((U32)val) >> 3);+#       else+            unsigned r;+            if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }+            r += (!val);+            return r;+#       endif+    }   }+}+++static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)+{+    const BYTE* const pStart = pIn;+    const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);++    while (pIn < pInLoopLimit) {+        size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);+        if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }+        pIn += ZSTD_NbCommonBytes(diff);+        return (size_t)(pIn - pStart);+    }+    if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }+    if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }+    if ((pIn<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) ; }+MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); }   /* only in zstd_opt.h */++static const U32 prime4bytes = 2654435761U;+static U32    ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }+static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }++static const U64 prime5bytes = 889523592379ULL;+static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u  << (64-40)) * prime5bytes) >> (64-h)) ; }+static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }++static const U64 prime6bytes = 227718039650203ULL;+static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u  << (64-48)) * prime6bytes) >> (64-h)) ; }+static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }++static const U64 prime7bytes = 58295818150454627ULL;+static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u  << (64-56)) * prime7bytes) >> (64-h)) ; }+static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }++static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;+static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }+static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }++static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)+{+    switch(mls)+    {+    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 current = (U32)(ip-base);+        U32 const matchIndex = hashTable[h];+        const BYTE* match = base + matchIndex;+        hashTable[h] = current;   /* update hash table */++        if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {+            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;+            ip++;+            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);+        } else {+            U32 offset;+            if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {+                ip += ((ip-anchor) >> g_searchStrength) + 1;+                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+current+2, hBits, mls)] = current+2;  /* here because current+2 could be > iend-8 */+            hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);+            /* check immediate repcode */+            while ( (ip <= ilimit)+                 && ( (offset_2>0)+                 & (MEM_read32(ip) == MEM_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->savedRep[0] = offset_1 ? offset_1 : offsetSaved;+    cctx->savedRep[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:+    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 current = (U32)(ip-base);+        const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */+        const BYTE* repBase = repIndex < dictLimit ? dictBase : base;+        const BYTE* repMatch = repBase + repIndex;+        size_t mLength;+        hashTable[h] = current;   /* update hash table */++        if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))+           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {+            const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;+            mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;+            ip++;+            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);+        } else {+            if ( (matchIndex < lowestIndex) ||+                 (MEM_read32(match) != MEM_read32(ip)) ) {+                ip += ((ip-anchor) >> g_searchStrength) + 1;+                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 = current - 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+current+2, hBits, mls)] = current+2;+            hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);+            /* check immediate repcode */+            while (ip <= ilimit) {+                U32 const current2 = (U32)(ip-base);+                U32 const repIndex2 = current2 - offset_2;+                const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;+                if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex))  /* intentional overflow */+                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {+                    const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;+                    size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;+                    U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */+                    ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);+                    hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;+                    ip += repLength2;+                    anchor = ip;+                    continue;+                }+                break;+    }   }   }++    /* save reps for next block */+    ctx->savedRep[0] = offset_1; ctx->savedRep[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:+    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 current = (U32)(ip-base);+        U32 const matchIndexL = hashLong[h2];+        U32 const matchIndexS = hashSmall[h];+        const BYTE* matchLong = base + matchIndexL;+        const BYTE* match = base + matchIndexS;+        hashLong[h2] = hashSmall[h] = current;   /* update hash tables */++        if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */+            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;+            ip++;+            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);+        } else {+            U32 offset;+            if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {+                mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;+                offset = (U32)(ip-matchLong);+                while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */+            } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {+                size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);+                U32 const matchIndex3 = hashLong[h3];+                const BYTE* match3 = base + matchIndex3;+                hashLong[h3] = current + 1;+                if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {+                    mLength = ZSTD_count(ip+9, match3+8, iend) + 8;+                    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+current+2, hBitsL, 8)] =+                hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;  /* here because current+2 could be > iend-8 */+            hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =+                hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);++            /* check immediate repcode */+            while ( (ip <= ilimit)+                 && ( (offset_2>0)+                 & (MEM_read32(ip) == MEM_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->savedRep[0] = offset_1 ? offset_1 : offsetSaved;+    cctx->savedRep[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:+    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 current = (U32)(ip-base);+        const U32 repIndex = current + 1 - offset_1;   /* offset_1 expected <= current +1 */+        const BYTE* repBase = repIndex < dictLimit ? dictBase : base;+        const BYTE* repMatch = repBase + repIndex;+        size_t mLength;+        hashSmall[hSmall] = hashLong[hLong] = current;   /* update hash table */++        if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))+           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {+            const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;+            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;+            ip++;+            ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);+        } else {+            if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {+                const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;+                const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;+                U32 offset;+                mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;+                offset = current - matchLongIndex;+                while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; }   /* catch up */+                offset_2 = offset_1;+                offset_1 = offset;+                ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);++            } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {+                size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);+                U32 const matchIndex3 = hashLong[h3];+                const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;+                const BYTE* match3 = match3Base + matchIndex3;+                U32 offset;+                hashLong[h3] = current + 1;+                if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {+                    const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;+                    const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;+                    mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;+                    ip++;+                    offset = current+1 - matchIndex3;+                    while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */+                } else {+                    const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;+                    const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;+                    mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;+                    offset = current - matchIndex;+                    while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */+                }+                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+current+2, hBitsS, mls)] = current+2;+			hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;+            hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);+            hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);+            /* check immediate repcode */+            while (ip <= ilimit) {+                U32 const current2 = (U32)(ip-base);+                U32 const repIndex2 = current2 - offset_2;+                const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;+                if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex))  /* intentional overflow */+                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {+                    const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;+                    size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;+                    U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */+                    ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);+                    hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;+                    hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;+                    ip += repLength2;+                    anchor = ip;+                    continue;+                }+                break;+    }   }   }++    /* save reps for next block */+    ctx->savedRep[0] = offset_1; ctx->savedRep[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:+    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 current = (U32)(ip-base);+    const U32 btLow = btMask >= current ? 0 : current - btMask;+    U32* smallerPtr = bt + 2*(current&btMask);+    U32* largerPtr  = smallerPtr + 1;+    U32 dummy32;   /* to be nullified at the end */+    U32 const windowLow = zc->lowLimit;+    U32 matchEndIdx = current+8;+    size_t bestLength = 8;+#ifdef ZSTD_C_PREDICT+    U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);+    U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);+    predictedSmall += (predictedSmall>0);+    predictedLarge += (predictedLarge>0);+#endif /* ZSTD_C_PREDICT */++    hashTable[h] = current;   /* Update Hash Table */++    while (nbCompares-- && (matchIndex > windowLow)) {+        U32* const nextPtr = bt + 2*(matchIndex & btMask);+        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */++#ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */+        const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */+        if (matchIndex == predictedSmall) {+            /* no need to check length, result known */+            *smallerPtr = matchIndex;+            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */+            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */+            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */+            predictedSmall = predictPtr[1] + (predictPtr[1]>0);+            continue;+        }+        if (matchIndex == predictedLarge) {+            *largerPtr = matchIndex;+            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */+            largerPtr = nextPtr;+            matchIndex = nextPtr[0];+            predictedLarge = predictPtr[0] + (predictPtr[0]>0);+            continue;+        }+#endif+        if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {+            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 current */+            *smallerPtr = matchIndex;             /* update smaller idx */+            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */+            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */+            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */+            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */+        } else {+            /* match is larger than current */+            *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 > current + 8) return matchEndIdx - current - 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 current = (U32)(ip-base);+    const U32 btLow = btMask >= current ? 0 : current - btMask;+    const U32 windowLow = zc->lowLimit;+    U32* smallerPtr = bt + 2*(current&btMask);+    U32* largerPtr  = bt + 2*(current&btMask) + 1;+    U32 matchEndIdx = current+8;+    U32 dummy32;   /* to be nullified at the end */+    size_t bestLength = 0;++    hashTable[h] = current;   /* 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(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )+                bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;+            if (ip+matchLength == iend)   /* equal : no way to know if inf or sup */+                break;   /* drop, to guarantee consistency (miss a little bit of compression) */+        }++        if (match[matchLength] < ip[matchLength]) {+            /* match is smaller than current */+            *smallerPtr = matchIndex;             /* update smaller idx */+            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */+            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */+            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */+            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */+        } else {+            /* match is larger than current */+            *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 > current + 8) ? matchEndIdx - 8 : current+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 :+    case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);+    case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);+    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 :+    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 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 (ie. 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)];+}++++FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */+size_t ZSTD_HcFindBestMatch_generic (+                        ZSTD_CCtx* zc,   /* Index table will be updated */+                        const BYTE* const ip, const BYTE* const iLimit,+                        size_t* offsetPtr,+                        const U32 maxNbAttempts, const U32 mls, const U32 extDict)+{+    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 current = (U32)(ip-base);+    const U32 minChain = current > chainSize ? current - 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 currentMl=0;+        if ((!extDict) || matchIndex >= dictLimit) {+            match = base + matchIndex;+            if (match[ml] == ip[ml])   /* potentially better */+                currentMl = ZSTD_count(ip, match, iLimit);+        } else {+            match = dictBase + matchIndex;+            if (MEM_read32(match) == MEM_read32(ip))   /* assumption : matchIndex <= dictLimit-4 (by table construction) */+                currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;+        }++        /* save best solution */+        if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }++        if (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 :+    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 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 :+    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 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) & (MEM_read32(ip+1) == MEM_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) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {+                size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;+                int const gain2 = (int)(mlRep * 3);+                int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);+                if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))+                    matchLength = mlRep, offset = 0, start = ip;+            }+            {   size_t offset2=99999999;+                size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);+                int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1));   /* raw approx */+                int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);+                if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {+                    matchLength = ml2, offset = offset2, start = ip;+                    continue;   /* search a better one */+            }   }++            /* let's find an even better one */+            if ((depth==2) && (ip<ilimit)) {+                ip ++;+                if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {+                    size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;+                    int const gain2 = (int)(ml2 * 4);+                    int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);+                    if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))+                        matchLength = ml2, offset = 0, start = ip;+                }+                {   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) {+            while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE]))   /* only search for offset within prefix */+                { start--; matchLength++; }+            offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);+        }++        /* 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)+             & (MEM_read32(ip) == MEM_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->savedRep[0] = offset_1 ? offset_1 : savedOffset;+    ctx->savedRep[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 current = (U32)(ip-base);++        /* check repCode */+        {   const U32 repIndex = (U32)(current+1 - offset_1);+            const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;+            const BYTE* const repMatch = repBase + repIndex;+            if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))   /* intentional overflow */+            if (MEM_read32(ip+1) == MEM_read32(repMatch)) {+                /* repcode detected we should take it */+                const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;+                matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;+                if (depth==0) goto _storeSequence;+        }   }++        /* first search (depth 0) */+        {   size_t offsetFound = 99999999;+            size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);+            if (ml2 > matchLength)+                matchLength = ml2, start = ip, offset=offsetFound;+        }++         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 ++;+            current++;+            /* check repCode */+            if (offset) {+                const U32 repIndex = (U32)(current - offset_1);+                const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;+                const BYTE* const repMatch = repBase + repIndex;+                if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */+                if (MEM_read32(ip) == MEM_read32(repMatch)) {+                    /* repcode detected */+                    const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;+                    size_t 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 ++;+                current++;+                /* check repCode */+                if (offset) {+                    const U32 repIndex = (U32)(current - offset_1);+                    const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;+                    const BYTE* const repMatch = repBase + repIndex;+                    if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex))  /* intentional overflow */+                    if (MEM_read32(ip) == MEM_read32(repMatch)) {+                        /* repcode detected */+                        const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;+                        size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;+                        int gain2 = (int)(repLength * 4);+                        int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);+                        if ((repLength >= EQUAL_READ32) && (gain2 > gain1))+                            matchLength = repLength, offset = 0, start = ip;+                }   }++                /* 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 (MEM_read32(ip) == MEM_read32(repMatch)) {+                /* repcode detected we should take it */+                const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;+                matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;+                offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset;   /* swap offset history */+                ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);+                ip += matchLength;+                anchor = ip;+                continue;   /* faster when present ... (?) */+            }+            break;+    }   }++    /* Save reps for next block */+    ctx->savedRep[0] = offset_1; ctx->savedRep[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 current = (U32)(istart-base);+    if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0;   /* don't even attempt compression below a certain srcSize */+    ZSTD_resetSeqStore(&(zc->seqStore));+    if (current > zc->nextToUpdate + 384)+        zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384));   /* update tree not updated after finding very long rep matches */+    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 > (2U<<30)) {+            U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;+            U32 const current = (U32)(ip - cctx->base);+            U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);+            U32 const correction = current - newCurrent;+            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);+            MEM_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);+            MEM_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-1));+    BYTE  const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);+    U32   const fcsCode = params.fParams.contentSizeFlag ?+                     (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) :   /* 0-3 */+                      0;+    BYTE  const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );+    size_t pos;++    if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);++    MEM_writeLE32(dst, ZSTD_MAGICNUMBER);+    op[4] = frameHeaderDecriptionByte; pos=5;+    if (!singleSegment) op[pos++] = windowLogByte;+    switch(dictIDSizeCode)+    {+        default:   /* impossible */+        case 0 : break;+        case 1 : op[pos] = (BYTE)(dictID); pos++; break;+        case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;+        case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;+    }+    switch(fcsCode)+    {+        default:   /* impossible */+        case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;+        case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;+        case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;+        case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;+    }+    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;++    {   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;+    }+}+++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);+}+++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 current 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 = (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:+        ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);+        break;++    case ZSTD_btlazy2:+    case ZSTD_btopt:+    case ZSTD_btopt2:+        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 = zc->loadedDictEnd;+    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 :+    Magic == ZSTD_DICT_MAGIC (4 bytes)+    HUF_writeCTable(256)+    FSE_writeNCount(off)+    FSE_writeNCount(ml)+    FSE_writeNCount(ll)+    RepOffsets+    Dictionary content+*/+/*! ZSTD_loadDictEntropyStats() :+    @return : size read from dictionary+    note : magic number supposed already checked */+static size_t ZSTD_loadDictEntropyStats(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;+    BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];++    {   size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);+        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, scratchBuffer, sizeof(scratchBuffer)), 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, scratchBuffer, sizeof(scratchBuffer)), 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, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);+        dictPtr += litlengthHeaderSize;+    }++    if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);+    cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] == 0 || cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);+    cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] == 0 || cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);+    cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] == 0 || cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);+    dictPtr += 12;++    {   U32 offcodeMax = MaxOff;+        if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) {+            U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */+            /* Calculate minimum offset code required to represent maxOffset */+            offcodeMax = ZSTD_highbit32(maxOffset);+        }+        /* Every possible supported offset <= dictContentSize + 128 KB must be representable */+        CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));+    }++    cctx->flagStaticTables = 1;+    return dictPtr - (const BYTE*)dict;+}++/** ZSTD_compress_insertDictionary() :+*   @return : 0, or an error code */+static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)+{+    if ((dict==NULL) || (dictSize<=8)) return 0;++    /* default : dict is pure content */+    if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);+    zc->dictID = zc->params.fParams.noDictIDFlag ? 0 :  MEM_readLE32((const char*)dict+4);++    /* known magic number : dict is parsed for entropy stats and content */+    {   size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);+        size_t const eSize = loadError + 8;+        if (ZSTD_isError(loadError)) return loadError;+        return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);+    }+}+++/*! 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* zc, int compressionLevel)+{+    return ZSTD_compressBegin_usingDict(zc, 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);+        MEM_writeLE32(op, cBlockHeader24);+        op += ZSTD_blockHeaderSize;+        dstCapacity -= ZSTD_blockHeaderSize;+    }++    if (cctx->params.fParams.checksumFlag) {+        U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);+        if (dstCapacity<4) return ERROR(dstSize_tooSmall);+        MEM_writeLE32(op, checksum);+        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_advanced (ZSTD_CCtx* ctx,+                               void* dst, size_t dstCapacity,+                         const void* src, size_t srcSize,+                         const void* dict,size_t dictSize,+                               ZSTD_parameters params)+{+    CHECK_F(ZSTD_checkCParams(params.cParams));+    return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);+}++size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel)+{+    ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);+    params.fParams.contentSizeFlag = 1;+    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, int compressionLevel)+{+    return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);+}++size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)+{+    size_t result;+    ZSTD_CCtx ctxBody;+    memset(&ctxBody, 0, sizeof(ctxBody));+    memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));+    result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);+    ZSTD_free(ctxBody.workSpace, defaultCustomMem);  /* can't free ctxBody itself, as it's on stack; free only heap content */+    return result;+}+++/* =====  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_sizeof_CDict(const ZSTD_CDict* cdict)+{+    if (cdict==NULL) return 0;   /* support sizeof on NULL */+    return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);+}++ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,+                                      ZSTD_parameters params, ZSTD_customMem customMem)+{+    if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;+    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_free(cctx, customMem);+            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(cctx, customMem);+                ZSTD_free(cdict, customMem);+                return NULL;+        }   }++        cdict->refContext = cctx;+        cdict->dictContentSize = dictSize;+        return cdict;+    }+}++ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)+{+    ZSTD_customMem const allocator = { NULL, NULL, NULL };+    ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);+    params.fParams.contentSizeFlag = 1;+    return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);+}++ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)+{+    ZSTD_customMem const allocator = { NULL, NULL, NULL };+    ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);+    params.fParams.contentSizeFlag = 1;+    return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);+}++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, U64 pledgedSrcSize)+{+    if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))+    else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->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;+    }++    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" */++ZSTD_CStream* ZSTD_createCStream(void)+{+    return ZSTD_createCStream_advanced(defaultCustomMem);+}++ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)+{+    ZSTD_CStream* zcs;++    if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;+    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);+        ZSTD_freeCDict(zcs->cdictLocal);+        ZSTD_free(zcs->inBuff, cMem);+        ZSTD_free(zcs->outBuff, cMem);+        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 */ ; }++size_t ZSTD_resetCStream(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_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) {+        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(zcs, pledgedSrcSize);+}++/* note : cdict must outlive compression session */+size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)+{+    ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);+    size_t const initError =  ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);+    zcs->cdict = cdict;+    return initError;+}++size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)+{+    ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);+    return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);+}++size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)+{+    ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);+    if (pledgedSrcSize) params.fParams.contentSizeFlag = 1;+    return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);+}++size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)+{+    return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);+}++size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)+{+    if (zcs==NULL) return 0;   /* support sizeof on NULL */+    return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;+}++/*======   Compression   ======*/++typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;++MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)+{+    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 current 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 (MEM_32bits()) {   /* auto-correction, for 32-bits mode */+        if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;+        if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;+        if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;+    }+    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;+}
+ zstd/lib/compress/zstd_opt.h view
@@ -0,0 +1,919 @@+/**+ * 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 this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */+++/* 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));+}+++MEM_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;+}+++MEM_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 (ie. 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 current = (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 >= current ? 0 : current - btMask;+    const U32 windowLow = zc->lowLimit;+    U32* smallerPtr = bt + 2*(current&btMask);+    U32* largerPtr  = bt + 2*(current&btMask) + 1;+    U32 matchEndIdx = current+8;+    U32 dummy32;   /* to be nullified at the end */+    U32 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 && (current - matchIndex3 < (1<<18))) {+            const BYTE* match;+            size_t currentMl=0;+            if ((!extDict) || matchIndex3 >= dictLimit) {+                match = base + matchIndex3;+                if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);+            } else {+                match = dictBase + matchIndex3;+                if (MEM_readMINMATCH(match, MINMATCH) == MEM_readMINMATCH(ip, MINMATCH))    /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */+                    currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;+            }++            /* save best solution */+            if (currentMl > bestLength) {+                bestLength = currentMl;+                matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;+                matches[mnum].len = (U32)currentMl;+                mnum++;+                if (currentMl > ZSTD_OPT_NUM) goto update;+                if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/+            }+        }+    }++    hashTable[h] = current;   /* 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 + current - 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 current */+            *smallerPtr = matchIndex;             /* update smaller idx */+            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */+            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */+            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */+            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */+        } else {+            /* match is larger than current */+            *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 > current + 8) ? matchEndIdx - 8 : current+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 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 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))+                    && (MEM_readMINMATCH(ip, minMatch) == MEM_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))+                       && (MEM_readMINMATCH(inr, minMatch) == MEM_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->savedRep[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 current = (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)(current - repCur);+                const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;+                const BYTE* const repMatch = repBase + repIndex;+                if ( (repCur > 0 && repCur <= (S32)current)+                   && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */+                   && (MEM_readMINMATCH(ip, minMatch) == MEM_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)(current+cur - repCur);+                    const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;+                    const BYTE* const repMatch = repBase + repIndex;+                    if ( (repCur > 0 && repCur <= (S32)(current+cur))+                      && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */+                      && (MEM_readMINMATCH(inr, minMatch) == MEM_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) {+                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 = (cur + matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM - cur;++                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->savedRep[i] = rep[i]; }++    /* Last Literals */+    {   size_t lastLLSize = iend - anchor;+        memcpy(seqStorePtr->lit, anchor, lastLLSize);+        seqStorePtr->lit += lastLLSize;+    }+}++#endif  /* ZSTD_OPT_H_91842398743 */
+ zstd/lib/decompress/huf_decompress.c view
@@ -0,0 +1,885 @@+/* ******************************************************************+   Huffman decoder, part of New Generation Entropy library+   Copyright (C) 2013-2016, Yann Collet.++   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)++   Redistribution and use in source and binary forms, with or without+   modification, are permitted provided that the following conditions are+   met:++       * Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+       * Redistributions in binary form must reproduce the above+   copyright notice, this list of conditions and the following disclaimer+   in the documentation and/or other materials provided with the+   distribution.++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.++    You can contact the author at :+    - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy+    - Public forum : https://groups.google.com/forum/#!forum/lz4c+****************************************************************** */++/* **************************************************************+*  Compiler specifics+****************************************************************/+#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)+/* inline is defined */+#elif defined(_MSC_VER) || defined(__GNUC__)+#  define inline __inline+#else+#  define inline /* disable inline */+#endif++#ifdef _MSC_VER    /* Visual Studio */+#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */+#endif+++/* **************************************************************+*  Dependencies+****************************************************************/+#include <string.h>     /* memcpy, memset */+#include "bitstream.h"  /* BIT_* */+#include "fse.h"        /* header compression */+#define HUF_STATIC_LINKING_ONLY+#include "huf.h"+++/* **************************************************************+*  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 (HUF_DTable* DTable, const void* src, size_t srcSize)+{+    BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1];+    U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1];   /* large enough for values from 0 to 16 */+    U32 tableLog = 0;+    U32 nbSymbols = 0;+    size_t iSize;+    void* const dtPtr = DTable + 1;+    HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr;++    HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));+    /* memset(huffWeight, 0, sizeof(huffWeight)); */   /* is not necessary, even though some analyzer complain ... */++    iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize);+    if (HUF_isError(iSize)) return iSize;++    /* 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));+    }++    /* Prepare ranks */+    {   U32 n, nextRankStart = 0;+        for (n=1; n<tableLog+1; n++) {+            U32 current = nextRankStart;+            nextRankStart += (rankVal[n] << (n-1));+            rankVal[n] = current;+    }   }++    /* fill DTable */+    {   U32 n;+        for (n=0; n<nbSymbols; n++) {+            U32 const w = huffWeight[n];+            U32 const length = (1 << w) >> 1;+            U32 i;+            HUF_DEltX2 D;+            D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w);+            for (i = rankVal[w]; i < rankVal[w] + length; i++)+                dt[i] = 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 (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \+        HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)++#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \+    if (MEM_64bits()) \+        HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)++static 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 (HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    const BYTE* ip = (const BYTE*) cSrc;++    size_t const hSize = HUF_readDTableX2 (DCtx, cSrc, cSrcSize);+    if (HUF_isError(hSize)) return hSize;+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);+    ip += hSize; cSrcSize -= hSize;++    return HUF_decompress1X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);+}++size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);+    return HUF_decompress1X2_DCtx (DTable, dst, dstSize, cSrc, cSrcSize);+}+++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 = MEM_readLE16(istart);+        size_t const length2 = MEM_readLE16(istart+2);+        size_t const length3 = MEM_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 (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    const BYTE* ip = (const BYTE*) cSrc;++    size_t const hSize = HUF_readDTableX2 (dctx, cSrc, cSrcSize);+    if (HUF_isError(hSize)) return hSize;+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);+    ip += hSize; cSrcSize -= hSize;++    return HUF_decompress4X2_usingDTable_internal (dst, dstSize, ip, cSrcSize, dctx);+}++size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX);+    return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);+}+++/* *************************/+/* 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];+        MEM_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;++            MEM_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];++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;+            MEM_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 (HUF_DTable* DTable, const void* src, size_t srcSize)+{+    BYTE weightList[HUF_SYMBOLVALUE_MAX + 1];+    sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1];+    U32 rankStats[HUF_TABLELOG_MAX + 1] = { 0 };+    U32 rankStart0[HUF_TABLELOG_MAX + 2] = { 0 };+    U32* const rankStart = rankStart0+1;+    rankVal_t rankVal;+    U32 tableLog, maxW, sizeOfSort, nbSymbols;+    DTableDesc dtd = HUF_getDTableDesc(DTable);+    U32 const maxTableLog = dtd.maxTableLog;+    size_t iSize;+    void* dtPtr = DTable+1;   /* force compiler to avoid strict-aliasing */+    HUF_DEltX4* const dt = (HUF_DEltX4*)dtPtr;++    HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable));   /* if compilation fails here, assertion is false */+    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(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize);+    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 current = nextRankStart;+            nextRankStart += rankStats[w];+            rankStart[w] = current;+        }+        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 current = nextRankVal;+                nextRankVal += rankStats[w] << (w+rescale);+                rankVal0[w] = current;+        }   }+        {   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))+                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 */+    }   }+    return 1;+}+++#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \+    ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)++#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \+    if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \+        ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)++#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \+    if (MEM_64bits()) \+        ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)++static 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 (HUF_DTable* DCtx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    const BYTE* ip = (const BYTE*) cSrc;++    size_t const hSize = HUF_readDTableX4 (DCtx, cSrc, cSrcSize);+    if (HUF_isError(hSize)) return hSize;+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);+    ip += hSize; cSrcSize -= hSize;++    return HUF_decompress1X4_usingDTable_internal (dst, dstSize, ip, cSrcSize, DCtx);+}++size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    HUF_CREATE_STATIC_DTABLEX4(DTable, HUF_TABLELOG_MAX);+    return HUF_decompress1X4_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);+}++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 = MEM_readLE16(istart);+        size_t const length2 = MEM_readLE16(istart+2);+        size_t const length3 = MEM_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 (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    const BYTE* ip = (const BYTE*) cSrc;++    size_t hSize = HUF_readDTableX4 (dctx, cSrc, cSrcSize);+    if (HUF_isError(hSize)) return hSize;+    if (hSize >= cSrcSize) return ERROR(srcSize_wrong);+    ip += hSize; cSrcSize -= hSize;++    return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx);+}++size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    HUF_CREATE_STATIC_DTABLEX4(DTable, HUF_TABLELOG_MAX);+    return HUF_decompress4X4_DCtx(DTable, dst, dstSize, cSrc, cSrcSize);+}+++/* ********************************/+/* 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_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    static const decompressionAlgo decompress[2] = { HUF_decompress4X2, HUF_decompress4X4 };++    /* 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 decompress[algoNb](dst, dstSize, cSrc, cSrcSize);+    }+}++size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    /* 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(dctx, dst, dstSize, cSrc, cSrcSize) :+                        HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;+    }+}++size_t HUF_decompress4X_hufOnly (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    /* 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(dctx, dst, dstSize, cSrc, cSrcSize) :+                        HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;+    }+}++size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize)+{+    /* 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(dctx, dst, dstSize, cSrc, cSrcSize) :+                        HUF_decompress1X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ;+    }+}
+ zstd/lib/decompress/zstd_decompress.c view
@@ -0,0 +1,2171 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */+++/* ***************************************************************+*  Tuning parameters+*****************************************************************/+/*!+ * HEAPMODE :+ * Select how default decompression function ZSTD_decompress() will allocate memory,+ * in memory stack (0), or in memory heap (1, requires malloc())+ */+#ifndef ZSTD_HEAPMODE+#  define ZSTD_HEAPMODE 1+#endif++/*!+*  LEGACY_SUPPORT :+*  if set to 1, ZSTD_decompress() can decode older formats (v0.1+)+*/+#ifndef ZSTD_LEGACY_SUPPORT+#  define ZSTD_LEGACY_SUPPORT 0+#endif++/*!+*  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 <string.h>      /* memcpy, memmove, memset */+#include "mem.h"         /* low level memory routines */+#define XXH_STATIC_LINKING_ONLY   /* XXH64_state_t */+#include "xxhash.h"      /* XXH64_* */+#define FSE_STATIC_LINKING_ONLY+#include "fse.h"+#define HUF_STATIC_LINKING_ONLY+#include "huf.h"+#include "zstd_internal.h"++#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)+#  include "zstd_legacy.h"+#endif+++#if defined(_MSC_VER)+#  include <mmintrin.h>   /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */+#  define ZSTD_PREFETCH(ptr)   _mm_prefetch((const char*)ptr, _MM_HINT_T0)+#elif defined(__GNUC__)+#  define ZSTD_PREFETCH(ptr)   __builtin_prefetch(ptr, 0, 0)+#else+#  define ZSTD_PREFETCH(ptr)   /* disabled */+#endif++/*-*************************************+*  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;++struct ZSTD_DCtx_s+{+    const FSE_DTable* LLTptr;+    const FSE_DTable* MLTptr;+    const FSE_DTable* OFTptr;+    const HUF_DTable* HUFptr;+    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 */+    const void* previousDstEnd;+    const void* base;+    const void* vBase;+    const void* dictEnd;+    size_t expected;+    U32 rep[ZSTD_REP_NUM];+    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;+    XXH64_state_t 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_sizeof_DCtx (const ZSTD_DCtx* dctx) { return (dctx==NULL) ? 0 : sizeof(ZSTD_DCtx); }++size_t ZSTD_estimateDCtxSize(void) { return 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->hufTable[0] = (HUF_DTable)((HufLog)*0x1000001);  /* cover both little and big endian */+    dctx->litEntropy = dctx->fseEntropy = 0;+    dctx->dictID = 0;+    MEM_STATIC_ASSERT(sizeof(dctx->rep) == sizeof(repStartValue));+    memcpy(dctx->rep, repStartValue, sizeof(repStartValue));  /* initial repcodes */+    dctx->LLTptr = dctx->LLTable;+    dctx->MLTptr = dctx->MLTable;+    dctx->OFTptr = dctx->OFTable;+    dctx->HUFptr = dctx->hufTable;+    return 0;+}++ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)+{+    ZSTD_DCtx* dctx;++    if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;+    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_createDCtx(void)+{+    return ZSTD_createDCtx_advanced(defaultCustomMem);+}++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_refDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)+{+    ZSTD_decompressBegin(dstDCtx);  /* init */+    if (srcDCtx) {   /* support refDCtx on NULL */+        dstDCtx->dictEnd = srcDCtx->dictEnd;+        dstDCtx->vBase = srcDCtx->vBase;+        dstDCtx->base = srcDCtx->base;+        dstDCtx->previousDstEnd = srcDCtx->previousDstEnd;+        dstDCtx->dictID = srcDCtx->dictID;+        dstDCtx->litEntropy = srcDCtx->litEntropy;+        dstDCtx->fseEntropy = srcDCtx->fseEntropy;+        dstDCtx->LLTptr = srcDCtx->LLTable;+        dstDCtx->MLTptr = srcDCtx->MLTable;+        dstDCtx->OFTptr = srcDCtx->OFTable;+        dstDCtx->HUFptr = srcDCtx->hufTable;+        dstDCtx->rep[0] = srcDCtx->rep[0];+        dstDCtx->rep[1] = srcDCtx->rep[1];+        dstDCtx->rep[2] = srcDCtx->rep[2];+    }+}+++/*-*************************************************************+*   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 = MEM_readLE32(buffer);+        if (magic == ZSTD_MAGICNUMBER) return 1;+        if ((magic & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) return 1;+    }+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)+    if (ZSTD_isLegacy(buffer, size)) return 1;+#endif+    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 (MEM_readLE32(src) != ZSTD_MAGICNUMBER) {+        if ((MEM_readLE32(src) & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {+            if (srcSize < ZSTD_skippableHeaderSize) return ZSTD_skippableHeaderSize; /* magic number + skippable frame length */+            memset(fparamsPtr, 0, sizeof(*fparamsPtr));+            fparamsPtr->frameContentSize = MEM_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 = MEM_readLE16(ip+pos); pos+=2; break;+            case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;+        }+        switch(fcsID)+        {+            default:   /* impossible */+            case 0 : if (singleSegment) frameContentSize = ip[pos]; break;+            case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;+            case 2 : frameContentSize = MEM_readLE32(ip+pos); break;+            case 3 : frameContentSize = MEM_readLE64(ip+pos); break;+        }+        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_getDecompressedSize() :+*   compatible with legacy mode+*   @return : decompressed size if known, 0 otherwise+              note : 0 can mean any of the following :+                   - decompressed size is not present within frame header+                   - frame header unknown / not supported+                   - frame header not complete (`srcSize` too small) */+unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)+{+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1)+    if (ZSTD_isLegacy(src, srcSize)) return ZSTD_getDecompressedSize_legacy(src, srcSize);+#endif+    {   ZSTD_frameParams fparams;+        size_t const frResult = ZSTD_getFrameParams(&fparams, src, srcSize);+        if (frResult!=0) return 0;+        return fparams.frameContentSize;+    }+}+++/** 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 = MEM_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 = MEM_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(dctx->hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize) :+                                        HUF_decompress4X_hufOnly (dctx->hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize)) ))+                    return ERROR(corruption_detected);++                dctx->litPtr = dctx->litBuffer;+                dctx->litSize = litSize;+                dctx->litEntropy = 1;+                if (litEncType==set_compressed) dctx->HUFptr = dctx->hufTable;+                memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);+                return litCSize + lhSize;+            }++        case set_basic:+            {   size_t litSize, lhSize;+                U32 const lhlCode = ((istart[0]) >> 2) & 3;+                switch(lhlCode)+                {+                case 0: case 2: default:   /* note : default is impossible, since lhlCode into [0..3] */+                    lhSize = 1;+                    litSize = istart[0] >> 3;+                    break;+                case 1:+                    lhSize = 2;+                    litSize = MEM_readLE16(istart) >> 4;+                    break;+                case 3:+                    lhSize = 3;+                    litSize = MEM_readLE24(istart) >> 4;+                    break;+                }++                if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) {  /* risk reading beyond src buffer with wildcopy */+                    if (litSize+lhSize > srcSize) return ERROR(corruption_detected);+                    memcpy(dctx->litBuffer, istart+lhSize, litSize);+                    dctx->litPtr = dctx->litBuffer;+                    dctx->litSize = litSize;+                    memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH);+                    return lhSize+litSize;+                }+                /* direct reference into compressed stream */+                dctx->litPtr = istart+lhSize;+                dctx->litSize = litSize;+                return lhSize+litSize;+            }++        case set_rle:+            {   U32 const lhlCode = ((istart[0]) >> 2) & 3;+                size_t litSize, lhSize;+                switch(lhlCode)+                {+                case 0: case 2: default:   /* note : default is impossible, since lhlCode into [0..3] */+                    lhSize = 1;+                    litSize = istart[0] >> 3;+                    break;+                case 1:+                    lhSize = 2;+                    litSize = MEM_readLE16(istart) >> 4;+                    break;+                case 3:+                    lhSize = 3;+                    litSize = MEM_readLE24(istart) >> 4;+                    if (srcSize<4) return ERROR(corruption_detected);   /* srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */+                    break;+                }+                if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX) return ERROR(corruption_detected);+                memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH);+                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)+{+    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[MaxSeq+1];+            size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize);+            if (FSE_isError(headerSize)) return ERROR(corruption_detected);+            if (tableLog > maxLog) return ERROR(corruption_detected);+            FSE_buildDTable(DTableSpace, norm, max, tableLog);+            *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 = MEM_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->LLTable, &dctx->LLTptr,+                                                      LLtype, MaxLL, LLFSELog,+                                                      ip, iend-ip, LL_defaultDTable, dctx->fseEntropy);+            if (ZSTD_isError(llhSize)) return ERROR(corruption_detected);+            ip += llhSize;+        }+        {   size_t const ofhSize = ZSTD_buildSeqTable(dctx->OFTable, &dctx->OFTptr,+                                                      OFtype, MaxOff, OffFSELog,+                                                      ip, iend-ip, OF_defaultDTable, dctx->fseEntropy);+            if (ZSTD_isError(ofhSize)) return ERROR(corruption_detected);+            ip += ofhSize;+        }+        {   size_t const mlhSize = ZSTD_buildSeqTable(dctx->MLTable, &dctx->MLTptr,+                                                      MLtype, MaxML, MLFSELog,+                                                      ip, iend-ip, ML_defaultDTable, dctx->fseEntropy);+            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;+    iPtrDiff 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 & currentPrefixSegment */+        {   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 (MEM_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 (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream);++    seq.litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0);    /* <=  16 bits */+    if (MEM_32bits() ||+       (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BIT_reloadDStream(&seqState->DStream);++    /* ANS state update */+    FSE_updateState(&seqState->stateLL, &seqState->DStream);    /* <=  9 bits */+    FSE_updateState(&seqState->stateML, &seqState->DStream);    /* <=  9 bits */+    if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);    /* <= 18 bits */+    FSE_updateState(&seqState->stateOffb, &seqState->DStream);  /* <=  8 bits */++    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-base);+        if (match + sequence.matchLength <= dictEnd) {+            memmove(oLitEnd, match, sequence.matchLength);+            return sequenceLength;+        }+        /* span extDict & currentPrefixSegment */+        {   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 };   /* substracted */+        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->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->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 seq_t ZSTD_decodeSequenceLong(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 (MEM_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 (MEM_32bits() && (mlBits+llBits>24)) BIT_reloadDStream(&seqState->DStream);++    seq.litLength = LL_base[llCode] + ((llCode>15) ? BIT_readBitsFast(&seqState->DStream, llBits) : 0);    /* <=  16 bits */+    if (MEM_32bits() ||+       (totalBits > 64 - 7 - (LLFSELog+MLFSELog+OffFSELog)) ) BIT_reloadDStream(&seqState->DStream);++    {   size_t const pos = seqState->pos + seq.litLength;+        seq.match = seqState->base + pos - seq.offset;    /* single memory segment */+        if (seq.offset > pos) seq.match += seqState->gotoDict;   /* separate memory segment */+        seqState->pos = pos + seq.matchLength;+    }++    /* ANS state update */+    FSE_updateState(&seqState->stateLL, &seqState->DStream);    /* <=  9 bits */+    FSE_updateState(&seqState->stateML, &seqState->DStream);    /* <=  9 bits */+    if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream);    /* <= 18 bits */+    FSE_updateState(&seqState->stateOffb, &seqState->DStream);  /* <=  8 bits */++    return seq;+}++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 1+    if (oMatchEnd>oend) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of WILDCOPY_OVERLENGTH from oend */+    if (iLitEnd > litLimit) return ERROR(corruption_detected);   /* over-read beyond lit buffer */+    if (oLitEnd>oend_w) return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, litLimit, base, vBase, dictEnd);+#endif++    /* 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 1+    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 & currentPrefixSegment */+        {   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 */+#endif++    /* match within prefix */+    if (sequence.offset < 8) {+        /* close range match, overlap */+        static const U32 dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 };   /* added */+        static const int dec64table[] = { 8, 8, 8, 7, 8, 9,10,11 };   /* substracted */+        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);+    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[STORED_SEQS];+        int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);+        seqState_t seqState;+        int seqNb;+        dctx->fseEntropy = 1;+        { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->rep[i]; }+        seqState.base = base;+        seqState.pos = (size_t)(op-base);+        seqState.gotoDict = (iPtrDiff)(dictEnd - base);+        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);+        }+        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);+            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->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 sub-block */+    {   size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize);+        if (ZSTD_isError(litCSize)) return litCSize;+        ip += litCSize;+        srcSize -= litCSize;+    }+    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. */+ZSTDLIB_API 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_decompressFrame() :+*   `dctx` must be properly initialized */+static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,+                                 void* dst, size_t dstCapacity,+                                 const void* src, size_t srcSize)+{+    const BYTE* ip = (const BYTE*)src;+    BYTE* const ostart = (BYTE* const)dst;+    BYTE* const oend = ostart + dstCapacity;+    BYTE* op = ostart;+    size_t remainingSize = srcSize;++    /* check */+    if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);++    /* Frame Header */+    {   size_t const frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_prefix);+        if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;+        if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong);+        CHECK_F(ZSTD_decodeFrameHeader(dctx, src, 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 = MEM_readLE32(ip);+        if (checkRead != checkCalc) return ERROR(checksum_wrong);+        remainingSize -= 4;+    }++    if (remainingSize) return ERROR(srcSize_wrong);+    return op-ostart;+}+++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)+{+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1)+    if (ZSTD_isLegacy(src, srcSize)) return ZSTD_decompressLegacy(dst, dstCapacity, src, srcSize, dict, dictSize);+#endif+    ZSTD_decompressBegin_usingDict(dctx, dict, dictSize);+    ZSTD_checkContinuity(dctx, dst);+    return ZSTD_decompressFrame(dctx, dst, dstCapacity, src, srcSize);+}+++size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)+{+    return ZSTD_decompress_usingDict(dctx, dst, dstCapacity, src, srcSize, NULL, 0);+}+++size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)+{+#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE==1)+    size_t regenSize;+    ZSTD_DCtx* const dctx = ZSTD_createDCtx();+    if (dctx==NULL) return ERROR(memory_allocation);+    regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);+    ZSTD_freeDCtx(dctx);+    return regenSize;+#else   /* stack mode */+    ZSTD_DCtx dctx;+    return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);+#endif+}+++/*-**************************************+*   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 ((MEM_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 = MEM_readLE32(src);   /* srcSize == 4, guaranteed by dctx->expected */+            if (check32 != h32) return ERROR(checksum_wrong);+            dctx->expected = 0;+            dctx->stage = ZSTDds_getFrameHeaderSize;+            return 0;+        }+    case ZSTDds_decodeSkippableHeader:+        {   memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, dctx->expected);+            dctx->expected = MEM_readLE32(dctx->headerBuffer + 4);+            dctx->stage = ZSTDds_skipFrame;+            return 0;+        }+    case ZSTDds_skipFrame:+        {   dctx->expected = 0;+            dctx->stage = ZSTDds_getFrameHeaderSize;+            return 0;+        }+    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;+}++static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* const dict, size_t const dictSize)+{+    const BYTE* dictPtr = (const BYTE*)dict;+    const BYTE* const dictEnd = dictPtr + dictSize;++    {   size_t const hSize = HUF_readDTableX4(dctx->hufTable, dict, dictSize);+        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(dctx->OFTable, offcodeNCount, offcodeMaxValue, offcodeLog), 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(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog), 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(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog), dictionary_corrupted);+        dictPtr += litlengthHeaderSize;+    }++    if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);+    dctx->rep[0] = MEM_readLE32(dictPtr+0); if (dctx->rep[0] == 0 || dctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);+    dctx->rep[1] = MEM_readLE32(dictPtr+4); if (dctx->rep[1] == 0 || dctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);+    dctx->rep[2] = MEM_readLE32(dictPtr+8); if (dctx->rep[2] == 0 || dctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);+    dictPtr += 12;++    dctx->litEntropy = dctx->fseEntropy = 1;+    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 = MEM_readLE32(dict);+        if (magic != ZSTD_DICT_MAGIC) {+            return ZSTD_refDictContent(dctx, dict, dictSize);   /* pure content mode */+    }   }+    dctx->dictID = MEM_readLE32((const char*)dict + 4);++    /* load entropy tables */+    dict = (const char*)dict + 8;+    dictSize -= 8;+    {   size_t const eSize = ZSTD_loadEntropy(dctx, dict, dictSize);+        if (ZSTD_isError(eSize)) return ERROR(dictionary_corrupted);+        dict = (const char*)dict + eSize;+        dictSize -= eSize;+    }++    /* 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_DCtx* refContext;+};  /* typedef'd to ZSTD_DDict within "zstd.h" */++ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, unsigned byReference, ZSTD_customMem customMem)+{+    if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;+    if (!customMem.customAlloc || !customMem.customFree) return NULL;++    {   ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem);+        ZSTD_DCtx* const dctx = ZSTD_createDCtx_advanced(customMem);++        if (!ddict || !dctx) {+            ZSTD_free(ddict, customMem);+            ZSTD_free(dctx, customMem);+            return NULL;+        }++        if ((byReference) || (!dict) || (!dictSize)) {+            ddict->dictBuffer = NULL;+            ddict->dictContent = dict;+        } else {+            void* const internalBuffer = ZSTD_malloc(dictSize, customMem);+            if (!internalBuffer) { ZSTD_free(dctx, customMem); ZSTD_free(ddict, customMem); return NULL; }+            memcpy(internalBuffer, dict, dictSize);+            ddict->dictBuffer = internalBuffer;+            ddict->dictContent = internalBuffer;+        }+        {   size_t const errorCode = ZSTD_decompressBegin_usingDict(dctx, ddict->dictContent, dictSize);+            if (ZSTD_isError(errorCode)) {+                ZSTD_free(ddict->dictBuffer, customMem);+                ZSTD_free(ddict, customMem);+                ZSTD_free(dctx, customMem);+                return NULL;+        }   }++        ddict->dictSize = dictSize;+        ddict->refContext = dctx;+        return ddict;+    }+}++/*! ZSTD_createDDict() :+*   Create a digested dictionary, ready to start decompression without startup delay.+*   `dict` can be released after `ZSTD_DDict` creation */+ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize)+{+    ZSTD_customMem const allocator = { NULL, NULL, NULL };+    return ZSTD_createDDict_advanced(dict, dictSize, 0, allocator);+}+++/*! ZSTD_createDDict_byReference() :+ *  Create a digested dictionary, ready to start decompression operation without startup delay.+ *  Dictionary content is simply referenced, and therefore stays in dictBuffer.+ *  It is important that dictBuffer outlives DDict, it must remain read accessible throughout the lifetime of DDict */+ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize)+{+    ZSTD_customMem const allocator = { NULL, NULL, NULL };+    return ZSTD_createDDict_advanced(dictBuffer, dictSize, 1, allocator);+}+++size_t ZSTD_freeDDict(ZSTD_DDict* ddict)+{+    if (ddict==NULL) return 0;   /* support free on NULL */+    {   ZSTD_customMem const cMem = ddict->refContext->customMem;+        ZSTD_freeDCtx(ddict->refContext);+        ZSTD_free(ddict->dictBuffer, cMem);+        ZSTD_free(ddict, cMem);+        return 0;+    }+}++size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict)+{+    if (ddict==NULL) return 0;   /* support sizeof on NULL */+    return sizeof(*ddict) + ZSTD_sizeof_DCtx(ddict->refContext) + (ddict->dictBuffer ? ddict->dictSize : 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 (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return 0;+    return MEM_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)+{+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1)+    if (ZSTD_isLegacy(src, srcSize)) return ZSTD_decompressLegacy(dst, dstCapacity, src, srcSize, ddict->dictContent, ddict->dictSize);+#endif+    ZSTD_refDCtx(dctx, ddict->refContext);+    ZSTD_checkContinuity(dctx, dst);+    return ZSTD_decompressFrame(dctx, dst, dstCapacity, src, srcSize);+}+++/*=====================================+*   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" */+++ZSTD_DStream* ZSTD_createDStream(void)+{+    return ZSTD_createDStream_advanced(defaultCustomMem);+}++ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)+{+    ZSTD_DStream* zds;++    if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;+    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;+}++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);+        ZSTD_freeDDict(zds->ddictLocal);+        ZSTD_free(zds->inBuff, cMem);+        ZSTD_free(zds->outBuff, cMem);+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)+        if (zds->legacyContext)+            ZSTD_freeLegacyStreamContext(zds->legacyContext, zds->previousLegacyVersion);+#endif+        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_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)+{+    zds->stage = zdss_loadHeader;+    zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;+    ZSTD_freeDDict(zds->ddictLocal);+    if (dict) {+        zds->ddictLocal = ZSTD_createDDict(dict, dictSize);+        if (zds->ddictLocal == NULL) return ERROR(memory_allocation);+    } else zds->ddictLocal = NULL;+    zds->ddict = zds->ddictLocal;+    zds->legacyVersion = 0;+    zds->hostageByte = 0;+    return ZSTD_frameHeaderSize_prefix;+}++size_t ZSTD_initDStream(ZSTD_DStream* zds)+{+    return ZSTD_initDStream_usingDict(zds, NULL, 0);+}++size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict)  /**< note : ddict will just be referenced, and must outlive decompression session */+{+    size_t const initResult = ZSTD_initDStream(zds);+    zds->ddict = ddict;+    return initResult;+}++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;+}++size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds,+                                ZSTD_DStreamParameter_e paramType, unsigned paramValue)+{+    switch(paramType)+    {+        default : return ERROR(parameter_unknown);+        case ZSTDdsp_maxWindowSize : zds->maxWindowSize = paramValue ? paramValue : (U32)(-1); break;+    }+    return 0;+}+++size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds)+{+    if (zds==NULL) return 0;   /* support sizeof on NULL */+    return sizeof(*zds) + ZSTD_sizeof_DCtx(zds->dctx) + ZSTD_sizeof_DDict(zds->ddictLocal) + zds->inBuffSize + zds->outBuffSize;+}+++/* *****   Decompression   ***** */++MEM_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;++#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)+    if (zds->legacyVersion)+        return ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);+#endif++    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))+#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)+                {   U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);+                    if (legacyVersion) {+                        const void* const dict = zds->ddict ? zds->ddict->dictContent : NULL;+                        size_t const dictSize = zds->ddict ? zds->ddict->dictSize : 0;+                        CHECK_F(ZSTD_initLegacyStream(&zds->legacyContext, zds->previousLegacyVersion, legacyVersion,+                                                       dict, dictSize));+                        zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;+                        return ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);+                    } else {+                        return hSize; /* error */+                }   }+#else+                return hSize;+#endif+                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;+            }   }++            /* Consume header */+            {   const ZSTD_DCtx* refContext = zds->ddict ? zds->ddict->refContext : NULL;+                ZSTD_refDCtx(zds->dctx, refContext);+            }+            {   size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zds->dctx);  /* == ZSTD_frameHeaderSize_prefix */+                CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer, h1Size));+                {   size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zds->dctx);+                    CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer+h1Size, h2Size));+            }   }++            zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);+            if (zds->fParams.windowSize > zds->maxWindowSize) return ERROR(frameParameter_windowTooLarge);++            /* Adapt buffer sizes to frame header instructions */+            {   size_t const blockSize = MIN(zds->fParams.windowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);+                size_t const neededOutSize = zds->fParams.windowSize + blockSize;+                zds->blockSize = blockSize;+                if (zds->inBuffSize < blockSize) {+                    ZSTD_free(zds->inBuff, zds->customMem);+                    zds->inBuffSize = blockSize;+                    zds->inBuff = (char*)ZSTD_malloc(blockSize, zds->customMem);+                    if (zds->inBuff == NULL) return ERROR(memory_allocation);+                }+                if (zds->outBuffSize < neededOutSize) {+                    ZSTD_free(zds->outBuff, zds->customMem);+                    zds->outBuffSize = neededOutSize;+                    zds->outBuff = (char*)ZSTD_malloc(neededOutSize, zds->customMem);+                    if (zds->outBuff == NULL) return ERROR(memory_allocation);+            }   }+            zds->stage = zdss_read;+            /* pass-through */++        case zdss_read:+            {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);+                if (neededInSize==0) {  /* end of frame */+                    zds->stage = zdss_init;+                    someMoreWork = 0;+                    break;+                }+                if ((size_t)(iend-ip) >= neededInSize) {  /* decode directly from src */+                    const int isSkipFrame = ZSTD_isSkipFrame(zds->dctx);+                    size_t const decodedSize = ZSTD_decompressContinue(zds->dctx,+                        zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart),+                        ip, neededInSize);+                    if (ZSTD_isError(decodedSize)) return decodedSize;+                    ip += neededInSize;+                    if (!decodedSize && !isSkipFrame) break;   /* this was just a header */+                    zds->outEnd = zds->outStart + decodedSize;+                    zds->stage = zdss_flush;+                    break;+                }+                if (ip==iend) { someMoreWork = 0; break; }   /* no more input */+                zds->stage = zdss_load;+                /* pass-through */+            }++        case zdss_load:+            {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds->dctx);+                size_t const toLoad = neededInSize - zds->inPos;   /* should always be <= remaining space within inBuff */+                size_t loadedSize;+                if (toLoad > zds->inBuffSize - zds->inPos) return ERROR(corruption_detected);   /* should never happen */+                loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);+                ip += loadedSize;+                zds->inPos += loadedSize;+                if (loadedSize < toLoad) { someMoreWork = 0; break; }   /* not enough input, wait for more */++                /* 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;+    }+}
+ zstd/lib/dictBuilder/cover.c view
@@ -0,0 +1,1021 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++/*-*************************************+*  Dependencies+***************************************/+#include <stdio.h>  /* fprintf */+#include <stdlib.h> /* malloc, free, qsort */+#include <string.h> /* memset */+#include <time.h>   /* clock */+#ifdef ZSTD_PTHREAD+#include "threading.h"+#endif++#include "mem.h"           /* read */+#include "zstd_internal.h" /* includes zstd.h */+#ifndef ZDICT_STATIC_LINKING_ONLY+#define ZDICT_STATIC_LINKING_ONLY+#endif+#include "zdict.h"++/*-*************************************+*  Constants+***************************************/+#define COVER_MAX_SAMPLES_SIZE ((U32)-1)++/*-*************************************+*  Console display+***************************************/+static int g_displayLevel = 2;+#define DISPLAY(...)                                                           \+  {                                                                            \+    fprintf(stderr, __VA_ARGS__);                                              \+    fflush(stderr);                                                            \+  }+#define LOCALDISPLAYLEVEL(displayLevel, l, ...)                                \+  if (displayLevel >= l) {                                                     \+    DISPLAY(__VA_ARGS__);                                                      \+  } /* 0 : no display;   1: errors;   2: default;  3: details;  4: debug */+#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__)++#define LOCALDISPLAYUPDATE(displayLevel, l, ...)                               \+  if (displayLevel >= l) {                                                     \+    if ((clock() - g_time > refreshRate) || (displayLevel >= 4)) {             \+      g_time = clock();                                                        \+      DISPLAY(__VA_ARGS__);                                                    \+      if (displayLevel >= 4)                                                   \+        fflush(stdout);                                                        \+    }                                                                          \+  }+#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__)+static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;+static clock_t g_time = 0;++/*-*************************************+* Hash table+***************************************+* A small specialized hash map for storing activeDmers.+* The map does not resize, so if it becomes full it will loop forever.+* Thus, the map must be large enough to store every value.+* The map implements linear probing and keeps its load less than 0.5.+*/++#define MAP_EMPTY_VALUE ((U32)-1)+typedef struct COVER_map_pair_t_s {+  U32 key;+  U32 value;+} COVER_map_pair_t;++typedef struct COVER_map_s {+  COVER_map_pair_t *data;+  U32 sizeLog;+  U32 size;+  U32 sizeMask;+} COVER_map_t;++/**+ * Clear the map.+ */+static void COVER_map_clear(COVER_map_t *map) {+  memset(map->data, MAP_EMPTY_VALUE, map->size * sizeof(COVER_map_pair_t));+}++/**+ * Initializes a map of the given size.+ * Returns 1 on success and 0 on failure.+ * The map must be destroyed with COVER_map_destroy().+ * The map is only guaranteed to be large enough to hold size elements.+ */+static int COVER_map_init(COVER_map_t *map, U32 size) {+  map->sizeLog = ZSTD_highbit32(size) + 2;+  map->size = (U32)1 << map->sizeLog;+  map->sizeMask = map->size - 1;+  map->data = (COVER_map_pair_t *)malloc(map->size * sizeof(COVER_map_pair_t));+  if (!map->data) {+    map->sizeLog = 0;+    map->size = 0;+    return 0;+  }+  COVER_map_clear(map);+  return 1;+}++/**+ * Internal hash function+ */+static const U32 prime4bytes = 2654435761U;+static U32 COVER_map_hash(COVER_map_t *map, U32 key) {+  return (key * prime4bytes) >> (32 - map->sizeLog);+}++/**+ * Helper function that returns the index that a key should be placed into.+ */+static U32 COVER_map_index(COVER_map_t *map, U32 key) {+  const U32 hash = COVER_map_hash(map, key);+  U32 i;+  for (i = hash;; i = (i + 1) & map->sizeMask) {+    COVER_map_pair_t *pos = &map->data[i];+    if (pos->value == MAP_EMPTY_VALUE) {+      return i;+    }+    if (pos->key == key) {+      return i;+    }+  }+}++/**+ * Returns the pointer to the value for key.+ * If key is not in the map, it is inserted and the value is set to 0.+ * The map must not be full.+ */+static U32 *COVER_map_at(COVER_map_t *map, U32 key) {+  COVER_map_pair_t *pos = &map->data[COVER_map_index(map, key)];+  if (pos->value == MAP_EMPTY_VALUE) {+    pos->key = key;+    pos->value = 0;+  }+  return &pos->value;+}++/**+ * Deletes key from the map if present.+ */+static void COVER_map_remove(COVER_map_t *map, U32 key) {+  U32 i = COVER_map_index(map, key);+  COVER_map_pair_t *del = &map->data[i];+  U32 shift = 1;+  if (del->value == MAP_EMPTY_VALUE) {+    return;+  }+  for (i = (i + 1) & map->sizeMask;; i = (i + 1) & map->sizeMask) {+    COVER_map_pair_t *const pos = &map->data[i];+    /* If the position is empty we are done */+    if (pos->value == MAP_EMPTY_VALUE) {+      del->value = MAP_EMPTY_VALUE;+      return;+    }+    /* If pos can be moved to del do so */+    if (((i - COVER_map_hash(map, pos->key)) & map->sizeMask) >= shift) {+      del->key = pos->key;+      del->value = pos->value;+      del = pos;+      shift = 1;+    } else {+      ++shift;+    }+  }+}++/**+ * Destroyes a map that is inited with COVER_map_init().+ */+static void COVER_map_destroy(COVER_map_t *map) {+  if (map->data) {+    free(map->data);+  }+  map->data = NULL;+  map->size = 0;+}++/*-*************************************+* Context+***************************************/++typedef struct {+  const BYTE *samples;+  size_t *offsets;+  const size_t *samplesSizes;+  size_t nbSamples;+  U32 *suffix;+  size_t suffixSize;+  U32 *freqs;+  U32 *dmerAt;+  unsigned d;+} COVER_ctx_t;++/* We need a global context for qsort... */+static COVER_ctx_t *g_ctx = NULL;++/*-*************************************+*  Helper functions+***************************************/++/**+ * Returns the sum of the sample sizes.+ */+static size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) {+  size_t sum = 0;+  size_t i;+  for (i = 0; i < nbSamples; ++i) {+    sum += samplesSizes[i];+  }+  return sum;+}++/**+ * Returns -1 if the dmer at lp is less than the dmer at rp.+ * Return 0 if the dmers at lp and rp are equal.+ * Returns 1 if the dmer at lp is greater than the dmer at rp.+ */+static int COVER_cmp(COVER_ctx_t *ctx, const void *lp, const void *rp) {+  const U32 lhs = *(const U32 *)lp;+  const U32 rhs = *(const U32 *)rp;+  return memcmp(ctx->samples + lhs, ctx->samples + rhs, ctx->d);+}++/**+ * Same as COVER_cmp() except ties are broken by pointer value+ * NOTE: g_ctx must be set to call this function.  A global is required because+ * qsort doesn't take an opaque pointer.+ */+static int COVER_strict_cmp(const void *lp, const void *rp) {+  int result = COVER_cmp(g_ctx, lp, rp);+  if (result == 0) {+    result = lp < rp ? -1 : 1;+  }+  return result;+}++/**+ * Returns the first pointer in [first, last) whose element does not compare+ * less than value.  If no such element exists it returns last.+ */+static const size_t *COVER_lower_bound(const size_t *first, const size_t *last,+                                       size_t value) {+  size_t count = last - first;+  while (count != 0) {+    size_t step = count / 2;+    const size_t *ptr = first;+    ptr += step;+    if (*ptr < value) {+      first = ++ptr;+      count -= step + 1;+    } else {+      count = step;+    }+  }+  return first;+}++/**+ * Generic groupBy function.+ * Groups an array sorted by cmp into groups with equivalent values.+ * Calls grp for each group.+ */+static void+COVER_groupBy(const void *data, size_t count, size_t size, COVER_ctx_t *ctx,+              int (*cmp)(COVER_ctx_t *, const void *, const void *),+              void (*grp)(COVER_ctx_t *, const void *, const void *)) {+  const BYTE *ptr = (const BYTE *)data;+  size_t num = 0;+  while (num < count) {+    const BYTE *grpEnd = ptr + size;+    ++num;+    while (num < count && cmp(ctx, ptr, grpEnd) == 0) {+      grpEnd += size;+      ++num;+    }+    grp(ctx, ptr, grpEnd);+    ptr = grpEnd;+  }+}++/*-*************************************+*  Cover functions+***************************************/++/**+ * Called on each group of positions with the same dmer.+ * Counts the frequency of each dmer and saves it in the suffix array.+ * Fills `ctx->dmerAt`.+ */+static void COVER_group(COVER_ctx_t *ctx, const void *group,+                        const void *groupEnd) {+  /* The group consists of all the positions with the same first d bytes. */+  const U32 *grpPtr = (const U32 *)group;+  const U32 *grpEnd = (const U32 *)groupEnd;+  /* The dmerId is how we will reference this dmer.+   * This allows us to map the whole dmer space to a much smaller space, the+   * size of the suffix array.+   */+  const U32 dmerId = (U32)(grpPtr - ctx->suffix);+  /* Count the number of samples this dmer shows up in */+  U32 freq = 0;+  /* Details */+  const size_t *curOffsetPtr = ctx->offsets;+  const size_t *offsetsEnd = ctx->offsets + ctx->nbSamples;+  /* Once *grpPtr >= curSampleEnd this occurrence of the dmer is in a+   * different sample than the last.+   */+  size_t curSampleEnd = ctx->offsets[0];+  for (; grpPtr != grpEnd; ++grpPtr) {+    /* Save the dmerId for this position so we can get back to it. */+    ctx->dmerAt[*grpPtr] = dmerId;+    /* Dictionaries only help for the first reference to the dmer.+     * After that zstd can reference the match from the previous reference.+     * So only count each dmer once for each sample it is in.+     */+    if (*grpPtr < curSampleEnd) {+      continue;+    }+    freq += 1;+    /* Binary search to find the end of the sample *grpPtr is in.+     * In the common case that grpPtr + 1 == grpEnd we can skip the binary+     * search because the loop is over.+     */+    if (grpPtr + 1 != grpEnd) {+      const size_t *sampleEndPtr =+          COVER_lower_bound(curOffsetPtr, offsetsEnd, *grpPtr);+      curSampleEnd = *sampleEndPtr;+      curOffsetPtr = sampleEndPtr + 1;+    }+  }+  /* At this point we are never going to look at this segment of the suffix+   * array again.  We take advantage of this fact to save memory.+   * We store the frequency of the dmer in the first position of the group,+   * which is dmerId.+   */+  ctx->suffix[dmerId] = freq;+}++/**+ * A segment is a range in the source as well as the score of the segment.+ */+typedef struct {+  U32 begin;+  U32 end;+  double score;+} COVER_segment_t;++/**+ * Selects the best segment in an epoch.+ * Segments of are scored according to the function:+ *+ * Let F(d) be the frequency of dmer d.+ * Let S_i be the dmer at position i of segment S which has length k.+ *+ *     Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1})+ *+ * Once the dmer d is in the dictionay we set F(d) = 0.+ */+static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs,+                                           COVER_map_t *activeDmers, U32 begin,+                                           U32 end, COVER_params_t parameters) {+  /* Constants */+  const U32 k = parameters.k;+  const U32 d = parameters.d;+  const U32 dmersInK = k - d + 1;+  /* Try each segment (activeSegment) and save the best (bestSegment) */+  COVER_segment_t bestSegment = {0, 0, 0};+  COVER_segment_t activeSegment;+  /* Reset the activeDmers in the segment */+  COVER_map_clear(activeDmers);+  /* The activeSegment starts at the beginning of the epoch. */+  activeSegment.begin = begin;+  activeSegment.end = begin;+  activeSegment.score = 0;+  /* Slide the activeSegment through the whole epoch.+   * Save the best segment in bestSegment.+   */+  while (activeSegment.end < end) {+    /* The dmerId for the dmer at the next position */+    U32 newDmer = ctx->dmerAt[activeSegment.end];+    /* The entry in activeDmers for this dmerId */+    U32 *newDmerOcc = COVER_map_at(activeDmers, newDmer);+    /* If the dmer isn't already present in the segment add its score. */+    if (*newDmerOcc == 0) {+      /* The paper suggest using the L-0.5 norm, but experiments show that it+       * doesn't help.+       */+      activeSegment.score += freqs[newDmer];+    }+    /* Add the dmer to the segment */+    activeSegment.end += 1;+    *newDmerOcc += 1;++    /* If the window is now too large, drop the first position */+    if (activeSegment.end - activeSegment.begin == dmersInK + 1) {+      U32 delDmer = ctx->dmerAt[activeSegment.begin];+      U32 *delDmerOcc = COVER_map_at(activeDmers, delDmer);+      activeSegment.begin += 1;+      *delDmerOcc -= 1;+      /* If this is the last occurence of the dmer, subtract its score */+      if (*delDmerOcc == 0) {+        COVER_map_remove(activeDmers, delDmer);+        activeSegment.score -= freqs[delDmer];+      }+    }++    /* If this segment is the best so far save it */+    if (activeSegment.score > bestSegment.score) {+      bestSegment = activeSegment;+    }+  }+  {+    /* Trim off the zero frequency head and tail from the segment. */+    U32 newBegin = bestSegment.end;+    U32 newEnd = bestSegment.begin;+    U32 pos;+    for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) {+      U32 freq = freqs[ctx->dmerAt[pos]];+      if (freq != 0) {+        newBegin = MIN(newBegin, pos);+        newEnd = pos + 1;+      }+    }+    bestSegment.begin = newBegin;+    bestSegment.end = newEnd;+  }+  {+    /* Zero out the frequency of each dmer covered by the chosen segment. */+    U32 pos;+    for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) {+      freqs[ctx->dmerAt[pos]] = 0;+    }+  }+  return bestSegment;+}++/**+ * Check the validity of the parameters.+ * Returns non-zero if the parameters are valid and 0 otherwise.+ */+static int COVER_checkParameters(COVER_params_t parameters) {+  /* k and d are required parameters */+  if (parameters.d == 0 || parameters.k == 0) {+    return 0;+  }+  /* d <= k */+  if (parameters.d > parameters.k) {+    return 0;+  }+  return 1;+}++/**+ * Clean up a context initialized with `COVER_ctx_init()`.+ */+static void COVER_ctx_destroy(COVER_ctx_t *ctx) {+  if (!ctx) {+    return;+  }+  if (ctx->suffix) {+    free(ctx->suffix);+    ctx->suffix = NULL;+  }+  if (ctx->freqs) {+    free(ctx->freqs);+    ctx->freqs = NULL;+  }+  if (ctx->dmerAt) {+    free(ctx->dmerAt);+    ctx->dmerAt = NULL;+  }+  if (ctx->offsets) {+    free(ctx->offsets);+    ctx->offsets = NULL;+  }+}++/**+ * Prepare a context for dictionary building.+ * The context is only dependent on the parameter `d` and can used multiple+ * times.+ * Returns 1 on success or zero on error.+ * The context must be destroyed with `COVER_ctx_destroy()`.+ */+static int COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer,+                          const size_t *samplesSizes, unsigned nbSamples,+                          unsigned d) {+  const BYTE *const samples = (const BYTE *)samplesBuffer;+  const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples);+  /* Checks */+  if (totalSamplesSize < d ||+      totalSamplesSize > (size_t)COVER_MAX_SAMPLES_SIZE) {+    return 0;+  }+  /* Zero the context */+  memset(ctx, 0, sizeof(*ctx));+  DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbSamples,+               (U32)totalSamplesSize);+  ctx->samples = samples;+  ctx->samplesSizes = samplesSizes;+  ctx->nbSamples = nbSamples;+  /* Partial suffix array */+  ctx->suffixSize = totalSamplesSize - d + 1;+  ctx->suffix = (U32 *)malloc(ctx->suffixSize * sizeof(U32));+  /* Maps index to the dmerID */+  ctx->dmerAt = (U32 *)malloc(ctx->suffixSize * sizeof(U32));+  /* The offsets of each file */+  ctx->offsets = (size_t *)malloc((nbSamples + 1) * sizeof(size_t));+  if (!ctx->suffix || !ctx->dmerAt || !ctx->offsets) {+    COVER_ctx_destroy(ctx);+    return 0;+  }+  ctx->freqs = NULL;+  ctx->d = d;++  /* Fill offsets from the samlesSizes */+  {+    U32 i;+    ctx->offsets[0] = 0;+    for (i = 1; i <= nbSamples; ++i) {+      ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1];+    }+  }+  DISPLAYLEVEL(2, "Constructing partial suffix array\n");+  {+    /* suffix is a partial suffix array.+     * It only sorts suffixes by their first parameters.d bytes.+     * The sort is stable, so each dmer group is sorted by position in input.+     */+    U32 i;+    for (i = 0; i < ctx->suffixSize; ++i) {+      ctx->suffix[i] = i;+    }+    /* qsort doesn't take an opaque pointer, so pass as a global */+    g_ctx = ctx;+    qsort(ctx->suffix, ctx->suffixSize, sizeof(U32), &COVER_strict_cmp);+  }+  DISPLAYLEVEL(2, "Computing frequencies\n");+  /* For each dmer group (group of positions with the same first d bytes):+   * 1. For each position we set dmerAt[position] = dmerID.  The dmerID is+   *    (groupBeginPtr - suffix).  This allows us to go from position to+   *    dmerID so we can look up values in freq.+   * 2. We calculate how many samples the dmer occurs in and save it in+   *    freqs[dmerId].+   */+  COVER_groupBy(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx, &COVER_cmp,+                &COVER_group);+  ctx->freqs = ctx->suffix;+  ctx->suffix = NULL;+  return 1;+}++/**+ * Given the prepared context build the dictionary.+ */+static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs,+                                    COVER_map_t *activeDmers, void *dictBuffer,+                                    size_t dictBufferCapacity,+                                    COVER_params_t parameters) {+  BYTE *const dict = (BYTE *)dictBuffer;+  size_t tail = dictBufferCapacity;+  /* Divide the data up into epochs of equal size.+   * We will select at least one segment from each epoch.+   */+  const U32 epochs = (U32)(dictBufferCapacity / parameters.k);+  const U32 epochSize = (U32)(ctx->suffixSize / epochs);+  size_t epoch;+  DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n", epochs,+               epochSize);+  /* Loop through the epochs until there are no more segments or the dictionary+   * is full.+   */+  for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs) {+    const U32 epochBegin = (U32)(epoch * epochSize);+    const U32 epochEnd = epochBegin + epochSize;+    size_t segmentSize;+    /* Select a segment */+    COVER_segment_t segment = COVER_selectSegment(+        ctx, freqs, activeDmers, epochBegin, epochEnd, parameters);+    /* Trim the segment if necessary and if it is empty then we are done */+    segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail);+    if (segmentSize == 0) {+      break;+    }+    /* We fill the dictionary from the back to allow the best segments to be+     * referenced with the smallest offsets.+     */+    tail -= segmentSize;+    memcpy(dict + tail, ctx->samples + segment.begin, segmentSize);+    DISPLAYUPDATE(+        2, "\r%u%%       ",+        (U32)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity));+  }+  DISPLAYLEVEL(2, "\r%79s\r", "");+  return tail;+}++/**+ * Translate from COVER_params_t to ZDICT_params_t required for finalizing the+ * dictionary.+ */+static ZDICT_params_t COVER_translateParams(COVER_params_t parameters) {+  ZDICT_params_t zdictParams;+  memset(&zdictParams, 0, sizeof(zdictParams));+  zdictParams.notificationLevel = 1;+  zdictParams.dictID = parameters.dictID;+  zdictParams.compressionLevel = parameters.compressionLevel;+  return zdictParams;+}++/**+ * Constructs a dictionary using a heuristic based on the following paper:+ *+ * Liao, Petri, Moffat, Wirth+ * Effective Construction of Relative Lempel-Ziv Dictionaries+ * Published in WWW 2016.+ */+ZDICTLIB_API size_t COVER_trainFromBuffer(+    void *dictBuffer, size_t dictBufferCapacity, const void *samplesBuffer,+    const size_t *samplesSizes, unsigned nbSamples, COVER_params_t parameters) {+  BYTE *const dict = (BYTE *)dictBuffer;+  COVER_ctx_t ctx;+  COVER_map_t activeDmers;+  /* Checks */+  if (!COVER_checkParameters(parameters)) {+    DISPLAYLEVEL(1, "Cover parameters incorrect\n");+    return ERROR(GENERIC);+  }+  if (nbSamples == 0) {+    DISPLAYLEVEL(1, "Cover must have at least one input file\n");+    return ERROR(GENERIC);+  }+  if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {+    DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",+                 ZDICT_DICTSIZE_MIN);+    return ERROR(dstSize_tooSmall);+  }+  /* Initialize global data */+  g_displayLevel = parameters.notificationLevel;+  /* Initialize context and activeDmers */+  if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples,+                      parameters.d)) {+    DISPLAYLEVEL(1, "Failed to initialize context\n");+    return ERROR(GENERIC);+  }+  if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) {+    DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n");+    COVER_ctx_destroy(&ctx);+    return ERROR(GENERIC);+  }++  DISPLAYLEVEL(2, "Building dictionary\n");+  {+    const size_t tail =+        COVER_buildDictionary(&ctx, ctx.freqs, &activeDmers, dictBuffer,+                              dictBufferCapacity, parameters);+    ZDICT_params_t zdictParams = COVER_translateParams(parameters);+    const size_t dictionarySize = ZDICT_finalizeDictionary(+        dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,+        samplesBuffer, samplesSizes, nbSamples, zdictParams);+    if (!ZSTD_isError(dictionarySize)) {+      DISPLAYLEVEL(2, "Constructed dictionary of size %u\n",+                   (U32)dictionarySize);+    }+    COVER_ctx_destroy(&ctx);+    COVER_map_destroy(&activeDmers);+    return dictionarySize;+  }+}++/**+ * COVER_best_t is used for two purposes:+ * 1. Synchronizing threads.+ * 2. Saving the best parameters and dictionary.+ *+ * All of the methods except COVER_best_init() are thread safe if zstd is+ * compiled with multithreaded support.+ */+typedef struct COVER_best_s {+#ifdef ZSTD_PTHREAD+  pthread_mutex_t mutex;+  pthread_cond_t cond;+  size_t liveJobs;+#endif+  void *dict;+  size_t dictSize;+  COVER_params_t parameters;+  size_t compressedSize;+} COVER_best_t;++/**+ * Initialize the `COVER_best_t`.+ */+static void COVER_best_init(COVER_best_t *best) {+  if (!best) {+    return;+  }+#ifdef ZSTD_PTHREAD+  pthread_mutex_init(&best->mutex, NULL);+  pthread_cond_init(&best->cond, NULL);+  best->liveJobs = 0;+#endif+  best->dict = NULL;+  best->dictSize = 0;+  best->compressedSize = (size_t)-1;+  memset(&best->parameters, 0, sizeof(best->parameters));+}++/**+ * Wait until liveJobs == 0.+ */+static void COVER_best_wait(COVER_best_t *best) {+  if (!best) {+    return;+  }+#ifdef ZSTD_PTHREAD+  pthread_mutex_lock(&best->mutex);+  while (best->liveJobs != 0) {+    pthread_cond_wait(&best->cond, &best->mutex);+  }+  pthread_mutex_unlock(&best->mutex);+#endif+}++/**+ * Call COVER_best_wait() and then destroy the COVER_best_t.+ */+static void COVER_best_destroy(COVER_best_t *best) {+  if (!best) {+    return;+  }+  COVER_best_wait(best);+  if (best->dict) {+    free(best->dict);+  }+#ifdef ZSTD_PTHREAD+  pthread_mutex_destroy(&best->mutex);+  pthread_cond_destroy(&best->cond);+#endif+}++/**+ * Called when a thread is about to be launched.+ * Increments liveJobs.+ */+static void COVER_best_start(COVER_best_t *best) {+  if (!best) {+    return;+  }+#ifdef ZSTD_PTHREAD+  pthread_mutex_lock(&best->mutex);+  ++best->liveJobs;+  pthread_mutex_unlock(&best->mutex);+#endif+}++/**+ * Called when a thread finishes executing, both on error or success.+ * Decrements liveJobs and signals any waiting threads if liveJobs == 0.+ * If this dictionary is the best so far save it and its parameters.+ */+static void COVER_best_finish(COVER_best_t *best, size_t compressedSize,+                              COVER_params_t parameters, void *dict,+                              size_t dictSize) {+  if (!best) {+    return;+  }+  {+#ifdef ZSTD_PTHREAD+    size_t liveJobs;+    pthread_mutex_lock(&best->mutex);+    --best->liveJobs;+    liveJobs = best->liveJobs;+#endif+    /* If the new dictionary is better */+    if (compressedSize < best->compressedSize) {+      /* Allocate space if necessary */+      if (!best->dict || best->dictSize < dictSize) {+        if (best->dict) {+          free(best->dict);+        }+        best->dict = malloc(dictSize);+        if (!best->dict) {+          best->compressedSize = ERROR(GENERIC);+          best->dictSize = 0;+          return;+        }+      }+      /* Save the dictionary, parameters, and size */+      memcpy(best->dict, dict, dictSize);+      best->dictSize = dictSize;+      best->parameters = parameters;+      best->compressedSize = compressedSize;+    }+#ifdef ZSTD_PTHREAD+    pthread_mutex_unlock(&best->mutex);+    if (liveJobs == 0) {+      pthread_cond_broadcast(&best->cond);+    }+#endif+  }+}++/**+ * Parameters for COVER_tryParameters().+ */+typedef struct COVER_tryParameters_data_s {+  const COVER_ctx_t *ctx;+  COVER_best_t *best;+  size_t dictBufferCapacity;+  COVER_params_t parameters;+} COVER_tryParameters_data_t;++/**+ * Tries a set of parameters and upates the COVER_best_t with the results.+ * This function is thread safe if zstd is compiled with multithreaded support.+ * It takes its parameters as an *OWNING* opaque pointer to support threading.+ */+static void COVER_tryParameters(void *opaque) {+  /* Save parameters as local variables */+  COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t *)opaque;+  const COVER_ctx_t *const ctx = data->ctx;+  const COVER_params_t parameters = data->parameters;+  size_t dictBufferCapacity = data->dictBufferCapacity;+  size_t totalCompressedSize = ERROR(GENERIC);+  /* Allocate space for hash table, dict, and freqs */+  COVER_map_t activeDmers;+  BYTE *const dict = (BYTE * const)malloc(dictBufferCapacity);+  U32 *freqs = (U32 *)malloc(ctx->suffixSize * sizeof(U32));+  if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) {+    DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n");+    goto _cleanup;+  }+  if (!dict || !freqs) {+    DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n");+    goto _cleanup;+  }+  /* Copy the frequencies because we need to modify them */+  memcpy(freqs, ctx->freqs, ctx->suffixSize * sizeof(U32));+  /* Build the dictionary */+  {+    const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict,+                                              dictBufferCapacity, parameters);+    const ZDICT_params_t zdictParams = COVER_translateParams(parameters);+    dictBufferCapacity = ZDICT_finalizeDictionary(+        dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail,+        ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbSamples, zdictParams);+    if (ZDICT_isError(dictBufferCapacity)) {+      DISPLAYLEVEL(1, "Failed to finalize dictionary\n");+      goto _cleanup;+    }+  }+  /* Check total compressed size */+  {+    /* Pointers */+    ZSTD_CCtx *cctx;+    ZSTD_CDict *cdict;+    void *dst;+    /* Local variables */+    size_t dstCapacity;+    size_t i;+    /* Allocate dst with enough space to compress the maximum sized sample */+    {+      size_t maxSampleSize = 0;+      for (i = 0; i < ctx->nbSamples; ++i) {+        maxSampleSize = MAX(ctx->samplesSizes[i], maxSampleSize);+      }+      dstCapacity = ZSTD_compressBound(maxSampleSize);+      dst = malloc(dstCapacity);+    }+    /* Create the cctx and cdict */+    cctx = ZSTD_createCCtx();+    cdict =+        ZSTD_createCDict(dict, dictBufferCapacity, parameters.compressionLevel);+    if (!dst || !cctx || !cdict) {+      goto _compressCleanup;+    }+    /* Compress each sample and sum their sizes (or error) */+    totalCompressedSize = 0;+    for (i = 0; i < ctx->nbSamples; ++i) {+      const size_t size = ZSTD_compress_usingCDict(+          cctx, dst, dstCapacity, ctx->samples + ctx->offsets[i],+          ctx->samplesSizes[i], cdict);+      if (ZSTD_isError(size)) {+        totalCompressedSize = ERROR(GENERIC);+        goto _compressCleanup;+      }+      totalCompressedSize += size;+    }+  _compressCleanup:+    ZSTD_freeCCtx(cctx);+    ZSTD_freeCDict(cdict);+    if (dst) {+      free(dst);+    }+  }++_cleanup:+  COVER_best_finish(data->best, totalCompressedSize, parameters, dict,+                    dictBufferCapacity);+  free(data);+  COVER_map_destroy(&activeDmers);+  if (dict) {+    free(dict);+  }+  if (freqs) {+    free(freqs);+  }+}++ZDICTLIB_API size_t COVER_optimizeTrainFromBuffer(void *dictBuffer,+                                                  size_t dictBufferCapacity,+                                                  const void *samplesBuffer,+                                                  const size_t *samplesSizes,+                                                  unsigned nbSamples,+                                                  COVER_params_t *parameters) {+  /* constants */+  const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d;+  const unsigned kMaxD = parameters->d == 0 ? 16 : parameters->d;+  const unsigned kMinK = parameters->k == 0 ? kMaxD : parameters->k;+  const unsigned kMaxK = parameters->k == 0 ? 2048 : parameters->k;+  const unsigned kSteps = parameters->steps == 0 ? 256 : parameters->steps;+  const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1);+  const unsigned kIterations =+      (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize);+  /* Local variables */+  const int displayLevel = parameters->notificationLevel;+  unsigned iteration = 1;+  unsigned d;+  unsigned k;+  COVER_best_t best;+  /* Checks */+  if (kMinK < kMaxD || kMaxK < kMinK) {+    LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n");+    return ERROR(GENERIC);+  }+  if (nbSamples == 0) {+    DISPLAYLEVEL(1, "Cover must have at least one input file\n");+    return ERROR(GENERIC);+  }+  if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) {+    DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n",+                 ZDICT_DICTSIZE_MIN);+    return ERROR(dstSize_tooSmall);+  }+  /* Initialization */+  COVER_best_init(&best);+  /* Turn down global display level to clean up display at level 2 and below */+  g_displayLevel = parameters->notificationLevel - 1;+  /* Loop through d first because each new value needs a new context */+  LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n",+                    kIterations);+  for (d = kMinD; d <= kMaxD; d += 2) {+    /* Initialize the context for this value of d */+    COVER_ctx_t ctx;+    LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d);+    if (!COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d)) {+      LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n");+      COVER_best_destroy(&best);+      return ERROR(GENERIC);+    }+    /* Loop through k reusing the same context */+    for (k = kMinK; k <= kMaxK; k += kStepSize) {+      /* Prepare the arguments */+      COVER_tryParameters_data_t *data = (COVER_tryParameters_data_t *)malloc(+          sizeof(COVER_tryParameters_data_t));+      LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k);+      if (!data) {+        LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n");+        COVER_best_destroy(&best);+        COVER_ctx_destroy(&ctx);+        return ERROR(GENERIC);+      }+      data->ctx = &ctx;+      data->best = &best;+      data->dictBufferCapacity = dictBufferCapacity;+      data->parameters = *parameters;+      data->parameters.k = k;+      data->parameters.d = d;+      data->parameters.steps = kSteps;+      /* Check the parameters */+      if (!COVER_checkParameters(data->parameters)) {+        DISPLAYLEVEL(1, "Cover parameters incorrect\n");+        continue;+      }+      /* Call the function and pass ownership of data to it */+      COVER_best_start(&best);+      COVER_tryParameters(data);+      /* Print status */+      LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%%       ",+                         (U32)((iteration * 100) / kIterations));+      ++iteration;+    }+    COVER_best_wait(&best);+    COVER_ctx_destroy(&ctx);+  }+  LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", "");+  /* Fill the output buffer and parameters with output of the best parameters */+  {+    const size_t dictSize = best.dictSize;+    if (ZSTD_isError(best.compressedSize)) {+      COVER_best_destroy(&best);+      return best.compressedSize;+    }+    *parameters = best.parameters;+    memcpy(dictBuffer, best.dict, dictSize);+    COVER_best_destroy(&best);+    return dictSize;+  }+}
+ zstd/lib/dictBuilder/divsufsort.c view
@@ -0,0 +1,1913 @@+/*+ * divsufsort.c for libdivsufsort-lite+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.+ *+ * Permission is hereby granted, free of charge, to any person+ * obtaining a copy of this software and associated documentation+ * files (the "Software"), to deal in the Software without+ * restriction, including without limitation the rights to use,+ * copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the+ * Software is furnished to do so, subject to the following+ * conditions:+ *+ * The above copyright notice and this permission notice shall be+ * included in all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+ * OTHER DEALINGS IN THE SOFTWARE.+ */++/*- Compiler specifics -*/+#ifdef __clang__+#pragma clang diagnostic ignored "-Wshorten-64-to-32"+#endif++#if defined(_MSC_VER)+#  pragma warning(disable : 4244)+#  pragma warning(disable : 4127)    /* C4127 : Condition expression is constant */+#endif+++/*- Dependencies -*/+#include <assert.h>+#include <stdio.h>+#include <stdlib.h>++#include "divsufsort.h"++/*- Constants -*/+#if defined(INLINE)+# undef INLINE+#endif+#if !defined(INLINE)+# define INLINE __inline+#endif+#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1)+# undef ALPHABET_SIZE+#endif+#if !defined(ALPHABET_SIZE)+# define ALPHABET_SIZE (256)+#endif+#define BUCKET_A_SIZE (ALPHABET_SIZE)+#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE)+#if defined(SS_INSERTIONSORT_THRESHOLD)+# if SS_INSERTIONSORT_THRESHOLD < 1+#  undef SS_INSERTIONSORT_THRESHOLD+#  define SS_INSERTIONSORT_THRESHOLD (1)+# endif+#else+# define SS_INSERTIONSORT_THRESHOLD (8)+#endif+#if defined(SS_BLOCKSIZE)+# if SS_BLOCKSIZE < 0+#  undef SS_BLOCKSIZE+#  define SS_BLOCKSIZE (0)+# elif 32768 <= SS_BLOCKSIZE+#  undef SS_BLOCKSIZE+#  define SS_BLOCKSIZE (32767)+# endif+#else+# define SS_BLOCKSIZE (1024)+#endif+/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */+#if SS_BLOCKSIZE == 0+# define SS_MISORT_STACKSIZE (96)+#elif SS_BLOCKSIZE <= 4096+# define SS_MISORT_STACKSIZE (16)+#else+# define SS_MISORT_STACKSIZE (24)+#endif+#define SS_SMERGE_STACKSIZE (32)+#define TR_INSERTIONSORT_THRESHOLD (8)+#define TR_STACKSIZE (64)+++/*- Macros -*/+#ifndef SWAP+# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0)+#endif /* SWAP */+#ifndef MIN+# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b))+#endif /* MIN */+#ifndef MAX+# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b))+#endif /* MAX */+#define STACK_PUSH(_a, _b, _c, _d)\+  do {\+    assert(ssize < STACK_SIZE);\+    stack[ssize].a = (_a), stack[ssize].b = (_b),\+    stack[ssize].c = (_c), stack[ssize++].d = (_d);\+  } while(0)+#define STACK_PUSH5(_a, _b, _c, _d, _e)\+  do {\+    assert(ssize < STACK_SIZE);\+    stack[ssize].a = (_a), stack[ssize].b = (_b),\+    stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\+  } while(0)+#define STACK_POP(_a, _b, _c, _d)\+  do {\+    assert(0 <= ssize);\+    if(ssize == 0) { return; }\+    (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\+    (_c) = stack[ssize].c, (_d) = stack[ssize].d;\+  } while(0)+#define STACK_POP5(_a, _b, _c, _d, _e)\+  do {\+    assert(0 <= ssize);\+    if(ssize == 0) { return; }\+    (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\+    (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\+  } while(0)+#define BUCKET_A(_c0) bucket_A[(_c0)]+#if ALPHABET_SIZE == 256+#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)])+#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)])+#else+#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)])+#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)])+#endif+++/*- Private Functions -*/++static const int lg_table[256]= {+ -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,+  5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,+  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,+  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7+};++#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)++static INLINE+int+ss_ilg(int n) {+#if SS_BLOCKSIZE == 0+  return (n & 0xffff0000) ?+          ((n & 0xff000000) ?+            24 + lg_table[(n >> 24) & 0xff] :+            16 + lg_table[(n >> 16) & 0xff]) :+          ((n & 0x0000ff00) ?+             8 + lg_table[(n >>  8) & 0xff] :+             0 + lg_table[(n >>  0) & 0xff]);+#elif SS_BLOCKSIZE < 256+  return lg_table[n];+#else+  return (n & 0xff00) ?+          8 + lg_table[(n >> 8) & 0xff] :+          0 + lg_table[(n >> 0) & 0xff];+#endif+}++#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */++#if SS_BLOCKSIZE != 0++static const int sqq_table[256] = {+  0,  16,  22,  27,  32,  35,  39,  42,  45,  48,  50,  53,  55,  57,  59,  61,+ 64,  65,  67,  69,  71,  73,  75,  76,  78,  80,  81,  83,  84,  86,  87,  89,+ 90,  91,  93,  94,  96,  97,  98,  99, 101, 102, 103, 104, 106, 107, 108, 109,+110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,+128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,+143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155,+156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,+169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180,+181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191,+192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201,+202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,+212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221,+221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230,+230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,+239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,+247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255+};++static INLINE+int+ss_isqrt(int x) {+  int y, e;++  if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; }+  e = (x & 0xffff0000) ?+        ((x & 0xff000000) ?+          24 + lg_table[(x >> 24) & 0xff] :+          16 + lg_table[(x >> 16) & 0xff]) :+        ((x & 0x0000ff00) ?+           8 + lg_table[(x >>  8) & 0xff] :+           0 + lg_table[(x >>  0) & 0xff]);++  if(e >= 16) {+    y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7);+    if(e >= 24) { y = (y + 1 + x / y) >> 1; }+    y = (y + 1 + x / y) >> 1;+  } else if(e >= 8) {+    y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1;+  } else {+    return sqq_table[x] >> 4;+  }++  return (x < (y * y)) ? y - 1 : y;+}++#endif /* SS_BLOCKSIZE != 0 */+++/*---------------------------------------------------------------------------*/++/* Compares two suffixes. */+static INLINE+int+ss_compare(const unsigned char *T,+           const int *p1, const int *p2,+           int depth) {+  const unsigned char *U1, *U2, *U1n, *U2n;++  for(U1 = T + depth + *p1,+      U2 = T + depth + *p2,+      U1n = T + *(p1 + 1) + 2,+      U2n = T + *(p2 + 1) + 2;+      (U1 < U1n) && (U2 < U2n) && (*U1 == *U2);+      ++U1, ++U2) {+  }++  return U1 < U1n ?+        (U2 < U2n ? *U1 - *U2 : 1) :+        (U2 < U2n ? -1 : 0);+}+++/*---------------------------------------------------------------------------*/++#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1)++/* Insertionsort for small size groups */+static+void+ss_insertionsort(const unsigned char *T, const int *PA,+                 int *first, int *last, int depth) {+  int *i, *j;+  int t;+  int r;++  for(i = last - 2; first <= i; --i) {+    for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) {+      do { *(j - 1) = *j; } while((++j < last) && (*j < 0));+      if(last <= j) { break; }+    }+    if(r == 0) { *j = ~*j; }+    *(j - 1) = t;+  }+}++#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */+++/*---------------------------------------------------------------------------*/++#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)++static INLINE+void+ss_fixdown(const unsigned char *Td, const int *PA,+           int *SA, int i, int size) {+  int j, k;+  int v;+  int c, d, e;++  for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {+    d = Td[PA[SA[k = j++]]];+    if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; }+    if(d <= c) { break; }+  }+  SA[i] = v;+}++/* Simple top-down heapsort. */+static+void+ss_heapsort(const unsigned char *Td, const int *PA, int *SA, int size) {+  int i, m;+  int t;++  m = size;+  if((size % 2) == 0) {+    m--;+    if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); }+  }++  for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); }+  if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); }+  for(i = m - 1; 0 < i; --i) {+    t = SA[0], SA[0] = SA[i];+    ss_fixdown(Td, PA, SA, 0, i);+    SA[i] = t;+  }+}+++/*---------------------------------------------------------------------------*/++/* Returns the median of three elements. */+static INLINE+int *+ss_median3(const unsigned char *Td, const int *PA,+           int *v1, int *v2, int *v3) {+  int *t;+  if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); }+  if(Td[PA[*v2]] > Td[PA[*v3]]) {+    if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; }+    else { return v3; }+  }+  return v2;+}++/* Returns the median of five elements. */+static INLINE+int *+ss_median5(const unsigned char *Td, const int *PA,+           int *v1, int *v2, int *v3, int *v4, int *v5) {+  int *t;+  if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); }+  if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); }+  if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); }+  if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); }+  if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); }+  if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; }+  return v3;+}++/* Returns the pivot element. */+static INLINE+int *+ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) {+  int *middle;+  int t;++  t = last - first;+  middle = first + t / 2;++  if(t <= 512) {+    if(t <= 32) {+      return ss_median3(Td, PA, first, middle, last - 1);+    } else {+      t >>= 2;+      return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1);+    }+  }+  t >>= 3;+  first  = ss_median3(Td, PA, first, first + t, first + (t << 1));+  middle = ss_median3(Td, PA, middle - t, middle, middle + t);+  last   = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1);+  return ss_median3(Td, PA, first, middle, last);+}+++/*---------------------------------------------------------------------------*/++/* Binary partition for substrings. */+static INLINE+int *+ss_partition(const int *PA,+                    int *first, int *last, int depth) {+  int *a, *b;+  int t;+  for(a = first - 1, b = last;;) {+    for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; }+    for(; (a < --b) && ((PA[*b] + depth) <  (PA[*b + 1] + 1));) { }+    if(b <= a) { break; }+    t = ~*b;+    *b = *a;+    *a = t;+  }+  if(first < a) { *first = ~*first; }+  return a;+}++/* Multikey introsort for medium size groups. */+static+void+ss_mintrosort(const unsigned char *T, const int *PA,+              int *first, int *last,+              int depth) {+#define STACK_SIZE SS_MISORT_STACKSIZE+  struct { int *a, *b, c; int d; } stack[STACK_SIZE];+  const unsigned char *Td;+  int *a, *b, *c, *d, *e, *f;+  int s, t;+  int ssize;+  int limit;+  int v, x = 0;++  for(ssize = 0, limit = ss_ilg(last - first);;) {++    if((last - first) <= SS_INSERTIONSORT_THRESHOLD) {+#if 1 < SS_INSERTIONSORT_THRESHOLD+      if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); }+#endif+      STACK_POP(first, last, depth, limit);+      continue;+    }++    Td = T + depth;+    if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); }+    if(limit < 0) {+      for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) {+        if((x = Td[PA[*a]]) != v) {+          if(1 < (a - first)) { break; }+          v = x;+          first = a;+        }+      }+      if(Td[PA[*first] - 1] < v) {+        first = ss_partition(PA, first, a, depth);+      }+      if((a - first) <= (last - a)) {+        if(1 < (a - first)) {+          STACK_PUSH(a, last, depth, -1);+          last = a, depth += 1, limit = ss_ilg(a - first);+        } else {+          first = a, limit = -1;+        }+      } else {+        if(1 < (last - a)) {+          STACK_PUSH(first, a, depth + 1, ss_ilg(a - first));+          first = a, limit = -1;+        } else {+          last = a, depth += 1, limit = ss_ilg(a - first);+        }+      }+      continue;+    }++    /* choose pivot */+    a = ss_pivot(Td, PA, first, last);+    v = Td[PA[*a]];+    SWAP(*first, *a);++    /* partition */+    for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { }+    if(((a = b) < last) && (x < v)) {+      for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) {+        if(x == v) { SWAP(*b, *a); ++a; }+      }+    }+    for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { }+    if((b < (d = c)) && (x > v)) {+      for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {+        if(x == v) { SWAP(*c, *d); --d; }+      }+    }+    for(; b < c;) {+      SWAP(*b, *c);+      for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) {+        if(x == v) { SWAP(*b, *a); ++a; }+      }+      for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) {+        if(x == v) { SWAP(*c, *d); --d; }+      }+    }++    if(a <= d) {+      c = b - 1;++      if((s = a - first) > (t = b - a)) { s = t; }+      for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }+      if((s = d - c) > (t = last - d - 1)) { s = t; }+      for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }++      a = first + (b - a), c = last - (d - c);+      b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth);++      if((a - first) <= (last - c)) {+        if((last - c) <= (c - b)) {+          STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));+          STACK_PUSH(c, last, depth, limit);+          last = a;+        } else if((a - first) <= (c - b)) {+          STACK_PUSH(c, last, depth, limit);+          STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));+          last = a;+        } else {+          STACK_PUSH(c, last, depth, limit);+          STACK_PUSH(first, a, depth, limit);+          first = b, last = c, depth += 1, limit = ss_ilg(c - b);+        }+      } else {+        if((a - first) <= (c - b)) {+          STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));+          STACK_PUSH(first, a, depth, limit);+          first = c;+        } else if((last - c) <= (c - b)) {+          STACK_PUSH(first, a, depth, limit);+          STACK_PUSH(b, c, depth + 1, ss_ilg(c - b));+          first = c;+        } else {+          STACK_PUSH(first, a, depth, limit);+          STACK_PUSH(c, last, depth, limit);+          first = b, last = c, depth += 1, limit = ss_ilg(c - b);+        }+      }+    } else {+      limit += 1;+      if(Td[PA[*first] - 1] < v) {+        first = ss_partition(PA, first, last, depth);+        limit = ss_ilg(last - first);+      }+      depth += 1;+    }+  }+#undef STACK_SIZE+}++#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */+++/*---------------------------------------------------------------------------*/++#if SS_BLOCKSIZE != 0++static INLINE+void+ss_blockswap(int *a, int *b, int n) {+  int t;+  for(; 0 < n; --n, ++a, ++b) {+    t = *a, *a = *b, *b = t;+  }+}++static INLINE+void+ss_rotate(int *first, int *middle, int *last) {+  int *a, *b, t;+  int l, r;+  l = middle - first, r = last - middle;+  for(; (0 < l) && (0 < r);) {+    if(l == r) { ss_blockswap(first, middle, l); break; }+    if(l < r) {+      a = last - 1, b = middle - 1;+      t = *a;+      do {+        *a-- = *b, *b-- = *a;+        if(b < first) {+          *a = t;+          last = a;+          if((r -= l + 1) <= l) { break; }+          a -= 1, b = middle - 1;+          t = *a;+        }+      } while(1);+    } else {+      a = first, b = middle;+      t = *a;+      do {+        *a++ = *b, *b++ = *a;+        if(last <= b) {+          *a = t;+          first = a + 1;+          if((l -= r + 1) <= r) { break; }+          a += 1, b = middle;+          t = *a;+        }+      } while(1);+    }+  }+}+++/*---------------------------------------------------------------------------*/++static+void+ss_inplacemerge(const unsigned char *T, const int *PA,+                int *first, int *middle, int *last,+                int depth) {+  const int *p;+  int *a, *b;+  int len, half;+  int q, r;+  int x;++  for(;;) {+    if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); }+    else                { x = 0; p = PA +  *(last - 1); }+    for(a = first, len = middle - first, half = len >> 1, r = -1;+        0 < len;+        len = half, half >>= 1) {+      b = a + half;+      q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth);+      if(q < 0) {+        a = b + 1;+        half -= (len & 1) ^ 1;+      } else {+        r = q;+      }+    }+    if(a < middle) {+      if(r == 0) { *a = ~*a; }+      ss_rotate(a, middle, last);+      last -= middle - a;+      middle = a;+      if(first == middle) { break; }+    }+    --last;+    if(x != 0) { while(*--last < 0) { } }+    if(middle == last) { break; }+  }+}+++/*---------------------------------------------------------------------------*/++/* Merge-forward with internal buffer. */+static+void+ss_mergeforward(const unsigned char *T, const int *PA,+                int *first, int *middle, int *last,+                int *buf, int depth) {+  int *a, *b, *c, *bufend;+  int t;+  int r;++  bufend = buf + (middle - first) - 1;+  ss_blockswap(buf, first, middle - first);++  for(t = *(a = first), b = buf, c = middle;;) {+    r = ss_compare(T, PA + *b, PA + *c, depth);+    if(r < 0) {+      do {+        *a++ = *b;+        if(bufend <= b) { *bufend = t; return; }+        *b++ = *a;+      } while(*b < 0);+    } else if(r > 0) {+      do {+        *a++ = *c, *c++ = *a;+        if(last <= c) {+          while(b < bufend) { *a++ = *b, *b++ = *a; }+          *a = *b, *b = t;+          return;+        }+      } while(*c < 0);+    } else {+      *c = ~*c;+      do {+        *a++ = *b;+        if(bufend <= b) { *bufend = t; return; }+        *b++ = *a;+      } while(*b < 0);++      do {+        *a++ = *c, *c++ = *a;+        if(last <= c) {+          while(b < bufend) { *a++ = *b, *b++ = *a; }+          *a = *b, *b = t;+          return;+        }+      } while(*c < 0);+    }+  }+}++/* Merge-backward with internal buffer. */+static+void+ss_mergebackward(const unsigned char *T, const int *PA,+                 int *first, int *middle, int *last,+                 int *buf, int depth) {+  const int *p1, *p2;+  int *a, *b, *c, *bufend;+  int t;+  int r;+  int x;++  bufend = buf + (last - middle) - 1;+  ss_blockswap(buf, middle, last - middle);++  x = 0;+  if(*bufend < 0)       { p1 = PA + ~*bufend; x |= 1; }+  else                  { p1 = PA +  *bufend; }+  if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; }+  else                  { p2 = PA +  *(middle - 1); }+  for(t = *(a = last - 1), b = bufend, c = middle - 1;;) {+    r = ss_compare(T, p1, p2, depth);+    if(0 < r) {+      if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }+      *a-- = *b;+      if(b <= buf) { *buf = t; break; }+      *b-- = *a;+      if(*b < 0) { p1 = PA + ~*b; x |= 1; }+      else       { p1 = PA +  *b; }+    } else if(r < 0) {+      if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }+      *a-- = *c, *c-- = *a;+      if(c < first) {+        while(buf < b) { *a-- = *b, *b-- = *a; }+        *a = *b, *b = t;+        break;+      }+      if(*c < 0) { p2 = PA + ~*c; x |= 2; }+      else       { p2 = PA +  *c; }+    } else {+      if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; }+      *a-- = ~*b;+      if(b <= buf) { *buf = t; break; }+      *b-- = *a;+      if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; }+      *a-- = *c, *c-- = *a;+      if(c < first) {+        while(buf < b) { *a-- = *b, *b-- = *a; }+        *a = *b, *b = t;+        break;+      }+      if(*b < 0) { p1 = PA + ~*b; x |= 1; }+      else       { p1 = PA +  *b; }+      if(*c < 0) { p2 = PA + ~*c; x |= 2; }+      else       { p2 = PA +  *c; }+    }+  }+}++/* D&C based merge. */+static+void+ss_swapmerge(const unsigned char *T, const int *PA,+             int *first, int *middle, int *last,+             int *buf, int bufsize, int depth) {+#define STACK_SIZE SS_SMERGE_STACKSIZE+#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a)))+#define MERGE_CHECK(a, b, c)\+  do {\+    if(((c) & 1) ||\+       (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\+      *(a) = ~*(a);\+    }\+    if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\+      *(b) = ~*(b);\+    }\+  } while(0)+  struct { int *a, *b, *c; int d; } stack[STACK_SIZE];+  int *l, *r, *lm, *rm;+  int m, len, half;+  int ssize;+  int check, next;++  for(check = 0, ssize = 0;;) {+    if((last - middle) <= bufsize) {+      if((first < middle) && (middle < last)) {+        ss_mergebackward(T, PA, first, middle, last, buf, depth);+      }+      MERGE_CHECK(first, last, check);+      STACK_POP(first, middle, last, check);+      continue;+    }++    if((middle - first) <= bufsize) {+      if(first < middle) {+        ss_mergeforward(T, PA, first, middle, last, buf, depth);+      }+      MERGE_CHECK(first, last, check);+      STACK_POP(first, middle, last, check);+      continue;+    }++    for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1;+        0 < len;+        len = half, half >>= 1) {+      if(ss_compare(T, PA + GETIDX(*(middle + m + half)),+                       PA + GETIDX(*(middle - m - half - 1)), depth) < 0) {+        m += half + 1;+        half -= (len & 1) ^ 1;+      }+    }++    if(0 < m) {+      lm = middle - m, rm = middle + m;+      ss_blockswap(lm, middle, m);+      l = r = middle, next = 0;+      if(rm < last) {+        if(*rm < 0) {+          *rm = ~*rm;+          if(first < lm) { for(; *--l < 0;) { } next |= 4; }+          next |= 1;+        } else if(first < lm) {+          for(; *r < 0; ++r) { }+          next |= 2;+        }+      }++      if((l - first) <= (last - r)) {+        STACK_PUSH(r, rm, last, (next & 3) | (check & 4));+        middle = lm, last = l, check = (check & 3) | (next & 4);+      } else {+        if((next & 2) && (r == middle)) { next ^= 6; }+        STACK_PUSH(first, lm, l, (check & 3) | (next & 4));+        first = r, middle = rm, check = (next & 3) | (check & 4);+      }+    } else {+      if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) {+        *middle = ~*middle;+      }+      MERGE_CHECK(first, last, check);+      STACK_POP(first, middle, last, check);+    }+  }+#undef STACK_SIZE+}++#endif /* SS_BLOCKSIZE != 0 */+++/*---------------------------------------------------------------------------*/++/* Substring sort */+static+void+sssort(const unsigned char *T, const int *PA,+       int *first, int *last,+       int *buf, int bufsize,+       int depth, int n, int lastsuffix) {+  int *a;+#if SS_BLOCKSIZE != 0+  int *b, *middle, *curbuf;+  int j, k, curbufsize, limit;+#endif+  int i;++  if(lastsuffix != 0) { ++first; }++#if SS_BLOCKSIZE == 0+  ss_mintrosort(T, PA, first, last, depth);+#else+  if((bufsize < SS_BLOCKSIZE) &&+      (bufsize < (last - first)) &&+      (bufsize < (limit = ss_isqrt(last - first)))) {+    if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; }+    buf = middle = last - limit, bufsize = limit;+  } else {+    middle = last, limit = 0;+  }+  for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) {+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE+    ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth);+#elif 1 < SS_BLOCKSIZE+    ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth);+#endif+    curbufsize = last - (a + SS_BLOCKSIZE);+    curbuf = a + SS_BLOCKSIZE;+    if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; }+    for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) {+      ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth);+    }+  }+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE+  ss_mintrosort(T, PA, a, middle, depth);+#elif 1 < SS_BLOCKSIZE+  ss_insertionsort(T, PA, a, middle, depth);+#endif+  for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) {+    if(i & 1) {+      ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth);+      a -= k;+    }+  }+  if(limit != 0) {+#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE+    ss_mintrosort(T, PA, middle, last, depth);+#elif 1 < SS_BLOCKSIZE+    ss_insertionsort(T, PA, middle, last, depth);+#endif+    ss_inplacemerge(T, PA, first, middle, last, depth);+  }+#endif++  if(lastsuffix != 0) {+    /* Insert last type B* suffix. */+    int PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2;+    for(a = first, i = *(first - 1);+        (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth)));+        ++a) {+      *(a - 1) = *a;+    }+    *(a - 1) = i;+  }+}+++/*---------------------------------------------------------------------------*/++static INLINE+int+tr_ilg(int n) {+  return (n & 0xffff0000) ?+          ((n & 0xff000000) ?+            24 + lg_table[(n >> 24) & 0xff] :+            16 + lg_table[(n >> 16) & 0xff]) :+          ((n & 0x0000ff00) ?+             8 + lg_table[(n >>  8) & 0xff] :+             0 + lg_table[(n >>  0) & 0xff]);+}+++/*---------------------------------------------------------------------------*/++/* Simple insertionsort for small size groups. */+static+void+tr_insertionsort(const int *ISAd, int *first, int *last) {+  int *a, *b;+  int t, r;++  for(a = first + 1; a < last; ++a) {+    for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) {+      do { *(b + 1) = *b; } while((first <= --b) && (*b < 0));+      if(b < first) { break; }+    }+    if(r == 0) { *b = ~*b; }+    *(b + 1) = t;+  }+}+++/*---------------------------------------------------------------------------*/++static INLINE+void+tr_fixdown(const int *ISAd, int *SA, int i, int size) {+  int j, k;+  int v;+  int c, d, e;++  for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) {+    d = ISAd[SA[k = j++]];+    if(d < (e = ISAd[SA[j]])) { k = j; d = e; }+    if(d <= c) { break; }+  }+  SA[i] = v;+}++/* Simple top-down heapsort. */+static+void+tr_heapsort(const int *ISAd, int *SA, int size) {+  int i, m;+  int t;++  m = size;+  if((size % 2) == 0) {+    m--;+    if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); }+  }++  for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); }+  if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); }+  for(i = m - 1; 0 < i; --i) {+    t = SA[0], SA[0] = SA[i];+    tr_fixdown(ISAd, SA, 0, i);+    SA[i] = t;+  }+}+++/*---------------------------------------------------------------------------*/++/* Returns the median of three elements. */+static INLINE+int *+tr_median3(const int *ISAd, int *v1, int *v2, int *v3) {+  int *t;+  if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); }+  if(ISAd[*v2] > ISAd[*v3]) {+    if(ISAd[*v1] > ISAd[*v3]) { return v1; }+    else { return v3; }+  }+  return v2;+}++/* Returns the median of five elements. */+static INLINE+int *+tr_median5(const int *ISAd,+           int *v1, int *v2, int *v3, int *v4, int *v5) {+  int *t;+  if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); }+  if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); }+  if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); }+  if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); }+  if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); }+  if(ISAd[*v3] > ISAd[*v4]) { return v4; }+  return v3;+}++/* Returns the pivot element. */+static INLINE+int *+tr_pivot(const int *ISAd, int *first, int *last) {+  int *middle;+  int t;++  t = last - first;+  middle = first + t / 2;++  if(t <= 512) {+    if(t <= 32) {+      return tr_median3(ISAd, first, middle, last - 1);+    } else {+      t >>= 2;+      return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1);+    }+  }+  t >>= 3;+  first  = tr_median3(ISAd, first, first + t, first + (t << 1));+  middle = tr_median3(ISAd, middle - t, middle, middle + t);+  last   = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1);+  return tr_median3(ISAd, first, middle, last);+}+++/*---------------------------------------------------------------------------*/++typedef struct _trbudget_t trbudget_t;+struct _trbudget_t {+  int chance;+  int remain;+  int incval;+  int count;+};++static INLINE+void+trbudget_init(trbudget_t *budget, int chance, int incval) {+  budget->chance = chance;+  budget->remain = budget->incval = incval;+}++static INLINE+int+trbudget_check(trbudget_t *budget, int size) {+  if(size <= budget->remain) { budget->remain -= size; return 1; }+  if(budget->chance == 0) { budget->count += size; return 0; }+  budget->remain += budget->incval - size;+  budget->chance -= 1;+  return 1;+}+++/*---------------------------------------------------------------------------*/++static INLINE+void+tr_partition(const int *ISAd,+             int *first, int *middle, int *last,+             int **pa, int **pb, int v) {+  int *a, *b, *c, *d, *e, *f;+  int t, s;+  int x = 0;++  for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { }+  if(((a = b) < last) && (x < v)) {+    for(; (++b < last) && ((x = ISAd[*b]) <= v);) {+      if(x == v) { SWAP(*b, *a); ++a; }+    }+  }+  for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { }+  if((b < (d = c)) && (x > v)) {+    for(; (b < --c) && ((x = ISAd[*c]) >= v);) {+      if(x == v) { SWAP(*c, *d); --d; }+    }+  }+  for(; b < c;) {+    SWAP(*b, *c);+    for(; (++b < c) && ((x = ISAd[*b]) <= v);) {+      if(x == v) { SWAP(*b, *a); ++a; }+    }+    for(; (b < --c) && ((x = ISAd[*c]) >= v);) {+      if(x == v) { SWAP(*c, *d); --d; }+    }+  }++  if(a <= d) {+    c = b - 1;+    if((s = a - first) > (t = b - a)) { s = t; }+    for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }+    if((s = d - c) > (t = last - d - 1)) { s = t; }+    for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); }+    first += (b - a), last -= (d - c);+  }+  *pa = first, *pb = last;+}++static+void+tr_copy(int *ISA, const int *SA,+        int *first, int *a, int *b, int *last,+        int depth) {+  /* sort suffixes of middle partition+     by using sorted order of suffixes of left and right partition. */+  int *c, *d, *e;+  int s, v;++  v = b - SA - 1;+  for(c = first, d = a - 1; c <= d; ++c) {+    if((0 <= (s = *c - depth)) && (ISA[s] == v)) {+      *++d = s;+      ISA[s] = d - SA;+    }+  }+  for(c = last - 1, e = d + 1, d = b; e < d; --c) {+    if((0 <= (s = *c - depth)) && (ISA[s] == v)) {+      *--d = s;+      ISA[s] = d - SA;+    }+  }+}++static+void+tr_partialcopy(int *ISA, const int *SA,+               int *first, int *a, int *b, int *last,+               int depth) {+  int *c, *d, *e;+  int s, v;+  int rank, lastrank, newrank = -1;++  v = b - SA - 1;+  lastrank = -1;+  for(c = first, d = a - 1; c <= d; ++c) {+    if((0 <= (s = *c - depth)) && (ISA[s] == v)) {+      *++d = s;+      rank = ISA[s + depth];+      if(lastrank != rank) { lastrank = rank; newrank = d - SA; }+      ISA[s] = newrank;+    }+  }++  lastrank = -1;+  for(e = d; first <= e; --e) {+    rank = ISA[*e];+    if(lastrank != rank) { lastrank = rank; newrank = e - SA; }+    if(newrank != rank) { ISA[*e] = newrank; }+  }++  lastrank = -1;+  for(c = last - 1, e = d + 1, d = b; e < d; --c) {+    if((0 <= (s = *c - depth)) && (ISA[s] == v)) {+      *--d = s;+      rank = ISA[s + depth];+      if(lastrank != rank) { lastrank = rank; newrank = d - SA; }+      ISA[s] = newrank;+    }+  }+}++static+void+tr_introsort(int *ISA, const int *ISAd,+             int *SA, int *first, int *last,+             trbudget_t *budget) {+#define STACK_SIZE TR_STACKSIZE+  struct { const int *a; int *b, *c; int d, e; }stack[STACK_SIZE];+  int *a, *b, *c;+  int t;+  int v, x = 0;+  int incr = ISAd - ISA;+  int limit, next;+  int ssize, trlink = -1;++  for(ssize = 0, limit = tr_ilg(last - first);;) {++    if(limit < 0) {+      if(limit == -1) {+        /* tandem repeat partition */+        tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1);++        /* update ranks */+        if(a < last) {+          for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; }+        }+        if(b < last) {+          for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; }+        }++        /* push */+        if(1 < (b - a)) {+          STACK_PUSH5(NULL, a, b, 0, 0);+          STACK_PUSH5(ISAd - incr, first, last, -2, trlink);+          trlink = ssize - 2;+        }+        if((a - first) <= (last - b)) {+          if(1 < (a - first)) {+            STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink);+            last = a, limit = tr_ilg(a - first);+          } else if(1 < (last - b)) {+            first = b, limit = tr_ilg(last - b);+          } else {+            STACK_POP5(ISAd, first, last, limit, trlink);+          }+        } else {+          if(1 < (last - b)) {+            STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink);+            first = b, limit = tr_ilg(last - b);+          } else if(1 < (a - first)) {+            last = a, limit = tr_ilg(a - first);+          } else {+            STACK_POP5(ISAd, first, last, limit, trlink);+          }+        }+      } else if(limit == -2) {+        /* tandem repeat copy */+        a = stack[--ssize].b, b = stack[ssize].c;+        if(stack[ssize].d == 0) {+          tr_copy(ISA, SA, first, a, b, last, ISAd - ISA);+        } else {+          if(0 <= trlink) { stack[trlink].d = -1; }+          tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA);+        }+        STACK_POP5(ISAd, first, last, limit, trlink);+      } else {+        /* sorted partition */+        if(0 <= *first) {+          a = first;+          do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a));+          first = a;+        }+        if(first < last) {+          a = first; do { *a = ~*a; } while(*++a < 0);+          next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1;+          if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } }++          /* push */+          if(trbudget_check(budget, a - first)) {+            if((a - first) <= (last - a)) {+              STACK_PUSH5(ISAd, a, last, -3, trlink);+              ISAd += incr, last = a, limit = next;+            } else {+              if(1 < (last - a)) {+                STACK_PUSH5(ISAd + incr, first, a, next, trlink);+                first = a, limit = -3;+              } else {+                ISAd += incr, last = a, limit = next;+              }+            }+          } else {+            if(0 <= trlink) { stack[trlink].d = -1; }+            if(1 < (last - a)) {+              first = a, limit = -3;+            } else {+              STACK_POP5(ISAd, first, last, limit, trlink);+            }+          }+        } else {+          STACK_POP5(ISAd, first, last, limit, trlink);+        }+      }+      continue;+    }++    if((last - first) <= TR_INSERTIONSORT_THRESHOLD) {+      tr_insertionsort(ISAd, first, last);+      limit = -3;+      continue;+    }++    if(limit-- == 0) {+      tr_heapsort(ISAd, first, last - first);+      for(a = last - 1; first < a; a = b) {+        for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; }+      }+      limit = -3;+      continue;+    }++    /* choose pivot */+    a = tr_pivot(ISAd, first, last);+    SWAP(*first, *a);+    v = ISAd[*first];++    /* partition */+    tr_partition(ISAd, first, first + 1, last, &a, &b, v);+    if((last - first) != (b - a)) {+      next = (ISA[*a] != v) ? tr_ilg(b - a) : -1;++      /* update ranks */+      for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; }+      if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } }++      /* push */+      if((1 < (b - a)) && (trbudget_check(budget, b - a))) {+        if((a - first) <= (last - b)) {+          if((last - b) <= (b - a)) {+            if(1 < (a - first)) {+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);+              STACK_PUSH5(ISAd, b, last, limit, trlink);+              last = a;+            } else if(1 < (last - b)) {+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);+              first = b;+            } else {+              ISAd += incr, first = a, last = b, limit = next;+            }+          } else if((a - first) <= (b - a)) {+            if(1 < (a - first)) {+              STACK_PUSH5(ISAd, b, last, limit, trlink);+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);+              last = a;+            } else {+              STACK_PUSH5(ISAd, b, last, limit, trlink);+              ISAd += incr, first = a, last = b, limit = next;+            }+          } else {+            STACK_PUSH5(ISAd, b, last, limit, trlink);+            STACK_PUSH5(ISAd, first, a, limit, trlink);+            ISAd += incr, first = a, last = b, limit = next;+          }+        } else {+          if((a - first) <= (b - a)) {+            if(1 < (last - b)) {+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);+              STACK_PUSH5(ISAd, first, a, limit, trlink);+              first = b;+            } else if(1 < (a - first)) {+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);+              last = a;+            } else {+              ISAd += incr, first = a, last = b, limit = next;+            }+          } else if((last - b) <= (b - a)) {+            if(1 < (last - b)) {+              STACK_PUSH5(ISAd, first, a, limit, trlink);+              STACK_PUSH5(ISAd + incr, a, b, next, trlink);+              first = b;+            } else {+              STACK_PUSH5(ISAd, first, a, limit, trlink);+              ISAd += incr, first = a, last = b, limit = next;+            }+          } else {+            STACK_PUSH5(ISAd, first, a, limit, trlink);+            STACK_PUSH5(ISAd, b, last, limit, trlink);+            ISAd += incr, first = a, last = b, limit = next;+          }+        }+      } else {+        if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; }+        if((a - first) <= (last - b)) {+          if(1 < (a - first)) {+            STACK_PUSH5(ISAd, b, last, limit, trlink);+            last = a;+          } else if(1 < (last - b)) {+            first = b;+          } else {+            STACK_POP5(ISAd, first, last, limit, trlink);+          }+        } else {+          if(1 < (last - b)) {+            STACK_PUSH5(ISAd, first, a, limit, trlink);+            first = b;+          } else if(1 < (a - first)) {+            last = a;+          } else {+            STACK_POP5(ISAd, first, last, limit, trlink);+          }+        }+      }+    } else {+      if(trbudget_check(budget, last - first)) {+        limit = tr_ilg(last - first), ISAd += incr;+      } else {+        if(0 <= trlink) { stack[trlink].d = -1; }+        STACK_POP5(ISAd, first, last, limit, trlink);+      }+    }+  }+#undef STACK_SIZE+}++++/*---------------------------------------------------------------------------*/++/* Tandem repeat sort */+static+void+trsort(int *ISA, int *SA, int n, int depth) {+  int *ISAd;+  int *first, *last;+  trbudget_t budget;+  int t, skip, unsorted;++  trbudget_init(&budget, tr_ilg(n) * 2 / 3, n);+/*  trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */+  for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) {+    first = SA;+    skip = 0;+    unsorted = 0;+    do {+      if((t = *first) < 0) { first -= t; skip += t; }+      else {+        if(skip != 0) { *(first + skip) = skip; skip = 0; }+        last = SA + ISA[t] + 1;+        if(1 < (last - first)) {+          budget.count = 0;+          tr_introsort(ISA, ISAd, SA, first, last, &budget);+          if(budget.count != 0) { unsorted += budget.count; }+          else { skip = first - last; }+        } else if((last - first) == 1) {+          skip = -1;+        }+        first = last;+      }+    } while(first < (SA + n));+    if(skip != 0) { *(first + skip) = skip; }+    if(unsorted == 0) { break; }+  }+}+++/*---------------------------------------------------------------------------*/++/* Sorts suffixes of type B*. */+static+int+sort_typeBstar(const unsigned char *T, int *SA,+               int *bucket_A, int *bucket_B,+               int n, int openMP) {+  int *PAb, *ISAb, *buf;+#ifdef LIBBSC_OPENMP+  int *curbuf;+  int l;+#endif+  int i, j, k, t, m, bufsize;+  int c0, c1;+#ifdef LIBBSC_OPENMP+  int d0, d1;+#endif+  (void)openMP;++  /* Initialize bucket arrays. */+  for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; }+  for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; }++  /* Count the number of occurrences of the first one or two characters of each+     type A, B and B* suffix. Moreover, store the beginning position of all+     type B* suffixes into the array SA. */+  for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) {+    /* type A suffix. */+    do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1));+    if(0 <= i) {+      /* type B* suffix. */+      ++BUCKET_BSTAR(c0, c1);+      SA[--m] = i;+      /* type B suffix. */+      for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) {+        ++BUCKET_B(c0, c1);+      }+    }+  }+  m = n - m;+/*+note:+  A type B* suffix is lexicographically smaller than a type B suffix that+  begins with the same first two characters.+*/++  /* Calculate the index of start/end point of each bucket. */+  for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) {+    t = i + BUCKET_A(c0);+    BUCKET_A(c0) = i + j; /* start point */+    i = t + BUCKET_B(c0, c0);+    for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) {+      j += BUCKET_BSTAR(c0, c1);+      BUCKET_BSTAR(c0, c1) = j; /* end point */+      i += BUCKET_B(c0, c1);+    }+  }++  if(0 < m) {+    /* Sort the type B* suffixes by their first two characters. */+    PAb = SA + n - m; ISAb = SA + m;+    for(i = m - 2; 0 <= i; --i) {+      t = PAb[i], c0 = T[t], c1 = T[t + 1];+      SA[--BUCKET_BSTAR(c0, c1)] = i;+    }+    t = PAb[m - 1], c0 = T[t], c1 = T[t + 1];+    SA[--BUCKET_BSTAR(c0, c1)] = m - 1;++    /* Sort the type B* substrings using sssort. */+#ifdef LIBBSC_OPENMP+    if (openMP)+    {+        buf = SA + m;+        c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m;+#pragma omp parallel default(shared) private(bufsize, curbuf, k, l, d0, d1)+        {+          bufsize = (n - (2 * m)) / omp_get_num_threads();+          curbuf = buf + omp_get_thread_num() * bufsize;+          k = 0;+          for(;;) {+            #pragma omp critical(sssort_lock)+            {+              if(0 < (l = j)) {+                d0 = c0, d1 = c1;+                do {+                  k = BUCKET_BSTAR(d0, d1);+                  if(--d1 <= d0) {+                    d1 = ALPHABET_SIZE - 1;+                    if(--d0 < 0) { break; }+                  }+                } while(((l - k) <= 1) && (0 < (l = k)));+                c0 = d0, c1 = d1, j = k;+              }+            }+            if(l == 0) { break; }+            sssort(T, PAb, SA + k, SA + l,+                   curbuf, bufsize, 2, n, *(SA + k) == (m - 1));+          }+        }+    }+    else+    {+        buf = SA + m, bufsize = n - (2 * m);+        for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) {+          for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) {+            i = BUCKET_BSTAR(c0, c1);+            if(1 < (j - i)) {+              sssort(T, PAb, SA + i, SA + j,+                     buf, bufsize, 2, n, *(SA + i) == (m - 1));+            }+          }+        }+    }+#else+    buf = SA + m, bufsize = n - (2 * m);+    for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) {+      for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) {+        i = BUCKET_BSTAR(c0, c1);+        if(1 < (j - i)) {+          sssort(T, PAb, SA + i, SA + j,+                 buf, bufsize, 2, n, *(SA + i) == (m - 1));+        }+      }+    }+#endif++    /* Compute ranks of type B* substrings. */+    for(i = m - 1; 0 <= i; --i) {+      if(0 <= SA[i]) {+        j = i;+        do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i]));+        SA[i + 1] = i - j;+        if(i <= 0) { break; }+      }+      j = i;+      do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0);+      ISAb[SA[i]] = j;+    }++    /* Construct the inverse suffix array of type B* suffixes using trsort. */+    trsort(ISAb, SA, m, 1);++    /* Set the sorted order of tyoe B* suffixes. */+    for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) {+      for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { }+      if(0 <= i) {+        t = i;+        for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { }+        SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t;+      }+    }++    /* Calculate the index of start/end point of each bucket. */+    BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */+    for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) {+      i = BUCKET_A(c0 + 1) - 1;+      for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) {+        t = i - BUCKET_B(c0, c1);+        BUCKET_B(c0, c1) = i; /* end point */++        /* Move all type B* suffixes to the correct position. */+        for(i = t, j = BUCKET_BSTAR(c0, c1);+            j <= k;+            --i, --k) { SA[i] = SA[k]; }+      }+      BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */+      BUCKET_B(c0, c0) = i; /* end point */+    }+  }++  return m;+}++/* Constructs the suffix array by using the sorted order of type B* suffixes. */+static+void+construct_SA(const unsigned char *T, int *SA,+             int *bucket_A, int *bucket_B,+             int n, int m) {+  int *i, *j, *k;+  int s;+  int c0, c1, c2;++  if(0 < m) {+    /* Construct the sorted order of type B suffixes by using+       the sorted order of type B* suffixes. */+    for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {+      /* Scan the suffix array from right to left. */+      for(i = SA + BUCKET_BSTAR(c1, c1 + 1),+          j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;+          i <= j;+          --j) {+        if(0 < (s = *j)) {+          assert(T[s] == c1);+          assert(((s + 1) < n) && (T[s] <= T[s + 1]));+          assert(T[s - 1] <= T[s]);+          *j = ~s;+          c0 = T[--s];+          if((0 < s) && (T[s - 1] > c0)) { s = ~s; }+          if(c0 != c2) {+            if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }+            k = SA + BUCKET_B(c2 = c0, c1);+          }+          assert(k < j);+          *k-- = s;+        } else {+          assert(((s == 0) && (T[s] == c1)) || (s < 0));+          *j = ~s;+        }+      }+    }+  }++  /* Construct the suffix array by using+     the sorted order of type B suffixes. */+  k = SA + BUCKET_A(c2 = T[n - 1]);+  *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1);+  /* Scan the suffix array from left to right. */+  for(i = SA, j = SA + n; i < j; ++i) {+    if(0 < (s = *i)) {+      assert(T[s - 1] >= T[s]);+      c0 = T[--s];+      if((s == 0) || (T[s - 1] < c0)) { s = ~s; }+      if(c0 != c2) {+        BUCKET_A(c2) = k - SA;+        k = SA + BUCKET_A(c2 = c0);+      }+      assert(i < k);+      *k++ = s;+    } else {+      assert(s < 0);+      *i = ~s;+    }+  }+}++/* Constructs the burrows-wheeler transformed string directly+   by using the sorted order of type B* suffixes. */+static+int+construct_BWT(const unsigned char *T, int *SA,+              int *bucket_A, int *bucket_B,+              int n, int m) {+  int *i, *j, *k, *orig;+  int s;+  int c0, c1, c2;++  if(0 < m) {+    /* Construct the sorted order of type B suffixes by using+       the sorted order of type B* suffixes. */+    for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {+      /* Scan the suffix array from right to left. */+      for(i = SA + BUCKET_BSTAR(c1, c1 + 1),+          j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;+          i <= j;+          --j) {+        if(0 < (s = *j)) {+          assert(T[s] == c1);+          assert(((s + 1) < n) && (T[s] <= T[s + 1]));+          assert(T[s - 1] <= T[s]);+          c0 = T[--s];+          *j = ~((int)c0);+          if((0 < s) && (T[s - 1] > c0)) { s = ~s; }+          if(c0 != c2) {+            if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }+            k = SA + BUCKET_B(c2 = c0, c1);+          }+          assert(k < j);+          *k-- = s;+        } else if(s != 0) {+          *j = ~s;+#ifndef NDEBUG+        } else {+          assert(T[s] == c1);+#endif+        }+      }+    }+  }++  /* Construct the BWTed string by using+     the sorted order of type B suffixes. */+  k = SA + BUCKET_A(c2 = T[n - 1]);+  *k++ = (T[n - 2] < c2) ? ~((int)T[n - 2]) : (n - 1);+  /* Scan the suffix array from left to right. */+  for(i = SA, j = SA + n, orig = SA; i < j; ++i) {+    if(0 < (s = *i)) {+      assert(T[s - 1] >= T[s]);+      c0 = T[--s];+      *i = c0;+      if((0 < s) && (T[s - 1] < c0)) { s = ~((int)T[s - 1]); }+      if(c0 != c2) {+        BUCKET_A(c2) = k - SA;+        k = SA + BUCKET_A(c2 = c0);+      }+      assert(i < k);+      *k++ = s;+    } else if(s != 0) {+      *i = ~s;+    } else {+      orig = i;+    }+  }++  return orig - SA;+}++/* Constructs the burrows-wheeler transformed string directly+   by using the sorted order of type B* suffixes. */+static+int+construct_BWT_indexes(const unsigned char *T, int *SA,+                      int *bucket_A, int *bucket_B,+                      int n, int m,+                      unsigned char * num_indexes, int * indexes) {+  int *i, *j, *k, *orig;+  int s;+  int c0, c1, c2;++  int mod = n / 8;+  {+      mod |= mod >> 1;  mod |= mod >> 2;+      mod |= mod >> 4;  mod |= mod >> 8;+      mod |= mod >> 16; mod >>= 1;++      *num_indexes = (unsigned char)((n - 1) / (mod + 1));+  }++  if(0 < m) {+    /* Construct the sorted order of type B suffixes by using+       the sorted order of type B* suffixes. */+    for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) {+      /* Scan the suffix array from right to left. */+      for(i = SA + BUCKET_BSTAR(c1, c1 + 1),+          j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1;+          i <= j;+          --j) {+        if(0 < (s = *j)) {+          assert(T[s] == c1);+          assert(((s + 1) < n) && (T[s] <= T[s + 1]));+          assert(T[s - 1] <= T[s]);++          if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = j - SA;++          c0 = T[--s];+          *j = ~((int)c0);+          if((0 < s) && (T[s - 1] > c0)) { s = ~s; }+          if(c0 != c2) {+            if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; }+            k = SA + BUCKET_B(c2 = c0, c1);+          }+          assert(k < j);+          *k-- = s;+        } else if(s != 0) {+          *j = ~s;+#ifndef NDEBUG+        } else {+          assert(T[s] == c1);+#endif+        }+      }+    }+  }++  /* Construct the BWTed string by using+     the sorted order of type B suffixes. */+  k = SA + BUCKET_A(c2 = T[n - 1]);+  if (T[n - 2] < c2) {+    if (((n - 1) & mod) == 0) indexes[(n - 1) / (mod + 1) - 1] = k - SA;+    *k++ = ~((int)T[n - 2]);+  }+  else {+    *k++ = n - 1;+  }++  /* Scan the suffix array from left to right. */+  for(i = SA, j = SA + n, orig = SA; i < j; ++i) {+    if(0 < (s = *i)) {+      assert(T[s - 1] >= T[s]);++      if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = i - SA;++      c0 = T[--s];+      *i = c0;+      if(c0 != c2) {+        BUCKET_A(c2) = k - SA;+        k = SA + BUCKET_A(c2 = c0);+      }+      assert(i < k);+      if((0 < s) && (T[s - 1] < c0)) {+          if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = k - SA;+          *k++ = ~((int)T[s - 1]);+      } else+        *k++ = s;+    } else if(s != 0) {+      *i = ~s;+    } else {+      orig = i;+    }+  }++  return orig - SA;+}+++/*---------------------------------------------------------------------------*/++/*- Function -*/++int+divsufsort(const unsigned char *T, int *SA, int n, int openMP) {+  int *bucket_A, *bucket_B;+  int m;+  int err = 0;++  /* Check arguments. */+  if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; }+  else if(n == 0) { return 0; }+  else if(n == 1) { SA[0] = 0; return 0; }+  else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; }++  bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int));+  bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int));++  /* Suffixsort. */+  if((bucket_A != NULL) && (bucket_B != NULL)) {+    m = sort_typeBstar(T, SA, bucket_A, bucket_B, n, openMP);+    construct_SA(T, SA, bucket_A, bucket_B, n, m);+  } else {+    err = -2;+  }++  free(bucket_B);+  free(bucket_A);++  return err;+}++int+divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP) {+  int *B;+  int *bucket_A, *bucket_B;+  int m, pidx, i;++  /* Check arguments. */+  if((T == NULL) || (U == NULL) || (n < 0)) { return -1; }+  else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; }++  if((B = A) == NULL) { B = (int *)malloc((size_t)(n + 1) * sizeof(int)); }+  bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int));+  bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int));++  /* Burrows-Wheeler Transform. */+  if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) {+    m = sort_typeBstar(T, B, bucket_A, bucket_B, n, openMP);++    if (num_indexes == NULL || indexes == NULL) {+        pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m);+    } else {+        pidx = construct_BWT_indexes(T, B, bucket_A, bucket_B, n, m, num_indexes, indexes);+    }++    /* Copy to output string. */+    U[0] = T[n - 1];+    for(i = 0; i < pidx; ++i) { U[i + 1] = (unsigned char)B[i]; }+    for(i += 1; i < n; ++i) { U[i] = (unsigned char)B[i]; }+    pidx += 1;+  } else {+    pidx = -2;+  }++  free(bucket_B);+  free(bucket_A);+  if(A == NULL) { free(B); }++  return pidx;+}
+ zstd/lib/dictBuilder/divsufsort.h view
@@ -0,0 +1,67 @@+/*+ * divsufsort.h for libdivsufsort-lite+ * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved.+ *+ * Permission is hereby granted, free of charge, to any person+ * obtaining a copy of this software and associated documentation+ * files (the "Software"), to deal in the Software without+ * restriction, including without limitation the rights to use,+ * copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the+ * Software is furnished to do so, subject to the following+ * conditions:+ *+ * The above copyright notice and this permission notice shall be+ * included in all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+ * OTHER DEALINGS IN THE SOFTWARE.+ */++#ifndef _DIVSUFSORT_H+#define _DIVSUFSORT_H 1++#ifdef __cplusplus+extern "C" {+#endif /* __cplusplus */+++/*- Prototypes -*/++/**+ * Constructs the suffix array of a given string.+ * @param T [0..n-1] The input string.+ * @param SA [0..n-1] The output array of suffixes.+ * @param n The length of the given string.+ * @param openMP enables OpenMP optimization.+ * @return 0 if no error occurred, -1 or -2 otherwise.+ */+int+divsufsort(const unsigned char *T, int *SA, int n, int openMP);++/**+ * Constructs the burrows-wheeler transformed string of a given string.+ * @param T [0..n-1] The input string.+ * @param U [0..n-1] The output string. (can be T)+ * @param A [0..n-1] The temporary array. (can be NULL)+ * @param n The length of the given string.+ * @param num_indexes The length of secondary indexes array. (can be NULL)+ * @param indexes The secondary indexes array. (can be NULL)+ * @param openMP enables OpenMP optimization.+ * @return The primary index if no error occurred, -1 or -2 otherwise.+ */+int+divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP);+++#ifdef __cplusplus+} /* extern "C" */+#endif /* __cplusplus */++#endif /* _DIVSUFSORT_H */
+ zstd/lib/dictBuilder/zdict.c view
@@ -0,0 +1,1060 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */+++/*-**************************************+*  Tuning parameters+****************************************/+#define ZDICT_MAX_SAMPLES_SIZE (2000U << 20)+#define ZDICT_MIN_SAMPLES_SIZE 512+++/*-**************************************+*  Compiler Options+****************************************/+/* Unix Large Files support (>4GB) */+#define _FILE_OFFSET_BITS 64+#if (defined(__sun__) && (!defined(__LP64__)))   /* Sun Solaris 32-bits requires specific definitions */+#  define _LARGEFILE_SOURCE+#elif ! defined(__LP64__)                        /* No point defining Large file for 64 bit */+#  define _LARGEFILE64_SOURCE+#endif+++/*-*************************************+*  Dependencies+***************************************/+#include <stdlib.h>        /* malloc, free */+#include <string.h>        /* memset */+#include <stdio.h>         /* fprintf, fopen, ftello64 */+#include <time.h>          /* clock */++#include "mem.h"           /* read */+#include "fse.h"           /* FSE_normalizeCount, FSE_writeNCount */+#define HUF_STATIC_LINKING_ONLY+#include "huf.h"           /* HUF_buildCTable, HUF_writeCTable */+#include "zstd_internal.h" /* includes zstd.h */+#include "xxhash.h"        /* XXH64 */+#include "divsufsort.h"+#ifndef ZDICT_STATIC_LINKING_ONLY+#  define ZDICT_STATIC_LINKING_ONLY+#endif+#include "zdict.h"+++/*-*************************************+*  Constants+***************************************/+#define KB *(1 <<10)+#define MB *(1 <<20)+#define GB *(1U<<30)++#define DICTLISTSIZE_DEFAULT 10000++#define NOISELENGTH 32++#define MINRATIO 4+static const int g_compressionLevel_default = 6;+static const U32 g_selectivity_default = 9;+static const size_t g_provision_entropySize = 200;+static const size_t g_min_fast_dictContent = 192;+++/*-*************************************+*  Console display+***************************************/+#define DISPLAY(...)         { fprintf(stderr, __VA_ARGS__); fflush( stderr ); }+#define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); }    /* 0 : no display;   1: errors;   2: default;  3: details;  4: debug */++static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }++static void ZDICT_printHex(const void* ptr, size_t length)+{+    const BYTE* const b = (const BYTE*)ptr;+    size_t u;+    for (u=0; u<length; u++) {+        BYTE c = b[u];+        if (c<32 || c>126) c = '.';   /* non-printable char */+        DISPLAY("%c", c);+    }+}+++/*-********************************************************+*  Helper functions+**********************************************************/+unsigned ZDICT_isError(size_t errorCode) { return ERR_isError(errorCode); }++const char* ZDICT_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }++unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize)+{+    if (dictSize < 8) return 0;+    if (MEM_readLE32(dictBuffer) != ZSTD_DICT_MAGIC) return 0;+    return MEM_readLE32((const char*)dictBuffer + 4);+}+++/*-********************************************************+*  Dictionary training functions+**********************************************************/+static unsigned ZDICT_NbCommonBytes (register size_t val)+{+    if (MEM_isLittleEndian()) {+        if (MEM_64bits()) {+#       if defined(_MSC_VER) && defined(_WIN64)+            unsigned long r = 0;+            _BitScanForward64( &r, (U64)val );+            return (unsigned)(r>>3);+#       elif defined(__GNUC__) && (__GNUC__ >= 3)+            return (__builtin_ctzll((U64)val) >> 3);+#       else+            static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };+            return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];+#       endif+        } else { /* 32 bits */+#       if defined(_MSC_VER)+            unsigned long r=0;+            _BitScanForward( &r, (U32)val );+            return (unsigned)(r>>3);+#       elif defined(__GNUC__) && (__GNUC__ >= 3)+            return (__builtin_ctz((U32)val) >> 3);+#       else+            static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };+            return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];+#       endif+        }+    } else {  /* Big Endian CPU */+        if (MEM_64bits()) {+#       if defined(_MSC_VER) && defined(_WIN64)+            unsigned long r = 0;+            _BitScanReverse64( &r, val );+            return (unsigned)(r>>3);+#       elif defined(__GNUC__) && (__GNUC__ >= 3)+            return (__builtin_clzll(val) >> 3);+#       else+            unsigned r;+            const unsigned n32 = sizeof(size_t)*4;   /* calculate this way due to compiler complaining in 32-bits mode */+            if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }+            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }+            r += (!val);+            return r;+#       endif+        } else { /* 32 bits */+#       if defined(_MSC_VER)+            unsigned long r = 0;+            _BitScanReverse( &r, (unsigned long)val );+            return (unsigned)(r>>3);+#       elif defined(__GNUC__) && (__GNUC__ >= 3)+            return (__builtin_clz((U32)val) >> 3);+#       else+            unsigned r;+            if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }+            r += (!val);+            return r;+#       endif+    }   }+}+++/*! ZDICT_count() :+    Count the nb of common bytes between 2 pointers.+    Note : this function presumes end of buffer followed by noisy guard band.+*/+static size_t ZDICT_count(const void* pIn, const void* pMatch)+{+    const char* const pStart = (const char*)pIn;+    for (;;) {+        size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);+        if (!diff) {+            pIn = (const char*)pIn+sizeof(size_t);+            pMatch = (const char*)pMatch+sizeof(size_t);+            continue;+        }+        pIn = (const char*)pIn+ZDICT_NbCommonBytes(diff);+        return (size_t)((const char*)pIn - pStart);+    }+}+++typedef struct {+    U32 pos;+    U32 length;+    U32 savings;+} dictItem;++static void ZDICT_initDictItem(dictItem* d)+{+    d->pos = 1;+    d->length = 0;+    d->savings = (U32)(-1);+}+++#define LLIMIT 64          /* heuristic determined experimentally */+#define MINMATCHLENGTH 7   /* heuristic determined experimentally */+static dictItem ZDICT_analyzePos(+                       BYTE* doneMarks,+                       const int* suffix, U32 start,+                       const void* buffer, U32 minRatio, U32 notificationLevel)+{+    U32 lengthList[LLIMIT] = {0};+    U32 cumulLength[LLIMIT] = {0};+    U32 savings[LLIMIT] = {0};+    const BYTE* b = (const BYTE*)buffer;+    size_t length;+    size_t maxLength = LLIMIT;+    size_t pos = suffix[start];+    U32 end = start;+    dictItem solution;++    /* init */+    memset(&solution, 0, sizeof(solution));+    doneMarks[pos] = 1;++    /* trivial repetition cases */+    if ( (MEM_read16(b+pos+0) == MEM_read16(b+pos+2))+       ||(MEM_read16(b+pos+1) == MEM_read16(b+pos+3))+       ||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) {+        /* skip and mark segment */+        U16 u16 = MEM_read16(b+pos+4);+        U32 u, e = 6;+        while (MEM_read16(b+pos+e) == u16) e+=2 ;+        if (b[pos+e] == b[pos+e-1]) e++;+        for (u=1; u<e; u++)+            doneMarks[pos+u] = 1;+        return solution;+    }++    /* look forward */+    do {+        end++;+        length = ZDICT_count(b + pos, b + suffix[end]);+    } while (length >=MINMATCHLENGTH);++    /* look backward */+    do {+        length = ZDICT_count(b + pos, b + *(suffix+start-1));+        if (length >=MINMATCHLENGTH) start--;+    } while(length >= MINMATCHLENGTH);++    /* exit if not found a minimum nb of repetitions */+    if (end-start < minRatio) {+        U32 idx;+        for(idx=start; idx<end; idx++)+            doneMarks[suffix[idx]] = 1;+        return solution;+    }++    {   int i;+        U32 searchLength;+        U32 refinedStart = start;+        U32 refinedEnd = end;++        DISPLAYLEVEL(4, "\n");+        DISPLAYLEVEL(4, "found %3u matches of length >= %i at pos %7u  ", (U32)(end-start), MINMATCHLENGTH, (U32)pos);+        DISPLAYLEVEL(4, "\n");++        for (searchLength = MINMATCHLENGTH ; ; searchLength++) {+            BYTE currentChar = 0;+            U32 currentCount = 0;+            U32 currentID = refinedStart;+            U32 id;+            U32 selectedCount = 0;+            U32 selectedID = currentID;+            for (id =refinedStart; id < refinedEnd; id++) {+                if (b[ suffix[id] + searchLength] != currentChar) {+                    if (currentCount > selectedCount) {+                        selectedCount = currentCount;+                        selectedID = currentID;+                    }+                    currentID = id;+                    currentChar = b[ suffix[id] + searchLength];+                    currentCount = 0;+                }+                currentCount ++;+            }+            if (currentCount > selectedCount) {  /* for last */+                selectedCount = currentCount;+                selectedID = currentID;+            }++            if (selectedCount < minRatio)+                break;+            refinedStart = selectedID;+            refinedEnd = refinedStart + selectedCount;+        }++        /* evaluate gain based on new ref */+        start = refinedStart;+        pos = suffix[refinedStart];+        end = start;+        memset(lengthList, 0, sizeof(lengthList));++        /* look forward */+        do {+            end++;+            length = ZDICT_count(b + pos, b + suffix[end]);+            if (length >= LLIMIT) length = LLIMIT-1;+            lengthList[length]++;+        } while (length >=MINMATCHLENGTH);++        /* look backward */+        length = MINMATCHLENGTH;+        while ((length >= MINMATCHLENGTH) & (start > 0)) {+        	length = ZDICT_count(b + pos, b + suffix[start - 1]);+        	if (length >= LLIMIT) length = LLIMIT - 1;+        	lengthList[length]++;+        	if (length >= MINMATCHLENGTH) start--;+        }++        /* largest useful length */+        memset(cumulLength, 0, sizeof(cumulLength));+        cumulLength[maxLength-1] = lengthList[maxLength-1];+        for (i=(int)(maxLength-2); i>=0; i--)+            cumulLength[i] = cumulLength[i+1] + lengthList[i];++        for (i=LLIMIT-1; i>=MINMATCHLENGTH; i--) if (cumulLength[i]>=minRatio) break;+        maxLength = i;++        /* reduce maxLength in case of final into repetitive data */+        {   U32 l = (U32)maxLength;+            BYTE const c = b[pos + maxLength-1];+            while (b[pos+l-2]==c) l--;+            maxLength = l;+        }+        if (maxLength < MINMATCHLENGTH) return solution;   /* skip : no long-enough solution */++        /* calculate savings */+        savings[5] = 0;+        for (i=MINMATCHLENGTH; i<=(int)maxLength; i++)+            savings[i] = savings[i-1] + (lengthList[i] * (i-3));++        DISPLAYLEVEL(4, "Selected ref at position %u, of length %u : saves %u (ratio: %.2f)  \n",+                     (U32)pos, (U32)maxLength, savings[maxLength], (double)savings[maxLength] / maxLength);++        solution.pos = (U32)pos;+        solution.length = (U32)maxLength;+        solution.savings = savings[maxLength];++        /* mark positions done */+        {   U32 id;+            for (id=start; id<end; id++) {+                U32 p, pEnd;+                U32 const testedPos = suffix[id];+                if (testedPos == pos)+                    length = solution.length;+                else {+                    length = ZDICT_count(b+pos, b+testedPos);+                    if (length > solution.length) length = solution.length;+                }+                pEnd = (U32)(testedPos + length);+                for (p=testedPos; p<pEnd; p++)+                    doneMarks[p] = 1;+    }   }   }++    return solution;+}+++/*! ZDICT_checkMerge+    check if dictItem can be merged, do it if possible+    @return : id of destination elt, 0 if not merged+*/+static U32 ZDICT_checkMerge(dictItem* table, dictItem elt, U32 eltNbToSkip)+{+    const U32 tableSize = table->pos;+    const U32 eltEnd = elt.pos + elt.length;++    /* tail overlap */+    U32 u; for (u=1; u<tableSize; u++) {+        if (u==eltNbToSkip) continue;+        if ((table[u].pos > elt.pos) && (table[u].pos <= eltEnd)) {  /* overlap, existing > new */+            /* append */+            U32 addedLength = table[u].pos - elt.pos;+            table[u].length += addedLength;+            table[u].pos = elt.pos;+            table[u].savings += elt.savings * addedLength / elt.length;   /* rough approx */+            table[u].savings += elt.length / 8;    /* rough approx bonus */+            elt = table[u];+            /* sort : improve rank */+            while ((u>1) && (table[u-1].savings < elt.savings))+            table[u] = table[u-1], u--;+            table[u] = elt;+            return u;+    }   }++    /* front overlap */+    for (u=1; u<tableSize; u++) {+        if (u==eltNbToSkip) continue;+        if ((table[u].pos + table[u].length >= elt.pos) && (table[u].pos < elt.pos)) {  /* overlap, existing < new */+            /* append */+            int addedLength = (int)eltEnd - (table[u].pos + table[u].length);+            table[u].savings += elt.length / 8;    /* rough approx bonus */+            if (addedLength > 0) {   /* otherwise, elt fully included into existing */+                table[u].length += addedLength;+                table[u].savings += elt.savings * addedLength / elt.length;   /* rough approx */+            }+            /* sort : improve rank */+            elt = table[u];+            while ((u>1) && (table[u-1].savings < elt.savings))+                table[u] = table[u-1], u--;+            table[u] = elt;+            return u;+    }   }++    return 0;+}+++static void ZDICT_removeDictItem(dictItem* table, U32 id)+{+    /* convention : first element is nb of elts */+    U32 const max = table->pos;+    U32 u;+    if (!id) return;   /* protection, should never happen */+    for (u=id; u<max-1; u++)+        table[u] = table[u+1];+    table->pos--;+}+++static void ZDICT_insertDictItem(dictItem* table, U32 maxSize, dictItem elt)+{+    /* merge if possible */+    U32 mergeId = ZDICT_checkMerge(table, elt, 0);+    if (mergeId) {+        U32 newMerge = 1;+        while (newMerge) {+            newMerge = ZDICT_checkMerge(table, table[mergeId], mergeId);+            if (newMerge) ZDICT_removeDictItem(table, mergeId);+            mergeId = newMerge;+        }+        return;+    }++    /* insert */+    {   U32 current;+        U32 nextElt = table->pos;+        if (nextElt >= maxSize) nextElt = maxSize-1;+        current = nextElt-1;+        while (table[current].savings < elt.savings) {+            table[current+1] = table[current];+            current--;+        }+        table[current+1] = elt;+        table->pos = nextElt+1;+    }+}+++static U32 ZDICT_dictSize(const dictItem* dictList)+{+    U32 u, dictSize = 0;+    for (u=1; u<dictList[0].pos; u++)+        dictSize += dictList[u].length;+    return dictSize;+}+++static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize,+                            const void* const buffer, size_t bufferSize,   /* buffer must end with noisy guard band */+                            const size_t* fileSizes, unsigned nbFiles,+                            U32 minRatio, U32 notificationLevel)+{+    int* const suffix0 = (int*)malloc((bufferSize+2)*sizeof(*suffix0));+    int* const suffix = suffix0+1;+    U32* reverseSuffix = (U32*)malloc((bufferSize)*sizeof(*reverseSuffix));+    BYTE* doneMarks = (BYTE*)malloc((bufferSize+16)*sizeof(*doneMarks));   /* +16 for overflow security */+    U32* filePos = (U32*)malloc(nbFiles * sizeof(*filePos));+    size_t result = 0;+    clock_t displayClock = 0;+    clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10;++#   define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \+            if (ZDICT_clockSpan(displayClock) > refreshRate)  \+            { displayClock = clock(); DISPLAY(__VA_ARGS__); \+            if (notificationLevel>=4) fflush(stdout); } }++    /* init */+    DISPLAYLEVEL(2, "\r%70s\r", "");   /* clean display line */+    if (!suffix0 || !reverseSuffix || !doneMarks || !filePos) {+        result = ERROR(memory_allocation);+        goto _cleanup;+    }+    if (minRatio < MINRATIO) minRatio = MINRATIO;+    memset(doneMarks, 0, bufferSize+16);++    /* limit sample set size (divsufsort limitation)*/+    if (bufferSize > ZDICT_MAX_SAMPLES_SIZE) DISPLAYLEVEL(3, "sample set too large : reduced to %u MB ...\n", (U32)(ZDICT_MAX_SAMPLES_SIZE>>20));+    while (bufferSize > ZDICT_MAX_SAMPLES_SIZE) bufferSize -= fileSizes[--nbFiles];++    /* sort */+    DISPLAYLEVEL(2, "sorting %u files of total size %u MB ...\n", nbFiles, (U32)(bufferSize>>20));+    {   int const divSuftSortResult = divsufsort((const unsigned char*)buffer, suffix, (int)bufferSize, 0);+        if (divSuftSortResult != 0) { result = ERROR(GENERIC); goto _cleanup; }+    }+    suffix[bufferSize] = (int)bufferSize;   /* leads into noise */+    suffix0[0] = (int)bufferSize;           /* leads into noise */+    /* build reverse suffix sort */+    {   size_t pos;+        for (pos=0; pos < bufferSize; pos++)+            reverseSuffix[suffix[pos]] = (U32)pos;+        /* note filePos tracks borders between samples.+           It's not used at this stage, but planned to become useful in a later update */+        filePos[0] = 0;+        for (pos=1; pos<nbFiles; pos++)+            filePos[pos] = (U32)(filePos[pos-1] + fileSizes[pos-1]);+    }++    DISPLAYLEVEL(2, "finding patterns ... \n");+    DISPLAYLEVEL(3, "minimum ratio : %u \n", minRatio);++    {   U32 cursor; for (cursor=0; cursor < bufferSize; ) {+            dictItem solution;+            if (doneMarks[cursor]) { cursor++; continue; }+            solution = ZDICT_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio, notificationLevel);+            if (solution.length==0) { cursor++; continue; }+            ZDICT_insertDictItem(dictList, dictListSize, solution);+            cursor += solution.length;+            DISPLAYUPDATE(2, "\r%4.2f %% \r", (double)cursor / bufferSize * 100);+    }   }++_cleanup:+    free(suffix0);+    free(reverseSuffix);+    free(doneMarks);+    free(filePos);+    return result;+}+++static void ZDICT_fillNoise(void* buffer, size_t length)+{+    unsigned const prime1 = 2654435761U;+    unsigned const prime2 = 2246822519U;+    unsigned acc = prime1;+    size_t p=0;;+    for (p=0; p<length; p++) {+        acc *= prime2;+        ((unsigned char*)buffer)[p] = (unsigned char)(acc >> 21);+    }+}+++typedef struct+{+    ZSTD_CCtx* ref;+    ZSTD_CCtx* zc;+    void* workPlace;   /* must be ZSTD_BLOCKSIZE_ABSOLUTEMAX allocated */+} EStats_ress_t;++#define MAXREPOFFSET 1024++static void ZDICT_countEStats(EStats_ress_t esr, ZSTD_parameters params,+                            U32* countLit, U32* offsetcodeCount, U32* matchlengthCount, U32* litlengthCount, U32* repOffsets,+                            const void* src, size_t srcSize, U32 notificationLevel)+{+    size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << params.cParams.windowLog);+    size_t cSize;++    if (srcSize > blockSizeMax) srcSize = blockSizeMax;   /* protection vs large samples */+    {  size_t const errorCode = ZSTD_copyCCtx(esr.zc, esr.ref, 0);+            if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_copyCCtx failed \n"); return; }+    }+    cSize = ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_ABSOLUTEMAX, src, srcSize);+    if (ZSTD_isError(cSize)) { DISPLAYLEVEL(3, "warning : could not compress sample size %u \n", (U32)srcSize); return; }++    if (cSize) {  /* if == 0; block is not compressible */+        const seqStore_t* seqStorePtr = ZSTD_getSeqStore(esr.zc);++        /* literals stats */+        {   const BYTE* bytePtr;+            for(bytePtr = seqStorePtr->litStart; bytePtr < seqStorePtr->lit; bytePtr++)+                countLit[*bytePtr]++;+        }++        /* seqStats */+        {   U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);+            ZSTD_seqToCodes(seqStorePtr);++            {   const BYTE* codePtr = seqStorePtr->ofCode;+                U32 u;+                for (u=0; u<nbSeq; u++) offsetcodeCount[codePtr[u]]++;+            }++            {   const BYTE* codePtr = seqStorePtr->mlCode;+                U32 u;+                for (u=0; u<nbSeq; u++) matchlengthCount[codePtr[u]]++;+            }++            {   const BYTE* codePtr = seqStorePtr->llCode;+                U32 u;+                for (u=0; u<nbSeq; u++) litlengthCount[codePtr[u]]++;+            }++            if (nbSeq >= 2) { /* rep offsets */+                const seqDef* const seq = seqStorePtr->sequencesStart;+                U32 offset1 = seq[0].offset - 3;+                U32 offset2 = seq[1].offset - 3;+                if (offset1 >= MAXREPOFFSET) offset1 = 0;+                if (offset2 >= MAXREPOFFSET) offset2 = 0;+                repOffsets[offset1] += 3;+                repOffsets[offset2] += 1;+    }   }   }+}++/*+static size_t ZDICT_maxSampleSize(const size_t* fileSizes, unsigned nbFiles)+{+    unsigned u;+    size_t max=0;+    for (u=0; u<nbFiles; u++)+        if (max < fileSizes[u]) max = fileSizes[u];+    return max;+}+*/++static size_t ZDICT_totalSampleSize(const size_t* fileSizes, unsigned nbFiles)+{+    size_t total=0;+    unsigned u;+    for (u=0; u<nbFiles; u++) total += fileSizes[u];+    return total;+}++typedef struct { U32 offset; U32 count; } offsetCount_t;++static void ZDICT_insertSortCount(offsetCount_t table[ZSTD_REP_NUM+1], U32 val, U32 count)+{+    U32 u;+    table[ZSTD_REP_NUM].offset = val;+    table[ZSTD_REP_NUM].count = count;+    for (u=ZSTD_REP_NUM; u>0; u--) {+        offsetCount_t tmp;+        if (table[u-1].count >= table[u].count) break;+        tmp = table[u-1];+        table[u-1] = table[u];+        table[u] = tmp;+    }+}+++#define OFFCODE_MAX 30  /* only applicable to first block */+static size_t ZDICT_analyzeEntropy(void*  dstBuffer, size_t maxDstSize,+                                   unsigned compressionLevel,+                             const void*  srcBuffer, const size_t* fileSizes, unsigned nbFiles,+                             const void* dictBuffer, size_t  dictBufferSize,+                                   unsigned notificationLevel)+{+    U32 countLit[256];+    HUF_CREATE_STATIC_CTABLE(hufTable, 255);+    U32 offcodeCount[OFFCODE_MAX+1];+    short offcodeNCount[OFFCODE_MAX+1];+    U32 offcodeMax = ZSTD_highbit32((U32)(dictBufferSize + 128 KB));+    U32 matchLengthCount[MaxML+1];+    short matchLengthNCount[MaxML+1];+    U32 litLengthCount[MaxLL+1];+    short litLengthNCount[MaxLL+1];+    U32 repOffset[MAXREPOFFSET];+    offsetCount_t bestRepOffset[ZSTD_REP_NUM+1];+    EStats_ress_t esr;+    ZSTD_parameters params;+    U32 u, huffLog = 11, Offlog = OffFSELog, mlLog = MLFSELog, llLog = LLFSELog, total;+    size_t pos = 0, errorCode;+    size_t eSize = 0;+    size_t const totalSrcSize = ZDICT_totalSampleSize(fileSizes, nbFiles);+    size_t const averageSampleSize = totalSrcSize / (nbFiles + !nbFiles);+    BYTE* dstPtr = (BYTE*)dstBuffer;++    /* init */+    esr.ref = ZSTD_createCCtx();+    esr.zc = ZSTD_createCCtx();+    esr.workPlace = malloc(ZSTD_BLOCKSIZE_ABSOLUTEMAX);+    if (!esr.ref || !esr.zc || !esr.workPlace) {+        eSize = ERROR(memory_allocation);+        DISPLAYLEVEL(1, "Not enough memory \n");+        goto _cleanup;+    }+    if (offcodeMax>OFFCODE_MAX) { eSize = ERROR(dictionary_wrong); goto _cleanup; }   /* too large dictionary */+    for (u=0; u<256; u++) countLit[u]=1;   /* any character must be described */+    for (u=0; u<=offcodeMax; u++) offcodeCount[u]=1;+    for (u=0; u<=MaxML; u++) matchLengthCount[u]=1;+    for (u=0; u<=MaxLL; u++) litLengthCount[u]=1;+    memset(repOffset, 0, sizeof(repOffset));+    repOffset[1] = repOffset[4] = repOffset[8] = 1;+    memset(bestRepOffset, 0, sizeof(bestRepOffset));+    if (compressionLevel==0) compressionLevel=g_compressionLevel_default;+    params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize);+    {   size_t const beginResult = ZSTD_compressBegin_advanced(esr.ref, dictBuffer, dictBufferSize, params, 0);+            if (ZSTD_isError(beginResult)) {+            eSize = ERROR(GENERIC);+            DISPLAYLEVEL(1, "error : ZSTD_compressBegin_advanced failed \n");+            goto _cleanup;+    }   }++    /* collect stats on all files */+    for (u=0; u<nbFiles; u++) {+        ZDICT_countEStats(esr, params,+                          countLit, offcodeCount, matchLengthCount, litLengthCount, repOffset,+                         (const char*)srcBuffer + pos, fileSizes[u],+                          notificationLevel);+        pos += fileSizes[u];+    }++    /* analyze */+    errorCode = HUF_buildCTable (hufTable, countLit, 255, huffLog);+    if (HUF_isError(errorCode)) {+        eSize = ERROR(GENERIC);+        DISPLAYLEVEL(1, "HUF_buildCTable error \n");+        goto _cleanup;+    }+    huffLog = (U32)errorCode;++    /* looking for most common first offsets */+    {   U32 offset;+        for (offset=1; offset<MAXREPOFFSET; offset++)+            ZDICT_insertSortCount(bestRepOffset, offset, repOffset[offset]);+    }+    /* note : the result of this phase should be used to better appreciate the impact on statistics */++    total=0; for (u=0; u<=offcodeMax; u++) total+=offcodeCount[u];+    errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, offcodeMax);+    if (FSE_isError(errorCode)) {+        eSize = ERROR(GENERIC);+        DISPLAYLEVEL(1, "FSE_normalizeCount error with offcodeCount \n");+        goto _cleanup;+    }+    Offlog = (U32)errorCode;++    total=0; for (u=0; u<=MaxML; u++) total+=matchLengthCount[u];+    errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML);+    if (FSE_isError(errorCode)) {+        eSize = ERROR(GENERIC);+        DISPLAYLEVEL(1, "FSE_normalizeCount error with matchLengthCount \n");+        goto _cleanup;+    }+    mlLog = (U32)errorCode;++    total=0; for (u=0; u<=MaxLL; u++) total+=litLengthCount[u];+    errorCode = FSE_normalizeCount(litLengthNCount, llLog, litLengthCount, total, MaxLL);+    if (FSE_isError(errorCode)) {+        eSize = ERROR(GENERIC);+        DISPLAYLEVEL(1, "FSE_normalizeCount error with litLengthCount \n");+        goto _cleanup;+    }+    llLog = (U32)errorCode;++    /* write result to buffer */+    {   size_t const hhSize = HUF_writeCTable(dstPtr, maxDstSize, hufTable, 255, huffLog);+        if (HUF_isError(hhSize)) {+            eSize = ERROR(GENERIC);+            DISPLAYLEVEL(1, "HUF_writeCTable error \n");+            goto _cleanup;+        }+        dstPtr += hhSize;+        maxDstSize -= hhSize;+        eSize += hhSize;+    }++    {   size_t const ohSize = FSE_writeNCount(dstPtr, maxDstSize, offcodeNCount, OFFCODE_MAX, Offlog);+        if (FSE_isError(ohSize)) {+            eSize = ERROR(GENERIC);+            DISPLAYLEVEL(1, "FSE_writeNCount error with offcodeNCount \n");+            goto _cleanup;+        }+        dstPtr += ohSize;+        maxDstSize -= ohSize;+        eSize += ohSize;+    }++    {   size_t const mhSize = FSE_writeNCount(dstPtr, maxDstSize, matchLengthNCount, MaxML, mlLog);+        if (FSE_isError(mhSize)) {+            eSize = ERROR(GENERIC);+            DISPLAYLEVEL(1, "FSE_writeNCount error with matchLengthNCount \n");+            goto _cleanup;+        }+        dstPtr += mhSize;+        maxDstSize -= mhSize;+        eSize += mhSize;+    }++    {   size_t const lhSize = FSE_writeNCount(dstPtr, maxDstSize, litLengthNCount, MaxLL, llLog);+        if (FSE_isError(lhSize)) {+            eSize = ERROR(GENERIC);+            DISPLAYLEVEL(1, "FSE_writeNCount error with litlengthNCount \n");+            goto _cleanup;+        }+        dstPtr += lhSize;+        maxDstSize -= lhSize;+        eSize += lhSize;+    }++    if (maxDstSize<12) {+        eSize = ERROR(GENERIC);+        DISPLAYLEVEL(1, "not enough space to write RepOffsets \n");+        goto _cleanup;+    }+# if 0+    MEM_writeLE32(dstPtr+0, bestRepOffset[0].offset);+    MEM_writeLE32(dstPtr+4, bestRepOffset[1].offset);+    MEM_writeLE32(dstPtr+8, bestRepOffset[2].offset);+#else+    /* at this stage, we don't use the result of "most common first offset",+       as the impact of statistics is not properly evaluated */+    MEM_writeLE32(dstPtr+0, repStartValue[0]);+    MEM_writeLE32(dstPtr+4, repStartValue[1]);+    MEM_writeLE32(dstPtr+8, repStartValue[2]);+#endif+    //dstPtr += 12;+    eSize += 12;++_cleanup:+    ZSTD_freeCCtx(esr.ref);+    ZSTD_freeCCtx(esr.zc);+    free(esr.workPlace);++    return eSize;+}++++size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,+                          const void* customDictContent, size_t dictContentSize,+                          const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,+                          ZDICT_params_t params)+{+    size_t hSize;+#define HBUFFSIZE 256+    BYTE header[HBUFFSIZE];+    int const compressionLevel = (params.compressionLevel <= 0) ? g_compressionLevel_default : params.compressionLevel;+    U32 const notificationLevel = params.notificationLevel;++    /* check conditions */+    if (dictBufferCapacity < dictContentSize) return ERROR(dstSize_tooSmall);+    if (dictContentSize < ZDICT_CONTENTSIZE_MIN) return ERROR(srcSize_wrong);+    if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) return ERROR(dstSize_tooSmall);++    /* dictionary header */+    MEM_writeLE32(header, ZSTD_DICT_MAGIC);+    {   U64 const randomID = XXH64(customDictContent, dictContentSize, 0);+        U32 const compliantID = (randomID % ((1U<<31)-32768)) + 32768;+        U32 const dictID = params.dictID ? params.dictID : compliantID;+        MEM_writeLE32(header+4, dictID);+    }+    hSize = 8;++    /* entropy tables */+    DISPLAYLEVEL(2, "\r%70s\r", "");   /* clean display line */+    DISPLAYLEVEL(2, "statistics ... \n");+    {   size_t const eSize = ZDICT_analyzeEntropy(header+hSize, HBUFFSIZE-hSize,+                                  compressionLevel,+                                  samplesBuffer, samplesSizes, nbSamples,+                                  customDictContent, dictContentSize,+                                  notificationLevel);+        if (ZDICT_isError(eSize)) return eSize;+        hSize += eSize;+    }++    /* copy elements in final buffer ; note : src and dst buffer can overlap */+    if (hSize + dictContentSize > dictBufferCapacity) dictContentSize = dictBufferCapacity - hSize;+    {   size_t const dictSize = hSize + dictContentSize;+        char* dictEnd = (char*)dictBuffer + dictSize;+        memmove(dictEnd - dictContentSize, customDictContent, dictContentSize);+        memcpy(dictBuffer, header, hSize);+        return dictSize;+    }+}+++size_t ZDICT_addEntropyTablesFromBuffer_advanced(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,+                                                 const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,+                                                 ZDICT_params_t params)+{+    size_t hSize;+    int const compressionLevel = (params.compressionLevel <= 0) ? g_compressionLevel_default : params.compressionLevel;+    U32 const notificationLevel = params.notificationLevel;++    /* dictionary header */+    MEM_writeLE32(dictBuffer, ZSTD_DICT_MAGIC);+    {   U64 const randomID = XXH64((char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize, 0);+        U32 const compliantID = (randomID % ((1U<<31)-32768)) + 32768;+        U32 const dictID = params.dictID ? params.dictID : compliantID;+        MEM_writeLE32((char*)dictBuffer+4, dictID);+    }+    hSize = 8;++    /* entropy tables */+    DISPLAYLEVEL(2, "\r%70s\r", "");   /* clean display line */+    DISPLAYLEVEL(2, "statistics ... \n");+    {   size_t const eSize = ZDICT_analyzeEntropy((char*)dictBuffer+hSize, dictBufferCapacity-hSize,+                                  compressionLevel,+                                  samplesBuffer, samplesSizes, nbSamples,+                                  (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize,+                                  notificationLevel);+        if (ZDICT_isError(eSize)) return eSize;+        hSize += eSize;+    }+++    if (hSize + dictContentSize < dictBufferCapacity)+        memmove((char*)dictBuffer + hSize, (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize);+    return MIN(dictBufferCapacity, hSize+dictContentSize);+}+++/*! ZDICT_trainFromBuffer_unsafe() :+*   Warning : `samplesBuffer` must be followed by noisy guard band.+*   @return : size of dictionary, or an error code which can be tested with ZDICT_isError()+*/+size_t ZDICT_trainFromBuffer_unsafe(+                            void* dictBuffer, size_t maxDictSize,+                            const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,+                            ZDICT_params_t params)+{+    U32 const dictListSize = MAX(MAX(DICTLISTSIZE_DEFAULT, nbSamples), (U32)(maxDictSize/16));+    dictItem* const dictList = (dictItem*)malloc(dictListSize * sizeof(*dictList));+    unsigned const selectivity = params.selectivityLevel == 0 ? g_selectivity_default : params.selectivityLevel;+    unsigned const minRep = (selectivity > 30) ? MINRATIO : nbSamples >> selectivity;+    size_t const targetDictSize = maxDictSize;+    size_t const samplesBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples);+    size_t dictSize = 0;+    U32 const notificationLevel = params.notificationLevel;++    /* checks */+    if (!dictList) return ERROR(memory_allocation);+    if (maxDictSize <= g_provision_entropySize + g_min_fast_dictContent) { free(dictList); return ERROR(dstSize_tooSmall); }+    if (samplesBuffSize < ZDICT_MIN_SAMPLES_SIZE) { free(dictList); return 0; }   /* not enough source to create dictionary */++    /* init */+    ZDICT_initDictItem(dictList);++    /* build dictionary */+    ZDICT_trainBuffer(dictList, dictListSize,+                    samplesBuffer, samplesBuffSize,+                    samplesSizes, nbSamples,+                    minRep, notificationLevel);++    /* display best matches */+    if (params.notificationLevel>= 3) {+        U32 const nb = MIN(25, dictList[0].pos);+        U32 const dictContentSize = ZDICT_dictSize(dictList);+        U32 u;+        DISPLAYLEVEL(3, "\n %u segments found, of total size %u \n", dictList[0].pos-1, dictContentSize);+        DISPLAYLEVEL(3, "list %u best segments \n", nb-1);+        for (u=1; u<nb; u++) {+            U32 const pos = dictList[u].pos;+            U32 const length = dictList[u].length;+            U32 const printedLength = MIN(40, length);+            if ((pos > samplesBuffSize) || ((pos + length) > samplesBuffSize))+                return ERROR(GENERIC);   /* should never happen */+            DISPLAYLEVEL(3, "%3u:%3u bytes at pos %8u, savings %7u bytes |",+                         u, length, pos, dictList[u].savings);+            ZDICT_printHex((const char*)samplesBuffer+pos, printedLength);+            DISPLAYLEVEL(3, "| \n");+    }   }+++    /* create dictionary */+    {   U32 dictContentSize = ZDICT_dictSize(dictList);+        if (dictContentSize < targetDictSize/3) {+            DISPLAYLEVEL(2, "!  warning : selected content significantly smaller than requested (%u < %u) \n", dictContentSize, (U32)maxDictSize);+            if (minRep > MINRATIO) {+                DISPLAYLEVEL(2, "!  consider increasing selectivity to produce larger dictionary (-s%u) \n", selectivity+1);+                DISPLAYLEVEL(2, "!  note : larger dictionaries are not necessarily better, test its efficiency on samples \n");+            }+            if (samplesBuffSize < 10 * targetDictSize)+                DISPLAYLEVEL(2, "!  consider increasing the number of samples (total size : %u MB)\n", (U32)(samplesBuffSize>>20));+        }++        if ((dictContentSize > targetDictSize*3) && (nbSamples > 2*MINRATIO) && (selectivity>1)) {+            U32 proposedSelectivity = selectivity-1;+            while ((nbSamples >> proposedSelectivity) <= MINRATIO) { proposedSelectivity--; }+            DISPLAYLEVEL(2, "!  note : calculated dictionary significantly larger than requested (%u > %u) \n", dictContentSize, (U32)maxDictSize);+            DISPLAYLEVEL(2, "!  consider increasing dictionary size, or produce denser dictionary (-s%u) \n", proposedSelectivity);+            DISPLAYLEVEL(2, "!  always test dictionary efficiency on samples \n");+        }++        /* limit dictionary size */+        {   U32 const max = dictList->pos;   /* convention : nb of useful elts within dictList */+            U32 currentSize = 0;+            U32 n; for (n=1; n<max; n++) {+                currentSize += dictList[n].length;+                if (currentSize > targetDictSize) { currentSize -= dictList[n].length; break; }+            }+            dictList->pos = n;+            dictContentSize = currentSize;+        }++        /* build dict content */+        {   U32 u;+            BYTE* ptr = (BYTE*)dictBuffer + maxDictSize;+            for (u=1; u<dictList->pos; u++) {+                U32 l = dictList[u].length;+                ptr -= l;+                if (ptr<(BYTE*)dictBuffer) { free(dictList); return ERROR(GENERIC); }   /* should not happen */+                memcpy(ptr, (const char*)samplesBuffer+dictList[u].pos, l);+        }   }++        dictSize = ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, maxDictSize,+                                                             samplesBuffer, samplesSizes, nbSamples,+                                                             params);+    }++    /* clean up */+    free(dictList);+    return dictSize;+}+++/* issue : samplesBuffer need to be followed by a noisy guard band.+*  work around : duplicate the buffer, and add the noise */+size_t ZDICT_trainFromBuffer_advanced(void* dictBuffer, size_t dictBufferCapacity,+                                      const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,+                                      ZDICT_params_t params)+{+    size_t result;+    void* newBuff;+    size_t const sBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples);+    if (sBuffSize < ZDICT_MIN_SAMPLES_SIZE) return 0;   /* not enough content => no dictionary */++    newBuff = malloc(sBuffSize + NOISELENGTH);+    if (!newBuff) return ERROR(memory_allocation);++    memcpy(newBuff, samplesBuffer, sBuffSize);+    ZDICT_fillNoise((char*)newBuff + sBuffSize, NOISELENGTH);   /* guard band, for end of buffer condition */++    result = ZDICT_trainFromBuffer_unsafe(+                                        dictBuffer, dictBufferCapacity,+                                        newBuff, samplesSizes, nbSamples,+                                        params);+    free(newBuff);+    return result;+}+++size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,+                             const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples)+{+    ZDICT_params_t params;+    memset(&params, 0, sizeof(params));+    return ZDICT_trainFromBuffer_advanced(dictBuffer, dictBufferCapacity,+                                          samplesBuffer, samplesSizes, nbSamples,+                                          params);+}++size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,+                                        const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples)+{+    ZDICT_params_t params;+    memset(&params, 0, sizeof(params));+    return ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, dictBufferCapacity,+                                                     samplesBuffer, samplesSizes, nbSamples,+                                                     params);+}
+ zstd/lib/dictBuilder/zdict.h view
@@ -0,0 +1,198 @@+/**+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++#ifndef DICTBUILDER_H_001+#define DICTBUILDER_H_001++#if defined (__cplusplus)+extern "C" {+#endif+++/*======  Dependencies  ======*/+#include <stddef.h>  /* size_t */+++/* =====   ZDICTLIB_API : control library symbols visibility   ===== */+#if defined(__GNUC__) && (__GNUC__ >= 4)+#  define ZDICTLIB_VISIBILITY __attribute__ ((visibility ("default")))+#else+#  define ZDICTLIB_VISIBILITY+#endif+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)+#  define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBILITY+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)+#  define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/+#else+#  define ZDICTLIB_API ZDICTLIB_VISIBILITY+#endif+++/*! ZDICT_trainFromBuffer() :+    Train a dictionary from an array of samples.+    Samples must be stored concatenated in a single flat buffer `samplesBuffer`,+    supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.+    The resulting dictionary will be saved into `dictBuffer`.+    @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)+              or an error code, which can be tested with ZDICT_isError().+    Tips : In general, a reasonable dictionary has a size of ~ 100 KB.+           It's obviously possible to target smaller or larger ones, just by specifying different `dictBufferCapacity`.+           In general, it's recommended to provide a few thousands samples, but this can vary a lot.+           It's recommended that total size of all samples be about ~x100 times the target size of dictionary.+*/+ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,+                       const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples);+++/*======   Helper functions   ======*/+ZDICTLIB_API unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize);  /**< extracts dictID; @return zero if error (not a valid dictionary) */+ZDICTLIB_API unsigned ZDICT_isError(size_t errorCode);+ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode);++++#ifdef ZDICT_STATIC_LINKING_ONLY++/* ====================================================================================+ * The definitions in this section are considered experimental.+ * They should never be used with a dynamic library, as they may change in the future.+ * They are provided for advanced usages.+ * Use them only in association with static linking.+ * ==================================================================================== */++typedef struct {+    unsigned selectivityLevel;   /* 0 means default; larger => select more => larger dictionary */+    int      compressionLevel;   /* 0 means default; target a specific zstd compression level */+    unsigned notificationLevel;  /* Write to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */+    unsigned dictID;             /* 0 means auto mode (32-bits random value); other : force dictID value */+    unsigned reserved[2];        /* reserved space for future parameters */+} ZDICT_params_t;+++/*! ZDICT_trainFromBuffer_advanced() :+    Same as ZDICT_trainFromBuffer() with control over more parameters.+    `parameters` is optional and can be provided with values set to 0 to mean "default".+    @return : size of dictionary stored into `dictBuffer` (<= `dictBufferSize`),+              or an error code, which can be tested by ZDICT_isError().+    note : ZDICT_trainFromBuffer_advanced() will send notifications into stderr if instructed to, using notificationLevel>0.+*/+ZDICTLIB_API size_t ZDICT_trainFromBuffer_advanced(void* dictBuffer, size_t dictBufferCapacity,+                                const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,+                                ZDICT_params_t parameters);++/*! COVER_params_t :+    For all values 0 means default.+    kMin and d are the only required parameters.+*/+typedef struct {+    unsigned k;                  /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */+    unsigned d;                  /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */+    unsigned steps;              /* Number of steps : Only used for optimization : 0 means default (256) : Higher means more parameters checked */++    unsigned notificationLevel;  /* Write to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */+    unsigned dictID;             /* 0 means auto mode (32-bits random value); other : force dictID value */+    int      compressionLevel;   /* 0 means default; target a specific zstd compression level */+} COVER_params_t;+++/*! COVER_trainFromBuffer() :+    Train a dictionary from an array of samples using the COVER algorithm.+    Samples must be stored concatenated in a single flat buffer `samplesBuffer`,+    supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order.+    The resulting dictionary will be saved into `dictBuffer`.+    @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)+              or an error code, which can be tested with ZDICT_isError().+    Tips : In general, a reasonable dictionary has a size of ~ 100 KB.+           It's obviously possible to target smaller or larger ones, just by specifying different `dictBufferCapacity`.+           In general, it's recommended to provide a few thousands samples, but this can vary a lot.+           It's recommended that total size of all samples be about ~x100 times the target size of dictionary.+*/+ZDICTLIB_API size_t COVER_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,+                              const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,+                              COVER_params_t parameters);++/*! COVER_optimizeTrainFromBuffer() :+    The same requirements as above hold for all the parameters except `parameters`.+    This function tries many parameter combinations and picks the best parameters.+    `*parameters` is filled with the best parameters found, and the dictionary+    constructed with those parameters is stored in `dictBuffer`.++    All of the parameters d, k, steps are optional.+    If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8, 10, 12, 14, 16}.+    if steps is zero it defaults to its default value.+    If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [16, 2048].++    @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)+              or an error code, which can be tested with ZDICT_isError().+              On success `*parameters` contains the parameters selected.+*/+ZDICTLIB_API size_t COVER_optimizeTrainFromBuffer(void* dictBuffer, size_t dictBufferCapacity,+                                     const void* samplesBuffer, const size_t *samplesSizes, unsigned nbSamples,+                                     COVER_params_t *parameters);++/*! ZDICT_finalizeDictionary() :++    Given a custom content as a basis for dictionary, and a set of samples,+    finalize dictionary by adding headers and statistics.++    Samples must be stored concatenated in a flat buffer `samplesBuffer`,+    supplied with an array of sizes `samplesSizes`, providing the size of each sample in order.++    dictContentSize must be > ZDICT_CONTENTSIZE_MIN bytes.+    maxDictSize must be >= dictContentSize, and must be > ZDICT_DICTSIZE_MIN bytes.++    @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`),+              or an error code, which can be tested by ZDICT_isError().+    note : ZDICT_finalizeDictionary() will push notifications into stderr if instructed to, using notificationLevel>0.+    note 2 : dictBuffer and customDictContent can overlap+*/+#define ZDICT_CONTENTSIZE_MIN 256+#define ZDICT_DICTSIZE_MIN    512+ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dictBuffer, size_t dictBufferCapacity,+                                const void* customDictContent, size_t dictContentSize,+                                const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,+                                ZDICT_params_t parameters);++++/* Deprecation warnings */+/* It is generally possible to disable deprecation warnings from compiler,+   for example with -Wno-deprecated-declarations for gcc+   or _CRT_SECURE_NO_WARNINGS in Visual.+   Otherwise, it's also possible to manually define ZDICT_DISABLE_DEPRECATE_WARNINGS */+#ifdef ZDICT_DISABLE_DEPRECATE_WARNINGS+#  define ZDICT_DEPRECATED(message) ZDICTLIB_API   /* disable deprecation warnings */+#else+#  define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)+#  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API [[deprecated(message)]]+#  elif (ZDICT_GCC_VERSION >= 405) || defined(__clang__)+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated(message)))+#  elif (ZDICT_GCC_VERSION >= 301)+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API __attribute__((deprecated))+#  elif defined(_MSC_VER)+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API __declspec(deprecated(message))+#  else+#    pragma message("WARNING: You need to implement ZDICT_DEPRECATED for this compiler")+#    define ZDICT_DEPRECATED(message) ZDICTLIB_API+#  endif+#endif /* ZDICT_DISABLE_DEPRECATE_WARNINGS */++ZDICT_DEPRECATED("use ZDICT_finalizeDictionary() instead")+size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity,+                                  const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples);+++#endif   /* ZDICT_STATIC_LINKING_ONLY */++#if defined (__cplusplus)+}+#endif++#endif   /* DICTBUILDER_H_001 */
+ zstd/lib/zstd.h view
@@ -0,0 +1,692 @@+/*+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.+ * All rights reserved.+ *+ * This source code is licensed under the BSD-style license found in the+ * LICENSE file in the root directory of this source tree. An additional grant+ * of patent rights can be found in the PATENTS file in the same directory.+ */++#if defined (__cplusplus)+extern "C" {+#endif++#ifndef ZSTD_H_235446+#define ZSTD_H_235446++/* ======   Dependency   ======*/+#include <stddef.h>   /* size_t */+++/* =====   ZSTDLIB_API : control library symbols visibility   ===== */+#if defined(__GNUC__) && (__GNUC__ >= 4)+#  define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default")))+#else+#  define ZSTDLIB_VISIBILITY+#endif+#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1)+#  define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY+#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1)+#  define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/+#else+#  define ZSTDLIB_API ZSTDLIB_VISIBILITY+#endif+++/*******************************************************************************************************+  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, labelled `--ultra`, should be used with caution, as they require more memory.+  Compression can be done in:+    - a single step (described as Simple API)+    - 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)++  Advanced experimental functions can be accessed using #define ZSTD_STATIC_LINKING_ONLY before including zstd.h.+  These APIs shall never be used with a dynamic library.+  They are not "stable", their definition may change in the future. Only static linking is allowed.+*********************************************************************************************************/++/*------   Version   ------*/+#define ZSTD_VERSION_MAJOR    1+#define ZSTD_VERSION_MINOR    1+#define ZSTD_VERSION_RELEASE  3++#define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE+#define ZSTD_QUOTE(str) #str+#define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str)+#define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION)++#define ZSTD_VERSION_NUMBER  (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)+ZSTDLIB_API unsigned ZSTD_versionNumber(void);   /**< library version number; to be used when checking dll version */+++/***************************************+*  Simple API+***************************************/+/*! ZSTD_compress() :+    Compresses `src` content as a single zstd compressed frame into already allocated `dst`.+    Hint : compression runs faster if `dstCapacity` >=  `ZSTD_compressBound(srcSize)`.+    @return : compressed size written into `dst` (<= `dstCapacity),+              or an error code if it fails (which can be tested using ZSTD_isError()). */+ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity,+                            const void* src, size_t srcSize,+                                  int compressionLevel);++/*! ZSTD_decompress() :+    `compressedSize` : must be the _exact_ size of a single compressed frame.+    `dstCapacity` is an upper bound of originalSize.+    If user cannot imply a maximum upper bound, it's better to use streaming mode to decompress data.+    @return : the number of bytes decompressed into `dst` (<= `dstCapacity`),+              or an errorCode if it fails (which can be tested using ZSTD_isError()). */+ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,+                              const void* src, size_t compressedSize);++/*! ZSTD_getDecompressedSize() :+*   'src' is the start of a zstd compressed frame.+*   @return : content size to be decompressed, as a 64-bits value _if known_, 0 otherwise.+*    note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode.+*             When `return==0`, data to decompress could be any size.+*             In which case, it's necessary to use streaming mode to decompress data.+*             Optionally, application can still use ZSTD_decompress() while relying on implied limits.+*             (For example, data may be necessarily cut into blocks <= 16 KB).+*    note 2 : decompressed size is always present when compression is done with ZSTD_compress()+*    note 3 : decompressed size can be very large (64-bits value),+*             potentially larger than what local system can handle as a single memory segment.+*             In which case, it's necessary to use streaming mode to decompress data.+*    note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified.+*             Always ensure result fits within application's authorized limits.+*             Each application can set its own limits.+*    note 5 : when `return==0`, if precise failure cause is needed, use ZSTD_getFrameParams() to know more. */+ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);+++/*======  Helper functions  ======*/+ZSTDLIB_API int         ZSTD_maxCLevel(void);               /*!< maximum compression level available */+ZSTDLIB_API size_t      ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case scenario */+ZSTDLIB_API unsigned    ZSTD_isError(size_t code);          /*!< tells if a `size_t` function result is an error code */+ZSTDLIB_API const char* ZSTD_getErrorName(size_t code);     /*!< provides readable string from an error code */+++/***************************************+*  Explicit memory management+***************************************/+/*= Compression context+*   When compressing many times,+*   it is recommended to allocate a context just once, and re-use it for each successive compression operation.+*   This will make workload friendlier for system's memory.+*   Use one context per thread for parallel execution in multi-threaded environments. */+typedef struct ZSTD_CCtx_s ZSTD_CCtx;+ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void);+ZSTDLIB_API size_t     ZSTD_freeCCtx(ZSTD_CCtx* cctx);++/*! ZSTD_compressCCtx() :+    Same as ZSTD_compress(), requires an allocated ZSTD_CCtx (see ZSTD_createCCtx()). */+ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel);++/*= Decompression context */+typedef struct ZSTD_DCtx_s ZSTD_DCtx;+ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void);+ZSTDLIB_API size_t     ZSTD_freeDCtx(ZSTD_DCtx* dctx);++/*! ZSTD_decompressDCtx() :+*   Same as ZSTD_decompress(), requires an allocated ZSTD_DCtx (see ZSTD_createDCtx()). */+ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);+++/**************************+*  Simple dictionary API+***************************/+/*! ZSTD_compress_usingDict() :+*   Compression using a predefined Dictionary (see dictBuilder/zdict.h).+*   Note : This function loads the dictionary, resulting in significant startup delay.+*   Note : When `dict == NULL || dictSize < 8` no dictionary is used. */+ZSTDLIB_API 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,+                                           int compressionLevel);++/*! ZSTD_decompress_usingDict() :+*   Decompression using a predefined Dictionary (see dictBuilder/zdict.h).+*   Dictionary must be identical to the one used during compression.+*   Note : This function loads the dictionary, resulting in significant startup delay.+*   Note : When `dict == NULL || dictSize < 8` no dictionary is used. */+ZSTDLIB_API 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);+++/****************************+*  Fast dictionary API+****************************/+typedef struct ZSTD_CDict_s ZSTD_CDict;++/*! ZSTD_createCDict() :+*   When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once.+*   ZSTD_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.+*   ZSTD_CDict can be created once and used by multiple threads concurrently, as its usage is read-only.+*   `dictBuffer` can be released after ZSTD_CDict creation, as its content is copied within CDict */+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize, int compressionLevel);++/*! ZSTD_freeCDict() :+*   Function frees memory allocated by ZSTD_createCDict(). */+ZSTDLIB_API size_t      ZSTD_freeCDict(ZSTD_CDict* CDict);++/*! 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. */+ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,+                                            void* dst, size_t dstCapacity,+                                      const void* src, size_t srcSize,+                                      const ZSTD_CDict* cdict);+++typedef struct ZSTD_DDict_s ZSTD_DDict;++/*! ZSTD_createDDict() :+*   Create a digested dictionary, ready to start decompression operation without startup delay.+*   dictBuffer can be released after DDict creation, as its content is copied inside DDict */+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize);++/*! ZSTD_freeDDict() :+*   Function frees memory allocated with ZSTD_createDDict() */+ZSTDLIB_API size_t      ZSTD_freeDDict(ZSTD_DDict* ddict);++/*! ZSTD_decompress_usingDDict() :+*   Decompression using a digested Dictionary.+*   Faster startup than ZSTD_decompress_usingDict(), recommended when same dictionary is used multiple times. */+ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,+                                              void* dst, size_t dstCapacity,+                                        const void* src, size_t srcSize,+                                        const ZSTD_DDict* ddict);+++/****************************+*  Streaming+****************************/++typedef struct ZSTD_inBuffer_s {+  const void* src;    /**< start of input buffer */+  size_t size;        /**< size of input buffer */+  size_t pos;         /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */+} ZSTD_inBuffer;++typedef struct ZSTD_outBuffer_s {+  void*  dst;         /**< start of output buffer */+  size_t size;        /**< size of output buffer */+  size_t pos;         /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */+} ZSTD_outBuffer;++++/*-***********************************************************************+*  Streaming compression - HowTo+*+*  A ZSTD_CStream object is required to track streaming operation.+*  Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources.+*  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,+*  since it will play nicer with system's memory, by re-using already allocated memory.+*  Use one separate ZSTD_CStream per thread for parallel execution.+*+*  Start a new compression by initializing ZSTD_CStream.+*  Use ZSTD_initCStream() to start a new compression operation.+*  Use ZSTD_initCStream_usingDict() or ZSTD_initCStream_usingCDict() for a compression which requires a dictionary (experimental section)+*+*  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.+*  @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.+*            Note 2 : size hint is guaranteed to be <= ZSTD_CStreamInSize()+*+*  At any moment, it's possible to flush whatever data remains within internal buffer, using ZSTD_flushStream().+*  `output->pos` will be updated.+*  Note that some content might still be left within internal buffer if `output->size` is too small.+*  @return : nb of bytes still present within internal buffer (0 if it's empty)+*            or an error code, which can be tested using ZSTD_isError().+*+*  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.+*  @return : nb of bytes still present within internal buffer (0 if it's empty, hence compression completed)+*            or an error code, which can be tested using ZSTD_isError().+*+* *******************************************************************/++typedef struct ZSTD_CStream_s ZSTD_CStream;+ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void);+ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs);++ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel);+ZSTDLIB_API size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input);+ZSTDLIB_API size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);+ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);++ZSTDLIB_API size_t ZSTD_CStreamInSize(void);    /**< recommended size for input buffer */+ZSTDLIB_API size_t ZSTD_CStreamOutSize(void);   /**< recommended size for output buffer. Guarantee to successfully flush at least one complete compressed block in all circumstances. */++++/*-***************************************************************************+*  Streaming decompression - HowTo+*+*  A ZSTD_DStream object is required to track streaming operations.+*  Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources.+*  ZSTD_DStream objects can be re-used multiple times.+*+*  Use ZSTD_initDStream() to start a new decompression operation,+*   or ZSTD_initDStream_usingDict() if decompression requires a dictionary.+*   @return : recommended first input size+*+*  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.+*  @return : 0 when a frame is completely decoded and fully flushed,+*            an error code, which can be tested using ZSTD_isError(),+*            any other value > 0, which means there is still some decoding to do to complete current frame.+*            The return value is a suggested next input size (a hint to improve latency) that will never load more than the current frame.+* *******************************************************************************/++typedef struct ZSTD_DStream_s ZSTD_DStream;+ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void);+ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds);++ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds);+ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input);++ZSTDLIB_API size_t ZSTD_DStreamInSize(void);    /*!< recommended size for input buffer */+ZSTDLIB_API size_t ZSTD_DStreamOutSize(void);   /*!< recommended size for output buffer. Guarantee to successfully flush at least one complete block in all circumstances. */++#endif  /* ZSTD_H_235446 */+++#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY)+#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY++/****************************************************************************************+ * START OF ADVANCED AND EXPERIMENTAL FUNCTIONS+ * The definitions in this section are considered experimental.+ * They should never be used with a dynamic library, as they may change in the future.+ * They are provided for advanced usages.+ * Use them only in association with static linking.+ * ***************************************************************************************/++/* --- Constants ---*/+#define ZSTD_MAGICNUMBER            0xFD2FB528   /* >= v0.8.0 */+#define ZSTD_MAGIC_SKIPPABLE_START  0x184D2A50U++#define ZSTD_WINDOWLOG_MAX_32  25+#define ZSTD_WINDOWLOG_MAX_64  27+#define ZSTD_WINDOWLOG_MAX    ((U32)(MEM_32bits() ? 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+#define ZSTD_SEARCHLENGTH_MAX   7   /* only for ZSTD_fast, other strategies are limited to 6 */+#define ZSTD_SEARCHLENGTH_MIN   3   /* only for ZSTD_btopt, other strategies are limited to 4 */+#define ZSTD_TARGETLENGTH_MIN   4+#define ZSTD_TARGETLENGTH_MAX 999++#define ZSTD_FRAMEHEADERSIZE_MAX 18    /* for static allocation */+#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;+static const size_t ZSTD_skippableHeaderSize = 8;  /* magic number + skippable frame length */+++/*--- Advanced types ---*/+typedef enum { ZSTD_fast, ZSTD_dfast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_btopt, ZSTD_btopt2 } ZSTD_strategy;   /* from faster to stronger */++typedef struct {+    unsigned windowLog;      /**< largest match distance : larger == more compression, more memory needed during decompression */+    unsigned chainLog;       /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */+    unsigned hashLog;        /**< dispatch table : larger == faster, more memory */+    unsigned searchLog;      /**< nb of searches : larger == more compression, slower */+    unsigned searchLength;   /**< match length searched : larger == faster decompression, sometimes less compression */+    unsigned targetLength;   /**< acceptable match size for optimal parser (only) : larger == more compression, slower */+    ZSTD_strategy strategy;+} ZSTD_compressionParameters;++typedef struct {+    unsigned contentSizeFlag; /**< 1: content size will be in frame header (if known). */+    unsigned checksumFlag;    /**< 1: will generate a 22-bits checksum at end of frame, to be used for error detection by decompressor */+    unsigned noDictIDFlag;    /**< 1: no dict ID will be saved into frame header (if dictionary compression) */+} ZSTD_frameParameters;++typedef struct {+    ZSTD_compressionParameters cParams;+    ZSTD_frameParameters fParams;+} ZSTD_parameters;++/*= 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;+++/***************************************+*  Advanced compression functions+***************************************/+/*! ZSTD_estimateCCtxSize() :+ *  Gives the amount of memory allocated for a ZSTD_CCtx given a set of compression parameters.+ *  `frameContentSize` is an optional parameter, provide `0` if unknown */+ZSTDLIB_API size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams);++/*! ZSTD_createCCtx_advanced() :+ *  Create a ZSTD compression context using external alloc and free functions */+ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem);++/*! ZSTD_sizeofCCtx() :+ *  Gives the amount of memory used by a given ZSTD_CCtx */+ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx);++/*! ZSTD_createCDict_byReference() :+ *  Create a digested dictionary for compression+ *  Dictionary content is simply referenced, and therefore stays in dictBuffer.+ *  It is important that dictBuffer outlives CDict, it must remain read accessible throughout the lifetime of CDict */+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel);++/*! ZSTD_createCDict_advanced() :+ *  Create a ZSTD_CDict using external alloc and free, and customized compression parameters */+ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, unsigned byReference,+                                                  ZSTD_parameters params, ZSTD_customMem customMem);++/*! ZSTD_sizeof_CDict() :+ *  Gives the amount of memory used by a given ZSTD_sizeof_CDict */+ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict);++/*! ZSTD_getCParams() :+*   @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize.+*   `estimatedSrcSize` value is optional, select 0 if not known */+ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);++/*! ZSTD_getParams() :+*   same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`.+*   All fields of `ZSTD_frameParameters` are set to default (0) */+ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize);++/*! ZSTD_checkCParams() :+*   Ensure param values remain within authorized range */+ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params);++/*! ZSTD_adjustCParams() :+*   optimize params for a given `srcSize` and `dictSize`.+*   both values are optional, select `0` if unknown. */+ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize);++/*! ZSTD_compress_advanced() :+*   Same as ZSTD_compress_usingDict(), with fine-tune control of each compression parameter */+ZSTDLIB_API size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,+                                           void* dst, size_t dstCapacity,+                                     const void* src, size_t srcSize,+                                     const void* dict,size_t dictSize,+                                           ZSTD_parameters params);+++/*--- Advanced decompression functions ---*/++/*! 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. */+ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size);++/*! ZSTD_estimateDCtxSize() :+ *  Gives the potential amount of memory allocated to create a ZSTD_DCtx */+ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void);++/*! ZSTD_createDCtx_advanced() :+ *  Create a ZSTD decompression context using external alloc and free functions */+ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem);++/*! ZSTD_sizeof_DCtx() :+ *  Gives the amount of memory used by a given ZSTD_DCtx */+ZSTDLIB_API size_t ZSTD_sizeof_DCtx(const ZSTD_DCtx* dctx);++/*! ZSTD_createDDict_byReference() :+ *  Create a digested dictionary, ready to start decompression operation without startup delay.+ *  Dictionary content is simply referenced, and therefore stays in dictBuffer.+ *  It is important that dictBuffer outlives DDict, it must remain read accessible throughout the lifetime of DDict */+ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize);++ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize,+                                                  unsigned byReference, ZSTD_customMem customMem);++/*! ZSTD_sizeof_DDict() :+ *  Gives the amount of memory used by a given ZSTD_DDict */+ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);++/*! 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. */+ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize);++/*! 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. */+ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict);++/*! 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. */+ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);+++/********************************************************************+*  Advanced streaming functions+********************************************************************/++/*=====   Advanced Streaming compression functions  =====*/+ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem);+ZSTDLIB_API size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize);   /**< pledgedSrcSize must be correct */+ZSTDLIB_API size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel);+ZSTDLIB_API size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, const void* dict, size_t dictSize,+                                             ZSTD_parameters params, unsigned long long pledgedSrcSize);  /**< pledgedSrcSize is optional and can be zero == unknown */+ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict);  /**< note : cdict will just be referenced, and must outlive compression session */+ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize);  /**< re-use compression parameters from previous init; skip dictionary loading stage; zcs must be init at least once before */+ZSTDLIB_API size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs);+++/*=====   Advanced Streaming decompression functions  =====*/+typedef enum { ZSTDdsp_maxWindowSize } ZSTD_DStreamParameter_e;+ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem);+ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize);+ZSTDLIB_API size_t ZSTD_setDStreamParameter(ZSTD_DStream* zds, ZSTD_DStreamParameter_e paramType, unsigned paramValue);+ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict);  /**< note : ddict will just be referenced, and must outlive decompression session */+ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);  /**< re-use decompression parameters from previous init; saves dictionary loading */+ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds);+++/*********************************************************************+*  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_createCCtx() / ZSTD_freeCCtx() to manage resource.+  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 a NULL,0 src content, in which case, it will write a final empty block to end the frame,+  Without last block mark, frames will be considered unfinished (broken) by decoders.++  You can then reuse `ZSTD_CCtx` (ZSTD_compressBegin()) to compress some new frame.+*/++/*=====   Buffer-less streaming compression functions  =====*/+ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel);+ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel);+ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize);+ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize);+ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);+ZSTDLIB_API 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_createDCtx() / ZSTD_freeDCtx() to manage it.+  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 : content size 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 correctly filled.+           >0 : `srcSize` is too small, please provide at least @result bytes on next attempt.+           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.++  @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.+  It also returns Frame Size as fparamsPtr->frameContentSize.+*/++typedef struct {+    unsigned long long frameContentSize;+    unsigned windowSize;+    unsigned dictID;+    unsigned checksumFlag;+} ZSTD_frameParams;++/*=====   Buffer-less streaming decompression functions  =====*/+ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize);   /**< doesn't consume input, see details below */+ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx);+ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize);+ZSTDLIB_API void   ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx);+ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx);+ZSTDLIB_API 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;+ZSTDLIB_API 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_createCCtx() and ZSTD_createDCtx()+    - 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 ZSTD_BLOCKSIZE_ABSOLUTEMAX (128 * 1024)   /* define, for static allocation */+/*=====   Raw zstd block functions  =====*/+ZSTDLIB_API size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx);+ZSTDLIB_API size_t ZSTD_compressBlock  (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);+ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize);+ZSTDLIB_API size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize);  /**< insert block into `dctx` history. Useful for uncompressed blocks */+++#endif   /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */++#if defined (__cplusplus)+}+#endif