grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/3] btrfs: Import kernel zstd


From: Gregg Levine
Subject: Re: [PATCH 1/3] btrfs: Import kernel zstd
Date: Mon, 27 Aug 2018 22:14:36 -0400

Hello!
I'm not the fellow who approves patches but I get my e-mail via Google
Mail and while I do like the patch Google did not.like it. I had to
pull it from the Spam bucket.
-----
Gregg C Levine address@hidden
"This signature fought the Time Wars, time and again."


On Mon, Aug 27, 2018 at 9:36 PM, Nick Terrell <address@hidden> wrote:
> Import xxhash and zstd from the upstream kernel as-is. This will not
> compile. The next patch in the series contains all the changes needed to
> make zstd compile in grub. Only the files needed for decompression are
> imported from zstd.
>
> The files are copied from these locations:
> include/linux/{xxhash,zstd}.h
> lib/xxhash.c
> lib/zstd/
>
> Signed-off-by: Nick Terrell <address@hidden>
> ---
>  grub-core/lib/zstd/bitstream.h      |  374 ++++++
>  grub-core/lib/zstd/decompress.c     | 2528 
> +++++++++++++++++++++++++++++++++++
>  grub-core/lib/zstd/entropy_common.c |  243 ++++
>  grub-core/lib/zstd/error_private.h  |   53 +
>  grub-core/lib/zstd/fse.h            |  575 ++++++++
>  grub-core/lib/zstd/fse_decompress.c |  332 +++++
>  grub-core/lib/zstd/huf.h            |  212 +++
>  grub-core/lib/zstd/huf_decompress.c |  960 +++++++++++++
>  grub-core/lib/zstd/mem.h            |  151 +++
>  grub-core/lib/zstd/xxhash.c         |  500 +++++++
>  grub-core/lib/zstd/xxhash.h         |  236 ++++
>  grub-core/lib/zstd/zstd.h           | 1157 ++++++++++++++++
>  grub-core/lib/zstd/zstd_common.c    |   75 ++
>  grub-core/lib/zstd/zstd_internal.h  |  263 ++++
>  14 files changed, 7659 insertions(+)
>  create mode 100644 grub-core/lib/zstd/bitstream.h
>  create mode 100644 grub-core/lib/zstd/decompress.c
>  create mode 100644 grub-core/lib/zstd/entropy_common.c
>  create mode 100644 grub-core/lib/zstd/error_private.h
>  create mode 100644 grub-core/lib/zstd/fse.h
>  create mode 100644 grub-core/lib/zstd/fse_decompress.c
>  create mode 100644 grub-core/lib/zstd/huf.h
>  create mode 100644 grub-core/lib/zstd/huf_decompress.c
>  create mode 100644 grub-core/lib/zstd/mem.h
>  create mode 100644 grub-core/lib/zstd/xxhash.c
>  create mode 100644 grub-core/lib/zstd/xxhash.h
>  create mode 100644 grub-core/lib/zstd/zstd.h
>  create mode 100644 grub-core/lib/zstd/zstd_common.c
>  create mode 100644 grub-core/lib/zstd/zstd_internal.h
>
> diff --git a/grub-core/lib/zstd/bitstream.h b/grub-core/lib/zstd/bitstream.h
> new file mode 100644
> index 000000000..a826b99e1
> --- /dev/null
> +++ b/grub-core/lib/zstd/bitstream.h
> @@ -0,0 +1,374 @@
> +/*
> + * bitstream
> + * Part of FSE library
> + * header file (to include)
> + * Copyright (C) 2013-2016, Yann Collet.
> + *
> + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the following disclaimer
> + * in the documentation and/or other materials provided with the
> + * distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + *
> + * You can contact the author at :
> + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
> + */
> +#ifndef BITSTREAM_H_MODULE
> +#define BITSTREAM_H_MODULE
> +
> +/*
> +*  This API consists of small unitary functions, which must be inlined for 
> best performance.
> +*  Since link-time-optimization is not available for all compilers,
> +*  these functions are defined into a .h to be included.
> +*/
> +
> +/*-****************************************
> +*  Dependencies
> +******************************************/
> +#include "error_private.h" /* error codes and messages */
> +#include "mem.h"          /* unaligned access routines */
> +
> +/*=========================================
> +*  Target specific
> +=========================================*/
> +#define STREAM_ACCUMULATOR_MIN_32 25
> +#define STREAM_ACCUMULATOR_MIN_64 57
> +#define STREAM_ACCUMULATOR_MIN ((U32)(ZSTD_32bits() ? 
> STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64))
> +
> +/*-******************************************
> +*  bitStream encoding API (write forward)
> +********************************************/
> +/* bitStream can mix input from multiple sources.
> +*  A critical property of these streams is that they encode and decode in 
> **reverse** direction.
> +*  So the first bit sequence you add will be the last to be read, like a 
> LIFO stack.
> +*/
> +typedef struct {
> +       size_t bitContainer;
> +       int bitPos;
> +       char *startPtr;
> +       char *ptr;
> +       char *endPtr;
> +} BIT_CStream_t;
> +
> +ZSTD_STATIC size_t BIT_initCStream(BIT_CStream_t *bitC, void *dstBuffer, 
> size_t dstCapacity);
> +ZSTD_STATIC void BIT_addBits(BIT_CStream_t *bitC, size_t value, unsigned 
> nbBits);
> +ZSTD_STATIC void BIT_flushBits(BIT_CStream_t *bitC);
> +ZSTD_STATIC size_t BIT_closeCStream(BIT_CStream_t *bitC);
> +
> +/* Start with initCStream, providing the size of buffer to write into.
> +*  bitStream will never write outside of this buffer.
> +*  `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return 
> will be an error code.
> +*
> +*  bits are first added to a local register.
> +*  Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 
> 32-bits systems.
> +*  Writing data into memory is an explicit operation, performed by the 
> flushBits function.
> +*  Hence keep track how many bits are potentially stored into local register 
> to avoid register overflow.
> +*  After a flushBits, a maximum of 7 bits might still be stored into local 
> register.
> +*
> +*  Avoid storing elements of more than 24 bits if you want compatibility 
> with 32-bits bitstream readers.
> +*
> +*  Last operation is to close the bitStream.
> +*  The function returns the final size of CStream in bytes.
> +*  If data couldn't fit into `dstBuffer`, it will return a 0 ( == not 
> storable)
> +*/
> +
> +/*-********************************************
> +*  bitStream decoding API (read backward)
> +**********************************************/
> +typedef struct {
> +       size_t bitContainer;
> +       unsigned bitsConsumed;
> +       const char *ptr;
> +       const char *start;
> +} BIT_DStream_t;
> +
> +typedef enum {
> +       BIT_DStream_unfinished = 0,
> +       BIT_DStream_endOfBuffer = 1,
> +       BIT_DStream_completed = 2,
> +       BIT_DStream_overflow = 3
> +} BIT_DStream_status; /* result of BIT_reloadDStream() */
> +/* 1,2,4,8 would be better for bitmap combinations, but slows down 
> performance a bit ... :( */
> +
> +ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void 
> *srcBuffer, size_t srcSize);
> +ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, unsigned nbBits);
> +ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD);
> +ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *bitD);
> +
> +/* Start by invoking BIT_initDStream().
> +*  A chunk of the bitStream is then stored into a local register.
> +*  Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits 
> systems (size_t).
> +*  You can then retrieve bitFields stored into the local register, **in 
> reverse order**.
> +*  Local register is explicitly reloaded from memory by the 
> BIT_reloadDStream() method.
> +*  A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits 
> when its result is BIT_DStream_unfinished.
> +*  Otherwise, it can be less than that, so proceed accordingly.
> +*  Checking if DStream has reached its end can be performed with 
> BIT_endOfDStream().
> +*/
> +
> +/*-****************************************
> +*  unsafe API
> +******************************************/
> +ZSTD_STATIC void BIT_addBitsFast(BIT_CStream_t *bitC, size_t value, unsigned 
> nbBits);
> +/* faster, but works only if value is "clean", meaning all high bits above 
> nbBits are 0 */
> +
> +ZSTD_STATIC void BIT_flushBitsFast(BIT_CStream_t *bitC);
> +/* unsafe version; does not check buffer overflow */
> +
> +ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, unsigned nbBits);
> +/* faster, but works only if nbBits >= 1 */
> +
> +/*-**************************************************************
> +*  Internal functions
> +****************************************************************/
> +ZSTD_STATIC unsigned BIT_highbit32(register U32 val) { return 31 - 
> __builtin_clz(val); }
> +
> +/*=====    Local Constants   =====*/
> +static const unsigned BIT_mask[] = {0,       1,       3,       7,      0xF,  
>     0x1F,     0x3F,     0x7F,      0xFF,
> +                                   0x1FF,   0x3FF,   0x7FF,   0xFFF,    
> 0x1FFF,   0x3FFF,   0x7FFF,   0xFFFF,    0x1FFFF,
> +                                   0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 
> 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF}; /* up to 26 bits */
> +
> +/*-**************************************************************
> +*  bitStream encoding
> +****************************************************************/
> +/*! BIT_initCStream() :
> + *  `dstCapacity` must be > sizeof(void*)
> + *  @return : 0 if success,
> +                         otherwise an error code (can be tested using 
> ERR_isError() ) */
> +ZSTD_STATIC size_t BIT_initCStream(BIT_CStream_t *bitC, void *startPtr, 
> size_t dstCapacity)
> +{
> +       bitC->bitContainer = 0;
> +       bitC->bitPos = 0;
> +       bitC->startPtr = (char *)startPtr;
> +       bitC->ptr = bitC->startPtr;
> +       bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->ptr);
> +       if (dstCapacity <= sizeof(bitC->ptr))
> +               return ERROR(dstSize_tooSmall);
> +       return 0;
> +}
> +
> +/*! BIT_addBits() :
> +       can add up to 26 bits into `bitC`.
> +       Does not check for register overflow ! */
> +ZSTD_STATIC void BIT_addBits(BIT_CStream_t *bitC, size_t value, unsigned 
> nbBits)
> +{
> +       bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
> +       bitC->bitPos += nbBits;
> +}
> +
> +/*! BIT_addBitsFast() :
> + *  works only if `value` is _clean_, meaning all high bits above nbBits are 
> 0 */
> +ZSTD_STATIC void BIT_addBitsFast(BIT_CStream_t *bitC, size_t value, unsigned 
> nbBits)
> +{
> +       bitC->bitContainer |= value << bitC->bitPos;
> +       bitC->bitPos += nbBits;
> +}
> +
> +/*! BIT_flushBitsFast() :
> + *  unsafe version; does not check buffer overflow */
> +ZSTD_STATIC void BIT_flushBitsFast(BIT_CStream_t *bitC)
> +{
> +       size_t const nbBytes = bitC->bitPos >> 3;
> +       ZSTD_writeLEST(bitC->ptr, bitC->bitContainer);
> +       bitC->ptr += nbBytes;
> +       bitC->bitPos &= 7;
> +       bitC->bitContainer >>= nbBytes * 8; /* if bitPos >= 
> sizeof(bitContainer)*8 --> undefined behavior */
> +}
> +
> +/*! BIT_flushBits() :
> + *  safe version; check for buffer overflow, and prevents it.
> + *  note : does not signal buffer overflow. This will be revealed later on 
> using BIT_closeCStream() */
> +ZSTD_STATIC void BIT_flushBits(BIT_CStream_t *bitC)
> +{
> +       size_t const nbBytes = bitC->bitPos >> 3;
> +       ZSTD_writeLEST(bitC->ptr, bitC->bitContainer);
> +       bitC->ptr += nbBytes;
> +       if (bitC->ptr > bitC->endPtr)
> +               bitC->ptr = bitC->endPtr;
> +       bitC->bitPos &= 7;
> +       bitC->bitContainer >>= nbBytes * 8; /* if bitPos >= 
> sizeof(bitContainer)*8 --> undefined behavior */
> +}
> +
> +/*! BIT_closeCStream() :
> + *  @return : size of CStream, in bytes,
> +                         or 0 if it could not fit into dstBuffer */
> +ZSTD_STATIC size_t BIT_closeCStream(BIT_CStream_t *bitC)
> +{
> +       BIT_addBitsFast(bitC, 1, 1); /* endMark */
> +       BIT_flushBits(bitC);
> +
> +       if (bitC->ptr >= bitC->endPtr)
> +               return 0; /* doesn't fit within authorized budget : cancel */
> +
> +       return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
> +}
> +
> +/*-********************************************************
> +* bitStream decoding
> +**********************************************************/
> +/*! BIT_initDStream() :
> +*   Initialize a BIT_DStream_t.
> +*   `bitD` : a pointer to an already allocated BIT_DStream_t structure.
> +*   `srcSize` must be the *exact* size of the bitStream, in bytes.
> +*   @return : size of stream (== srcSize) or an errorCode if a problem is 
> detected
> +*/
> +ZSTD_STATIC size_t BIT_initDStream(BIT_DStream_t *bitD, const void 
> *srcBuffer, size_t srcSize)
> +{
> +       if (srcSize < 1) {
> +               memset(bitD, 0, sizeof(*bitD));
> +               return ERROR(srcSize_wrong);
> +       }
> +
> +       if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
> +               bitD->start = (const char *)srcBuffer;
> +               bitD->ptr = (const char *)srcBuffer + srcSize - 
> sizeof(bitD->bitContainer);
> +               bitD->bitContainer = ZSTD_readLEST(bitD->ptr);
> +               {
> +                       BYTE const lastByte = ((const BYTE 
> *)srcBuffer)[srcSize - 1];
> +                       bitD->bitsConsumed = lastByte ? 8 - 
> BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
> +                       if (lastByte == 0)
> +                               return ERROR(GENERIC); /* endMark not present 
> */
> +               }
> +       } else {
> +               bitD->start = (const char *)srcBuffer;
> +               bitD->ptr = bitD->start;
> +               bitD->bitContainer = *(const BYTE *)(bitD->start);
> +               switch (srcSize) {
> +               case 7: bitD->bitContainer += (size_t)(((const BYTE 
> *)(srcBuffer))[6]) << (sizeof(bitD->bitContainer) * 8 - 16);
> +               case 6: bitD->bitContainer += (size_t)(((const BYTE 
> *)(srcBuffer))[5]) << (sizeof(bitD->bitContainer) * 8 - 24);
> +               case 5: bitD->bitContainer += (size_t)(((const BYTE 
> *)(srcBuffer))[4]) << (sizeof(bitD->bitContainer) * 8 - 32);
> +               case 4: bitD->bitContainer += (size_t)(((const BYTE 
> *)(srcBuffer))[3]) << 24;
> +               case 3: bitD->bitContainer += (size_t)(((const BYTE 
> *)(srcBuffer))[2]) << 16;
> +               case 2: bitD->bitContainer += (size_t)(((const BYTE 
> *)(srcBuffer))[1]) << 8;
> +               default:;
> +               }
> +               {
> +                       BYTE const lastByte = ((const BYTE 
> *)srcBuffer)[srcSize - 1];
> +                       bitD->bitsConsumed = lastByte ? 8 - 
> BIT_highbit32(lastByte) : 0;
> +                       if (lastByte == 0)
> +                               return ERROR(GENERIC); /* endMark not present 
> */
> +               }
> +               bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - 
> srcSize) * 8;
> +       }
> +
> +       return srcSize;
> +}
> +
> +ZSTD_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) { 
> return bitContainer >> start; }
> +
> +ZSTD_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, 
> U32 const nbBits) { return (bitContainer >> start) & BIT_mask[nbBits]; }
> +
> +ZSTD_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) { 
> return bitContainer & BIT_mask[nbBits]; }
> +
> +/*! BIT_lookBits() :
> + *  Provides next n bits from local register.
> + *  local register is not modified.
> + *  On 32-bits, maxNbBits==24.
> + *  On 64-bits, maxNbBits==56.
> + *  @return : value extracted
> + */
> +ZSTD_STATIC size_t BIT_lookBits(const BIT_DStream_t *bitD, U32 nbBits)
> +{
> +       U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1;
> +       return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) 
> >> ((bitMask - nbBits) & bitMask);
> +}
> +
> +/*! BIT_lookBitsFast() :
> +*   unsafe version; only works only if nbBits >= 1 */
> +ZSTD_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t *bitD, U32 nbBits)
> +{
> +       U32 const bitMask = sizeof(bitD->bitContainer) * 8 - 1;
> +       return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 
> (((bitMask + 1) - nbBits) & bitMask);
> +}
> +
> +ZSTD_STATIC void BIT_skipBits(BIT_DStream_t *bitD, U32 nbBits) { 
> bitD->bitsConsumed += nbBits; }
> +
> +/*! BIT_readBits() :
> + *  Read (consume) next n bits from local register and update.
> + *  Pay attention to not read more than nbBits contained into local register.
> + *  @return : extracted value.
> + */
> +ZSTD_STATIC size_t BIT_readBits(BIT_DStream_t *bitD, U32 nbBits)
> +{
> +       size_t const value = BIT_lookBits(bitD, nbBits);
> +       BIT_skipBits(bitD, nbBits);
> +       return value;
> +}
> +
> +/*! BIT_readBitsFast() :
> +*   unsafe version; only works only if nbBits >= 1 */
> +ZSTD_STATIC size_t BIT_readBitsFast(BIT_DStream_t *bitD, U32 nbBits)
> +{
> +       size_t const value = BIT_lookBitsFast(bitD, nbBits);
> +       BIT_skipBits(bitD, nbBits);
> +       return value;
> +}
> +
> +/*! BIT_reloadDStream() :
> +*   Refill `bitD` from buffer previously set in BIT_initDStream() .
> +*   This function is safe, it guarantees it will not read beyond src buffer.
> +*   @return : status of `BIT_DStream_t` internal register.
> +                         if status == BIT_DStream_unfinished, internal 
> register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
> +ZSTD_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t *bitD)
> +{
> +       if (bitD->bitsConsumed > (sizeof(bitD->bitContainer) * 8)) /* should 
> not happen => corruption detected */
> +               return BIT_DStream_overflow;
> +
> +       if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
> +               bitD->ptr -= bitD->bitsConsumed >> 3;
> +               bitD->bitsConsumed &= 7;
> +               bitD->bitContainer = ZSTD_readLEST(bitD->ptr);
> +               return BIT_DStream_unfinished;
> +       }
> +       if (bitD->ptr == bitD->start) {
> +               if (bitD->bitsConsumed < sizeof(bitD->bitContainer) * 8)
> +                       return BIT_DStream_endOfBuffer;
> +               return BIT_DStream_completed;
> +       }
> +       {
> +               U32 nbBytes = bitD->bitsConsumed >> 3;
> +               BIT_DStream_status result = BIT_DStream_unfinished;
> +               if (bitD->ptr - nbBytes < bitD->start) {
> +                       nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > 
> start */
> +                       result = BIT_DStream_endOfBuffer;
> +               }
> +               bitD->ptr -= nbBytes;
> +               bitD->bitsConsumed -= nbBytes * 8;
> +               bitD->bitContainer = ZSTD_readLEST(bitD->ptr); /* reminder : 
> srcSize > sizeof(bitD) */
> +               return result;
> +       }
> +}
> +
> +/*! BIT_endOfDStream() :
> +*   @return Tells if DStream has exactly reached its end (all bits consumed).
> +*/
> +ZSTD_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t *DStream)
> +{
> +       return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == 
> sizeof(DStream->bitContainer) * 8));
> +}
> +
> +#endif /* BITSTREAM_H_MODULE */
> diff --git a/grub-core/lib/zstd/decompress.c b/grub-core/lib/zstd/decompress.c
> new file mode 100644
> index 000000000..b17846725
> --- /dev/null
> +++ b/grub-core/lib/zstd/decompress.c
> @@ -0,0 +1,2528 @@
> +/**
> + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
> + * All rights reserved.
> + *
> + * This source code is licensed under the BSD-style license found in the
> + * LICENSE file in the root directory of https://github.com/facebook/zstd.
> + * An additional grant of patent rights can be found in the PATENTS file in 
> the
> + * same directory.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + */
> +
> +/* ***************************************************************
> +*  Tuning parameters
> +*****************************************************************/
> +/*!
> +*  MAXWINDOWSIZE_DEFAULT :
> +*  maximum window size accepted by DStream, by default.
> +*  Frames requiring more memory will be rejected.
> +*/
> +#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
> +#define ZSTD_MAXWINDOWSIZE_DEFAULT ((1 << ZSTD_WINDOWLOG_MAX) + 1) /* 
> defined within zstd.h */
> +#endif
> +
> +/*-*******************************************************
> +*  Dependencies
> +*********************************************************/
> +#include "fse.h"
> +#include "huf.h"
> +#include "mem.h" /* low level memory routines */
> +#include "zstd_internal.h"
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/string.h> /* memcpy, memmove, memset */
> +
> +#define ZSTD_PREFETCH(ptr) __builtin_prefetch(ptr, 0, 0)
> +
> +/*-*************************************
> +*  Macros
> +***************************************/
> +#define ZSTD_isError ERR_isError /* for inlining */
> +#define FSE_isError ERR_isError
> +#define HUF_isError ERR_isError
> +
> +/*_*******************************************************
> +*  Memory operations
> +**********************************************************/
> +static void ZSTD_copy4(void *dst, const void *src) { memcpy(dst, src, 4); }
> +
> +/*-*************************************************************
> +*   Context management
> +***************************************************************/
> +typedef enum {
> +       ZSTDds_getFrameHeaderSize,
> +       ZSTDds_decodeFrameHeader,
> +       ZSTDds_decodeBlockHeader,
> +       ZSTDds_decompressBlock,
> +       ZSTDds_decompressLastBlock,
> +       ZSTDds_checkChecksum,
> +       ZSTDds_decodeSkippableHeader,
> +       ZSTDds_skipFrame
> +} ZSTD_dStage;
> +
> +typedef struct {
> +       FSE_DTable LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)];
> +       FSE_DTable OFTable[FSE_DTABLE_SIZE_U32(OffFSELog)];
> +       FSE_DTable MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)];
> +       HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate 
> HUF_decompress4X */
> +       U64 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32 / 2];
> +       U32 rep[ZSTD_REP_NUM];
> +} ZSTD_entropyTables_t;
> +
> +struct ZSTD_DCtx_s {
> +       const FSE_DTable *LLTptr;
> +       const FSE_DTable *MLTptr;
> +       const FSE_DTable *OFTptr;
> +       const HUF_DTable *HUFptr;
> +       ZSTD_entropyTables_t entropy;
> +       const void *previousDstEnd; /* detect continuity */
> +       const void *base;          /* start of curr segment */
> +       const void *vBase;        /* virtual start of previous segment if it 
> was just before curr one */
> +       const void *dictEnd;    /* end of previous segment */
> +       size_t expected;
> +       ZSTD_frameParams fParams;
> +       blockType_e bType; /* used in ZSTD_decompressContinue(), to transfer 
> blockType between header decoding and block decoding stages */
> +       ZSTD_dStage stage;
> +       U32 litEntropy;
> +       U32 fseEntropy;
> +       struct xxh64_state xxhState;
> +       size_t headerSize;
> +       U32 dictID;
> +       const BYTE *litPtr;
> +       ZSTD_customMem customMem;
> +       size_t litSize;
> +       size_t rleSize;
> +       BYTE litBuffer[ZSTD_BLOCKSIZE_ABSOLUTEMAX + WILDCOPY_OVERLENGTH];
> +       BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
> +}; /* typedef'd to ZSTD_DCtx within "zstd.h" */
> +
> +size_t ZSTD_DCtxWorkspaceBound(void) { return ZSTD_ALIGN(sizeof(ZSTD_stack)) 
> + ZSTD_ALIGN(sizeof(ZSTD_DCtx)); }
> +
> +size_t ZSTD_decompressBegin(ZSTD_DCtx *dctx)
> +{
> +       dctx->expected = ZSTD_frameHeaderSize_prefix;
> +       dctx->stage = ZSTDds_getFrameHeaderSize;
> +       dctx->previousDstEnd = NULL;
> +       dctx->base = NULL;
> +       dctx->vBase = NULL;
> +       dctx->dictEnd = NULL;
> +       dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* 
> cover both little and big endian */
> +       dctx->litEntropy = dctx->fseEntropy = 0;
> +       dctx->dictID = 0;
> +       ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == 
> sizeof(repStartValue));
> +       memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* 
> initial repcodes */
> +       dctx->LLTptr = dctx->entropy.LLTable;
> +       dctx->MLTptr = dctx->entropy.MLTable;
> +       dctx->OFTptr = dctx->entropy.OFTable;
> +       dctx->HUFptr = dctx->entropy.hufTable;
> +       return 0;
> +}
> +
> +ZSTD_DCtx *ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
> +{
> +       ZSTD_DCtx *dctx;
> +
> +       if (!customMem.customAlloc || !customMem.customFree)
> +               return NULL;
> +
> +       dctx = (ZSTD_DCtx *)ZSTD_malloc(sizeof(ZSTD_DCtx), customMem);
> +       if (!dctx)
> +               return NULL;
> +       memcpy(&dctx->customMem, &customMem, sizeof(customMem));
> +       ZSTD_decompressBegin(dctx);
> +       return dctx;
> +}
> +
> +ZSTD_DCtx *ZSTD_initDCtx(void *workspace, size_t workspaceSize)
> +{
> +       ZSTD_customMem const stackMem = ZSTD_initStack(workspace, 
> workspaceSize);
> +       return ZSTD_createDCtx_advanced(stackMem);
> +}
> +
> +size_t ZSTD_freeDCtx(ZSTD_DCtx *dctx)
> +{
> +       if (dctx == NULL)
> +               return 0; /* support free on NULL */
> +       ZSTD_free(dctx, dctx->customMem);
> +       return 0; /* reserved as a potential error code in the future */
> +}
> +
> +void ZSTD_copyDCtx(ZSTD_DCtx *dstDCtx, const ZSTD_DCtx *srcDCtx)
> +{
> +       size_t const workSpaceSize = (ZSTD_BLOCKSIZE_ABSOLUTEMAX + 
> WILDCOPY_OVERLENGTH) + ZSTD_frameHeaderSize_max;
> +       memcpy(dstDCtx, srcDCtx, sizeof(ZSTD_DCtx) - workSpaceSize); /* no 
> need to copy workspace */
> +}
> +
> +static void ZSTD_refDDict(ZSTD_DCtx *dstDCtx, const ZSTD_DDict *ddict);
> +
> +/*-*************************************************************
> +*   Decompression section
> +***************************************************************/
> +
> +/*! ZSTD_isFrame() :
> + *  Tells if the content of `buffer` starts with a valid Frame Identifier.
> + *  Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always 
> be 0.
> + *  Note 2 : Legacy Frame Identifiers are considered valid only if Legacy 
> Support is enabled.
> + *  Note 3 : Skippable Frame Identifiers are considered valid. */
> +unsigned ZSTD_isFrame(const void *buffer, size_t size)
> +{
> +       if (size < 4)
> +               return 0;
> +       {
> +               U32 const magic = ZSTD_readLE32(buffer);
> +               if (magic == ZSTD_MAGICNUMBER)
> +                       return 1;
> +               if ((magic & 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START)
> +                       return 1;
> +       }
> +       return 0;
> +}
> +
> +/** ZSTD_frameHeaderSize() :
> +*   srcSize must be >= ZSTD_frameHeaderSize_prefix.
> +*   @return : size of the Frame Header */
> +static size_t ZSTD_frameHeaderSize(const void *src, size_t srcSize)
> +{
> +       if (srcSize < ZSTD_frameHeaderSize_prefix)
> +               return ERROR(srcSize_wrong);
> +       {
> +               BYTE const fhd = ((const BYTE *)src)[4];
> +               U32 const dictID = fhd & 3;
> +               U32 const singleSegment = (fhd >> 5) & 1;
> +               U32 const fcsId = fhd >> 6;
> +               return ZSTD_frameHeaderSize_prefix + !singleSegment + 
> ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId] + (singleSegment && 
> !fcsId);
> +       }
> +}
> +
> +/** ZSTD_getFrameParams() :
> +*   decode Frame Header, or require larger `srcSize`.
> +*   @return : 0, `fparamsPtr` is correctly filled,
> +*            >0, `srcSize` is too small, result is expected `srcSize`,
> +*             or an error code, which can be tested using ZSTD_isError() */
> +size_t ZSTD_getFrameParams(ZSTD_frameParams *fparamsPtr, const void *src, 
> size_t srcSize)
> +{
> +       const BYTE *ip = (const BYTE *)src;
> +
> +       if (srcSize < ZSTD_frameHeaderSize_prefix)
> +               return ZSTD_frameHeaderSize_prefix;
> +       if (ZSTD_readLE32(src) != ZSTD_MAGICNUMBER) {
> +               if ((ZSTD_readLE32(src) & 0xFFFFFFF0U) == 
> ZSTD_MAGIC_SKIPPABLE_START) {
> +                       if (srcSize < ZSTD_skippableHeaderSize)
> +                               return ZSTD_skippableHeaderSize; /* magic 
> number + skippable frame length */
> +                       memset(fparamsPtr, 0, sizeof(*fparamsPtr));
> +                       fparamsPtr->frameContentSize = ZSTD_readLE32((const 
> char *)src + 4);
> +                       fparamsPtr->windowSize = 0; /* windowSize==0 means a 
> frame is skippable */
> +                       return 0;
> +               }
> +               return ERROR(prefix_unknown);
> +       }
> +
> +       /* ensure there is enough `srcSize` to fully read/decode frame header 
> */
> +       {
> +               size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize);
> +               if (srcSize < fhsize)
> +                       return fhsize;
> +       }
> +
> +       {
> +               BYTE const fhdByte = ip[4];
> +               size_t pos = 5;
> +               U32 const dictIDSizeCode = fhdByte & 3;
> +               U32 const checksumFlag = (fhdByte >> 2) & 1;
> +               U32 const singleSegment = (fhdByte >> 5) & 1;
> +               U32 const fcsID = fhdByte >> 6;
> +               U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX;
> +               U32 windowSize = 0;
> +               U32 dictID = 0;
> +               U64 frameContentSize = 0;
> +               if ((fhdByte & 0x08) != 0)
> +                       return ERROR(frameParameter_unsupported); /* reserved 
> bits, which must be zero */
> +               if (!singleSegment) {
> +                       BYTE const wlByte = ip[pos++];
> +                       U32 const windowLog = (wlByte >> 3) + 
> ZSTD_WINDOWLOG_ABSOLUTEMIN;
> +                       if (windowLog > ZSTD_WINDOWLOG_MAX)
> +                               return ERROR(frameParameter_windowTooLarge); 
> /* avoids issue with 1 << windowLog */
> +                       windowSize = (1U << windowLog);
> +                       windowSize += (windowSize >> 3) * (wlByte & 7);
> +               }
> +
> +               switch (dictIDSizeCode) {
> +               default: /* impossible */
> +               case 0: break;
> +               case 1:
> +                       dictID = ip[pos];
> +                       pos++;
> +                       break;
> +               case 2:
> +                       dictID = ZSTD_readLE16(ip + pos);
> +                       pos += 2;
> +                       break;
> +               case 3:
> +                       dictID = ZSTD_readLE32(ip + pos);
> +                       pos += 4;
> +                       break;
> +               }
> +               switch (fcsID) {
> +               default: /* impossible */
> +               case 0:
> +                       if (singleSegment)
> +                               frameContentSize = ip[pos];
> +                       break;
> +               case 1: frameContentSize = ZSTD_readLE16(ip + pos) + 256; 
> break;
> +               case 2: frameContentSize = ZSTD_readLE32(ip + pos); break;
> +               case 3: frameContentSize = ZSTD_readLE64(ip + pos); break;
> +               }
> +               if (!windowSize)
> +                       windowSize = (U32)frameContentSize;
> +               if (windowSize > windowSizeMax)
> +                       return ERROR(frameParameter_windowTooLarge);
> +               fparamsPtr->frameContentSize = frameContentSize;
> +               fparamsPtr->windowSize = windowSize;
> +               fparamsPtr->dictID = dictID;
> +               fparamsPtr->checksumFlag = checksumFlag;
> +       }
> +       return 0;
> +}
> +
> +/** ZSTD_getFrameContentSize() :
> +*   compatible with legacy mode
> +*   @return : decompressed size of the single frame pointed to be `src` if 
> known, otherwise
> +*             - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
> +*             - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid 
> magic number, srcSize too small) */
> +unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
> +{
> +       {
> +               ZSTD_frameParams fParams;
> +               if (ZSTD_getFrameParams(&fParams, src, srcSize) != 0)
> +                       return ZSTD_CONTENTSIZE_ERROR;
> +               if (fParams.windowSize == 0) {
> +                       /* Either skippable or empty frame, size == 0 either 
> way */
> +                       return 0;
> +               } else if (fParams.frameContentSize != 0) {
> +                       return fParams.frameContentSize;
> +               } else {
> +                       return ZSTD_CONTENTSIZE_UNKNOWN;
> +               }
> +       }
> +}
> +
> +/** ZSTD_findDecompressedSize() :
> + *  compatible with legacy mode
> + *  `srcSize` must be the exact length of some number of ZSTD compressed 
> and/or
> + *      skippable frames
> + *  @return : decompressed size of the frames contained */
> +unsigned long long ZSTD_findDecompressedSize(const void *src, size_t srcSize)
> +{
> +       {
> +               unsigned long long totalDstSize = 0;
> +               while (srcSize >= ZSTD_frameHeaderSize_prefix) {
> +                       const U32 magicNumber = ZSTD_readLE32(src);
> +
> +                       if ((magicNumber & 0xFFFFFFF0U) == 
> ZSTD_MAGIC_SKIPPABLE_START) {
> +                               size_t skippableSize;
> +                               if (srcSize < ZSTD_skippableHeaderSize)
> +                                       return ERROR(srcSize_wrong);
> +                               skippableSize = ZSTD_readLE32((const BYTE 
> *)src + 4) + ZSTD_skippableHeaderSize;
> +                               if (srcSize < skippableSize) {
> +                                       return ZSTD_CONTENTSIZE_ERROR;
> +                               }
> +
> +                               src = (const BYTE *)src + skippableSize;
> +                               srcSize -= skippableSize;
> +                               continue;
> +                       }
> +
> +                       {
> +                               unsigned long long const ret = 
> ZSTD_getFrameContentSize(src, srcSize);
> +                               if (ret >= ZSTD_CONTENTSIZE_ERROR)
> +                                       return ret;
> +
> +                               /* check for overflow */
> +                               if (totalDstSize + ret < totalDstSize)
> +                                       return ZSTD_CONTENTSIZE_ERROR;
> +                               totalDstSize += ret;
> +                       }
> +                       {
> +                               size_t const frameSrcSize = 
> ZSTD_findFrameCompressedSize(src, srcSize);
> +                               if (ZSTD_isError(frameSrcSize)) {
> +                                       return ZSTD_CONTENTSIZE_ERROR;
> +                               }
> +
> +                               src = (const BYTE *)src + frameSrcSize;
> +                               srcSize -= frameSrcSize;
> +                       }
> +               }
> +
> +               if (srcSize) {
> +                       return ZSTD_CONTENTSIZE_ERROR;
> +               }
> +
> +               return totalDstSize;
> +       }
> +}
> +
> +/** ZSTD_decodeFrameHeader() :
> +*   `headerSize` must be the size provided by ZSTD_frameHeaderSize().
> +*   @return : 0 if success, or an error code, which can be tested using 
> ZSTD_isError() */
> +static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx *dctx, const void *src, 
> size_t headerSize)
> +{
> +       size_t const result = ZSTD_getFrameParams(&(dctx->fParams), src, 
> headerSize);
> +       if (ZSTD_isError(result))
> +               return result; /* invalid header */
> +       if (result > 0)
> +               return ERROR(srcSize_wrong); /* headerSize too small */
> +       if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID))
> +               return ERROR(dictionary_wrong);
> +       if (dctx->fParams.checksumFlag)
> +               xxh64_reset(&dctx->xxhState, 0);
> +       return 0;
> +}
> +
> +typedef struct {
> +       blockType_e blockType;
> +       U32 lastBlock;
> +       U32 origSize;
> +} blockProperties_t;
> +
> +/*! ZSTD_getcBlockSize() :
> +*   Provides the size of compressed block from block header `src` */
> +size_t ZSTD_getcBlockSize(const void *src, size_t srcSize, blockProperties_t 
> *bpPtr)
> +{
> +       if (srcSize < ZSTD_blockHeaderSize)
> +               return ERROR(srcSize_wrong);
> +       {
> +               U32 const cBlockHeader = ZSTD_readLE24(src);
> +               U32 const cSize = cBlockHeader >> 3;
> +               bpPtr->lastBlock = cBlockHeader & 1;
> +               bpPtr->blockType = (blockType_e)((cBlockHeader >> 1) & 3);
> +               bpPtr->origSize = cSize; /* only useful for RLE */
> +               if (bpPtr->blockType == bt_rle)
> +                       return 1;
> +               if (bpPtr->blockType == bt_reserved)
> +                       return ERROR(corruption_detected);
> +               return cSize;
> +       }
> +}
> +
> +static size_t ZSTD_copyRawBlock(void *dst, size_t dstCapacity, const void 
> *src, size_t srcSize)
> +{
> +       if (srcSize > dstCapacity)
> +               return ERROR(dstSize_tooSmall);
> +       memcpy(dst, src, srcSize);
> +       return srcSize;
> +}
> +
> +static size_t ZSTD_setRleBlock(void *dst, size_t dstCapacity, const void 
> *src, size_t srcSize, size_t regenSize)
> +{
> +       if (srcSize != 1)
> +               return ERROR(srcSize_wrong);
> +       if (regenSize > dstCapacity)
> +               return ERROR(dstSize_tooSmall);
> +       memset(dst, *(const BYTE *)src, regenSize);
> +       return regenSize;
> +}
> +
> +/*! ZSTD_decodeLiteralsBlock() :
> +       @return : nb of bytes read from src (< srcSize ) */
> +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx *dctx, const void *src, size_t 
> srcSize) /* note : srcSize < BLOCKSIZE */
> +{
> +       if (srcSize < MIN_CBLOCK_SIZE)
> +               return ERROR(corruption_detected);
> +
> +       {
> +               const BYTE *const istart = (const BYTE *)src;
> +               symbolEncodingType_e const litEncType = 
> (symbolEncodingType_e)(istart[0] & 3);
> +
> +               switch (litEncType) {
> +               case set_repeat:
> +                       if (dctx->litEntropy == 0)
> +                               return ERROR(dictionary_corrupted);
> +               /* fall-through */
> +               case set_compressed:
> +                       if (srcSize < 5)
> +                               return ERROR(corruption_detected); /* srcSize 
> >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3 */
> +                       {
> +                               size_t lhSize, litSize, litCSize;
> +                               U32 singleStream = 0;
> +                               U32 const lhlCode = (istart[0] >> 2) & 3;
> +                               U32 const lhc = ZSTD_readLE32(istart);
> +                               switch (lhlCode) {
> +                               case 0:
> +                               case 1:
> +                               default: /* note : default is impossible, 
> since lhlCode into [0..3] */
> +                                       /* 2 - 2 - 10 - 10 */
> +                                       singleStream = !lhlCode;
> +                                       lhSize = 3;
> +                                       litSize = (lhc >> 4) & 0x3FF;
> +                                       litCSize = (lhc >> 14) & 0x3FF;
> +                                       break;
> +                               case 2:
> +                                       /* 2 - 2 - 14 - 14 */
> +                                       lhSize = 4;
> +                                       litSize = (lhc >> 4) & 0x3FFF;
> +                                       litCSize = lhc >> 18;
> +                                       break;
> +                               case 3:
> +                                       /* 2 - 2 - 18 - 18 */
> +                                       lhSize = 5;
> +                                       litSize = (lhc >> 4) & 0x3FFFF;
> +                                       litCSize = (lhc >> 22) + (istart[4] 
> << 10);
> +                                       break;
> +                               }
> +                               if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX)
> +                                       return ERROR(corruption_detected);
> +                               if (litCSize + lhSize > srcSize)
> +                                       return ERROR(corruption_detected);
> +
> +                               if (HUF_isError(
> +                                       (litEncType == set_repeat)
> +                                           ? (singleStream ? 
> HUF_decompress1X_usingDTable(dctx->litBuffer, litSize, istart + lhSize, 
> litCSize, dctx->HUFptr)
> +                                                           : 
> HUF_decompress4X_usingDTable(dctx->litBuffer, litSize, istart + lhSize, 
> litCSize, dctx->HUFptr))
> +                                           : (singleStream
> +                                                  ? 
> HUF_decompress1X2_DCtx_wksp(dctx->entropy.hufTable, dctx->litBuffer, litSize, 
> istart + lhSize, litCSize,
> +                                                                             
>    dctx->entropy.workspace, sizeof(dctx->entropy.workspace))
> +                                                  : 
> HUF_decompress4X_hufOnly_wksp(dctx->entropy.hufTable, dctx->litBuffer, 
> litSize, istart + lhSize, litCSize,
> +                                                                             
>      dctx->entropy.workspace, sizeof(dctx->entropy.workspace)))))
> +                                       return ERROR(corruption_detected);
> +
> +                               dctx->litPtr = dctx->litBuffer;
> +                               dctx->litSize = litSize;
> +                               dctx->litEntropy = 1;
> +                               if (litEncType == set_compressed)
> +                                       dctx->HUFptr = dctx->entropy.hufTable;
> +                               memset(dctx->litBuffer + dctx->litSize, 0, 
> WILDCOPY_OVERLENGTH);
> +                               return litCSize + lhSize;
> +                       }
> +
> +               case set_basic: {
> +                       size_t litSize, lhSize;
> +                       U32 const lhlCode = ((istart[0]) >> 2) & 3;
> +                       switch (lhlCode) {
> +                       case 0:
> +                       case 2:
> +                       default: /* note : default is impossible, since 
> lhlCode into [0..3] */
> +                               lhSize = 1;
> +                               litSize = istart[0] >> 3;
> +                               break;
> +                       case 1:
> +                               lhSize = 2;
> +                               litSize = ZSTD_readLE16(istart) >> 4;
> +                               break;
> +                       case 3:
> +                               lhSize = 3;
> +                               litSize = ZSTD_readLE24(istart) >> 4;
> +                               break;
> +                       }
> +
> +                       if (lhSize + litSize + WILDCOPY_OVERLENGTH > srcSize) 
> { /* risk reading beyond src buffer with wildcopy */
> +                               if (litSize + lhSize > srcSize)
> +                                       return ERROR(corruption_detected);
> +                               memcpy(dctx->litBuffer, istart + lhSize, 
> litSize);
> +                               dctx->litPtr = dctx->litBuffer;
> +                               dctx->litSize = litSize;
> +                               memset(dctx->litBuffer + dctx->litSize, 0, 
> WILDCOPY_OVERLENGTH);
> +                               return lhSize + litSize;
> +                       }
> +                       /* direct reference into compressed stream */
> +                       dctx->litPtr = istart + lhSize;
> +                       dctx->litSize = litSize;
> +                       return lhSize + litSize;
> +               }
> +
> +               case set_rle: {
> +                       U32 const lhlCode = ((istart[0]) >> 2) & 3;
> +                       size_t litSize, lhSize;
> +                       switch (lhlCode) {
> +                       case 0:
> +                       case 2:
> +                       default: /* note : default is impossible, since 
> lhlCode into [0..3] */
> +                               lhSize = 1;
> +                               litSize = istart[0] >> 3;
> +                               break;
> +                       case 1:
> +                               lhSize = 2;
> +                               litSize = ZSTD_readLE16(istart) >> 4;
> +                               break;
> +                       case 3:
> +                               lhSize = 3;
> +                               litSize = ZSTD_readLE24(istart) >> 4;
> +                               if (srcSize < 4)
> +                                       return ERROR(corruption_detected); /* 
> srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4 */
> +                               break;
> +                       }
> +                       if (litSize > ZSTD_BLOCKSIZE_ABSOLUTEMAX)
> +                               return ERROR(corruption_detected);
> +                       memset(dctx->litBuffer, istart[lhSize], litSize + 
> WILDCOPY_OVERLENGTH);
> +                       dctx->litPtr = dctx->litBuffer;
> +                       dctx->litSize = litSize;
> +                       return lhSize + 1;
> +               }
> +               default:
> +                       return ERROR(corruption_detected); /* impossible */
> +               }
> +       }
> +}
> +
> +typedef union {
> +       FSE_decode_t realData;
> +       U32 alignedBy4;
> +} FSE_decode_t4;
> +
> +static const FSE_decode_t4 LL_defaultDTable[(1 << LL_DEFAULTNORMLOG) + 1] = {
> +    {{LL_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */
> +    {{0, 0, 4}},                /* 0 : base, symbol, bits */
> +    {{16, 0, 4}},
> +    {{32, 1, 5}},
> +    {{0, 3, 5}},
> +    {{0, 4, 5}},
> +    {{0, 6, 5}},
> +    {{0, 7, 5}},
> +    {{0, 9, 5}},
> +    {{0, 10, 5}},
> +    {{0, 12, 5}},
> +    {{0, 14, 6}},
> +    {{0, 16, 5}},
> +    {{0, 18, 5}},
> +    {{0, 19, 5}},
> +    {{0, 21, 5}},
> +    {{0, 22, 5}},
> +    {{0, 24, 5}},
> +    {{32, 25, 5}},
> +    {{0, 26, 5}},
> +    {{0, 27, 6}},
> +    {{0, 29, 6}},
> +    {{0, 31, 6}},
> +    {{32, 0, 4}},
> +    {{0, 1, 4}},
> +    {{0, 2, 5}},
> +    {{32, 4, 5}},
> +    {{0, 5, 5}},
> +    {{32, 7, 5}},
> +    {{0, 8, 5}},
> +    {{32, 10, 5}},
> +    {{0, 11, 5}},
> +    {{0, 13, 6}},
> +    {{32, 16, 5}},
> +    {{0, 17, 5}},
> +    {{32, 19, 5}},
> +    {{0, 20, 5}},
> +    {{32, 22, 5}},
> +    {{0, 23, 5}},
> +    {{0, 25, 4}},
> +    {{16, 25, 4}},
> +    {{32, 26, 5}},
> +    {{0, 28, 6}},
> +    {{0, 30, 6}},
> +    {{48, 0, 4}},
> +    {{16, 1, 4}},
> +    {{32, 2, 5}},
> +    {{32, 3, 5}},
> +    {{32, 5, 5}},
> +    {{32, 6, 5}},
> +    {{32, 8, 5}},
> +    {{32, 9, 5}},
> +    {{32, 11, 5}},
> +    {{32, 12, 5}},
> +    {{0, 15, 6}},
> +    {{32, 17, 5}},
> +    {{32, 18, 5}},
> +    {{32, 20, 5}},
> +    {{32, 21, 5}},
> +    {{32, 23, 5}},
> +    {{32, 24, 5}},
> +    {{0, 35, 6}},
> +    {{0, 34, 6}},
> +    {{0, 33, 6}},
> +    {{0, 32, 6}},
> +}; /* LL_defaultDTable */
> +
> +static const FSE_decode_t4 ML_defaultDTable[(1 << ML_DEFAULTNORMLOG) + 1] = {
> +    {{ML_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */
> +    {{0, 0, 6}},                /* 0 : base, symbol, bits */
> +    {{0, 1, 4}},
> +    {{32, 2, 5}},
> +    {{0, 3, 5}},
> +    {{0, 5, 5}},
> +    {{0, 6, 5}},
> +    {{0, 8, 5}},
> +    {{0, 10, 6}},
> +    {{0, 13, 6}},
> +    {{0, 16, 6}},
> +    {{0, 19, 6}},
> +    {{0, 22, 6}},
> +    {{0, 25, 6}},
> +    {{0, 28, 6}},
> +    {{0, 31, 6}},
> +    {{0, 33, 6}},
> +    {{0, 35, 6}},
> +    {{0, 37, 6}},
> +    {{0, 39, 6}},
> +    {{0, 41, 6}},
> +    {{0, 43, 6}},
> +    {{0, 45, 6}},
> +    {{16, 1, 4}},
> +    {{0, 2, 4}},
> +    {{32, 3, 5}},
> +    {{0, 4, 5}},
> +    {{32, 6, 5}},
> +    {{0, 7, 5}},
> +    {{0, 9, 6}},
> +    {{0, 12, 6}},
> +    {{0, 15, 6}},
> +    {{0, 18, 6}},
> +    {{0, 21, 6}},
> +    {{0, 24, 6}},
> +    {{0, 27, 6}},
> +    {{0, 30, 6}},
> +    {{0, 32, 6}},
> +    {{0, 34, 6}},
> +    {{0, 36, 6}},
> +    {{0, 38, 6}},
> +    {{0, 40, 6}},
> +    {{0, 42, 6}},
> +    {{0, 44, 6}},
> +    {{32, 1, 4}},
> +    {{48, 1, 4}},
> +    {{16, 2, 4}},
> +    {{32, 4, 5}},
> +    {{32, 5, 5}},
> +    {{32, 7, 5}},
> +    {{32, 8, 5}},
> +    {{0, 11, 6}},
> +    {{0, 14, 6}},
> +    {{0, 17, 6}},
> +    {{0, 20, 6}},
> +    {{0, 23, 6}},
> +    {{0, 26, 6}},
> +    {{0, 29, 6}},
> +    {{0, 52, 6}},
> +    {{0, 51, 6}},
> +    {{0, 50, 6}},
> +    {{0, 49, 6}},
> +    {{0, 48, 6}},
> +    {{0, 47, 6}},
> +    {{0, 46, 6}},
> +}; /* ML_defaultDTable */
> +
> +static const FSE_decode_t4 OF_defaultDTable[(1 << OF_DEFAULTNORMLOG) + 1] = {
> +    {{OF_DEFAULTNORMLOG, 1, 1}}, /* header : tableLog, fastMode, fastMode */
> +    {{0, 0, 5}},                /* 0 : base, symbol, bits */
> +    {{0, 6, 4}},
> +    {{0, 9, 5}},
> +    {{0, 15, 5}},
> +    {{0, 21, 5}},
> +    {{0, 3, 5}},
> +    {{0, 7, 4}},
> +    {{0, 12, 5}},
> +    {{0, 18, 5}},
> +    {{0, 23, 5}},
> +    {{0, 5, 5}},
> +    {{0, 8, 4}},
> +    {{0, 14, 5}},
> +    {{0, 20, 5}},
> +    {{0, 2, 5}},
> +    {{16, 7, 4}},
> +    {{0, 11, 5}},
> +    {{0, 17, 5}},
> +    {{0, 22, 5}},
> +    {{0, 4, 5}},
> +    {{16, 8, 4}},
> +    {{0, 13, 5}},
> +    {{0, 19, 5}},
> +    {{0, 1, 5}},
> +    {{16, 6, 4}},
> +    {{0, 10, 5}},
> +    {{0, 16, 5}},
> +    {{0, 28, 5}},
> +    {{0, 27, 5}},
> +    {{0, 26, 5}},
> +    {{0, 25, 5}},
> +    {{0, 24, 5}},
> +}; /* OF_defaultDTable */
> +
> +/*! ZSTD_buildSeqTable() :
> +       @return : nb bytes read from src,
> +                         or an error code if it fails, testable with 
> ZSTD_isError()
> +*/
> +static size_t ZSTD_buildSeqTable(FSE_DTable *DTableSpace, const FSE_DTable 
> **DTablePtr, symbolEncodingType_e type, U32 max, U32 maxLog, const void *src,
> +                                size_t srcSize, const FSE_decode_t4 
> *defaultTable, U32 flagRepeatTable, void *workspace, size_t workspaceSize)
> +{
> +       const void *const tmpPtr = defaultTable; /* bypass strict aliasing */
> +       switch (type) {
> +       case set_rle:
> +               if (!srcSize)
> +                       return ERROR(srcSize_wrong);
> +               if ((*(const BYTE *)src) > max)
> +                       return ERROR(corruption_detected);
> +               FSE_buildDTable_rle(DTableSpace, *(const BYTE *)src);
> +               *DTablePtr = DTableSpace;
> +               return 1;
> +       case set_basic: *DTablePtr = (const FSE_DTable *)tmpPtr; return 0;
> +       case set_repeat:
> +               if (!flagRepeatTable)
> +                       return ERROR(corruption_detected);
> +               return 0;
> +       default: /* impossible */
> +       case set_compressed: {
> +               U32 tableLog;
> +               S16 *norm = (S16 *)workspace;
> +               size_t const spaceUsed32 = ALIGN(sizeof(S16) * (MaxSeq + 1), 
> sizeof(U32)) >> 2;
> +
> +               if ((spaceUsed32 << 2) > workspaceSize)
> +                       return ERROR(GENERIC);
> +               workspace = (U32 *)workspace + spaceUsed32;
> +               workspaceSize -= (spaceUsed32 << 2);
> +               {
> +                       size_t const headerSize = FSE_readNCount(norm, &max, 
> &tableLog, src, srcSize);
> +                       if (FSE_isError(headerSize))
> +                               return ERROR(corruption_detected);
> +                       if (tableLog > maxLog)
> +                               return ERROR(corruption_detected);
> +                       FSE_buildDTable_wksp(DTableSpace, norm, max, 
> tableLog, workspace, workspaceSize);
> +                       *DTablePtr = DTableSpace;
> +                       return headerSize;
> +               }
> +       }
> +       }
> +}
> +
> +size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx *dctx, int *nbSeqPtr, const void 
> *src, size_t srcSize)
> +{
> +       const BYTE *const istart = (const BYTE *const)src;
> +       const BYTE *const iend = istart + srcSize;
> +       const BYTE *ip = istart;
> +
> +       /* check */
> +       if (srcSize < MIN_SEQUENCES_SIZE)
> +               return ERROR(srcSize_wrong);
> +
> +       /* SeqHead */
> +       {
> +               int nbSeq = *ip++;
> +               if (!nbSeq) {
> +                       *nbSeqPtr = 0;
> +                       return 1;
> +               }
> +               if (nbSeq > 0x7F) {
> +                       if (nbSeq == 0xFF) {
> +                               if (ip + 2 > iend)
> +                                       return ERROR(srcSize_wrong);
> +                               nbSeq = ZSTD_readLE16(ip) + LONGNBSEQ, ip += 
> 2;
> +                       } else {
> +                               if (ip >= iend)
> +                                       return ERROR(srcSize_wrong);
> +                               nbSeq = ((nbSeq - 0x80) << 8) + *ip++;
> +                       }
> +               }
> +               *nbSeqPtr = nbSeq;
> +       }
> +
> +       /* FSE table descriptors */
> +       if (ip + 4 > iend)
> +               return ERROR(srcSize_wrong); /* minimum possible size */
> +       {
> +               symbolEncodingType_e const LLtype = 
> (symbolEncodingType_e)(*ip >> 6);
> +               symbolEncodingType_e const OFtype = 
> (symbolEncodingType_e)((*ip >> 4) & 3);
> +               symbolEncodingType_e const MLtype = 
> (symbolEncodingType_e)((*ip >> 2) & 3);
> +               ip++;
> +
> +               /* Build DTables */
> +               {
> +                       size_t const llhSize = 
> ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, LLtype, MaxLL, 
> LLFSELog, ip, iend - ip,
> +                                                                 
> LL_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, 
> sizeof(dctx->entropy.workspace));
> +                       if (ZSTD_isError(llhSize))
> +                               return ERROR(corruption_detected);
> +                       ip += llhSize;
> +               }
> +               {
> +                       size_t const ofhSize = 
> ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, OFtype, MaxOff, 
> OffFSELog, ip, iend - ip,
> +                                                                 
> OF_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, 
> sizeof(dctx->entropy.workspace));
> +                       if (ZSTD_isError(ofhSize))
> +                               return ERROR(corruption_detected);
> +                       ip += ofhSize;
> +               }
> +               {
> +                       size_t const mlhSize = 
> ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, MLtype, MaxML, 
> MLFSELog, ip, iend - ip,
> +                                                                 
> ML_defaultDTable, dctx->fseEntropy, dctx->entropy.workspace, 
> sizeof(dctx->entropy.workspace));
> +                       if (ZSTD_isError(mlhSize))
> +                               return ERROR(corruption_detected);
> +                       ip += mlhSize;
> +               }
> +       }
> +
> +       return ip - istart;
> +}
> +
> +typedef struct {
> +       size_t litLength;
> +       size_t matchLength;
> +       size_t offset;
> +       const BYTE *match;
> +} seq_t;
> +
> +typedef struct {
> +       BIT_DStream_t DStream;
> +       FSE_DState_t stateLL;
> +       FSE_DState_t stateOffb;
> +       FSE_DState_t stateML;
> +       size_t prevOffset[ZSTD_REP_NUM];
> +       const BYTE *base;
> +       size_t pos;
> +       uPtrDiff gotoDict;
> +} seqState_t;
> +
> +FORCE_NOINLINE
> +size_t ZSTD_execSequenceLast7(BYTE *op, BYTE *const oend, seq_t sequence, 
> const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
> +                             const BYTE *const vBase, const BYTE *const 
> dictEnd)
> +{
> +       BYTE *const oLitEnd = op + sequence.litLength;
> +       size_t const sequenceLength = sequence.litLength + 
> sequence.matchLength;
> +       BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space 
> overflow (32-bits) */
> +       BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
> +       const BYTE *const iLitEnd = *litPtr + sequence.litLength;
> +       const BYTE *match = oLitEnd - sequence.offset;
> +
> +       /* check */
> +       if (oMatchEnd > oend)
> +               return ERROR(dstSize_tooSmall); /* last match must start at a 
> minimum distance of WILDCOPY_OVERLENGTH from oend */
> +       if (iLitEnd > litLimit)
> +               return ERROR(corruption_detected); /* over-read beyond lit 
> buffer */
> +       if (oLitEnd <= oend_w)
> +               return ERROR(GENERIC); /* Precondition */
> +
> +       /* copy literals */
> +       if (op < oend_w) {
> +               ZSTD_wildcopy(op, *litPtr, oend_w - op);
> +               *litPtr += oend_w - op;
> +               op = oend_w;
> +       }
> +       while (op < oLitEnd)
> +               *op++ = *(*litPtr)++;
> +
> +       /* copy Match */
> +       if (sequence.offset > (size_t)(oLitEnd - base)) {
> +               /* offset beyond prefix */
> +               if (sequence.offset > (size_t)(oLitEnd - vBase))
> +                       return ERROR(corruption_detected);
> +               match = dictEnd - (base - match);
> +               if (match + sequence.matchLength <= dictEnd) {
> +                       memmove(oLitEnd, match, sequence.matchLength);
> +                       return sequenceLength;
> +               }
> +               /* span extDict & currPrefixSegment */
> +               {
> +                       size_t const length1 = dictEnd - match;
> +                       memmove(oLitEnd, match, length1);
> +                       op = oLitEnd + length1;
> +                       sequence.matchLength -= length1;
> +                       match = base;
> +               }
> +       }
> +       while (op < oMatchEnd)
> +               *op++ = *match++;
> +       return sequenceLength;
> +}
> +
> +static seq_t ZSTD_decodeSequence(seqState_t *seqState)
> +{
> +       seq_t seq;
> +
> +       U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
> +       U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
> +       U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= 
> maxOff, by table construction */
> +
> +       U32 const llBits = LL_bits[llCode];
> +       U32 const mlBits = ML_bits[mlCode];
> +       U32 const ofBits = ofCode;
> +       U32 const totalBits = llBits + mlBits + ofBits;
> +
> +       static const U32 LL_base[MaxLL + 1] = {0,  1,  2,  3,  4,  5,  6,  7, 
>  8,    9,     10,    11,    12,    13,     14,     15,     16,     18,
> +                                              20, 22, 24, 28, 32, 40, 48, 
> 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 
> 0x10000};
> +
> +       static const U32 ML_base[MaxML + 1] = {3,  4,  5,  6,  7,  8,  9,  
> 10,   11,    12,    13,    14,    15,     16,     17,     18,     19,     20,
> +                                              21, 22, 23, 24, 25, 26, 27, 
> 28,   29,    30,    31,    32,    33,     34,     35,     37,     39,     41,
> +                                              43, 47, 51, 59, 67, 83, 99, 
> 0x83, 0x103, 0x203, 0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003};
> +
> +       static const U32 OF_base[MaxOff + 1] = {0,       1,     1,      5,    
>   0xD,      0x1D,      0x3D,      0x7D,      0xFD,     0x1FD,
> +                                               0x3FD,   0x7FD,    0xFFD,    
> 0x1FFD,   0x3FFD,   0x7FFD,    0xFFFD,    0x1FFFD,   0x3FFFD,  0x7FFFD,
> +                                               0xFFFFD, 0x1FFFFD, 0x3FFFFD, 
> 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD};
> +
> +       /* sequence */
> +       {
> +               size_t offset;
> +               if (!ofCode)
> +                       offset = 0;
> +               else {
> +                       offset = OF_base[ofCode] + 
> BIT_readBitsFast(&seqState->DStream, ofBits); /* <=  (ZSTD_WINDOWLOG_MAX-1) 
> bits */
> +                       if (ZSTD_32bits())
> +                               BIT_reloadDStream(&seqState->DStream);
> +               }
> +
> +               if (ofCode <= 1) {
> +                       offset += (llCode == 0);
> +                       if (offset) {
> +                               size_t temp = (offset == 3) ? 
> seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
> +                               temp += !temp; /* 0 is not valid; input is 
> corrupted; force offset to 1 */
> +                               if (offset != 1)
> +                                       seqState->prevOffset[2] = 
> seqState->prevOffset[1];
> +                               seqState->prevOffset[1] = 
> seqState->prevOffset[0];
> +                               seqState->prevOffset[0] = offset = temp;
> +                       } else {
> +                               offset = seqState->prevOffset[0];
> +                       }
> +               } else {
> +                       seqState->prevOffset[2] = seqState->prevOffset[1];
> +                       seqState->prevOffset[1] = seqState->prevOffset[0];
> +                       seqState->prevOffset[0] = offset;
> +               }
> +               seq.offset = offset;
> +       }
> +
> +       seq.matchLength = ML_base[mlCode] + ((mlCode > 31) ? 
> BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <=  16 bits */
> +       if (ZSTD_32bits() && (mlBits + llBits > 24))
> +               BIT_reloadDStream(&seqState->DStream);
> +
> +       seq.litLength = LL_base[llCode] + ((llCode > 15) ? 
> BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <=  16 bits */
> +       if (ZSTD_32bits() || (totalBits > 64 - 7 - (LLFSELog + MLFSELog + 
> OffFSELog)))
> +               BIT_reloadDStream(&seqState->DStream);
> +
> +       /* ANS state update */
> +       FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <=  9 
> bits */
> +       FSE_updateState(&seqState->stateML, &seqState->DStream); /* <=  9 
> bits */
> +       if (ZSTD_32bits())
> +               BIT_reloadDStream(&seqState->DStream);             /* <= 18 
> bits */
> +       FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <=  8 
> bits */
> +
> +       seq.match = NULL;
> +
> +       return seq;
> +}
> +
> +FORCE_INLINE
> +size_t ZSTD_execSequence(BYTE *op, BYTE *const oend, seq_t sequence, const 
> BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
> +                        const BYTE *const vBase, const BYTE *const dictEnd)
> +{
> +       BYTE *const oLitEnd = op + sequence.litLength;
> +       size_t const sequenceLength = sequence.litLength + 
> sequence.matchLength;
> +       BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space 
> overflow (32-bits) */
> +       BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
> +       const BYTE *const iLitEnd = *litPtr + sequence.litLength;
> +       const BYTE *match = oLitEnd - sequence.offset;
> +
> +       /* check */
> +       if (oMatchEnd > oend)
> +               return ERROR(dstSize_tooSmall); /* last match must start at a 
> minimum distance of WILDCOPY_OVERLENGTH from oend */
> +       if (iLitEnd > litLimit)
> +               return ERROR(corruption_detected); /* over-read beyond lit 
> buffer */
> +       if (oLitEnd > oend_w)
> +               return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, 
> litLimit, base, vBase, dictEnd);
> +
> +       /* copy Literals */
> +       ZSTD_copy8(op, *litPtr);
> +       if (sequence.litLength > 8)
> +               ZSTD_wildcopy(op + 8, (*litPtr) + 8,
> +                             sequence.litLength - 8); /* note : since 
> oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
> +       op = oLitEnd;
> +       *litPtr = iLitEnd; /* update for next sequence */
> +
> +       /* copy Match */
> +       if (sequence.offset > (size_t)(oLitEnd - base)) {
> +               /* offset beyond prefix */
> +               if (sequence.offset > (size_t)(oLitEnd - vBase))
> +                       return ERROR(corruption_detected);
> +               match = dictEnd + (match - base);
> +               if (match + sequence.matchLength <= dictEnd) {
> +                       memmove(oLitEnd, match, sequence.matchLength);
> +                       return sequenceLength;
> +               }
> +               /* span extDict & currPrefixSegment */
> +               {
> +                       size_t const length1 = dictEnd - match;
> +                       memmove(oLitEnd, match, length1);
> +                       op = oLitEnd + length1;
> +                       sequence.matchLength -= length1;
> +                       match = base;
> +                       if (op > oend_w || sequence.matchLength < MINMATCH) {
> +                               U32 i;
> +                               for (i = 0; i < sequence.matchLength; ++i)
> +                                       op[i] = match[i];
> +                               return sequenceLength;
> +                       }
> +               }
> +       }
> +       /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
> +
> +       /* match within prefix */
> +       if (sequence.offset < 8) {
> +               /* close range match, overlap */
> +               static const U32 dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4};   
> /* added */
> +               static const int dec64table[] = {8, 8, 8, 7, 8, 9, 10, 11}; 
> /* subtracted */
> +               int const sub2 = dec64table[sequence.offset];
> +               op[0] = match[0];
> +               op[1] = match[1];
> +               op[2] = match[2];
> +               op[3] = match[3];
> +               match += dec32table[sequence.offset];
> +               ZSTD_copy4(op + 4, match);
> +               match -= sub2;
> +       } else {
> +               ZSTD_copy8(op, match);
> +       }
> +       op += 8;
> +       match += 8;
> +
> +       if (oMatchEnd > oend - (16 - MINMATCH)) {
> +               if (op < oend_w) {
> +                       ZSTD_wildcopy(op, match, oend_w - op);
> +                       match += oend_w - op;
> +                       op = oend_w;
> +               }
> +               while (op < oMatchEnd)
> +                       *op++ = *match++;
> +       } else {
> +               ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 
> 8); /* works even if matchLength < 8 */
> +       }
> +       return sequenceLength;
> +}
> +
> +static size_t ZSTD_decompressSequences(ZSTD_DCtx *dctx, void *dst, size_t 
> maxDstSize, const void *seqStart, size_t seqSize)
> +{
> +       const BYTE *ip = (const BYTE *)seqStart;
> +       const BYTE *const iend = ip + seqSize;
> +       BYTE *const ostart = (BYTE * const)dst;
> +       BYTE *const oend = ostart + maxDstSize;
> +       BYTE *op = ostart;
> +       const BYTE *litPtr = dctx->litPtr;
> +       const BYTE *const litEnd = litPtr + dctx->litSize;
> +       const BYTE *const base = (const BYTE *)(dctx->base);
> +       const BYTE *const vBase = (const BYTE *)(dctx->vBase);
> +       const BYTE *const dictEnd = (const BYTE *)(dctx->dictEnd);
> +       int nbSeq;
> +
> +       /* Build Decoding Tables */
> +       {
> +               size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, 
> ip, seqSize);
> +               if (ZSTD_isError(seqHSize))
> +                       return seqHSize;
> +               ip += seqHSize;
> +       }
> +
> +       /* Regen sequences */
> +       if (nbSeq) {
> +               seqState_t seqState;
> +               dctx->fseEntropy = 1;
> +               {
> +                       U32 i;
> +                       for (i = 0; i < ZSTD_REP_NUM; i++)
> +                               seqState.prevOffset[i] = dctx->entropy.rep[i];
> +               }
> +               CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend - ip), 
> corruption_detected);
> +               FSE_initDState(&seqState.stateLL, &seqState.DStream, 
> dctx->LLTptr);
> +               FSE_initDState(&seqState.stateOffb, &seqState.DStream, 
> dctx->OFTptr);
> +               FSE_initDState(&seqState.stateML, &seqState.DStream, 
> dctx->MLTptr);
> +
> +               for (; (BIT_reloadDStream(&(seqState.DStream)) <= 
> BIT_DStream_completed) && nbSeq;) {
> +                       nbSeq--;
> +                       {
> +                               seq_t const sequence = 
> ZSTD_decodeSequence(&seqState);
> +                               size_t const oneSeqSize = 
> ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, base, vBase, dictEnd);
> +                               if (ZSTD_isError(oneSeqSize))
> +                                       return oneSeqSize;
> +                               op += oneSeqSize;
> +                       }
> +               }
> +
> +               /* check if reached exact end */
> +               if (nbSeq)
> +                       return ERROR(corruption_detected);
> +               /* save reps for next block */
> +               {
> +                       U32 i;
> +                       for (i = 0; i < ZSTD_REP_NUM; i++)
> +                               dctx->entropy.rep[i] = 
> (U32)(seqState.prevOffset[i]);
> +               }
> +       }
> +
> +       /* last literal segment */
> +       {
> +               size_t const lastLLSize = litEnd - litPtr;
> +               if (lastLLSize > (size_t)(oend - op))
> +                       return ERROR(dstSize_tooSmall);
> +               memcpy(op, litPtr, lastLLSize);
> +               op += lastLLSize;
> +       }
> +
> +       return op - ostart;
> +}
> +
> +FORCE_INLINE seq_t ZSTD_decodeSequenceLong_generic(seqState_t *seqState, int 
> const longOffsets)
> +{
> +       seq_t seq;
> +
> +       U32 const llCode = FSE_peekSymbol(&seqState->stateLL);
> +       U32 const mlCode = FSE_peekSymbol(&seqState->stateML);
> +       U32 const ofCode = FSE_peekSymbol(&seqState->stateOffb); /* <= 
> maxOff, by table construction */
> +
> +       U32 const llBits = LL_bits[llCode];
> +       U32 const mlBits = ML_bits[mlCode];
> +       U32 const ofBits = ofCode;
> +       U32 const totalBits = llBits + mlBits + ofBits;
> +
> +       static const U32 LL_base[MaxLL + 1] = {0,  1,  2,  3,  4,  5,  6,  7, 
>  8,    9,     10,    11,    12,    13,     14,     15,     16,     18,
> +                                              20, 22, 24, 28, 32, 40, 48, 
> 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 
> 0x10000};
> +
> +       static const U32 ML_base[MaxML + 1] = {3,  4,  5,  6,  7,  8,  9,  
> 10,   11,    12,    13,    14,    15,     16,     17,     18,     19,     20,
> +                                              21, 22, 23, 24, 25, 26, 27, 
> 28,   29,    30,    31,    32,    33,     34,     35,     37,     39,     41,
> +                                              43, 47, 51, 59, 67, 83, 99, 
> 0x83, 0x103, 0x203, 0x403, 0x803, 0x1003, 0x2003, 0x4003, 0x8003, 0x10003};
> +
> +       static const U32 OF_base[MaxOff + 1] = {0,       1,     1,      5,    
>   0xD,      0x1D,      0x3D,      0x7D,      0xFD,     0x1FD,
> +                                               0x3FD,   0x7FD,    0xFFD,    
> 0x1FFD,   0x3FFD,   0x7FFD,    0xFFFD,    0x1FFFD,   0x3FFFD,  0x7FFFD,
> +                                               0xFFFFD, 0x1FFFFD, 0x3FFFFD, 
> 0x7FFFFD, 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD};
> +
> +       /* sequence */
> +       {
> +               size_t offset;
> +               if (!ofCode)
> +                       offset = 0;
> +               else {
> +                       if (longOffsets) {
> +                               int const extraBits = ofBits - MIN(ofBits, 
> STREAM_ACCUMULATOR_MIN);
> +                               offset = OF_base[ofCode] + 
> (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits);
> +                               if (ZSTD_32bits() || extraBits)
> +                                       BIT_reloadDStream(&seqState->DStream);
> +                               if (extraBits)
> +                                       offset += 
> BIT_readBitsFast(&seqState->DStream, extraBits);
> +                       } else {
> +                               offset = OF_base[ofCode] + 
> BIT_readBitsFast(&seqState->DStream, ofBits); /* <=  (ZSTD_WINDOWLOG_MAX-1) 
> bits */
> +                               if (ZSTD_32bits())
> +                                       BIT_reloadDStream(&seqState->DStream);
> +                       }
> +               }
> +
> +               if (ofCode <= 1) {
> +                       offset += (llCode == 0);
> +                       if (offset) {
> +                               size_t temp = (offset == 3) ? 
> seqState->prevOffset[0] - 1 : seqState->prevOffset[offset];
> +                               temp += !temp; /* 0 is not valid; input is 
> corrupted; force offset to 1 */
> +                               if (offset != 1)
> +                                       seqState->prevOffset[2] = 
> seqState->prevOffset[1];
> +                               seqState->prevOffset[1] = 
> seqState->prevOffset[0];
> +                               seqState->prevOffset[0] = offset = temp;
> +                       } else {
> +                               offset = seqState->prevOffset[0];
> +                       }
> +               } else {
> +                       seqState->prevOffset[2] = seqState->prevOffset[1];
> +                       seqState->prevOffset[1] = seqState->prevOffset[0];
> +                       seqState->prevOffset[0] = offset;
> +               }
> +               seq.offset = offset;
> +       }
> +
> +       seq.matchLength = ML_base[mlCode] + ((mlCode > 31) ? 
> BIT_readBitsFast(&seqState->DStream, mlBits) : 0); /* <=  16 bits */
> +       if (ZSTD_32bits() && (mlBits + llBits > 24))
> +               BIT_reloadDStream(&seqState->DStream);
> +
> +       seq.litLength = LL_base[llCode] + ((llCode > 15) ? 
> BIT_readBitsFast(&seqState->DStream, llBits) : 0); /* <=  16 bits */
> +       if (ZSTD_32bits() || (totalBits > 64 - 7 - (LLFSELog + MLFSELog + 
> OffFSELog)))
> +               BIT_reloadDStream(&seqState->DStream);
> +
> +       {
> +               size_t const pos = seqState->pos + seq.litLength;
> +               seq.match = seqState->base + pos - seq.offset; /* single 
> memory segment */
> +               if (seq.offset > pos)
> +                       seq.match += seqState->gotoDict; /* separate memory 
> segment */
> +               seqState->pos = pos + seq.matchLength;
> +       }
> +
> +       /* ANS state update */
> +       FSE_updateState(&seqState->stateLL, &seqState->DStream); /* <=  9 
> bits */
> +       FSE_updateState(&seqState->stateML, &seqState->DStream); /* <=  9 
> bits */
> +       if (ZSTD_32bits())
> +               BIT_reloadDStream(&seqState->DStream);             /* <= 18 
> bits */
> +       FSE_updateState(&seqState->stateOffb, &seqState->DStream); /* <=  8 
> bits */
> +
> +       return seq;
> +}
> +
> +static seq_t ZSTD_decodeSequenceLong(seqState_t *seqState, unsigned const 
> windowSize)
> +{
> +       if (ZSTD_highbit32(windowSize) > STREAM_ACCUMULATOR_MIN) {
> +               return ZSTD_decodeSequenceLong_generic(seqState, 1);
> +       } else {
> +               return ZSTD_decodeSequenceLong_generic(seqState, 0);
> +       }
> +}
> +
> +FORCE_INLINE
> +size_t ZSTD_execSequenceLong(BYTE *op, BYTE *const oend, seq_t sequence, 
> const BYTE **litPtr, const BYTE *const litLimit, const BYTE *const base,
> +                            const BYTE *const vBase, const BYTE *const 
> dictEnd)
> +{
> +       BYTE *const oLitEnd = op + sequence.litLength;
> +       size_t const sequenceLength = sequence.litLength + 
> sequence.matchLength;
> +       BYTE *const oMatchEnd = op + sequenceLength; /* risk : address space 
> overflow (32-bits) */
> +       BYTE *const oend_w = oend - WILDCOPY_OVERLENGTH;
> +       const BYTE *const iLitEnd = *litPtr + sequence.litLength;
> +       const BYTE *match = sequence.match;
> +
> +       /* check */
> +       if (oMatchEnd > oend)
> +               return ERROR(dstSize_tooSmall); /* last match must start at a 
> minimum distance of WILDCOPY_OVERLENGTH from oend */
> +       if (iLitEnd > litLimit)
> +               return ERROR(corruption_detected); /* over-read beyond lit 
> buffer */
> +       if (oLitEnd > oend_w)
> +               return ZSTD_execSequenceLast7(op, oend, sequence, litPtr, 
> litLimit, base, vBase, dictEnd);
> +
> +       /* copy Literals */
> +       ZSTD_copy8(op, *litPtr);
> +       if (sequence.litLength > 8)
> +               ZSTD_wildcopy(op + 8, (*litPtr) + 8,
> +                             sequence.litLength - 8); /* note : since 
> oLitEnd <= oend-WILDCOPY_OVERLENGTH, no risk of overwrite beyond oend */
> +       op = oLitEnd;
> +       *litPtr = iLitEnd; /* update for next sequence */
> +
> +       /* copy Match */
> +       if (sequence.offset > (size_t)(oLitEnd - base)) {
> +               /* offset beyond prefix */
> +               if (sequence.offset > (size_t)(oLitEnd - vBase))
> +                       return ERROR(corruption_detected);
> +               if (match + sequence.matchLength <= dictEnd) {
> +                       memmove(oLitEnd, match, sequence.matchLength);
> +                       return sequenceLength;
> +               }
> +               /* span extDict & currPrefixSegment */
> +               {
> +                       size_t const length1 = dictEnd - match;
> +                       memmove(oLitEnd, match, length1);
> +                       op = oLitEnd + length1;
> +                       sequence.matchLength -= length1;
> +                       match = base;
> +                       if (op > oend_w || sequence.matchLength < MINMATCH) {
> +                               U32 i;
> +                               for (i = 0; i < sequence.matchLength; ++i)
> +                                       op[i] = match[i];
> +                               return sequenceLength;
> +                       }
> +               }
> +       }
> +       /* Requirement: op <= oend_w && sequence.matchLength >= MINMATCH */
> +
> +       /* match within prefix */
> +       if (sequence.offset < 8) {
> +               /* close range match, overlap */
> +               static const U32 dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4};   
> /* added */
> +               static const int dec64table[] = {8, 8, 8, 7, 8, 9, 10, 11}; 
> /* subtracted */
> +               int const sub2 = dec64table[sequence.offset];
> +               op[0] = match[0];
> +               op[1] = match[1];
> +               op[2] = match[2];
> +               op[3] = match[3];
> +               match += dec32table[sequence.offset];
> +               ZSTD_copy4(op + 4, match);
> +               match -= sub2;
> +       } else {
> +               ZSTD_copy8(op, match);
> +       }
> +       op += 8;
> +       match += 8;
> +
> +       if (oMatchEnd > oend - (16 - MINMATCH)) {
> +               if (op < oend_w) {
> +                       ZSTD_wildcopy(op, match, oend_w - op);
> +                       match += oend_w - op;
> +                       op = oend_w;
> +               }
> +               while (op < oMatchEnd)
> +                       *op++ = *match++;
> +       } else {
> +               ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 
> 8); /* works even if matchLength < 8 */
> +       }
> +       return sequenceLength;
> +}
> +
> +static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx *dctx, void *dst, 
> size_t maxDstSize, const void *seqStart, size_t seqSize)
> +{
> +       const BYTE *ip = (const BYTE *)seqStart;
> +       const BYTE *const iend = ip + seqSize;
> +       BYTE *const ostart = (BYTE * const)dst;
> +       BYTE *const oend = ostart + maxDstSize;
> +       BYTE *op = ostart;
> +       const BYTE *litPtr = dctx->litPtr;
> +       const BYTE *const litEnd = litPtr + dctx->litSize;
> +       const BYTE *const base = (const BYTE *)(dctx->base);
> +       const BYTE *const vBase = (const BYTE *)(dctx->vBase);
> +       const BYTE *const dictEnd = (const BYTE *)(dctx->dictEnd);
> +       unsigned const windowSize = dctx->fParams.windowSize;
> +       int nbSeq;
> +
> +       /* Build Decoding Tables */
> +       {
> +               size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, 
> ip, seqSize);
> +               if (ZSTD_isError(seqHSize))
> +                       return seqHSize;
> +               ip += seqHSize;
> +       }
> +
> +       /* Regen sequences */
> +       if (nbSeq) {
> +#define STORED_SEQS 4
> +#define STOSEQ_MASK (STORED_SEQS - 1)
> +#define ADVANCED_SEQS 4
> +               seq_t *sequences = (seq_t *)dctx->entropy.workspace;
> +               int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS);
> +               seqState_t seqState;
> +               int seqNb;
> +               ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.workspace) >= 
> sizeof(seq_t) * STORED_SEQS);
> +               dctx->fseEntropy = 1;
> +               {
> +                       U32 i;
> +                       for (i = 0; i < ZSTD_REP_NUM; i++)
> +                               seqState.prevOffset[i] = dctx->entropy.rep[i];
> +               }
> +               seqState.base = base;
> +               seqState.pos = (size_t)(op - base);
> +               seqState.gotoDict = (uPtrDiff)dictEnd - (uPtrDiff)base; /* 
> cast to avoid undefined behaviour */
> +               CHECK_E(BIT_initDStream(&seqState.DStream, ip, iend - ip), 
> corruption_detected);
> +               FSE_initDState(&seqState.stateLL, &seqState.DStream, 
> dctx->LLTptr);
> +               FSE_initDState(&seqState.stateOffb, &seqState.DStream, 
> dctx->OFTptr);
> +               FSE_initDState(&seqState.stateML, &seqState.DStream, 
> dctx->MLTptr);
> +
> +               /* prepare in advance */
> +               for (seqNb = 0; (BIT_reloadDStream(&seqState.DStream) <= 
> BIT_DStream_completed) && seqNb < seqAdvance; seqNb++) {
> +                       sequences[seqNb] = ZSTD_decodeSequenceLong(&seqState, 
> windowSize);
> +               }
> +               if (seqNb < seqAdvance)
> +                       return ERROR(corruption_detected);
> +
> +               /* decode and decompress */
> +               for (; (BIT_reloadDStream(&(seqState.DStream)) <= 
> BIT_DStream_completed) && seqNb < nbSeq; seqNb++) {
> +                       seq_t const sequence = 
> ZSTD_decodeSequenceLong(&seqState, windowSize);
> +                       size_t const oneSeqSize =
> +                           ZSTD_execSequenceLong(op, oend, sequences[(seqNb 
> - ADVANCED_SEQS) & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd);
> +                       if (ZSTD_isError(oneSeqSize))
> +                               return oneSeqSize;
> +                       ZSTD_PREFETCH(sequence.match);
> +                       sequences[seqNb & STOSEQ_MASK] = sequence;
> +                       op += oneSeqSize;
> +               }
> +               if (seqNb < nbSeq)
> +                       return ERROR(corruption_detected);
> +
> +               /* finish queue */
> +               seqNb -= seqAdvance;
> +               for (; seqNb < nbSeq; seqNb++) {
> +                       size_t const oneSeqSize = ZSTD_execSequenceLong(op, 
> oend, sequences[seqNb & STOSEQ_MASK], &litPtr, litEnd, base, vBase, dictEnd);
> +                       if (ZSTD_isError(oneSeqSize))
> +                               return oneSeqSize;
> +                       op += oneSeqSize;
> +               }
> +
> +               /* save reps for next block */
> +               {
> +                       U32 i;
> +                       for (i = 0; i < ZSTD_REP_NUM; i++)
> +                               dctx->entropy.rep[i] = 
> (U32)(seqState.prevOffset[i]);
> +               }
> +       }
> +
> +       /* last literal segment */
> +       {
> +               size_t const lastLLSize = litEnd - litPtr;
> +               if (lastLLSize > (size_t)(oend - op))
> +                       return ERROR(dstSize_tooSmall);
> +               memcpy(op, litPtr, lastLLSize);
> +               op += lastLLSize;
> +       }
> +
> +       return op - ostart;
> +}
> +
> +static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx *dctx, void *dst, 
> size_t dstCapacity, const void *src, size_t srcSize)
> +{ /* blockType == blockCompressed */
> +       const BYTE *ip = (const BYTE *)src;
> +
> +       if (srcSize >= ZSTD_BLOCKSIZE_ABSOLUTEMAX)
> +               return ERROR(srcSize_wrong);
> +
> +       /* Decode literals section */
> +       {
> +               size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, 
> srcSize);
> +               if (ZSTD_isError(litCSize))
> +                       return litCSize;
> +               ip += litCSize;
> +               srcSize -= litCSize;
> +       }
> +       if (sizeof(size_t) > 4) /* do not enable prefetching on 32-bits x86, 
> as it's performance detrimental */
> +                               /* likely because of register pressure */
> +                               /* if that's the correct cause, then 32-bits 
> ARM should be affected differently */
> +                               /* it would be good to test this on ARM real 
> hardware, to see if prefetch version improves speed */
> +               if (dctx->fParams.windowSize > (1 << 23))
> +                       return ZSTD_decompressSequencesLong(dctx, dst, 
> dstCapacity, ip, srcSize);
> +       return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize);
> +}
> +
> +static void ZSTD_checkContinuity(ZSTD_DCtx *dctx, const void *dst)
> +{
> +       if (dst != dctx->previousDstEnd) { /* not contiguous */
> +               dctx->dictEnd = dctx->previousDstEnd;
> +               dctx->vBase = (const char *)dst - ((const char 
> *)(dctx->previousDstEnd) - (const char *)(dctx->base));
> +               dctx->base = dst;
> +               dctx->previousDstEnd = dst;
> +       }
> +}
> +
> +size_t ZSTD_decompressBlock(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, 
> const void *src, size_t srcSize)
> +{
> +       size_t dSize;
> +       ZSTD_checkContinuity(dctx, dst);
> +       dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, 
> srcSize);
> +       dctx->previousDstEnd = (char *)dst + dSize;
> +       return dSize;
> +}
> +
> +/** ZSTD_insertBlock() :
> +       insert `src` block into `dctx` history. Useful to track uncompressed 
> blocks. */
> +size_t ZSTD_insertBlock(ZSTD_DCtx *dctx, const void *blockStart, size_t 
> blockSize)
> +{
> +       ZSTD_checkContinuity(dctx, blockStart);
> +       dctx->previousDstEnd = (const char *)blockStart + blockSize;
> +       return blockSize;
> +}
> +
> +size_t ZSTD_generateNxBytes(void *dst, size_t dstCapacity, BYTE byte, size_t 
> length)
> +{
> +       if (length > dstCapacity)
> +               return ERROR(dstSize_tooSmall);
> +       memset(dst, byte, length);
> +       return length;
> +}
> +
> +/** ZSTD_findFrameCompressedSize() :
> + *  compatible with legacy mode
> + *  `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or 
> skippable frame
> + *  `srcSize` must be at least as large as the frame contained
> + *  @return : the compressed size of the frame starting at `src` */
> +size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
> +{
> +       if (srcSize >= ZSTD_skippableHeaderSize && (ZSTD_readLE32(src) & 
> 0xFFFFFFF0U) == ZSTD_MAGIC_SKIPPABLE_START) {
> +               return ZSTD_skippableHeaderSize + ZSTD_readLE32((const BYTE 
> *)src + 4);
> +       } else {
> +               const BYTE *ip = (const BYTE *)src;
> +               const BYTE *const ipstart = ip;
> +               size_t remainingSize = srcSize;
> +               ZSTD_frameParams fParams;
> +
> +               size_t const headerSize = ZSTD_frameHeaderSize(ip, 
> remainingSize);
> +               if (ZSTD_isError(headerSize))
> +                       return headerSize;
> +
> +               /* Frame Header */
> +               {
> +                       size_t const ret = ZSTD_getFrameParams(&fParams, ip, 
> remainingSize);
> +                       if (ZSTD_isError(ret))
> +                               return ret;
> +                       if (ret > 0)
> +                               return ERROR(srcSize_wrong);
> +               }
> +
> +               ip += headerSize;
> +               remainingSize -= headerSize;
> +
> +               /* Loop on each block */
> +               while (1) {
> +                       blockProperties_t blockProperties;
> +                       size_t const cBlockSize = ZSTD_getcBlockSize(ip, 
> remainingSize, &blockProperties);
> +                       if (ZSTD_isError(cBlockSize))
> +                               return cBlockSize;
> +
> +                       if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
> +                               return ERROR(srcSize_wrong);
> +
> +                       ip += ZSTD_blockHeaderSize + cBlockSize;
> +                       remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
> +
> +                       if (blockProperties.lastBlock)
> +                               break;
> +               }
> +
> +               if (fParams.checksumFlag) { /* Frame content checksum */
> +                       if (remainingSize < 4)
> +                               return ERROR(srcSize_wrong);
> +                       ip += 4;
> +                       remainingSize -= 4;
> +               }
> +
> +               return ip - ipstart;
> +       }
> +}
> +
> +/*! ZSTD_decompressFrame() :
> +*   @dctx must be properly initialized */
> +static size_t ZSTD_decompressFrame(ZSTD_DCtx *dctx, void *dst, size_t 
> dstCapacity, const void **srcPtr, size_t *srcSizePtr)
> +{
> +       const BYTE *ip = (const BYTE *)(*srcPtr);
> +       BYTE *const ostart = (BYTE * const)dst;
> +       BYTE *const oend = ostart + dstCapacity;
> +       BYTE *op = ostart;
> +       size_t remainingSize = *srcSizePtr;
> +
> +       /* check */
> +       if (remainingSize < ZSTD_frameHeaderSize_min + ZSTD_blockHeaderSize)
> +               return ERROR(srcSize_wrong);
> +
> +       /* Frame Header */
> +       {
> +               size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, 
> ZSTD_frameHeaderSize_prefix);
> +               if (ZSTD_isError(frameHeaderSize))
> +                       return frameHeaderSize;
> +               if (remainingSize < frameHeaderSize + ZSTD_blockHeaderSize)
> +                       return ERROR(srcSize_wrong);
> +               CHECK_F(ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize));
> +               ip += frameHeaderSize;
> +               remainingSize -= frameHeaderSize;
> +       }
> +
> +       /* Loop on each block */
> +       while (1) {
> +               size_t decodedSize;
> +               blockProperties_t blockProperties;
> +               size_t const cBlockSize = ZSTD_getcBlockSize(ip, 
> remainingSize, &blockProperties);
> +               if (ZSTD_isError(cBlockSize))
> +                       return cBlockSize;
> +
> +               ip += ZSTD_blockHeaderSize;
> +               remainingSize -= ZSTD_blockHeaderSize;
> +               if (cBlockSize > remainingSize)
> +                       return ERROR(srcSize_wrong);
> +
> +               switch (blockProperties.blockType) {
> +               case bt_compressed: decodedSize = 
> ZSTD_decompressBlock_internal(dctx, op, oend - op, ip, cBlockSize); break;
> +               case bt_raw: decodedSize = ZSTD_copyRawBlock(op, oend - op, 
> ip, cBlockSize); break;
> +               case bt_rle: decodedSize = ZSTD_generateNxBytes(op, oend - 
> op, *ip, blockProperties.origSize); break;
> +               case bt_reserved:
> +               default: return ERROR(corruption_detected);
> +               }
> +
> +               if (ZSTD_isError(decodedSize))
> +                       return decodedSize;
> +               if (dctx->fParams.checksumFlag)
> +                       xxh64_update(&dctx->xxhState, op, decodedSize);
> +               op += decodedSize;
> +               ip += cBlockSize;
> +               remainingSize -= cBlockSize;
> +               if (blockProperties.lastBlock)
> +                       break;
> +       }
> +
> +       if (dctx->fParams.checksumFlag) { /* Frame content checksum 
> verification */
> +               U32 const checkCalc = (U32)xxh64_digest(&dctx->xxhState);
> +               U32 checkRead;
> +               if (remainingSize < 4)
> +                       return ERROR(checksum_wrong);
> +               checkRead = ZSTD_readLE32(ip);
> +               if (checkRead != checkCalc)
> +                       return ERROR(checksum_wrong);
> +               ip += 4;
> +               remainingSize -= 4;
> +       }
> +
> +       /* Allow caller to get size read */
> +       *srcPtr = ip;
> +       *srcSizePtr = remainingSize;
> +       return op - ostart;
> +}
> +
> +static const void *ZSTD_DDictDictContent(const ZSTD_DDict *ddict);
> +static size_t ZSTD_DDictDictSize(const ZSTD_DDict *ddict);
> +
> +static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx *dctx, void *dst, size_t 
> dstCapacity, const void *src, size_t srcSize, const void *dict, size_t 
> dictSize,
> +                                       const ZSTD_DDict *ddict)
> +{
> +       void *const dststart = dst;
> +
> +       if (ddict) {
> +               if (dict) {
> +                       /* programmer error, these two cases should be 
> mutually exclusive */
> +                       return ERROR(GENERIC);
> +               }
> +
> +               dict = ZSTD_DDictDictContent(ddict);
> +               dictSize = ZSTD_DDictDictSize(ddict);
> +       }
> +
> +       while (srcSize >= ZSTD_frameHeaderSize_prefix) {
> +               U32 magicNumber;
> +
> +               magicNumber = ZSTD_readLE32(src);
> +               if (magicNumber != ZSTD_MAGICNUMBER) {
> +                       if ((magicNumber & 0xFFFFFFF0U) == 
> ZSTD_MAGIC_SKIPPABLE_START) {
> +                               size_t skippableSize;
> +                               if (srcSize < ZSTD_skippableHeaderSize)
> +                                       return ERROR(srcSize_wrong);
> +                               skippableSize = ZSTD_readLE32((const BYTE 
> *)src + 4) + ZSTD_skippableHeaderSize;
> +                               if (srcSize < skippableSize) {
> +                                       return ERROR(srcSize_wrong);
> +                               }
> +
> +                               src = (const BYTE *)src + skippableSize;
> +                               srcSize -= skippableSize;
> +                               continue;
> +                       } else {
> +                               return ERROR(prefix_unknown);
> +                       }
> +               }
> +
> +               if (ddict) {
> +                       /* we were called from ZSTD_decompress_usingDDict */
> +                       ZSTD_refDDict(dctx, ddict);
> +               } else {
> +                       /* this will initialize correctly with no dict if 
> dict == NULL, so
> +                        * use this in all cases but ddict */
> +                       CHECK_F(ZSTD_decompressBegin_usingDict(dctx, dict, 
> dictSize));
> +               }
> +               ZSTD_checkContinuity(dctx, dst);
> +
> +               {
> +                       const size_t res = ZSTD_decompressFrame(dctx, dst, 
> dstCapacity, &src, &srcSize);
> +                       if (ZSTD_isError(res))
> +                               return res;
> +                       /* don't need to bounds check this, 
> ZSTD_decompressFrame will have
> +                        * already */
> +                       dst = (BYTE *)dst + res;
> +                       dstCapacity -= res;
> +               }
> +       }
> +
> +       if (srcSize)
> +               return ERROR(srcSize_wrong); /* input not entirely consumed */
> +
> +       return (BYTE *)dst - (BYTE *)dststart;
> +}
> +
> +size_t ZSTD_decompress_usingDict(ZSTD_DCtx *dctx, void *dst, size_t 
> dstCapacity, const void *src, size_t srcSize, const void *dict, size_t 
> dictSize)
> +{
> +       return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, 
> srcSize, dict, dictSize, NULL);
> +}
> +
> +size_t ZSTD_decompressDCtx(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity, 
> const void *src, size_t srcSize)
> +{
> +       return ZSTD_decompress_usingDict(dctx, dst, dstCapacity, src, 
> srcSize, NULL, 0);
> +}
> +
> +/*-**************************************
> +*   Advanced Streaming Decompression API
> +*   Bufferless and synchronous
> +****************************************/
> +size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx *dctx) { return 
> dctx->expected; }
> +
> +ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx *dctx)
> +{
> +       switch (dctx->stage) {
> +       default: /* should not happen */
> +       case ZSTDds_getFrameHeaderSize:
> +       case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader;
> +       case ZSTDds_decodeBlockHeader: return ZSTDnit_blockHeader;
> +       case ZSTDds_decompressBlock: return ZSTDnit_block;
> +       case ZSTDds_decompressLastBlock: return ZSTDnit_lastBlock;
> +       case ZSTDds_checkChecksum: return ZSTDnit_checksum;
> +       case ZSTDds_decodeSkippableHeader:
> +       case ZSTDds_skipFrame: return ZSTDnit_skippableFrame;
> +       }
> +}
> +
> +int ZSTD_isSkipFrame(ZSTD_DCtx *dctx) { return dctx->stage == 
> ZSTDds_skipFrame; } /* for zbuff */
> +
> +/** ZSTD_decompressContinue() :
> +*   @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
> +*             or an error code, which can be tested using ZSTD_isError() */
> +size_t ZSTD_decompressContinue(ZSTD_DCtx *dctx, void *dst, size_t 
> dstCapacity, const void *src, size_t srcSize)
> +{
> +       /* Sanity check */
> +       if (srcSize != dctx->expected)
> +               return ERROR(srcSize_wrong);
> +       if (dstCapacity)
> +               ZSTD_checkContinuity(dctx, dst);
> +
> +       switch (dctx->stage) {
> +       case ZSTDds_getFrameHeaderSize:
> +               if (srcSize != ZSTD_frameHeaderSize_prefix)
> +                       return ERROR(srcSize_wrong);                          
>           /* impossible */
> +               if ((ZSTD_readLE32(src) & 0xFFFFFFF0U) == 
> ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
> +                       memcpy(dctx->headerBuffer, src, 
> ZSTD_frameHeaderSize_prefix);
> +                       dctx->expected = ZSTD_skippableHeaderSize - 
> ZSTD_frameHeaderSize_prefix; /* magic number + skippable frame length */
> +                       dctx->stage = ZSTDds_decodeSkippableHeader;
> +                       return 0;
> +               }
> +               dctx->headerSize = ZSTD_frameHeaderSize(src, 
> ZSTD_frameHeaderSize_prefix);
> +               if (ZSTD_isError(dctx->headerSize))
> +                       return dctx->headerSize;
> +               memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_prefix);
> +               if (dctx->headerSize > ZSTD_frameHeaderSize_prefix) {
> +                       dctx->expected = dctx->headerSize - 
> ZSTD_frameHeaderSize_prefix;
> +                       dctx->stage = ZSTDds_decodeFrameHeader;
> +                       return 0;
> +               }
> +               dctx->expected = 0; /* not necessary to copy more */
> +
> +       case ZSTDds_decodeFrameHeader:
> +               memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, 
> dctx->expected);
> +               CHECK_F(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, 
> dctx->headerSize));
> +               dctx->expected = ZSTD_blockHeaderSize;
> +               dctx->stage = ZSTDds_decodeBlockHeader;
> +               return 0;
> +
> +       case ZSTDds_decodeBlockHeader: {
> +               blockProperties_t bp;
> +               size_t const cBlockSize = ZSTD_getcBlockSize(src, 
> ZSTD_blockHeaderSize, &bp);
> +               if (ZSTD_isError(cBlockSize))
> +                       return cBlockSize;
> +               dctx->expected = cBlockSize;
> +               dctx->bType = bp.blockType;
> +               dctx->rleSize = bp.origSize;
> +               if (cBlockSize) {
> +                       dctx->stage = bp.lastBlock ? 
> ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
> +                       return 0;
> +               }
> +               /* empty block */
> +               if (bp.lastBlock) {
> +                       if (dctx->fParams.checksumFlag) {
> +                               dctx->expected = 4;
> +                               dctx->stage = ZSTDds_checkChecksum;
> +                       } else {
> +                               dctx->expected = 0; /* end of frame */
> +                               dctx->stage = ZSTDds_getFrameHeaderSize;
> +                       }
> +               } else {
> +                       dctx->expected = 3; /* go directly to next header */
> +                       dctx->stage = ZSTDds_decodeBlockHeader;
> +               }
> +               return 0;
> +       }
> +       case ZSTDds_decompressLastBlock:
> +       case ZSTDds_decompressBlock: {
> +               size_t rSize;
> +               switch (dctx->bType) {
> +               case bt_compressed: rSize = 
> ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize); break;
> +               case bt_raw: rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, 
> srcSize); break;
> +               case bt_rle: rSize = ZSTD_setRleBlock(dst, dstCapacity, src, 
> srcSize, dctx->rleSize); break;
> +               case bt_reserved: /* should never happen */
> +               default: return ERROR(corruption_detected);
> +               }
> +               if (ZSTD_isError(rSize))
> +                       return rSize;
> +               if (dctx->fParams.checksumFlag)
> +                       xxh64_update(&dctx->xxhState, dst, rSize);
> +
> +               if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of 
> frame */
> +                       if (dctx->fParams.checksumFlag) {       /* another 
> round for frame checksum */
> +                               dctx->expected = 4;
> +                               dctx->stage = ZSTDds_checkChecksum;
> +                       } else {
> +                               dctx->expected = 0; /* ends here */
> +                               dctx->stage = ZSTDds_getFrameHeaderSize;
> +                       }
> +               } else {
> +                       dctx->stage = ZSTDds_decodeBlockHeader;
> +                       dctx->expected = ZSTD_blockHeaderSize;
> +                       dctx->previousDstEnd = (char *)dst + rSize;
> +               }
> +               return rSize;
> +       }
> +       case ZSTDds_checkChecksum: {
> +               U32 const h32 = (U32)xxh64_digest(&dctx->xxhState);
> +               U32 const check32 = ZSTD_readLE32(src); /* srcSize == 4, 
> guaranteed by dctx->expected */
> +               if (check32 != h32)
> +                       return ERROR(checksum_wrong);
> +               dctx->expected = 0;
> +               dctx->stage = ZSTDds_getFrameHeaderSize;
> +               return 0;
> +       }
> +       case ZSTDds_decodeSkippableHeader: {
> +               memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_prefix, src, 
> dctx->expected);
> +               dctx->expected = ZSTD_readLE32(dctx->headerBuffer + 4);
> +               dctx->stage = ZSTDds_skipFrame;
> +               return 0;
> +       }
> +       case ZSTDds_skipFrame: {
> +               dctx->expected = 0;
> +               dctx->stage = ZSTDds_getFrameHeaderSize;
> +               return 0;
> +       }
> +       default:
> +               return ERROR(GENERIC); /* impossible */
> +       }
> +}
> +
> +static size_t ZSTD_refDictContent(ZSTD_DCtx *dctx, const void *dict, size_t 
> dictSize)
> +{
> +       dctx->dictEnd = dctx->previousDstEnd;
> +       dctx->vBase = (const char *)dict - ((const char 
> *)(dctx->previousDstEnd) - (const char *)(dctx->base));
> +       dctx->base = dict;
> +       dctx->previousDstEnd = (const char *)dict + dictSize;
> +       return 0;
> +}
> +
> +/* ZSTD_loadEntropy() :
> + * dict : must point at beginning of a valid zstd dictionary
> + * @return : size of entropy tables read */
> +static size_t ZSTD_loadEntropy(ZSTD_entropyTables_t *entropy, const void 
> *const dict, size_t const dictSize)
> +{
> +       const BYTE *dictPtr = (const BYTE *)dict;
> +       const BYTE *const dictEnd = dictPtr + dictSize;
> +
> +       if (dictSize <= 8)
> +               return ERROR(dictionary_corrupted);
> +       dictPtr += 8; /* skip header = magic + dictID */
> +
> +       {
> +               size_t const hSize = HUF_readDTableX4_wksp(entropy->hufTable, 
> dictPtr, dictEnd - dictPtr, entropy->workspace, sizeof(entropy->workspace));
> +               if (HUF_isError(hSize))
> +                       return ERROR(dictionary_corrupted);
> +               dictPtr += hSize;
> +       }
> +
> +       {
> +               short offcodeNCount[MaxOff + 1];
> +               U32 offcodeMaxValue = MaxOff, offcodeLog;
> +               size_t const offcodeHeaderSize = 
> FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd 
> - dictPtr);
> +               if (FSE_isError(offcodeHeaderSize))
> +                       return ERROR(dictionary_corrupted);
> +               if (offcodeLog > OffFSELog)
> +                       return ERROR(dictionary_corrupted);
> +               CHECK_E(FSE_buildDTable_wksp(entropy->OFTable, offcodeNCount, 
> offcodeMaxValue, offcodeLog, entropy->workspace, sizeof(entropy->workspace)), 
> dictionary_corrupted);
> +               dictPtr += offcodeHeaderSize;
> +       }
> +
> +       {
> +               short matchlengthNCount[MaxML + 1];
> +               unsigned matchlengthMaxValue = MaxML, matchlengthLog;
> +               size_t const matchlengthHeaderSize = 
> FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, 
> dictPtr, dictEnd - dictPtr);
> +               if (FSE_isError(matchlengthHeaderSize))
> +                       return ERROR(dictionary_corrupted);
> +               if (matchlengthLog > MLFSELog)
> +                       return ERROR(dictionary_corrupted);
> +               CHECK_E(FSE_buildDTable_wksp(entropy->MLTable, 
> matchlengthNCount, matchlengthMaxValue, matchlengthLog, entropy->workspace, 
> sizeof(entropy->workspace)), dictionary_corrupted);
> +               dictPtr += matchlengthHeaderSize;
> +       }
> +
> +       {
> +               short litlengthNCount[MaxLL + 1];
> +               unsigned litlengthMaxValue = MaxLL, litlengthLog;
> +               size_t const litlengthHeaderSize = 
> FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, 
> dictEnd - dictPtr);
> +               if (FSE_isError(litlengthHeaderSize))
> +                       return ERROR(dictionary_corrupted);
> +               if (litlengthLog > LLFSELog)
> +                       return ERROR(dictionary_corrupted);
> +               CHECK_E(FSE_buildDTable_wksp(entropy->LLTable, 
> litlengthNCount, litlengthMaxValue, litlengthLog, entropy->workspace, 
> sizeof(entropy->workspace)), dictionary_corrupted);
> +               dictPtr += litlengthHeaderSize;
> +       }
> +
> +       if (dictPtr + 12 > dictEnd)
> +               return ERROR(dictionary_corrupted);
> +       {
> +               int i;
> +               size_t const dictContentSize = (size_t)(dictEnd - (dictPtr + 
> 12));
> +               for (i = 0; i < 3; i++) {
> +                       U32 const rep = ZSTD_readLE32(dictPtr);
> +                       dictPtr += 4;
> +                       if (rep == 0 || rep >= dictContentSize)
> +                               return ERROR(dictionary_corrupted);
> +                       entropy->rep[i] = rep;
> +               }
> +       }
> +
> +       return dictPtr - (const BYTE *)dict;
> +}
> +
> +static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx *dctx, const void 
> *dict, size_t dictSize)
> +{
> +       if (dictSize < 8)
> +               return ZSTD_refDictContent(dctx, dict, dictSize);
> +       {
> +               U32 const magic = ZSTD_readLE32(dict);
> +               if (magic != ZSTD_DICT_MAGIC) {
> +                       return ZSTD_refDictContent(dctx, dict, dictSize); /* 
> pure content mode */
> +               }
> +       }
> +       dctx->dictID = ZSTD_readLE32((const char *)dict + 4);
> +
> +       /* load entropy tables */
> +       {
> +               size_t const eSize = ZSTD_loadEntropy(&dctx->entropy, dict, 
> dictSize);
> +               if (ZSTD_isError(eSize))
> +                       return ERROR(dictionary_corrupted);
> +               dict = (const char *)dict + eSize;
> +               dictSize -= eSize;
> +       }
> +       dctx->litEntropy = dctx->fseEntropy = 1;
> +
> +       /* reference dictionary content */
> +       return ZSTD_refDictContent(dctx, dict, dictSize);
> +}
> +
> +size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx *dctx, const void *dict, 
> size_t dictSize)
> +{
> +       CHECK_F(ZSTD_decompressBegin(dctx));
> +       if (dict && dictSize)
> +               CHECK_E(ZSTD_decompress_insertDictionary(dctx, dict, 
> dictSize), dictionary_corrupted);
> +       return 0;
> +}
> +
> +/* ======   ZSTD_DDict   ====== */
> +
> +struct ZSTD_DDict_s {
> +       void *dictBuffer;
> +       const void *dictContent;
> +       size_t dictSize;
> +       ZSTD_entropyTables_t entropy;
> +       U32 dictID;
> +       U32 entropyPresent;
> +       ZSTD_customMem cMem;
> +}; /* typedef'd to ZSTD_DDict within "zstd.h" */
> +
> +size_t ZSTD_DDictWorkspaceBound(void) { return 
> ZSTD_ALIGN(sizeof(ZSTD_stack)) + ZSTD_ALIGN(sizeof(ZSTD_DDict)); }
> +
> +static const void *ZSTD_DDictDictContent(const ZSTD_DDict *ddict) { return 
> ddict->dictContent; }
> +
> +static size_t ZSTD_DDictDictSize(const ZSTD_DDict *ddict) { return 
> ddict->dictSize; }
> +
> +static void ZSTD_refDDict(ZSTD_DCtx *dstDCtx, const ZSTD_DDict *ddict)
> +{
> +       ZSTD_decompressBegin(dstDCtx); /* init */
> +       if (ddict) {                   /* support refDDict on NULL */
> +               dstDCtx->dictID = ddict->dictID;
> +               dstDCtx->base = ddict->dictContent;
> +               dstDCtx->vBase = ddict->dictContent;
> +               dstDCtx->dictEnd = (const BYTE *)ddict->dictContent + 
> ddict->dictSize;
> +               dstDCtx->previousDstEnd = dstDCtx->dictEnd;
> +               if (ddict->entropyPresent) {
> +                       dstDCtx->litEntropy = 1;
> +                       dstDCtx->fseEntropy = 1;
> +                       dstDCtx->LLTptr = ddict->entropy.LLTable;
> +                       dstDCtx->MLTptr = ddict->entropy.MLTable;
> +                       dstDCtx->OFTptr = ddict->entropy.OFTable;
> +                       dstDCtx->HUFptr = ddict->entropy.hufTable;
> +                       dstDCtx->entropy.rep[0] = ddict->entropy.rep[0];
> +                       dstDCtx->entropy.rep[1] = ddict->entropy.rep[1];
> +                       dstDCtx->entropy.rep[2] = ddict->entropy.rep[2];
> +               } else {
> +                       dstDCtx->litEntropy = 0;
> +                       dstDCtx->fseEntropy = 0;
> +               }
> +       }
> +}
> +
> +static size_t ZSTD_loadEntropy_inDDict(ZSTD_DDict *ddict)
> +{
> +       ddict->dictID = 0;
> +       ddict->entropyPresent = 0;
> +       if (ddict->dictSize < 8)
> +               return 0;
> +       {
> +               U32 const magic = ZSTD_readLE32(ddict->dictContent);
> +               if (magic != ZSTD_DICT_MAGIC)
> +                       return 0; /* pure content mode */
> +       }
> +       ddict->dictID = ZSTD_readLE32((const char *)ddict->dictContent + 4);
> +
> +       /* load entropy tables */
> +       CHECK_E(ZSTD_loadEntropy(&ddict->entropy, ddict->dictContent, 
> ddict->dictSize), dictionary_corrupted);
> +       ddict->entropyPresent = 1;
> +       return 0;
> +}
> +
> +static ZSTD_DDict *ZSTD_createDDict_advanced(const void *dict, size_t 
> dictSize, unsigned byReference, ZSTD_customMem customMem)
> +{
> +       if (!customMem.customAlloc || !customMem.customFree)
> +               return NULL;
> +
> +       {
> +               ZSTD_DDict *const ddict = (ZSTD_DDict 
> *)ZSTD_malloc(sizeof(ZSTD_DDict), customMem);
> +               if (!ddict)
> +                       return NULL;
> +               ddict->cMem = customMem;
> +
> +               if ((byReference) || (!dict) || (!dictSize)) {
> +                       ddict->dictBuffer = NULL;
> +                       ddict->dictContent = dict;
> +               } else {
> +                       void *const internalBuffer = ZSTD_malloc(dictSize, 
> customMem);
> +                       if (!internalBuffer) {
> +                               ZSTD_freeDDict(ddict);
> +                               return NULL;
> +                       }
> +                       memcpy(internalBuffer, dict, dictSize);
> +                       ddict->dictBuffer = internalBuffer;
> +                       ddict->dictContent = internalBuffer;
> +               }
> +               ddict->dictSize = dictSize;
> +               ddict->entropy.hufTable[0] = 
> (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
> +               /* parse dictionary content */
> +               {
> +                       size_t const errorCode = 
> ZSTD_loadEntropy_inDDict(ddict);
> +                       if (ZSTD_isError(errorCode)) {
> +                               ZSTD_freeDDict(ddict);
> +                               return NULL;
> +                       }
> +               }
> +
> +               return ddict;
> +       }
> +}
> +
> +/*! ZSTD_initDDict() :
> +*   Create a digested dictionary, to start decompression without startup 
> delay.
> +*   `dict` content is copied inside DDict.
> +*   Consequently, `dict` can be released after `ZSTD_DDict` creation */
> +ZSTD_DDict *ZSTD_initDDict(const void *dict, size_t dictSize, void 
> *workspace, size_t workspaceSize)
> +{
> +       ZSTD_customMem const stackMem = ZSTD_initStack(workspace, 
> workspaceSize);
> +       return ZSTD_createDDict_advanced(dict, dictSize, 1, stackMem);
> +}
> +
> +size_t ZSTD_freeDDict(ZSTD_DDict *ddict)
> +{
> +       if (ddict == NULL)
> +               return 0; /* support free on NULL */
> +       {
> +               ZSTD_customMem const cMem = ddict->cMem;
> +               ZSTD_free(ddict->dictBuffer, cMem);
> +               ZSTD_free(ddict, cMem);
> +               return 0;
> +       }
> +}
> +
> +/*! ZSTD_getDictID_fromDict() :
> + *  Provides the dictID stored within dictionary.
> + *  if @return == 0, the dictionary is not conformant with Zstandard 
> specification.
> + *  It can still be loaded, but as a content-only dictionary. */
> +unsigned ZSTD_getDictID_fromDict(const void *dict, size_t dictSize)
> +{
> +       if (dictSize < 8)
> +               return 0;
> +       if (ZSTD_readLE32(dict) != ZSTD_DICT_MAGIC)
> +               return 0;
> +       return ZSTD_readLE32((const char *)dict + 4);
> +}
> +
> +/*! ZSTD_getDictID_fromDDict() :
> + *  Provides the dictID of the dictionary loaded into `ddict`.
> + *  If @return == 0, the dictionary is not conformant to Zstandard 
> specification, or empty.
> + *  Non-conformant dictionaries can still be loaded, but as content-only 
> dictionaries. */
> +unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict *ddict)
> +{
> +       if (ddict == NULL)
> +               return 0;
> +       return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize);
> +}
> +
> +/*! ZSTD_getDictID_fromFrame() :
> + *  Provides the dictID required to decompressed the frame stored within 
> `src`.
> + *  If @return == 0, the dictID could not be decoded.
> + *  This could for one of the following reasons :
> + *  - The frame does not require a dictionary to be decoded (most common 
> case).
> + *  - The frame was built with dictID intentionally removed. Whatever 
> dictionary is necessary is a hidden information.
> + *    Note : this use case also happens when using a non-conformant 
> dictionary.
> + *  - `srcSize` is too small, and as a result, the frame header could not be 
> decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`).
> + *  - This is not a Zstandard frame.
> + *  When identifying the exact failure cause, it's possible to used 
> ZSTD_getFrameParams(), which will provide a more precise error code. */
> +unsigned ZSTD_getDictID_fromFrame(const void *src, size_t srcSize)
> +{
> +       ZSTD_frameParams zfp = {0, 0, 0, 0};
> +       size_t const hError = ZSTD_getFrameParams(&zfp, src, srcSize);
> +       if (ZSTD_isError(hError))
> +               return 0;
> +       return zfp.dictID;
> +}
> +
> +/*! ZSTD_decompress_usingDDict() :
> +*   Decompression using a pre-digested Dictionary
> +*   Use dictionary without significant overhead. */
> +size_t ZSTD_decompress_usingDDict(ZSTD_DCtx *dctx, void *dst, size_t 
> dstCapacity, const void *src, size_t srcSize, const ZSTD_DDict *ddict)
> +{
> +       /* pass content and size in case legacy frames are encountered */
> +       return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, 
> srcSize, NULL, 0, ddict);
> +}
> +
> +/*=====================================
> +*   Streaming decompression
> +*====================================*/
> +
> +typedef enum { zdss_init, zdss_loadHeader, zdss_read, zdss_load, zdss_flush 
> } ZSTD_dStreamStage;
> +
> +/* *** Resource management *** */
> +struct ZSTD_DStream_s {
> +       ZSTD_DCtx *dctx;
> +       ZSTD_DDict *ddictLocal;
> +       const ZSTD_DDict *ddict;
> +       ZSTD_frameParams fParams;
> +       ZSTD_dStreamStage stage;
> +       char *inBuff;
> +       size_t inBuffSize;
> +       size_t inPos;
> +       size_t maxWindowSize;
> +       char *outBuff;
> +       size_t outBuffSize;
> +       size_t outStart;
> +       size_t outEnd;
> +       size_t blockSize;
> +       BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; /* tmp buffer to store 
> frame header */
> +       size_t lhSize;
> +       ZSTD_customMem customMem;
> +       void *legacyContext;
> +       U32 previousLegacyVersion;
> +       U32 legacyVersion;
> +       U32 hostageByte;
> +}; /* typedef'd to ZSTD_DStream within "zstd.h" */
> +
> +size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize)
> +{
> +       size_t const blockSize = MIN(maxWindowSize, 
> ZSTD_BLOCKSIZE_ABSOLUTEMAX);
> +       size_t const inBuffSize = blockSize;
> +       size_t const outBuffSize = maxWindowSize + blockSize + 
> WILDCOPY_OVERLENGTH * 2;
> +       return ZSTD_DCtxWorkspaceBound() + ZSTD_ALIGN(sizeof(ZSTD_DStream)) + 
> ZSTD_ALIGN(inBuffSize) + ZSTD_ALIGN(outBuffSize);
> +}
> +
> +static ZSTD_DStream *ZSTD_createDStream_advanced(ZSTD_customMem customMem)
> +{
> +       ZSTD_DStream *zds;
> +
> +       if (!customMem.customAlloc || !customMem.customFree)
> +               return NULL;
> +
> +       zds = (ZSTD_DStream *)ZSTD_malloc(sizeof(ZSTD_DStream), customMem);
> +       if (zds == NULL)
> +               return NULL;
> +       memset(zds, 0, sizeof(ZSTD_DStream));
> +       memcpy(&zds->customMem, &customMem, sizeof(ZSTD_customMem));
> +       zds->dctx = ZSTD_createDCtx_advanced(customMem);
> +       if (zds->dctx == NULL) {
> +               ZSTD_freeDStream(zds);
> +               return NULL;
> +       }
> +       zds->stage = zdss_init;
> +       zds->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
> +       return zds;
> +}
> +
> +ZSTD_DStream *ZSTD_initDStream(size_t maxWindowSize, void *workspace, size_t 
> workspaceSize)
> +{
> +       ZSTD_customMem const stackMem = ZSTD_initStack(workspace, 
> workspaceSize);
> +       ZSTD_DStream *zds = ZSTD_createDStream_advanced(stackMem);
> +       if (!zds) {
> +               return NULL;
> +       }
> +
> +       zds->maxWindowSize = maxWindowSize;
> +       zds->stage = zdss_loadHeader;
> +       zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
> +       ZSTD_freeDDict(zds->ddictLocal);
> +       zds->ddictLocal = NULL;
> +       zds->ddict = zds->ddictLocal;
> +       zds->legacyVersion = 0;
> +       zds->hostageByte = 0;
> +
> +       {
> +               size_t const blockSize = MIN(zds->maxWindowSize, 
> ZSTD_BLOCKSIZE_ABSOLUTEMAX);
> +               size_t const neededOutSize = zds->maxWindowSize + blockSize + 
> WILDCOPY_OVERLENGTH * 2;
> +
> +               zds->inBuff = (char *)ZSTD_malloc(blockSize, zds->customMem);
> +               zds->inBuffSize = blockSize;
> +               zds->outBuff = (char *)ZSTD_malloc(neededOutSize, 
> zds->customMem);
> +               zds->outBuffSize = neededOutSize;
> +               if (zds->inBuff == NULL || zds->outBuff == NULL) {
> +                       ZSTD_freeDStream(zds);
> +                       return NULL;
> +               }
> +       }
> +       return zds;
> +}
> +
> +ZSTD_DStream *ZSTD_initDStream_usingDDict(size_t maxWindowSize, const 
> ZSTD_DDict *ddict, void *workspace, size_t workspaceSize)
> +{
> +       ZSTD_DStream *zds = ZSTD_initDStream(maxWindowSize, workspace, 
> workspaceSize);
> +       if (zds) {
> +               zds->ddict = ddict;
> +       }
> +       return zds;
> +}
> +
> +size_t ZSTD_freeDStream(ZSTD_DStream *zds)
> +{
> +       if (zds == NULL)
> +               return 0; /* support free on null */
> +       {
> +               ZSTD_customMem const cMem = zds->customMem;
> +               ZSTD_freeDCtx(zds->dctx);
> +               zds->dctx = NULL;
> +               ZSTD_freeDDict(zds->ddictLocal);
> +               zds->ddictLocal = NULL;
> +               ZSTD_free(zds->inBuff, cMem);
> +               zds->inBuff = NULL;
> +               ZSTD_free(zds->outBuff, cMem);
> +               zds->outBuff = NULL;
> +               ZSTD_free(zds, cMem);
> +               return 0;
> +       }
> +}
> +
> +/* *** Initialization *** */
> +
> +size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX + 
> ZSTD_blockHeaderSize; }
> +size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
> +
> +size_t ZSTD_resetDStream(ZSTD_DStream *zds)
> +{
> +       zds->stage = zdss_loadHeader;
> +       zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
> +       zds->legacyVersion = 0;
> +       zds->hostageByte = 0;
> +       return ZSTD_frameHeaderSize_prefix;
> +}
> +
> +/* *****   Decompression   ***** */
> +
> +ZSTD_STATIC size_t ZSTD_limitCopy(void *dst, size_t dstCapacity, const void 
> *src, size_t srcSize)
> +{
> +       size_t const length = MIN(dstCapacity, srcSize);
> +       memcpy(dst, src, length);
> +       return length;
> +}
> +
> +size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output, 
> ZSTD_inBuffer *input)
> +{
> +       const char *const istart = (const char *)(input->src) + input->pos;
> +       const char *const iend = (const char *)(input->src) + input->size;
> +       const char *ip = istart;
> +       char *const ostart = (char *)(output->dst) + output->pos;
> +       char *const oend = (char *)(output->dst) + output->size;
> +       char *op = ostart;
> +       U32 someMoreWork = 1;
> +
> +       while (someMoreWork) {
> +               switch (zds->stage) {
> +               case zdss_init:
> +                       ZSTD_resetDStream(zds); /* transparent reset on 
> starting decoding a new frame */
> +                                               /* fall-through */
> +
> +               case zdss_loadHeader: {
> +                       size_t const hSize = 
> ZSTD_getFrameParams(&zds->fParams, zds->headerBuffer, zds->lhSize);
> +                       if (ZSTD_isError(hSize))
> +                               return hSize;
> +                       if (hSize != 0) {                                  /* 
> need more input */
> +                               size_t const toLoad = hSize - zds->lhSize; /* 
> if hSize!=0, hSize > zds->lhSize */
> +                               if (toLoad > (size_t)(iend - ip)) {     /* 
> not enough input to load full header */
> +                                       memcpy(zds->headerBuffer + 
> zds->lhSize, ip, iend - ip);
> +                                       zds->lhSize += iend - ip;
> +                                       input->pos = input->size;
> +                                       return (MAX(ZSTD_frameHeaderSize_min, 
> hSize) - zds->lhSize) +
> +                                              ZSTD_blockHeaderSize; /* 
> remaining header bytes + next block header */
> +                               }
> +                               memcpy(zds->headerBuffer + zds->lhSize, ip, 
> toLoad);
> +                               zds->lhSize = hSize;
> +                               ip += toLoad;
> +                               break;
> +                       }
> +
> +                       /* check for single-pass mode opportunity */
> +                       if (zds->fParams.frameContentSize && 
> zds->fParams.windowSize /* skippable frame if == 0 */
> +                           && (U64)(size_t)(oend - op) >= 
> zds->fParams.frameContentSize) {
> +                               size_t const cSize = 
> ZSTD_findFrameCompressedSize(istart, iend - istart);
> +                               if (cSize <= (size_t)(iend - istart)) {
> +                                       size_t const decompressedSize = 
> ZSTD_decompress_usingDDict(zds->dctx, op, oend - op, istart, cSize, 
> zds->ddict);
> +                                       if (ZSTD_isError(decompressedSize))
> +                                               return decompressedSize;
> +                                       ip = istart + cSize;
> +                                       op += decompressedSize;
> +                                       zds->dctx->expected = 0;
> +                                       zds->stage = zdss_init;
> +                                       someMoreWork = 0;
> +                                       break;
> +                               }
> +                       }
> +
> +                       /* Consume header */
> +                       ZSTD_refDDict(zds->dctx, zds->ddict);
> +                       {
> +                               size_t const h1Size = 
> ZSTD_nextSrcSizeToDecompress(zds->dctx); /* == ZSTD_frameHeaderSize_prefix */
> +                               CHECK_F(ZSTD_decompressContinue(zds->dctx, 
> NULL, 0, zds->headerBuffer, h1Size));
> +                               {
> +                                       size_t const h2Size = 
> ZSTD_nextSrcSizeToDecompress(zds->dctx);
> +                                       
> CHECK_F(ZSTD_decompressContinue(zds->dctx, NULL, 0, zds->headerBuffer + 
> h1Size, h2Size));
> +                               }
> +                       }
> +
> +                       zds->fParams.windowSize = 
> MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
> +                       if (zds->fParams.windowSize > zds->maxWindowSize)
> +                               return ERROR(frameParameter_windowTooLarge);
> +
> +                       /* Buffers are preallocated, but double check */
> +                       {
> +                               size_t const blockSize = 
> MIN(zds->maxWindowSize, ZSTD_BLOCKSIZE_ABSOLUTEMAX);
> +                               size_t const neededOutSize = 
> zds->maxWindowSize + blockSize + WILDCOPY_OVERLENGTH * 2;
> +                               if (zds->inBuffSize < blockSize) {
> +                                       return ERROR(GENERIC);
> +                               }
> +                               if (zds->outBuffSize < neededOutSize) {
> +                                       return ERROR(GENERIC);
> +                               }
> +                               zds->blockSize = blockSize;
> +                       }
> +                       zds->stage = zdss_read;
> +               }
> +               /* pass-through */
> +
> +               case zdss_read: {
> +                       size_t const neededInSize = 
> ZSTD_nextSrcSizeToDecompress(zds->dctx);
> +                       if (neededInSize == 0) { /* end of frame */
> +                               zds->stage = zdss_init;
> +                               someMoreWork = 0;
> +                               break;
> +                       }
> +                       if ((size_t)(iend - ip) >= neededInSize) { /* decode 
> directly from src */
> +                               const int isSkipFrame = 
> ZSTD_isSkipFrame(zds->dctx);
> +                               size_t const decodedSize = 
> ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart,
> +                                                                             
>      (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart), ip, neededInSize);
> +                               if (ZSTD_isError(decodedSize))
> +                                       return decodedSize;
> +                               ip += neededInSize;
> +                               if (!decodedSize && !isSkipFrame)
> +                                       break; /* this was just a header */
> +                               zds->outEnd = zds->outStart + decodedSize;
> +                               zds->stage = zdss_flush;
> +                               break;
> +                       }
> +                       if (ip == iend) {
> +                               someMoreWork = 0;
> +                               break;
> +                       } /* no more input */
> +                       zds->stage = zdss_load;
> +                       /* pass-through */
> +               }
> +
> +               case zdss_load: {
> +                       size_t const neededInSize = 
> ZSTD_nextSrcSizeToDecompress(zds->dctx);
> +                       size_t const toLoad = neededInSize - zds->inPos; /* 
> should always be <= remaining space within inBuff */
> +                       size_t loadedSize;
> +                       if (toLoad > zds->inBuffSize - zds->inPos)
> +                               return ERROR(corruption_detected); /* should 
> never happen */
> +                       loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, 
> toLoad, ip, iend - ip);
> +                       ip += loadedSize;
> +                       zds->inPos += loadedSize;
> +                       if (loadedSize < toLoad) {
> +                               someMoreWork = 0;
> +                               break;
> +                       } /* not enough input, wait for more */
> +
> +                       /* decode loaded input */
> +                       {
> +                               const int isSkipFrame = 
> ZSTD_isSkipFrame(zds->dctx);
> +                               size_t const decodedSize = 
> ZSTD_decompressContinue(zds->dctx, zds->outBuff + zds->outStart, 
> zds->outBuffSize - zds->outStart,
> +                                                                             
>      zds->inBuff, neededInSize);
> +                               if (ZSTD_isError(decodedSize))
> +                                       return decodedSize;
> +                               zds->inPos = 0; /* input is consumed */
> +                               if (!decodedSize && !isSkipFrame) {
> +                                       zds->stage = zdss_read;
> +                                       break;
> +                               } /* this was just a header */
> +                               zds->outEnd = zds->outStart + decodedSize;
> +                               zds->stage = zdss_flush;
> +                               /* pass-through */
> +                       }
> +               }
> +
> +               case zdss_flush: {
> +                       size_t const toFlushSize = zds->outEnd - 
> zds->outStart;
> +                       size_t const flushedSize = ZSTD_limitCopy(op, oend - 
> op, zds->outBuff + zds->outStart, toFlushSize);
> +                       op += flushedSize;
> +                       zds->outStart += flushedSize;
> +                       if (flushedSize == toFlushSize) { /* flush completed 
> */
> +                               zds->stage = zdss_read;
> +                               if (zds->outStart + zds->blockSize > 
> zds->outBuffSize)
> +                                       zds->outStart = zds->outEnd = 0;
> +                               break;
> +                       }
> +                       /* cannot complete flush */
> +                       someMoreWork = 0;
> +                       break;
> +               }
> +               default:
> +                       return ERROR(GENERIC); /* impossible */
> +               }
> +       }
> +
> +       /* result */
> +       input->pos += (size_t)(ip - istart);
> +       output->pos += (size_t)(op - ostart);
> +       {
> +               size_t nextSrcSizeHint = 
> ZSTD_nextSrcSizeToDecompress(zds->dctx);
> +               if (!nextSrcSizeHint) {                     /* frame fully 
> decoded */
> +                       if (zds->outEnd == zds->outStart) { /* output fully 
> flushed */
> +                               if (zds->hostageByte) {
> +                                       if (input->pos >= input->size) {
> +                                               zds->stage = zdss_read;
> +                                               return 1;
> +                                       }            /* can't release hostage 
> (not present) */
> +                                       input->pos++; /* release hostage */
> +                               }
> +                               return 0;
> +                       }
> +                       if (!zds->hostageByte) { /* output not fully flushed; 
> keep last byte as hostage; will be released when all output is flushed */
> +                               input->pos--;    /* note : pos > 0, 
> otherwise, impossible to finish reading last block */
> +                               zds->hostageByte = 1;
> +                       }
> +                       return 1;
> +               }
> +               nextSrcSizeHint += ZSTD_blockHeaderSize * 
> (ZSTD_nextInputType(zds->dctx) == ZSTDnit_block); /* preload header of next 
> block */
> +               if (zds->inPos > nextSrcSizeHint)
> +                       return ERROR(GENERIC); /* should never happen */
> +               nextSrcSizeHint -= zds->inPos; /* already loaded*/
> +               return nextSrcSizeHint;
> +       }
> +}
> +
> +EXPORT_SYMBOL(ZSTD_DCtxWorkspaceBound);
> +EXPORT_SYMBOL(ZSTD_initDCtx);
> +EXPORT_SYMBOL(ZSTD_decompressDCtx);
> +EXPORT_SYMBOL(ZSTD_decompress_usingDict);
> +
> +EXPORT_SYMBOL(ZSTD_DDictWorkspaceBound);
> +EXPORT_SYMBOL(ZSTD_initDDict);
> +EXPORT_SYMBOL(ZSTD_decompress_usingDDict);
> +
> +EXPORT_SYMBOL(ZSTD_DStreamWorkspaceBound);
> +EXPORT_SYMBOL(ZSTD_initDStream);
> +EXPORT_SYMBOL(ZSTD_initDStream_usingDDict);
> +EXPORT_SYMBOL(ZSTD_resetDStream);
> +EXPORT_SYMBOL(ZSTD_decompressStream);
> +EXPORT_SYMBOL(ZSTD_DStreamInSize);
> +EXPORT_SYMBOL(ZSTD_DStreamOutSize);
> +
> +EXPORT_SYMBOL(ZSTD_findFrameCompressedSize);
> +EXPORT_SYMBOL(ZSTD_getFrameContentSize);
> +EXPORT_SYMBOL(ZSTD_findDecompressedSize);
> +
> +EXPORT_SYMBOL(ZSTD_isFrame);
> +EXPORT_SYMBOL(ZSTD_getDictID_fromDict);
> +EXPORT_SYMBOL(ZSTD_getDictID_fromDDict);
> +EXPORT_SYMBOL(ZSTD_getDictID_fromFrame);
> +
> +EXPORT_SYMBOL(ZSTD_getFrameParams);
> +EXPORT_SYMBOL(ZSTD_decompressBegin);
> +EXPORT_SYMBOL(ZSTD_decompressBegin_usingDict);
> +EXPORT_SYMBOL(ZSTD_copyDCtx);
> +EXPORT_SYMBOL(ZSTD_nextSrcSizeToDecompress);
> +EXPORT_SYMBOL(ZSTD_decompressContinue);
> +EXPORT_SYMBOL(ZSTD_nextInputType);
> +
> +EXPORT_SYMBOL(ZSTD_decompressBlock);
> +EXPORT_SYMBOL(ZSTD_insertBlock);
> +
> +MODULE_LICENSE("Dual BSD/GPL");
> +MODULE_DESCRIPTION("Zstd Decompressor");
> diff --git a/grub-core/lib/zstd/entropy_common.c 
> b/grub-core/lib/zstd/entropy_common.c
> new file mode 100644
> index 000000000..2b0a643c3
> --- /dev/null
> +++ b/grub-core/lib/zstd/entropy_common.c
> @@ -0,0 +1,243 @@
> +/*
> + * Common functions of New Generation Entropy library
> + * Copyright (C) 2016, Yann Collet.
> + *
> + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the following disclaimer
> + * in the documentation and/or other materials provided with the
> + * distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + *
> + * You can contact the author at :
> + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
> + */
> +
> +/* *************************************
> +*  Dependencies
> +***************************************/
> +#include "error_private.h" /* ERR_*, ERROR */
> +#include "fse.h"
> +#include "huf.h"
> +#include "mem.h"
> +
> +/*===   Version   ===*/
> +unsigned FSE_versionNumber(void) { return FSE_VERSION_NUMBER; }
> +
> +/*===   Error Management   ===*/
> +unsigned FSE_isError(size_t code) { return ERR_isError(code); }
> +
> +unsigned HUF_isError(size_t code) { return ERR_isError(code); }
> +
> +/*-**************************************************************
> +*  FSE NCount encoding-decoding
> +****************************************************************/
> +size_t FSE_readNCount(short *normalizedCounter, unsigned *maxSVPtr, unsigned 
> *tableLogPtr, const void *headerBuffer, size_t hbSize)
> +{
> +       const BYTE *const istart = (const BYTE *)headerBuffer;
> +       const BYTE *const iend = istart + hbSize;
> +       const BYTE *ip = istart;
> +       int nbBits;
> +       int remaining;
> +       int threshold;
> +       U32 bitStream;
> +       int bitCount;
> +       unsigned charnum = 0;
> +       int previous0 = 0;
> +
> +       if (hbSize < 4)
> +               return ERROR(srcSize_wrong);
> +       bitStream = ZSTD_readLE32(ip);
> +       nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
> +       if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX)
> +               return ERROR(tableLog_tooLarge);
> +       bitStream >>= 4;
> +       bitCount = 4;
> +       *tableLogPtr = nbBits;
> +       remaining = (1 << nbBits) + 1;
> +       threshold = 1 << nbBits;
> +       nbBits++;
> +
> +       while ((remaining > 1) & (charnum <= *maxSVPtr)) {
> +               if (previous0) {
> +                       unsigned n0 = charnum;
> +                       while ((bitStream & 0xFFFF) == 0xFFFF) {
> +                               n0 += 24;
> +                               if (ip < iend - 5) {
> +                                       ip += 2;
> +                                       bitStream = ZSTD_readLE32(ip) >> 
> bitCount;
> +                               } else {
> +                                       bitStream >>= 16;
> +                                       bitCount += 16;
> +                               }
> +                       }
> +                       while ((bitStream & 3) == 3) {
> +                               n0 += 3;
> +                               bitStream >>= 2;
> +                               bitCount += 2;
> +                       }
> +                       n0 += bitStream & 3;
> +                       bitCount += 2;
> +                       if (n0 > *maxSVPtr)
> +                               return ERROR(maxSymbolValue_tooSmall);
> +                       while (charnum < n0)
> +                               normalizedCounter[charnum++] = 0;
> +                       if ((ip <= iend - 7) || (ip + (bitCount >> 3) <= iend 
> - 4)) {
> +                               ip += bitCount >> 3;
> +                               bitCount &= 7;
> +                               bitStream = ZSTD_readLE32(ip) >> bitCount;
> +                       } else {
> +                               bitStream >>= 2;
> +                       }
> +               }
> +               {
> +                       int const max = (2 * threshold - 1) - remaining;
> +                       int count;
> +
> +                       if ((bitStream & (threshold - 1)) < (U32)max) {
> +                               count = bitStream & (threshold - 1);
> +                               bitCount += nbBits - 1;
> +                       } else {
> +                               count = bitStream & (2 * threshold - 1);
> +                               if (count >= threshold)
> +                                       count -= max;
> +                               bitCount += nbBits;
> +                       }
> +
> +                       count--;                                 /* extra 
> accuracy */
> +                       remaining -= count < 0 ? -count : count; /* -1 means 
> +1 */
> +                       normalizedCounter[charnum++] = (short)count;
> +                       previous0 = !count;
> +                       while (remaining < threshold) {
> +                               nbBits--;
> +                               threshold >>= 1;
> +                       }
> +
> +                       if ((ip <= iend - 7) || (ip + (bitCount >> 3) <= iend 
> - 4)) {
> +                               ip += bitCount >> 3;
> +                               bitCount &= 7;
> +                       } else {
> +                               bitCount -= (int)(8 * (iend - 4 - ip));
> +                               ip = iend - 4;
> +                       }
> +                       bitStream = ZSTD_readLE32(ip) >> (bitCount & 31);
> +               }
> +       } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
> +       if (remaining != 1)
> +               return ERROR(corruption_detected);
> +       if (bitCount > 32)
> +               return ERROR(corruption_detected);
> +       *maxSVPtr = charnum - 1;
> +
> +       ip += (bitCount + 7) >> 3;
> +       return ip - istart;
> +}
> +
> +/*! HUF_readStats() :
> +       Read compact Huffman tree, saved by HUF_writeCTable().
> +       `huffWeight` is destination buffer.
> +       `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
> +       @return : size read from `src` , or an error Code .
> +       Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
> +*/
> +size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, 
> U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize, void 
> *workspace, size_t workspaceSize)
> +{
> +       U32 weightTotal;
> +       const BYTE *ip = (const BYTE *)src;
> +       size_t iSize;
> +       size_t oSize;
> +
> +       if (!srcSize)
> +               return ERROR(srcSize_wrong);
> +       iSize = ip[0];
> +       /* memset(huffWeight, 0, hwSize);   */ /* is not necessary, even 
> though some analyzer complain ... */
> +
> +       if (iSize >= 128) { /* special header */
> +               oSize = iSize - 127;
> +               iSize = ((oSize + 1) / 2);
> +               if (iSize + 1 > srcSize)
> +                       return ERROR(srcSize_wrong);
> +               if (oSize >= hwSize)
> +                       return ERROR(corruption_detected);
> +               ip += 1;
> +               {
> +                       U32 n;
> +                       for (n = 0; n < oSize; n += 2) {
> +                               huffWeight[n] = ip[n / 2] >> 4;
> +                               huffWeight[n + 1] = ip[n / 2] & 15;
> +                       }
> +               }
> +       } else {                                                 /* header 
> compressed with FSE (normal case) */
> +               if (iSize + 1 > srcSize)
> +                       return ERROR(srcSize_wrong);
> +               oSize = FSE_decompress_wksp(huffWeight, hwSize - 1, ip + 1, 
> iSize, 6, workspace, workspaceSize); /* max (hwSize-1) values decoded, as 
> last one is implied */
> +               if (FSE_isError(oSize))
> +                       return oSize;
> +       }
> +
> +       /* collect weight stats */
> +       memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
> +       weightTotal = 0;
> +       {
> +               U32 n;
> +               for (n = 0; n < oSize; n++) {
> +                       if (huffWeight[n] >= HUF_TABLELOG_MAX)
> +                               return ERROR(corruption_detected);
> +                       rankStats[huffWeight[n]]++;
> +                       weightTotal += (1 << huffWeight[n]) >> 1;
> +               }
> +       }
> +       if (weightTotal == 0)
> +               return ERROR(corruption_detected);
> +
> +       /* get last non-null symbol weight (implied, total must be 2^n) */
> +       {
> +               U32 const tableLog = BIT_highbit32(weightTotal) + 1;
> +               if (tableLog > HUF_TABLELOG_MAX)
> +                       return ERROR(corruption_detected);
> +               *tableLogPtr = tableLog;
> +               /* determine last weight */
> +               {
> +                       U32 const total = 1 << tableLog;
> +                       U32 const rest = total - weightTotal;
> +                       U32 const verif = 1 << BIT_highbit32(rest);
> +                       U32 const lastWeight = BIT_highbit32(rest) + 1;
> +                       if (verif != rest)
> +                               return ERROR(corruption_detected); /* last 
> value must be a clean power of 2 */
> +                       huffWeight[oSize] = (BYTE)lastWeight;
> +                       rankStats[lastWeight]++;
> +               }
> +       }
> +
> +       /* check tree construction validity */
> +       if ((rankStats[1] < 2) || (rankStats[1] & 1))
> +               return ERROR(corruption_detected); /* by construction : at 
> least 2 elts of rank 1, must be even */
> +
> +       /* results */
> +       *nbSymbolsPtr = (U32)(oSize + 1);
> +       return iSize + 1;
> +}
> diff --git a/grub-core/lib/zstd/error_private.h 
> b/grub-core/lib/zstd/error_private.h
> new file mode 100644
> index 000000000..1a60b31f7
> --- /dev/null
> +++ b/grub-core/lib/zstd/error_private.h
> @@ -0,0 +1,53 @@
> +/**
> + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
> + * All rights reserved.
> + *
> + * This source code is licensed under the BSD-style license found in the
> + * LICENSE file in the root directory of https://github.com/facebook/zstd.
> + * An additional grant of patent rights can be found in the PATENTS file in 
> the
> + * same directory.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + */
> +
> +/* Note : this module is expected to remain private, do not expose it */
> +
> +#ifndef ERROR_H_MODULE
> +#define ERROR_H_MODULE
> +
> +/* ****************************************
> +*  Dependencies
> +******************************************/
> +#include <linux/types.h> /* size_t */
> +#include <linux/zstd.h>  /* enum list */
> +
> +/* ****************************************
> +*  Compiler-specific
> +******************************************/
> +#define ERR_STATIC static __attribute__((unused))
> +
> +/*-****************************************
> +*  Customization (error_public.h)
> +******************************************/
> +typedef ZSTD_ErrorCode ERR_enum;
> +#define PREFIX(name) ZSTD_error_##name
> +
> +/*-****************************************
> +*  Error codes handling
> +******************************************/
> +#define ERROR(name) ((size_t)-PREFIX(name))
> +
> +ERR_STATIC unsigned ERR_isError(size_t code) { return (code > 
> ERROR(maxCode)); }
> +
> +ERR_STATIC ERR_enum ERR_getErrorCode(size_t code)
> +{
> +       if (!ERR_isError(code))
> +               return (ERR_enum)0;
> +       return (ERR_enum)(0 - code);
> +}
> +
> +#endif /* ERROR_H_MODULE */
> diff --git a/grub-core/lib/zstd/fse.h b/grub-core/lib/zstd/fse.h
> new file mode 100644
> index 000000000..7460ab04b
> --- /dev/null
> +++ b/grub-core/lib/zstd/fse.h
> @@ -0,0 +1,575 @@
> +/*
> + * FSE : Finite State Entropy codec
> + * Public Prototypes declaration
> + * Copyright (C) 2013-2016, Yann Collet.
> + *
> + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the following disclaimer
> + * in the documentation and/or other materials provided with the
> + * distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + *
> + * You can contact the author at :
> + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
> + */
> +#ifndef FSE_H
> +#define FSE_H
> +
> +/*-*****************************************
> +*  Dependencies
> +******************************************/
> +#include <linux/types.h> /* size_t, ptrdiff_t */
> +
> +/*-*****************************************
> +*  FSE_PUBLIC_API : control library symbols visibility
> +******************************************/
> +#define FSE_PUBLIC_API
> +
> +/*------   Version   ------*/
> +#define FSE_VERSION_MAJOR 0
> +#define FSE_VERSION_MINOR 9
> +#define FSE_VERSION_RELEASE 0
> +
> +#define FSE_LIB_VERSION 
> FSE_VERSION_MAJOR.FSE_VERSION_MINOR.FSE_VERSION_RELEASE
> +#define FSE_QUOTE(str) #str
> +#define FSE_EXPAND_AND_QUOTE(str) FSE_QUOTE(str)
> +#define FSE_VERSION_STRING FSE_EXPAND_AND_QUOTE(FSE_LIB_VERSION)
> +
> +#define FSE_VERSION_NUMBER (FSE_VERSION_MAJOR * 100 * 100 + 
> FSE_VERSION_MINOR * 100 + FSE_VERSION_RELEASE)
> +FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version 
> number; to be used when checking dll version */
> +
> +/*-*****************************************
> +*  Tool functions
> +******************************************/
> +FSE_PUBLIC_API size_t FSE_compressBound(size_t size); /* maximum compressed 
> size */
> +
> +/* Error Management */
> +FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return value 
> is an error code */
> +
> +/*-*****************************************
> +*  FSE detailed API
> +******************************************/
> +/*!
> +FSE_compress() does the following:
> +1. count symbol occurrence from source[] into table count[]
> +2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
> +3. save normalized counters to memory buffer using writeNCount()
> +4. build encoding table 'CTable' from normalized counters
> +5. encode the data stream using encoding table 'CTable'
> +
> +FSE_decompress() does the following:
> +1. read normalized counters with readNCount()
> +2. build decoding table 'DTable' from normalized counters
> +3. decode the data stream using decoding table 'DTable'
> +
> +The following API allows targeting specific sub-functions for advanced tasks.
> +For example, it's possible to compress several blocks using the same 
> 'CTable',
> +or to save and provide normalized distribution using external method.
> +*/
> +
> +/* *** COMPRESSION *** */
> +/*! FSE_optimalTableLog():
> +       dynamically downsize 'tableLog' when conditions are met.
> +       It saves CPU time, by using smaller tables, while preserving or even 
> improving compression ratio.
> +       @return : recommended tableLog (necessarily <= 'maxTableLog') */
> +FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t 
> srcSize, unsigned maxSymbolValue);
> +
> +/*! FSE_normalizeCount():
> +       normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
> +       'normalizedCounter' is a table of short, of minimum size 
> (maxSymbolValue+1).
> +       @return : tableLog,
> +                         or an errorCode, which can be tested using 
> FSE_isError() */
> +FSE_PUBLIC_API size_t FSE_normalizeCount(short *normalizedCounter, unsigned 
> tableLog, const unsigned *count, size_t srcSize, unsigned maxSymbolValue);
> +
> +/*! FSE_NCountWriteBound():
> +       Provides the maximum possible size of an FSE normalized table, given 
> 'maxSymbolValue' and 'tableLog'.
> +       Typically useful for allocation purpose. */
> +FSE_PUBLIC_API size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned 
> tableLog);
> +
> +/*! FSE_writeNCount():
> +       Compactly save 'normalizedCounter' into 'buffer'.
> +       @return : size of the compressed table,
> +                         or an errorCode, which can be tested using 
> FSE_isError(). */
> +FSE_PUBLIC_API size_t FSE_writeNCount(void *buffer, size_t bufferSize, const 
> short *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
> +
> +/*! Constructor and Destructor of FSE_CTable.
> +       Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' 
> */
> +typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be 
> more restrictive than void* */
> +
> +/*! FSE_compress_usingCTable():
> +       Compress `src` using `ct` into `dst` which must be already allocated.
> +       @return : size of compressed data (<= `dstCapacity`),
> +                         or 0 if compressed data could not fit into `dst`,
> +                         or an errorCode, which can be tested using 
> FSE_isError() */
> +FSE_PUBLIC_API size_t FSE_compress_usingCTable(void *dst, size_t 
> dstCapacity, const void *src, size_t srcSize, const FSE_CTable *ct);
> +
> +/*!
> +Tutorial :
> +----------
> +The first step is to count all symbols. FSE_count() does this job very fast.
> +Result will be saved into 'count', a table of unsigned int, which must be 
> already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
> +'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be 
> <= maxSymbolValuePtr[0]
> +maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= 
> original value)
> +FSE_count() will return the number of occurrence of the most frequent symbol.
> +This can be used to know if there is a single symbol within 'src', and to 
> quickly evaluate its compressibility.
> +If there is an error, the function will return an ErrorCode (which can be 
> tested using FSE_isError()).
> +
> +The next step is to normalize the frequencies.
> +FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
> +It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
> +You can use 'tableLog'==0 to mean "use default tableLog value".
> +If you are unsure of which tableLog value to use, you can ask 
> FSE_optimalTableLog(),
> +which will provide the optimal valid tableLog given sourceSize, 
> maxSymbolValue, and a user-defined maximum (0 means "default").
> +
> +The result of FSE_normalizeCount() will be saved into a table,
> +called 'normalizedCounter', which is a table of signed short.
> +'normalizedCounter' must be already allocated, and have at least 
> 'maxSymbolValue+1' cells.
> +The return value is tableLog if everything proceeded as expected.
> +It is 0 if there is a single symbol within distribution.
> +If there is an error (ex: invalid tableLog value), the function will return 
> an ErrorCode (which can be tested using FSE_isError()).
> +
> +'normalizedCounter' can be saved in a compact manner to a memory area using 
> FSE_writeNCount().
> +'buffer' must be already allocated.
> +For guaranteed success, buffer size must be at least FSE_headerBound().
> +The result of the function is the number of bytes written into 'buffer'.
> +If there is an error, the function will return an ErrorCode (which can be 
> tested using FSE_isError(); ex : buffer size too small).
> +
> +'normalizedCounter' can then be used to create the compression table 
> 'CTable'.
> +The space required by 'CTable' must be already allocated, using 
> FSE_createCTable().
> +You can then use FSE_buildCTable() to fill 'CTable'.
> +If there is an error, both functions will return an ErrorCode (which can be 
> tested using FSE_isError()).
> +
> +'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
> +Similar to FSE_count(), the convention is that 'src' is assumed to be a 
> table of char of size 'srcSize'
> +The function returns the size of compressed data (without header), 
> necessarily <= `dstCapacity`.
> +If it returns '0', compressed data could not fit into 'dst'.
> +If there is an error, the function will return an ErrorCode (which can be 
> tested using FSE_isError()).
> +*/
> +
> +/* *** DECOMPRESSION *** */
> +
> +/*! FSE_readNCount():
> +       Read compactly saved 'normalizedCounter' from 'rBuffer'.
> +       @return : size read from 'rBuffer',
> +                         or an errorCode, which can be tested using 
> FSE_isError().
> +                         maxSymbolValuePtr[0] and tableLogPtr[0] will also 
> be updated with their respective values */
> +FSE_PUBLIC_API size_t FSE_readNCount(short *normalizedCounter, unsigned 
> *maxSymbolValuePtr, unsigned *tableLogPtr, const void *rBuffer, size_t 
> rBuffSize);
> +
> +/*! Constructor and Destructor of FSE_DTable.
> +       Note that its size depends on 'tableLog' */
> +typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be 
> more restrictive than void* */
> +
> +/*! FSE_buildDTable():
> +       Builds 'dt', which must be already allocated, using 
> FSE_createDTable().
> +       return : 0, or an errorCode, which can be tested using FSE_isError() 
> */
> +FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short 
> *normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void 
> *workspace, size_t workspaceSize);
> +
> +/*! FSE_decompress_usingDTable():
> +       Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
> +       into `dst` which must be already allocated.
> +       @return : size of regenerated data (necessarily <= `dstCapacity`),
> +                         or an errorCode, which can be tested using 
> FSE_isError() */
> +FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void *dst, size_t 
> dstCapacity, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt);
> +
> +/*!
> +Tutorial :
> +----------
> +(Note : these functions only decompress FSE-compressed blocks.
> + If block is uncompressed, use memcpy() instead
> + If block is a single repeated byte, use memset() instead )
> +
> +The first step is to obtain the normalized frequencies of symbols.
> +This can be performed by FSE_readNCount() if it was saved using 
> FSE_writeNCount().
> +'normalizedCounter' must be already allocated, and have at least 
> 'maxSymbolValuePtr[0]+1' cells of signed short.
> +In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
> +or size the table to handle worst case situations (typically 256).
> +FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
> +The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
> +Note that 'rBufferSize' must be at least 4 bytes, even if useful information 
> is less than that.
> +If there is an error, the function will return an error code, which can be 
> tested using FSE_isError().
> +
> +The next step is to build the decompression tables 'FSE_DTable' from 
> 'normalizedCounter'.
> +This is performed by the function FSE_buildDTable().
> +The space required by 'FSE_DTable' must be already allocated using 
> FSE_createDTable().
> +If there is an error, the function will return an error code, which can be 
> tested using FSE_isError().
> +
> +`FSE_DTable` can then be used to decompress `cSrc`, with 
> FSE_decompress_usingDTable().
> +`cSrcSize` must be strictly correct, otherwise decompression will fail.
> +FSE_decompress_usingDTable() result will tell how many bytes were 
> regenerated (<=`dstCapacity`).
> +If there is an error, the function will return an error code, which can be 
> tested using FSE_isError(). (ex: dst buffer too small)
> +*/
> +
> +/* *** Dependency *** */
> +#include "bitstream.h"
> +
> +/* *****************************************
> +*  Static allocation
> +*******************************************/
> +/* FSE buffer bounds */
> +#define FSE_NCOUNTBOUND 512
> +#define FSE_BLOCKBOUND(size) (size + (size >> 7))
> +#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* 
> Macro version, useful for static allocation */
> +
> +/* It is possible to statically allocate FSE CTable/DTable as a table of 
> FSE_CTable/FSE_DTable using below macros */
> +#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1 << 
> (maxTableLog - 1)) + ((maxSymbolValue + 1) * 2))
> +#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1 << maxTableLog))
> +
> +/* *****************************************
> +*  FSE advanced API
> +*******************************************/
> +/* FSE_count_wksp() :
> + * Same as FSE_count(), but using an externally provided scratch buffer.
> + * `workSpace` size must be table of >= `1024` unsigned
> + */
> +size_t FSE_count_wksp(unsigned *count, unsigned *maxSymbolValuePtr, const 
> void *source, size_t sourceSize, unsigned *workSpace);
> +
> +/* FSE_countFast_wksp() :
> + * Same as FSE_countFast(), but using an externally provided scratch buffer.
> + * `workSpace` must be a table of minimum `1024` unsigned
> + */
> +size_t FSE_countFast_wksp(unsigned *count, unsigned *maxSymbolValuePtr, 
> const void *src, size_t srcSize, unsigned *workSpace);
> +
> +/*! FSE_count_simple
> + * Same as FSE_countFast(), but does not use any additional memory (not even 
> on stack).
> + * This function is unsafe, and will segfault if any value within `src` is 
> `> *maxSymbolValuePtr` (presuming it's also the size of `count`).
> +*/
> +size_t FSE_count_simple(unsigned *count, unsigned *maxSymbolValuePtr, const 
> void *src, size_t srcSize);
> +
> +unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, 
> unsigned maxSymbolValue, unsigned minus);
> +/**< same as FSE_optimalTableLog(), which used `minus==2` */
> +
> +size_t FSE_buildCTable_raw(FSE_CTable *ct, unsigned nbBits);
> +/**< build a fake FSE_CTable, designed for a flat distribution, where each 
> symbol uses nbBits */
> +
> +size_t FSE_buildCTable_rle(FSE_CTable *ct, unsigned char symbolValue);
> +/**< build a fake FSE_CTable, designed to compress always the same 
> symbolValue */
> +
> +/* FSE_buildCTable_wksp() :
> + * Same as FSE_buildCTable(), but using an externally allocated scratch 
> buffer (`workSpace`).
> + * `wkspSize` must be >= `(1<<tableLog)`.
> + */
> +size_t FSE_buildCTable_wksp(FSE_CTable *ct, const short *normalizedCounter, 
> unsigned maxSymbolValue, unsigned tableLog, void *workSpace, size_t wkspSize);
> +
> +size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits);
> +/**< build a fake FSE_DTable, designed to read a flat distribution where 
> each symbol uses nbBits */
> +
> +size_t FSE_buildDTable_rle(FSE_DTable *dt, unsigned char symbolValue);
> +/**< build a fake FSE_DTable, designed to always generate the same 
> symbolValue */
> +
> +size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, 
> size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize);
> +/**< same as FSE_decompress(), using an externally allocated `workSpace` 
> produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
> +
> +/* *****************************************
> +*  FSE symbol compression API
> +*******************************************/
> +/*!
> +   This API consists of small unitary functions, which highly benefit from 
> being inlined.
> +   Hence their body are included in next section.
> +*/
> +typedef struct {
> +       ptrdiff_t value;
> +       const void *stateTable;
> +       const void *symbolTT;
> +       unsigned stateLog;
> +} FSE_CState_t;
> +
> +static void FSE_initCState(FSE_CState_t *CStatePtr, const FSE_CTable *ct);
> +
> +static void FSE_encodeSymbol(BIT_CStream_t *bitC, FSE_CState_t *CStatePtr, 
> unsigned symbol);
> +
> +static void FSE_flushCState(BIT_CStream_t *bitC, const FSE_CState_t 
> *CStatePtr);
> +
> +/**<
> +These functions are inner components of FSE_compress_usingCTable().
> +They allow the creation of custom streams, mixing multiple tables and bit 
> sources.
> +
> +A key property to keep in mind is that encoding and decoding are done **in 
> reverse direction**.
> +So the first symbol you will encode is the last you will decode, like a LIFO 
> stack.
> +
> +You will need a few variables to track your CStream. They are :
> +
> +FSE_CTable    ct;         // Provided by FSE_buildCTable()
> +BIT_CStream_t bitStream;  // bitStream tracking structure
> +FSE_CState_t  state;      // State tracking structure (can have several)
> +
> +
> +The first thing to do is to init bitStream and state.
> +       size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
> +       FSE_initCState(&state, ct);
> +
> +Note that BIT_initCStream() can produce an error code, so its result should 
> be tested, using FSE_isError();
> +You can then encode your input data, byte after byte.
> +FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
> +Remember decoding will be done in reverse direction.
> +       FSE_encodeByte(&bitStream, &state, symbol);
> +
> +At any time, you can also add any bit sequence.
> +Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
> +       BIT_addBits(&bitStream, bitField, nbBits);
> +
> +The above methods don't commit data to memory, they just store it into local 
> register, for speed.
> +Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits 
> systems (size_t).
> +Writing data to memory is a manual operation, performed by the flushBits 
> function.
> +       BIT_flushBits(&bitStream);
> +
> +Your last FSE encoding operation shall be to flush your last state value(s).
> +       FSE_flushState(&bitStream, &state);
> +
> +Finally, you must close the bitStream.
> +The function returns the size of CStream in bytes.
> +If data couldn't fit into dstBuffer, it will return a 0 ( == not 
> compressible)
> +If there is an error, it returns an errorCode (which can be tested using 
> FSE_isError()).
> +       size_t size = BIT_closeCStream(&bitStream);
> +*/
> +
> +/* *****************************************
> +*  FSE symbol decompression API
> +*******************************************/
> +typedef struct {
> +       size_t state;
> +       const void *table; /* precise table may vary, depending on U16 */
> +} FSE_DState_t;
> +
> +static void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t *bitD, 
> const FSE_DTable *dt);
> +
> +static unsigned char FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t 
> *bitD);
> +
> +static unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr);
> +
> +/**<
> +Let's now decompose FSE_decompress_usingDTable() into its unitary components.
> +You will decode FSE-encoded symbols from the bitStream,
> +and also any other bitFields you put in, **in reverse order**.
> +
> +You will need a few variables to track your bitStream. They are :
> +
> +BIT_DStream_t DStream;    // Stream context
> +FSE_DState_t  DState;     // State context. Multiple ones are possible
> +FSE_DTable*   DTablePtr;  // Decoding table, provided by FSE_buildDTable()
> +
> +The first thing to do is to init the bitStream.
> +       errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
> +
> +You should then retrieve your initial state(s)
> +(in reverse flushing order if you have several ones) :
> +       errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
> +
> +You can then decode your data, symbol after symbol.
> +For information the maximum number of bits read by FSE_decodeSymbol() is 
> 'tableLog'.
> +Keep in mind that symbols are decoded in reverse order, like a LIFO stack 
> (last in, first out).
> +       unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
> +
> +You can retrieve any bitfield you eventually stored into the bitStream (in 
> reverse order)
> +Note : maximum allowed nbBits is 25, for 32-bits compatibility
> +       size_t bitField = BIT_readBits(&DStream, nbBits);
> +
> +All above operations only read from local register (which size depends on 
> size_t).
> +Refueling the register from memory is manually performed by the reload 
> method.
> +       endSignal = FSE_reloadDStream(&DStream);
> +
> +BIT_reloadDStream() result tells if there is still some more data to read 
> from DStream.
> +BIT_DStream_unfinished : there is still some data left into the DStream.
> +BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may 
> no longer be completely filled.
> +BIT_DStream_completed : Dstream reached its exact end, corresponding in 
> general to decompression completed.
> +BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
> +
> +When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, 
> notably if you decode multiple symbols per loop,
> +to properly detect the exact end of stream.
> +After each decoded symbol, check if DStream is fully consumed using this 
> simple test :
> +       BIT_reloadDStream(&DStream) >= BIT_DStream_completed
> +
> +When it's done, verify decompression is fully completed, by checking both 
> DStream and the relevant states.
> +Checking if DStream has reached its end is performed by :
> +       BIT_endOfDStream(&DStream);
> +Check also the states. There might be some symbols left there, if some high 
> probability ones (>50%) are possible.
> +       FSE_endOfDState(&DState);
> +*/
> +
> +/* *****************************************
> +*  FSE unsafe API
> +*******************************************/
> +static unsigned char FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, 
> BIT_DStream_t *bitD);
> +/* faster, but works only if nbBits is always >= 1 (otherwise, result will 
> be corrupted) */
> +
> +/* *****************************************
> +*  Implementation of inlined functions
> +*******************************************/
> +typedef struct {
> +       int deltaFindState;
> +       U32 deltaNbBits;
> +} FSE_symbolCompressionTransform; /* total 8 bytes */
> +
> +ZSTD_STATIC void FSE_initCState(FSE_CState_t *statePtr, const FSE_CTable *ct)
> +{
> +       const void *ptr = ct;
> +       const U16 *u16ptr = (const U16 *)ptr;
> +       const U32 tableLog = ZSTD_read16(ptr);
> +       statePtr->value = (ptrdiff_t)1 << tableLog;
> +       statePtr->stateTable = u16ptr + 2;
> +       statePtr->symbolTT = ((const U32 *)ct + 1 + (tableLog ? (1 << 
> (tableLog - 1)) : 1));
> +       statePtr->stateLog = tableLog;
> +}
> +
> +/*! FSE_initCState2() :
> +*   Same as FSE_initCState(), but the first symbol to include (which will be 
> the last to be read)
> +*   uses the smallest state value possible, saving the cost of this symbol */
> +ZSTD_STATIC void FSE_initCState2(FSE_CState_t *statePtr, const FSE_CTable 
> *ct, U32 symbol)
> +{
> +       FSE_initCState(statePtr, ct);
> +       {
> +               const FSE_symbolCompressionTransform symbolTT = ((const 
> FSE_symbolCompressionTransform *)(statePtr->symbolTT))[symbol];
> +               const U16 *stateTable = (const U16 *)(statePtr->stateTable);
> +               U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1 << 15)) >> 
> 16);
> +               statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
> +               statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + 
> symbolTT.deltaFindState];
> +       }
> +}
> +
> +ZSTD_STATIC void FSE_encodeSymbol(BIT_CStream_t *bitC, FSE_CState_t 
> *statePtr, U32 symbol)
> +{
> +       const FSE_symbolCompressionTransform symbolTT = ((const 
> FSE_symbolCompressionTransform *)(statePtr->symbolTT))[symbol];
> +       const U16 *const stateTable = (const U16 *)(statePtr->stateTable);
> +       U32 nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
> +       BIT_addBits(bitC, statePtr->value, nbBitsOut);
> +       statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + 
> symbolTT.deltaFindState];
> +}
> +
> +ZSTD_STATIC void FSE_flushCState(BIT_CStream_t *bitC, const FSE_CState_t 
> *statePtr)
> +{
> +       BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
> +       BIT_flushBits(bitC);
> +}
> +
> +/* ======    Decompression    ====== */
> +
> +typedef struct {
> +       U16 tableLog;
> +       U16 fastMode;
> +} FSE_DTableHeader; /* sizeof U32 */
> +
> +typedef struct {
> +       unsigned short newState;
> +       unsigned char symbol;
> +       unsigned char nbBits;
> +} FSE_decode_t; /* size == U32 */
> +
> +ZSTD_STATIC void FSE_initDState(FSE_DState_t *DStatePtr, BIT_DStream_t 
> *bitD, const FSE_DTable *dt)
> +{
> +       const void *ptr = dt;
> +       const FSE_DTableHeader *const DTableH = (const FSE_DTableHeader *)ptr;
> +       DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
> +       BIT_reloadDStream(bitD);
> +       DStatePtr->table = dt + 1;
> +}
> +
> +ZSTD_STATIC BYTE FSE_peekSymbol(const FSE_DState_t *DStatePtr)
> +{
> +       FSE_decode_t const DInfo = ((const FSE_decode_t 
> *)(DStatePtr->table))[DStatePtr->state];
> +       return DInfo.symbol;
> +}
> +
> +ZSTD_STATIC void FSE_updateState(FSE_DState_t *DStatePtr, BIT_DStream_t 
> *bitD)
> +{
> +       FSE_decode_t const DInfo = ((const FSE_decode_t 
> *)(DStatePtr->table))[DStatePtr->state];
> +       U32 const nbBits = DInfo.nbBits;
> +       size_t const lowBits = BIT_readBits(bitD, nbBits);
> +       DStatePtr->state = DInfo.newState + lowBits;
> +}
> +
> +ZSTD_STATIC BYTE FSE_decodeSymbol(FSE_DState_t *DStatePtr, BIT_DStream_t 
> *bitD)
> +{
> +       FSE_decode_t const DInfo = ((const FSE_decode_t 
> *)(DStatePtr->table))[DStatePtr->state];
> +       U32 const nbBits = DInfo.nbBits;
> +       BYTE const symbol = DInfo.symbol;
> +       size_t const lowBits = BIT_readBits(bitD, nbBits);
> +
> +       DStatePtr->state = DInfo.newState + lowBits;
> +       return symbol;
> +}
> +
> +/*! FSE_decodeSymbolFast() :
> +       unsafe, only works if no symbol has a probability > 50% */
> +ZSTD_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t *DStatePtr, BIT_DStream_t 
> *bitD)
> +{
> +       FSE_decode_t const DInfo = ((const FSE_decode_t 
> *)(DStatePtr->table))[DStatePtr->state];
> +       U32 const nbBits = DInfo.nbBits;
> +       BYTE const symbol = DInfo.symbol;
> +       size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
> +
> +       DStatePtr->state = DInfo.newState + lowBits;
> +       return symbol;
> +}
> +
> +ZSTD_STATIC unsigned FSE_endOfDState(const FSE_DState_t *DStatePtr) { return 
> DStatePtr->state == 0; }
> +
> +/* **************************************************************
> +*  Tuning parameters
> +****************************************************************/
> +/*!MEMORY_USAGE :
> +*  Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 
> -> 64KB; 20 -> 1MB; etc.)
> +*  Increasing memory usage improves compression ratio
> +*  Reduced memory usage can improve speed, due to cache effect
> +*  Recommended max value is 14, for 16KB, which nicely fits into Intel x86 
> L1 cache */
> +#ifndef FSE_MAX_MEMORY_USAGE
> +#define FSE_MAX_MEMORY_USAGE 14
> +#endif
> +#ifndef FSE_DEFAULT_MEMORY_USAGE
> +#define FSE_DEFAULT_MEMORY_USAGE 13
> +#endif
> +
> +/*!FSE_MAX_SYMBOL_VALUE :
> +*  Maximum symbol value authorized.
> +*  Required for proper stack allocation */
> +#ifndef FSE_MAX_SYMBOL_VALUE
> +#define FSE_MAX_SYMBOL_VALUE 255
> +#endif
> +
> +/* **************************************************************
> +*  template functions type & suffix
> +****************************************************************/
> +#define FSE_FUNCTION_TYPE BYTE
> +#define FSE_FUNCTION_EXTENSION
> +#define FSE_DECODE_TYPE FSE_decode_t
> +
> +/* ***************************************************************
> +*  Constants
> +*****************************************************************/
> +#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE - 2)
> +#define FSE_MAX_TABLESIZE (1U << FSE_MAX_TABLELOG)
> +#define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE - 1)
> +#define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE - 2)
> +#define FSE_MIN_TABLELOG 5
> +
> +#define FSE_TABLELOG_ABSOLUTE_MAX 15
> +#if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
> +#error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
> +#endif
> +
> +#define FSE_TABLESTEP(tableSize) ((tableSize >> 1) + (tableSize >> 3) + 3)
> +
> +#endif /* FSE_H */
> diff --git a/grub-core/lib/zstd/fse_decompress.c 
> b/grub-core/lib/zstd/fse_decompress.c
> new file mode 100644
> index 000000000..a84300e5a
> --- /dev/null
> +++ b/grub-core/lib/zstd/fse_decompress.c
> @@ -0,0 +1,332 @@
> +/*
> + * FSE : Finite State Entropy decoder
> + * Copyright (C) 2013-2015, Yann Collet.
> + *
> + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the following disclaimer
> + * in the documentation and/or other materials provided with the
> + * distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + *
> + * You can contact the author at :
> + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
> + */
> +
> +/* **************************************************************
> +*  Compiler specifics
> +****************************************************************/
> +#define FORCE_INLINE static __always_inline
> +
> +/* **************************************************************
> +*  Includes
> +****************************************************************/
> +#include "bitstream.h"
> +#include "fse.h"
> +#include <linux/compiler.h>
> +#include <linux/kernel.h>
> +#include <linux/string.h> /* memcpy, memset */
> +
> +/* **************************************************************
> +*  Error Management
> +****************************************************************/
> +#define FSE_isError ERR_isError
> +#define FSE_STATIC_ASSERT(c)                                   \
> +       {                                                      \
> +               enum { FSE_static_assert = 1 / (int)(!!(c)) }; \
> +       } /* use only *after* variable declarations */
> +
> +/* check and forward error code */
> +#define CHECK_F(f)                  \
> +       {                           \
> +               size_t const e = f; \
> +               if (FSE_isError(e)) \
> +                       return e;   \
> +       }
> +
> +/* **************************************************************
> +*  Templates
> +****************************************************************/
> +/*
> +  designed to be included
> +  for type-specific functions (template emulation in C)
> +  Objective is to write these functions only once, for improved maintenance
> +*/
> +
> +/* safety checks */
> +#ifndef FSE_FUNCTION_EXTENSION
> +#error "FSE_FUNCTION_EXTENSION must be defined"
> +#endif
> +#ifndef FSE_FUNCTION_TYPE
> +#error "FSE_FUNCTION_TYPE must be defined"
> +#endif
> +
> +/* Function names */
> +#define FSE_CAT(X, Y) X##Y
> +#define FSE_FUNCTION_NAME(X, Y) FSE_CAT(X, Y)
> +#define FSE_TYPE_NAME(X, Y) FSE_CAT(X, Y)
> +
> +/* Function templates */
> +
> +size_t FSE_buildDTable_wksp(FSE_DTable *dt, const short *normalizedCounter, 
> unsigned maxSymbolValue, unsigned tableLog, void *workspace, size_t 
> workspaceSize)
> +{
> +       void *const tdPtr = dt + 1; /* because *dt is unsigned, 32-bits 
> aligned on 32-bits */
> +       FSE_DECODE_TYPE *const tableDecode = (FSE_DECODE_TYPE *)(tdPtr);
> +       U16 *symbolNext = (U16 *)workspace;
> +
> +       U32 const maxSV1 = maxSymbolValue + 1;
> +       U32 const tableSize = 1 << tableLog;
> +       U32 highThreshold = tableSize - 1;
> +
> +       /* Sanity Checks */
> +       if (workspaceSize < sizeof(U16) * (FSE_MAX_SYMBOL_VALUE + 1))
> +               return ERROR(tableLog_tooLarge);
> +       if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE)
> +               return ERROR(maxSymbolValue_tooLarge);
> +       if (tableLog > FSE_MAX_TABLELOG)
> +               return ERROR(tableLog_tooLarge);
> +
> +       /* Init, lay down lowprob symbols */
> +       {
> +               FSE_DTableHeader DTableH;
> +               DTableH.tableLog = (U16)tableLog;
> +               DTableH.fastMode = 1;
> +               {
> +                       S16 const largeLimit = (S16)(1 << (tableLog - 1));
> +                       U32 s;
> +                       for (s = 0; s < maxSV1; s++) {
> +                               if (normalizedCounter[s] == -1) {
> +                                       tableDecode[highThreshold--].symbol = 
> (FSE_FUNCTION_TYPE)s;
> +                                       symbolNext[s] = 1;
> +                               } else {
> +                                       if (normalizedCounter[s] >= 
> largeLimit)
> +                                               DTableH.fastMode = 0;
> +                                       symbolNext[s] = normalizedCounter[s];
> +                               }
> +                       }
> +               }
> +               memcpy(dt, &DTableH, sizeof(DTableH));
> +       }
> +
> +       /* Spread symbols */
> +       {
> +               U32 const tableMask = tableSize - 1;
> +               U32 const step = FSE_TABLESTEP(tableSize);
> +               U32 s, position = 0;
> +               for (s = 0; s < maxSV1; s++) {
> +                       int i;
> +                       for (i = 0; i < normalizedCounter[s]; i++) {
> +                               tableDecode[position].symbol = 
> (FSE_FUNCTION_TYPE)s;
> +                               position = (position + step) & tableMask;
> +                               while (position > highThreshold)
> +                                       position = (position + step) & 
> tableMask; /* lowprob area */
> +                       }
> +               }
> +               if (position != 0)
> +                       return ERROR(GENERIC); /* position must reach all 
> cells once, otherwise normalizedCounter is incorrect */
> +       }
> +
> +       /* Build Decoding table */
> +       {
> +               U32 u;
> +               for (u = 0; u < tableSize; u++) {
> +                       FSE_FUNCTION_TYPE const symbol = 
> (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
> +                       U16 nextState = symbolNext[symbol]++;
> +                       tableDecode[u].nbBits = (BYTE)(tableLog - 
> BIT_highbit32((U32)nextState));
> +                       tableDecode[u].newState = (U16)((nextState << 
> tableDecode[u].nbBits) - tableSize);
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +/*-*******************************************************
> +*  Decompression (Byte symbols)
> +*********************************************************/
> +size_t FSE_buildDTable_rle(FSE_DTable *dt, BYTE symbolValue)
> +{
> +       void *ptr = dt;
> +       FSE_DTableHeader *const DTableH = (FSE_DTableHeader *)ptr;
> +       void *dPtr = dt + 1;
> +       FSE_decode_t *const cell = (FSE_decode_t *)dPtr;
> +
> +       DTableH->tableLog = 0;
> +       DTableH->fastMode = 0;
> +
> +       cell->newState = 0;
> +       cell->symbol = symbolValue;
> +       cell->nbBits = 0;
> +
> +       return 0;
> +}
> +
> +size_t FSE_buildDTable_raw(FSE_DTable *dt, unsigned nbBits)
> +{
> +       void *ptr = dt;
> +       FSE_DTableHeader *const DTableH = (FSE_DTableHeader *)ptr;
> +       void *dPtr = dt + 1;
> +       FSE_decode_t *const dinfo = (FSE_decode_t *)dPtr;
> +       const unsigned tableSize = 1 << nbBits;
> +       const unsigned tableMask = tableSize - 1;
> +       const unsigned maxSV1 = tableMask + 1;
> +       unsigned s;
> +
> +       /* Sanity checks */
> +       if (nbBits < 1)
> +               return ERROR(GENERIC); /* min size */
> +
> +       /* Build Decoding Table */
> +       DTableH->tableLog = (U16)nbBits;
> +       DTableH->fastMode = 1;
> +       for (s = 0; s < maxSV1; s++) {
> +               dinfo[s].newState = 0;
> +               dinfo[s].symbol = (BYTE)s;
> +               dinfo[s].nbBits = (BYTE)nbBits;
> +       }
> +
> +       return 0;
> +}
> +
> +FORCE_INLINE size_t FSE_decompress_usingDTable_generic(void *dst, size_t 
> maxDstSize, const void *cSrc, size_t cSrcSize, const FSE_DTable *dt,
> +                                                      const unsigned fast)
> +{
> +       BYTE *const ostart = (BYTE *)dst;
> +       BYTE *op = ostart;
> +       BYTE *const omax = op + maxDstSize;
> +       BYTE *const olimit = omax - 3;
> +
> +       BIT_DStream_t bitD;
> +       FSE_DState_t state1;
> +       FSE_DState_t state2;
> +
> +       /* Init */
> +       CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
> +
> +       FSE_initDState(&state1, &bitD, dt);
> +       FSE_initDState(&state2, &bitD, dt);
> +
> +#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) 
> : FSE_decodeSymbol(statePtr, &bitD)
> +
> +       /* 4 symbols per loop */
> +       for (; (BIT_reloadDStream(&bitD) == BIT_DStream_unfinished) & (op < 
> olimit); op += 4) {
> +               op[0] = FSE_GETSYMBOL(&state1);
> +
> +               if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) 
> /* This test must be static */
> +                       BIT_reloadDStream(&bitD);
> +
> +               op[1] = FSE_GETSYMBOL(&state2);
> +
> +               if (FSE_MAX_TABLELOG * 4 + 7 > sizeof(bitD.bitContainer) * 8) 
> /* This test must be static */
> +               {
> +                       if (BIT_reloadDStream(&bitD) > 
> BIT_DStream_unfinished) {
> +                               op += 2;
> +                               break;
> +                       }
> +               }
> +
> +               op[2] = FSE_GETSYMBOL(&state1);
> +
> +               if (FSE_MAX_TABLELOG * 2 + 7 > sizeof(bitD.bitContainer) * 8) 
> /* This test must be static */
> +                       BIT_reloadDStream(&bitD);
> +
> +               op[3] = FSE_GETSYMBOL(&state2);
> +       }
> +
> +       /* tail */
> +       /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; 
> Ends at exactly BIT_DStream_completed */
> +       while (1) {
> +               if (op > (omax - 2))
> +                       return ERROR(dstSize_tooSmall);
> +               *op++ = FSE_GETSYMBOL(&state1);
> +               if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) {
> +                       *op++ = FSE_GETSYMBOL(&state2);
> +                       break;
> +               }
> +
> +               if (op > (omax - 2))
> +                       return ERROR(dstSize_tooSmall);
> +               *op++ = FSE_GETSYMBOL(&state2);
> +               if (BIT_reloadDStream(&bitD) == BIT_DStream_overflow) {
> +                       *op++ = FSE_GETSYMBOL(&state1);
> +                       break;
> +               }
> +       }
> +
> +       return op - ostart;
> +}
> +
> +size_t FSE_decompress_usingDTable(void *dst, size_t originalSize, const void 
> *cSrc, size_t cSrcSize, const FSE_DTable *dt)
> +{
> +       const void *ptr = dt;
> +       const FSE_DTableHeader *DTableH = (const FSE_DTableHeader *)ptr;
> +       const U32 fastMode = DTableH->fastMode;
> +
> +       /* select fast mode (static) */
> +       if (fastMode)
> +               return FSE_decompress_usingDTable_generic(dst, originalSize, 
> cSrc, cSrcSize, dt, 1);
> +       return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, 
> cSrcSize, dt, 0);
> +}
> +
> +size_t FSE_decompress_wksp(void *dst, size_t dstCapacity, const void *cSrc, 
> size_t cSrcSize, unsigned maxLog, void *workspace, size_t workspaceSize)
> +{
> +       const BYTE *const istart = (const BYTE *)cSrc;
> +       const BYTE *ip = istart;
> +       unsigned tableLog;
> +       unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
> +       size_t NCountLength;
> +
> +       FSE_DTable *dt;
> +       short *counting;
> +       size_t spaceUsed32 = 0;
> +
> +       FSE_STATIC_ASSERT(sizeof(FSE_DTable) == sizeof(U32));
> +
> +       dt = (FSE_DTable *)((U32 *)workspace + spaceUsed32);
> +       spaceUsed32 += FSE_DTABLE_SIZE_U32(maxLog);
> +       counting = (short *)((U32 *)workspace + spaceUsed32);
> +       spaceUsed32 += ALIGN(sizeof(short) * (FSE_MAX_SYMBOL_VALUE + 1), 
> sizeof(U32)) >> 2;
> +
> +       if ((spaceUsed32 << 2) > workspaceSize)
> +               return ERROR(tableLog_tooLarge);
> +       workspace = (U32 *)workspace + spaceUsed32;
> +       workspaceSize -= (spaceUsed32 << 2);
> +
> +       /* normal FSE decoding mode */
> +       NCountLength = FSE_readNCount(counting, &maxSymbolValue, &tableLog, 
> istart, cSrcSize);
> +       if (FSE_isError(NCountLength))
> +               return NCountLength;
> +       // if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong);   /* 
> too small input size; supposed to be already checked in NCountLength, only 
> remaining
> +       // case : NCountLength==cSrcSize */
> +       if (tableLog > maxLog)
> +               return ERROR(tableLog_tooLarge);
> +       ip += NCountLength;
> +       cSrcSize -= NCountLength;
> +
> +       CHECK_F(FSE_buildDTable_wksp(dt, counting, maxSymbolValue, tableLog, 
> workspace, workspaceSize));
> +
> +       return FSE_decompress_usingDTable(dst, dstCapacity, ip, cSrcSize, 
> dt); /* always return, even if it is an error code */
> +}
> diff --git a/grub-core/lib/zstd/huf.h b/grub-core/lib/zstd/huf.h
> new file mode 100644
> index 000000000..2143da28d
> --- /dev/null
> +++ b/grub-core/lib/zstd/huf.h
> @@ -0,0 +1,212 @@
> +/*
> + * Huffman coder, part of New Generation Entropy library
> + * header file
> + * Copyright (C) 2013-2016, Yann Collet.
> + *
> + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the following disclaimer
> + * in the documentation and/or other materials provided with the
> + * distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + *
> + * You can contact the author at :
> + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
> + */
> +#ifndef HUF_H_298734234
> +#define HUF_H_298734234
> +
> +/* *** Dependencies *** */
> +#include <linux/types.h> /* size_t */
> +
> +/* ***   Tool functions *** */
> +#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single 
> block compressed with HUF_compress */
> +size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst 
> case) */
> +
> +/* Error Management */
> +unsigned HUF_isError(size_t code); /**< tells if a return value is an error 
> code */
> +
> +/* ***   Advanced function   *** */
> +
> +/** HUF_compress4X_wksp() :
> +*   Same as HUF_compress2(), but uses externally allocated `workSpace`, 
> which must be a table of >= 1024 unsigned */
> +size_t HUF_compress4X_wksp(void *dst, size_t dstSize, const void *src, 
> size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
> +                          size_t wkspSize); /**< `workSpace` must be a table 
> of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
> +
> +/* *** Dependencies *** */
> +#include "mem.h" /* U32 */
> +
> +/* *** Constants *** */
> +#define HUF_TABLELOG_MAX 12     /* max configured tableLog (for static 
> allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
> +#define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */
> +#define HUF_SYMBOLVALUE_MAX 255
> +
> +#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. 
> Beyond that value, code does not work */
> +#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
> +#error "HUF_TABLELOG_MAX is too large !"
> +#endif
> +
> +/* ****************************************
> +*  Static allocation
> +******************************************/
> +/* HUF buffer bounds */
> +#define HUF_CTABLEBOUND 129
> +#define HUF_BLOCKBOUND(size) (size + (size >> 8) + 8)                   /* 
> only true if incompressible pre-filtered with fast heuristic */
> +#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* 
> Macro version, useful for static allocation */
> +
> +/* static allocation of HUF's Compression Table */
> +#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
> +       U32 name##hb[maxSymbolValue + 1];              \
> +       void *name##hv = &(name##hb);                  \
> +       HUF_CElt *name = (HUF_CElt *)(name##hv) /* no final ; */
> +
> +/* static allocation of HUF's DTable */
> +typedef U32 HUF_DTable;
> +#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1 << (maxTableLog)))
> +#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) HUF_DTable 
> DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = {((U32)((maxTableLog)-1) * 
> 0x01000001)}
> +#define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) HUF_DTable 
> DTable[HUF_DTABLE_SIZE(maxTableLog)] = {((U32)(maxTableLog)*0x01000001)}
> +
> +/* The workspace must have alignment at least 4 and be at least this large */
> +#define HUF_COMPRESS_WORKSPACE_SIZE (6 << 10)
> +#define HUF_COMPRESS_WORKSPACE_SIZE_U32 (HUF_COMPRESS_WORKSPACE_SIZE / 
> sizeof(U32))
> +
> +/* The workspace must have alignment at least 4 and be at least this large */
> +#define HUF_DECOMPRESS_WORKSPACE_SIZE (3 << 10)
> +#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / 
> sizeof(U32))
> +
> +/* ****************************************
> +*  Advanced decompression functions
> +******************************************/
> +size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize); /**< decodes RLE and uncompressed */
> +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
> +                               size_t workspaceSize);                        
>                                  /**< considers RLE and uncompressed as 
> errors */
> +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
> +                                  size_t workspaceSize); /**< single-symbol 
> decoder */
> +size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
> +                                  size_t workspaceSize); /**< double-symbols 
> decoder */
> +
> +/* ****************************************
> +*  HUF detailed API
> +******************************************/
> +/*!
> +HUF_compress() does the following:
> +1. count symbol occurrence from source[] into table count[] using FSE_count()
> +2. (optional) refine tableLog using HUF_optimalTableLog()
> +3. build Huffman table from count using HUF_buildCTable()
> +4. save Huffman table to memory buffer using HUF_writeCTable_wksp()
> +5. encode the data stream using HUF_compress4X_usingCTable()
> +
> +The following API allows targeting specific sub-functions for advanced tasks.
> +For example, it's possible to compress several blocks using the same 
> 'CTable',
> +or to save and regenerate 'CTable' using external methods.
> +*/
> +/* FSE_count() : find it within "fse.h" */
> +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned 
> maxSymbolValue);
> +typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
> +size_t HUF_writeCTable_wksp(void *dst, size_t maxDstSize, const HUF_CElt 
> *CTable, unsigned maxSymbolValue, unsigned huffLog, void *workspace, size_t 
> workspaceSize);
> +size_t HUF_compress4X_usingCTable(void *dst, size_t dstSize, const void 
> *src, size_t srcSize, const HUF_CElt *CTable);
> +
> +typedef enum {
> +       HUF_repeat_none,  /**< Cannot use the previous table */
> +       HUF_repeat_check, /**< Can use the previous table but it must be 
> checked. Note : The previous table must have been constructed by 
> HUF_compress{1,
> +                            4}X_repeat */
> +       HUF_repeat_valid  /**< Can use the previous table and it is asumed to 
> be valid */
> +} HUF_repeat;
> +/** HUF_compress4X_repeat() :
> +*   Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat 
> != HUF_repeat_none.
> +*   If it uses hufTable it does not modify hufTable or repeat.
> +*   If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable 
> to the table used.
> +*   If preferRepeat then the old table will always be used if valid. */
> +size_t HUF_compress4X_repeat(void *dst, size_t dstSize, const void *src, 
> size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
> +                            size_t wkspSize, HUF_CElt *hufTable, HUF_repeat 
> *repeat,
> +                            int preferRepeat); /**< `workSpace` must be a 
> table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
> +
> +/** HUF_buildCTable_wksp() :
> + *  Same as HUF_buildCTable(), but using externally allocated scratch buffer.
> + *  `workSpace` must be aligned on 4-bytes boundaries, and be at least as 
> large as a table of 1024 unsigned.
> + */
> +size_t HUF_buildCTable_wksp(HUF_CElt *tree, const U32 *count, U32 
> maxSymbolValue, U32 maxNbBits, void *workSpace, size_t wkspSize);
> +
> +/*! HUF_readStats() :
> +       Read compact Huffman tree, saved by HUF_writeCTable().
> +       `huffWeight` is destination buffer.
> +       @return : size read from `src` , or an error Code .
> +       Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
> +size_t HUF_readStats_wksp(BYTE *huffWeight, size_t hwSize, U32 *rankStats, 
> U32 *nbSymbolsPtr, U32 *tableLogPtr, const void *src, size_t srcSize,
> +                         void *workspace, size_t workspaceSize);
> +
> +/** HUF_readCTable() :
> +*   Loading a CTable saved with HUF_writeCTable() */
> +size_t HUF_readCTable_wksp(HUF_CElt *CTable, unsigned maxSymbolValue, const 
> void *src, size_t srcSize, void *workspace, size_t workspaceSize);
> +
> +/*
> +HUF_decompress() does the following:
> +1. select the decompression algorithm (X2, X4) based on pre-computed 
> heuristics
> +2. build Huffman table from save, using HUF_readDTableXn()
> +3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable
> +*/
> +
> +/** HUF_selectDecoder() :
> +*   Tells which decoder is likely to decode faster,
> +*   based on a set of pre-determined metrics.
> +*   @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
> +*   Assumption : 0 < cSrcSize < dstSize <= 128 KB */
> +U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize);
> +
> +size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t 
> srcSize, void *workspace, size_t workspaceSize);
> +size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t 
> srcSize, void *workspace, size_t workspaceSize);
> +
> +size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void 
> *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
> +size_t HUF_decompress4X2_usingDTable(void *dst, size_t maxDstSize, const 
> void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
> +size_t HUF_decompress4X4_usingDTable(void *dst, size_t maxDstSize, const 
> void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
> +
> +/* single stream variants */
> +
> +size_t HUF_compress1X_wksp(void *dst, size_t dstSize, const void *src, 
> size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
> +                          size_t wkspSize); /**< `workSpace` must be a table 
> of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
> +size_t HUF_compress1X_usingCTable(void *dst, size_t dstSize, const void 
> *src, size_t srcSize, const HUF_CElt *CTable);
> +/** HUF_compress1X_repeat() :
> +*   Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat 
> != HUF_repeat_none.
> +*   If it uses hufTable it does not modify hufTable or repeat.
> +*   If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable 
> to the table used.
> +*   If preferRepeat then the old table will always be used if valid. */
> +size_t HUF_compress1X_repeat(void *dst, size_t dstSize, const void *src, 
> size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void *workSpace,
> +                            size_t wkspSize, HUF_CElt *hufTable, HUF_repeat 
> *repeat,
> +                            int preferRepeat); /**< `workSpace` must be a 
> table of at least HUF_COMPRESS_WORKSPACE_SIZE_U32 unsigned */
> +
> +size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize);
> +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
> +                                  size_t workspaceSize); /**< single-symbol 
> decoder */
> +size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace,
> +                                  size_t workspaceSize); /**< double-symbols 
> decoder */
> +
> +size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void 
> *cSrc, size_t cSrcSize,
> +                                   const HUF_DTable *DTable); /**< automatic 
> selection of sing or double symbol decoder, based on DTable */
> +size_t HUF_decompress1X2_usingDTable(void *dst, size_t maxDstSize, const 
> void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
> +size_t HUF_decompress1X4_usingDTable(void *dst, size_t maxDstSize, const 
> void *cSrc, size_t cSrcSize, const HUF_DTable *DTable);
> +
> +#endif /* HUF_H_298734234 */
> diff --git a/grub-core/lib/zstd/huf_decompress.c 
> b/grub-core/lib/zstd/huf_decompress.c
> new file mode 100644
> index 000000000..652648204
> --- /dev/null
> +++ b/grub-core/lib/zstd/huf_decompress.c
> @@ -0,0 +1,960 @@
> +/*
> + * Huffman decoder, part of New Generation Entropy library
> + * Copyright (C) 2013-2016, Yann Collet.
> + *
> + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the following disclaimer
> + * in the documentation and/or other materials provided with the
> + * distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + *
> + * You can contact the author at :
> + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
> + */
> +
> +/* **************************************************************
> +*  Compiler specifics
> +****************************************************************/
> +#define FORCE_INLINE static __always_inline
> +
> +/* **************************************************************
> +*  Dependencies
> +****************************************************************/
> +#include "bitstream.h" /* BIT_* */
> +#include "fse.h"       /* header compression */
> +#include "huf.h"
> +#include <linux/compiler.h>
> +#include <linux/kernel.h>
> +#include <linux/string.h> /* memcpy, memset */
> +
> +/* **************************************************************
> +*  Error Management
> +****************************************************************/
> +#define HUF_STATIC_ASSERT(c)                                   \
> +       {                                                      \
> +               enum { HUF_static_assert = 1 / (int)(!!(c)) }; \
> +       } /* use only *after* variable declarations */
> +
> +/*-***************************/
> +/*  generic DTableDesc       */
> +/*-***************************/
> +
> +typedef struct {
> +       BYTE maxTableLog;
> +       BYTE tableType;
> +       BYTE tableLog;
> +       BYTE reserved;
> +} DTableDesc;
> +
> +static DTableDesc HUF_getDTableDesc(const HUF_DTable *table)
> +{
> +       DTableDesc dtd;
> +       memcpy(&dtd, table, sizeof(dtd));
> +       return dtd;
> +}
> +
> +/*-***************************/
> +/*  single-symbol decoding   */
> +/*-***************************/
> +
> +typedef struct {
> +       BYTE byte;
> +       BYTE nbBits;
> +} HUF_DEltX2; /* single-symbol decoding */
> +
> +size_t HUF_readDTableX2_wksp(HUF_DTable *DTable, const void *src, size_t 
> srcSize, void *workspace, size_t workspaceSize)
> +{
> +       U32 tableLog = 0;
> +       U32 nbSymbols = 0;
> +       size_t iSize;
> +       void *const dtPtr = DTable + 1;
> +       HUF_DEltX2 *const dt = (HUF_DEltX2 *)dtPtr;
> +
> +       U32 *rankVal;
> +       BYTE *huffWeight;
> +       size_t spaceUsed32 = 0;
> +
> +       rankVal = (U32 *)workspace + spaceUsed32;
> +       spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1;
> +       huffWeight = (BYTE *)((U32 *)workspace + spaceUsed32);
> +       spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
> +
> +       if ((spaceUsed32 << 2) > workspaceSize)
> +               return ERROR(tableLog_tooLarge);
> +       workspace = (U32 *)workspace + spaceUsed32;
> +       workspaceSize -= (spaceUsed32 << 2);
> +
> +       HUF_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable));
> +       /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, 
> even though some analyzer complain ... */
> +
> +       iSize = HUF_readStats_wksp(huffWeight, HUF_SYMBOLVALUE_MAX + 1, 
> rankVal, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
> +       if (HUF_isError(iSize))
> +               return iSize;
> +
> +       /* Table header */
> +       {
> +               DTableDesc dtd = HUF_getDTableDesc(DTable);
> +               if (tableLog > (U32)(dtd.maxTableLog + 1))
> +                       return ERROR(tableLog_tooLarge); /* DTable too small, 
> Huffman tree cannot fit in */
> +               dtd.tableType = 0;
> +               dtd.tableLog = (BYTE)tableLog;
> +               memcpy(DTable, &dtd, sizeof(dtd));
> +       }
> +
> +       /* Calculate starting value for each rank */
> +       {
> +               U32 n, nextRankStart = 0;
> +               for (n = 1; n < tableLog + 1; n++) {
> +                       U32 const curr = nextRankStart;
> +                       nextRankStart += (rankVal[n] << (n - 1));
> +                       rankVal[n] = curr;
> +               }
> +       }
> +
> +       /* fill DTable */
> +       {
> +               U32 n;
> +               for (n = 0; n < nbSymbols; n++) {
> +                       U32 const w = huffWeight[n];
> +                       U32 const length = (1 << w) >> 1;
> +                       U32 u;
> +                       HUF_DEltX2 D;
> +                       D.byte = (BYTE)n;
> +                       D.nbBits = (BYTE)(tableLog + 1 - w);
> +                       for (u = rankVal[w]; u < rankVal[w] + length; u++)
> +                               dt[u] = D;
> +                       rankVal[w] += length;
> +               }
> +       }
> +
> +       return iSize;
> +}
> +
> +static BYTE HUF_decodeSymbolX2(BIT_DStream_t *Dstream, const HUF_DEltX2 *dt, 
> const U32 dtLog)
> +{
> +       size_t const val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog 
> >= 1 */
> +       BYTE const c = dt[val].byte;
> +       BIT_skipBits(Dstream, dt[val].nbBits);
> +       return c;
> +}
> +
> +#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) *ptr++ = 
> HUF_decodeSymbolX2(DStreamPtr, dt, dtLog)
> +
> +#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr)         \
> +       if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
> +       HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
> +
> +#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
> +       if (ZSTD_64bits())                     \
> +       HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr)
> +
> +FORCE_INLINE size_t HUF_decodeStreamX2(BYTE *p, BIT_DStream_t *const 
> bitDPtr, BYTE *const pEnd, const HUF_DEltX2 *const dt, const U32 dtLog)
> +{
> +       BYTE *const pStart = p;
> +
> +       /* up to 4 symbols at a time */
> +       while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p 
> <= pEnd - 4)) {
> +               HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
> +               HUF_DECODE_SYMBOLX2_1(p, bitDPtr);
> +               HUF_DECODE_SYMBOLX2_2(p, bitDPtr);
> +               HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
> +       }
> +
> +       /* closer to the end */
> +       while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < 
> pEnd))
> +               HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
> +
> +       /* no more data to retrieve from bitstream, hence no need to reload */
> +       while (p < pEnd)
> +               HUF_DECODE_SYMBOLX2_0(p, bitDPtr);
> +
> +       return pEnd - pStart;
> +}
> +
> +static size_t HUF_decompress1X2_usingDTable_internal(void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       BYTE *op = (BYTE *)dst;
> +       BYTE *const oend = op + dstSize;
> +       const void *dtPtr = DTable + 1;
> +       const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
> +       BIT_DStream_t bitD;
> +       DTableDesc const dtd = HUF_getDTableDesc(DTable);
> +       U32 const dtLog = dtd.tableLog;
> +
> +       {
> +               size_t const errorCode = BIT_initDStream(&bitD, cSrc, 
> cSrcSize);
> +               if (HUF_isError(errorCode))
> +                       return errorCode;
> +       }
> +
> +       HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog);
> +
> +       /* check */
> +       if (!BIT_endOfDStream(&bitD))
> +               return ERROR(corruption_detected);
> +
> +       return dstSize;
> +}
> +
> +size_t HUF_decompress1X2_usingDTable(void *dst, size_t dstSize, const void 
> *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       DTableDesc dtd = HUF_getDTableDesc(DTable);
> +       if (dtd.tableType != 0)
> +               return ERROR(GENERIC);
> +       return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, 
> cSrcSize, DTable);
> +}
> +
> +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize)
> +{
> +       const BYTE *ip = (const BYTE *)cSrc;
> +
> +       size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, 
> workspace, workspaceSize);
> +       if (HUF_isError(hSize))
> +               return hSize;
> +       if (hSize >= cSrcSize)
> +               return ERROR(srcSize_wrong);
> +       ip += hSize;
> +       cSrcSize -= hSize;
> +
> +       return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, 
> cSrcSize, DCtx);
> +}
> +
> +static size_t HUF_decompress4X2_usingDTable_internal(void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       /* Check */
> +       if (cSrcSize < 10)
> +               return ERROR(corruption_detected); /* strict minimum : jump 
> table + 1 byte per stream */
> +
> +       {
> +               const BYTE *const istart = (const BYTE *)cSrc;
> +               BYTE *const ostart = (BYTE *)dst;
> +               BYTE *const oend = ostart + dstSize;
> +               const void *const dtPtr = DTable + 1;
> +               const HUF_DEltX2 *const dt = (const HUF_DEltX2 *)dtPtr;
> +
> +               /* Init */
> +               BIT_DStream_t bitD1;
> +               BIT_DStream_t bitD2;
> +               BIT_DStream_t bitD3;
> +               BIT_DStream_t bitD4;
> +               size_t const length1 = ZSTD_readLE16(istart);
> +               size_t const length2 = ZSTD_readLE16(istart + 2);
> +               size_t const length3 = ZSTD_readLE16(istart + 4);
> +               size_t const length4 = cSrcSize - (length1 + length2 + 
> length3 + 6);
> +               const BYTE *const istart1 = istart + 6; /* jumpTable */
> +               const BYTE *const istart2 = istart1 + length1;
> +               const BYTE *const istart3 = istart2 + length2;
> +               const BYTE *const istart4 = istart3 + length3;
> +               const size_t segmentSize = (dstSize + 3) / 4;
> +               BYTE *const opStart2 = ostart + segmentSize;
> +               BYTE *const opStart3 = opStart2 + segmentSize;
> +               BYTE *const opStart4 = opStart3 + segmentSize;
> +               BYTE *op1 = ostart;
> +               BYTE *op2 = opStart2;
> +               BYTE *op3 = opStart3;
> +               BYTE *op4 = opStart4;
> +               U32 endSignal;
> +               DTableDesc const dtd = HUF_getDTableDesc(DTable);
> +               U32 const dtLog = dtd.tableLog;
> +
> +               if (length4 > cSrcSize)
> +                       return ERROR(corruption_detected); /* overflow */
> +               {
> +                       size_t const errorCode = BIT_initDStream(&bitD1, 
> istart1, length1);
> +                       if (HUF_isError(errorCode))
> +                               return errorCode;
> +               }
> +               {
> +                       size_t const errorCode = BIT_initDStream(&bitD2, 
> istart2, length2);
> +                       if (HUF_isError(errorCode))
> +                               return errorCode;
> +               }
> +               {
> +                       size_t const errorCode = BIT_initDStream(&bitD3, 
> istart3, length3);
> +                       if (HUF_isError(errorCode))
> +                               return errorCode;
> +               }
> +               {
> +                       size_t const errorCode = BIT_initDStream(&bitD4, 
> istart4, length4);
> +                       if (HUF_isError(errorCode))
> +                               return errorCode;
> +               }
> +
> +               /* 16-32 symbols per loop (4-8 symbols per stream) */
> +               endSignal = BIT_reloadDStream(&bitD1) | 
> BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | 
> BIT_reloadDStream(&bitD4);
> +               for (; (endSignal == BIT_DStream_unfinished) && (op4 < (oend 
> - 7));) {
> +                       HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
> +                       HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
> +                       HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
> +                       HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
> +                       HUF_DECODE_SYMBOLX2_1(op1, &bitD1);
> +                       HUF_DECODE_SYMBOLX2_1(op2, &bitD2);
> +                       HUF_DECODE_SYMBOLX2_1(op3, &bitD3);
> +                       HUF_DECODE_SYMBOLX2_1(op4, &bitD4);
> +                       HUF_DECODE_SYMBOLX2_2(op1, &bitD1);
> +                       HUF_DECODE_SYMBOLX2_2(op2, &bitD2);
> +                       HUF_DECODE_SYMBOLX2_2(op3, &bitD3);
> +                       HUF_DECODE_SYMBOLX2_2(op4, &bitD4);
> +                       HUF_DECODE_SYMBOLX2_0(op1, &bitD1);
> +                       HUF_DECODE_SYMBOLX2_0(op2, &bitD2);
> +                       HUF_DECODE_SYMBOLX2_0(op3, &bitD3);
> +                       HUF_DECODE_SYMBOLX2_0(op4, &bitD4);
> +                       endSignal = BIT_reloadDStream(&bitD1) | 
> BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | 
> BIT_reloadDStream(&bitD4);
> +               }
> +
> +               /* check corruption */
> +               if (op1 > opStart2)
> +                       return ERROR(corruption_detected);
> +               if (op2 > opStart3)
> +                       return ERROR(corruption_detected);
> +               if (op3 > opStart4)
> +                       return ERROR(corruption_detected);
> +               /* note : op4 supposed already verified within main loop */
> +
> +               /* finish bitStreams one by one */
> +               HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog);
> +               HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog);
> +               HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog);
> +               HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog);
> +
> +               /* check */
> +               endSignal = BIT_endOfDStream(&bitD1) & 
> BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & 
> BIT_endOfDStream(&bitD4);
> +               if (!endSignal)
> +                       return ERROR(corruption_detected);
> +
> +               /* decoded size */
> +               return dstSize;
> +       }
> +}
> +
> +size_t HUF_decompress4X2_usingDTable(void *dst, size_t dstSize, const void 
> *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       DTableDesc dtd = HUF_getDTableDesc(DTable);
> +       if (dtd.tableType != 0)
> +               return ERROR(GENERIC);
> +       return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, 
> cSrcSize, DTable);
> +}
> +
> +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize)
> +{
> +       const BYTE *ip = (const BYTE *)cSrc;
> +
> +       size_t const hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, 
> workspace, workspaceSize);
> +       if (HUF_isError(hSize))
> +               return hSize;
> +       if (hSize >= cSrcSize)
> +               return ERROR(srcSize_wrong);
> +       ip += hSize;
> +       cSrcSize -= hSize;
> +
> +       return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, 
> cSrcSize, dctx);
> +}
> +
> +/* *************************/
> +/* double-symbols decoding */
> +/* *************************/
> +typedef struct {
> +       U16 sequence;
> +       BYTE nbBits;
> +       BYTE length;
> +} HUF_DEltX4; /* double-symbols decoding */
> +
> +typedef struct {
> +       BYTE symbol;
> +       BYTE weight;
> +} sortedSymbol_t;
> +
> +/* HUF_fillDTableX4Level2() :
> + * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */
> +static void HUF_fillDTableX4Level2(HUF_DEltX4 *DTable, U32 sizeLog, const 
> U32 consumed, const U32 *rankValOrigin, const int minWeight,
> +                                  const sortedSymbol_t *sortedSymbols, const 
> U32 sortedListSize, U32 nbBitsBaseline, U16 baseSeq)
> +{
> +       HUF_DEltX4 DElt;
> +       U32 rankVal[HUF_TABLELOG_MAX + 1];
> +
> +       /* get pre-calculated rankVal */
> +       memcpy(rankVal, rankValOrigin, sizeof(rankVal));
> +
> +       /* fill skipped values */
> +       if (minWeight > 1) {
> +               U32 i, skipSize = rankVal[minWeight];
> +               ZSTD_writeLE16(&(DElt.sequence), baseSeq);
> +               DElt.nbBits = (BYTE)(consumed);
> +               DElt.length = 1;
> +               for (i = 0; i < skipSize; i++)
> +                       DTable[i] = DElt;
> +       }
> +
> +       /* fill DTable */
> +       {
> +               U32 s;
> +               for (s = 0; s < sortedListSize; s++) { /* note : 
> sortedSymbols already skipped */
> +                       const U32 symbol = sortedSymbols[s].symbol;
> +                       const U32 weight = sortedSymbols[s].weight;
> +                       const U32 nbBits = nbBitsBaseline - weight;
> +                       const U32 length = 1 << (sizeLog - nbBits);
> +                       const U32 start = rankVal[weight];
> +                       U32 i = start;
> +                       const U32 end = start + length;
> +
> +                       ZSTD_writeLE16(&(DElt.sequence), (U16)(baseSeq + 
> (symbol << 8)));
> +                       DElt.nbBits = (BYTE)(nbBits + consumed);
> +                       DElt.length = 2;
> +                       do {
> +                               DTable[i++] = DElt;
> +                       } while (i < end); /* since length >= 1 */
> +
> +                       rankVal[weight] += length;
> +               }
> +       }
> +}
> +
> +typedef U32 rankVal_t[HUF_TABLELOG_MAX][HUF_TABLELOG_MAX + 1];
> +typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1];
> +
> +static void HUF_fillDTableX4(HUF_DEltX4 *DTable, const U32 targetLog, const 
> sortedSymbol_t *sortedList, const U32 sortedListSize, const U32 *rankStart,
> +                            rankVal_t rankValOrigin, const U32 maxWeight, 
> const U32 nbBitsBaseline)
> +{
> +       U32 rankVal[HUF_TABLELOG_MAX + 1];
> +       const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog 
> >= srcLog, hence scaleLog <= 1 */
> +       const U32 minBits = nbBitsBaseline - maxWeight;
> +       U32 s;
> +
> +       memcpy(rankVal, rankValOrigin, sizeof(rankVal));
> +
> +       /* fill DTable */
> +       for (s = 0; s < sortedListSize; s++) {
> +               const U16 symbol = sortedList[s].symbol;
> +               const U32 weight = sortedList[s].weight;
> +               const U32 nbBits = nbBitsBaseline - weight;
> +               const U32 start = rankVal[weight];
> +               const U32 length = 1 << (targetLog - nbBits);
> +
> +               if (targetLog - nbBits >= minBits) { /* enough room for a 
> second symbol */
> +                       U32 sortedRank;
> +                       int minWeight = nbBits + scaleLog;
> +                       if (minWeight < 1)
> +                               minWeight = 1;
> +                       sortedRank = rankStart[minWeight];
> +                       HUF_fillDTableX4Level2(DTable + start, targetLog - 
> nbBits, nbBits, rankValOrigin[nbBits], minWeight, sortedList + sortedRank,
> +                                              sortedListSize - sortedRank, 
> nbBitsBaseline, symbol);
> +               } else {
> +                       HUF_DEltX4 DElt;
> +                       ZSTD_writeLE16(&(DElt.sequence), symbol);
> +                       DElt.nbBits = (BYTE)(nbBits);
> +                       DElt.length = 1;
> +                       {
> +                               U32 const end = start + length;
> +                               U32 u;
> +                               for (u = start; u < end; u++)
> +                                       DTable[u] = DElt;
> +                       }
> +               }
> +               rankVal[weight] += length;
> +       }
> +}
> +
> +size_t HUF_readDTableX4_wksp(HUF_DTable *DTable, const void *src, size_t 
> srcSize, void *workspace, size_t workspaceSize)
> +{
> +       U32 tableLog, maxW, sizeOfSort, nbSymbols;
> +       DTableDesc dtd = HUF_getDTableDesc(DTable);
> +       U32 const maxTableLog = dtd.maxTableLog;
> +       size_t iSize;
> +       void *dtPtr = DTable + 1; /* force compiler to avoid strict-aliasing 
> */
> +       HUF_DEltX4 *const dt = (HUF_DEltX4 *)dtPtr;
> +       U32 *rankStart;
> +
> +       rankValCol_t *rankVal;
> +       U32 *rankStats;
> +       U32 *rankStart0;
> +       sortedSymbol_t *sortedSymbol;
> +       BYTE *weightList;
> +       size_t spaceUsed32 = 0;
> +
> +       HUF_STATIC_ASSERT((sizeof(rankValCol_t) & 3) == 0);
> +
> +       rankVal = (rankValCol_t *)((U32 *)workspace + spaceUsed32);
> +       spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2;
> +       rankStats = (U32 *)workspace + spaceUsed32;
> +       spaceUsed32 += HUF_TABLELOG_MAX + 1;
> +       rankStart0 = (U32 *)workspace + spaceUsed32;
> +       spaceUsed32 += HUF_TABLELOG_MAX + 2;
> +       sortedSymbol = (sortedSymbol_t *)((U32 *)workspace + spaceUsed32);
> +       spaceUsed32 += ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 
> 1), sizeof(U32)) >> 2;
> +       weightList = (BYTE *)((U32 *)workspace + spaceUsed32);
> +       spaceUsed32 += ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2;
> +
> +       if ((spaceUsed32 << 2) > workspaceSize)
> +               return ERROR(tableLog_tooLarge);
> +       workspace = (U32 *)workspace + spaceUsed32;
> +       workspaceSize -= (spaceUsed32 << 2);
> +
> +       rankStart = rankStart0 + 1;
> +       memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1));
> +
> +       HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(HUF_DTable)); /* if 
> compiler fails here, assertion is wrong */
> +       if (maxTableLog > HUF_TABLELOG_MAX)
> +               return ERROR(tableLog_tooLarge);
> +       /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, 
> even though some analyzer complain ... */
> +
> +       iSize = HUF_readStats_wksp(weightList, HUF_SYMBOLVALUE_MAX + 1, 
> rankStats, &nbSymbols, &tableLog, src, srcSize, workspace, workspaceSize);
> +       if (HUF_isError(iSize))
> +               return iSize;
> +
> +       /* check result */
> +       if (tableLog > maxTableLog)
> +               return ERROR(tableLog_tooLarge); /* DTable can't fit code 
> depth */
> +
> +       /* find maxWeight */
> +       for (maxW = tableLog; rankStats[maxW] == 0; maxW--) {
> +       } /* necessarily finds a solution before 0 */
> +
> +       /* Get start index of each weight */
> +       {
> +               U32 w, nextRankStart = 0;
> +               for (w = 1; w < maxW + 1; w++) {
> +                       U32 curr = nextRankStart;
> +                       nextRankStart += rankStats[w];
> +                       rankStart[w] = curr;
> +               }
> +               rankStart[0] = nextRankStart; /* put all 0w symbols at the 
> end of sorted list*/
> +               sizeOfSort = nextRankStart;
> +       }
> +
> +       /* sort symbols by weight */
> +       {
> +               U32 s;
> +               for (s = 0; s < nbSymbols; s++) {
> +                       U32 const w = weightList[s];
> +                       U32 const r = rankStart[w]++;
> +                       sortedSymbol[r].symbol = (BYTE)s;
> +                       sortedSymbol[r].weight = (BYTE)w;
> +               }
> +               rankStart[0] = 0; /* forget 0w symbols; this is beginning of 
> weight(1) */
> +       }
> +
> +       /* Build rankVal */
> +       {
> +               U32 *const rankVal0 = rankVal[0];
> +               {
> +                       int const rescale = (maxTableLog - tableLog) - 1; /* 
> tableLog <= maxTableLog */
> +                       U32 nextRankVal = 0;
> +                       U32 w;
> +                       for (w = 1; w < maxW + 1; w++) {
> +                               U32 curr = nextRankVal;
> +                               nextRankVal += rankStats[w] << (w + rescale);
> +                               rankVal0[w] = curr;
> +                       }
> +               }
> +               {
> +                       U32 const minBits = tableLog + 1 - maxW;
> +                       U32 consumed;
> +                       for (consumed = minBits; consumed < maxTableLog - 
> minBits + 1; consumed++) {
> +                               U32 *const rankValPtr = rankVal[consumed];
> +                               U32 w;
> +                               for (w = 1; w < maxW + 1; w++) {
> +                                       rankValPtr[w] = rankVal0[w] >> 
> consumed;
> +                               }
> +                       }
> +               }
> +       }
> +
> +       HUF_fillDTableX4(dt, maxTableLog, sortedSymbol, sizeOfSort, 
> rankStart0, rankVal, maxW, tableLog + 1);
> +
> +       dtd.tableLog = (BYTE)maxTableLog;
> +       dtd.tableType = 1;
> +       memcpy(DTable, &dtd, sizeof(dtd));
> +       return iSize;
> +}
> +
> +static U32 HUF_decodeSymbolX4(void *op, BIT_DStream_t *DStream, const 
> HUF_DEltX4 *dt, const U32 dtLog)
> +{
> +       size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog 
> >= 1 */
> +       memcpy(op, dt + val, 2);
> +       BIT_skipBits(DStream, dt[val].nbBits);
> +       return dt[val].length;
> +}
> +
> +static U32 HUF_decodeLastSymbolX4(void *op, BIT_DStream_t *DStream, const 
> HUF_DEltX4 *dt, const U32 dtLog)
> +{
> +       size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog 
> >= 1 */
> +       memcpy(op, dt + val, 1);
> +       if (dt[val].length == 1)
> +               BIT_skipBits(DStream, dt[val].nbBits);
> +       else {
> +               if (DStream->bitsConsumed < (sizeof(DStream->bitContainer) * 
> 8)) {
> +                       BIT_skipBits(DStream, dt[val].nbBits);
> +                       if (DStream->bitsConsumed > 
> (sizeof(DStream->bitContainer) * 8))
> +                               /* ugly hack; works only because it's the 
> last symbol. Note : can't easily extract nbBits from just this symbol */
> +                               DStream->bitsConsumed = 
> (sizeof(DStream->bitContainer) * 8);
> +               }
> +       }
> +       return 1;
> +}
> +
> +#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) ptr += 
> HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
> +
> +#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr)         \
> +       if (ZSTD_64bits() || (HUF_TABLELOG_MAX <= 12)) \
> +       ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
> +
> +#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \
> +       if (ZSTD_64bits())                     \
> +       ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog)
> +
> +FORCE_INLINE size_t HUF_decodeStreamX4(BYTE *p, BIT_DStream_t *bitDPtr, BYTE 
> *const pEnd, const HUF_DEltX4 *const dt, const U32 dtLog)
> +{
> +       BYTE *const pStart = p;
> +
> +       /* up to 8 symbols at a time */
> +       while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < 
> pEnd - (sizeof(bitDPtr->bitContainer) - 1))) {
> +               HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
> +               HUF_DECODE_SYMBOLX4_1(p, bitDPtr);
> +               HUF_DECODE_SYMBOLX4_2(p, bitDPtr);
> +               HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
> +       }
> +
> +       /* closer to end : up to 2 symbols at a time */
> +       while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= 
> pEnd - 2))
> +               HUF_DECODE_SYMBOLX4_0(p, bitDPtr);
> +
> +       while (p <= pEnd - 2)
> +               HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : 
> reached the end of DStream */
> +
> +       if (p < pEnd)
> +               p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog);
> +
> +       return p - pStart;
> +}
> +
> +static size_t HUF_decompress1X4_usingDTable_internal(void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       BIT_DStream_t bitD;
> +
> +       /* Init */
> +       {
> +               size_t const errorCode = BIT_initDStream(&bitD, cSrc, 
> cSrcSize);
> +               if (HUF_isError(errorCode))
> +                       return errorCode;
> +       }
> +
> +       /* decode */
> +       {
> +               BYTE *const ostart = (BYTE *)dst;
> +               BYTE *const oend = ostart + dstSize;
> +               const void *const dtPtr = DTable + 1; /* force compiler to 
> not use strict-aliasing */
> +               const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
> +               DTableDesc const dtd = HUF_getDTableDesc(DTable);
> +               HUF_decodeStreamX4(ostart, &bitD, oend, dt, dtd.tableLog);
> +       }
> +
> +       /* check */
> +       if (!BIT_endOfDStream(&bitD))
> +               return ERROR(corruption_detected);
> +
> +       /* decoded size */
> +       return dstSize;
> +}
> +
> +size_t HUF_decompress1X4_usingDTable(void *dst, size_t dstSize, const void 
> *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       DTableDesc dtd = HUF_getDTableDesc(DTable);
> +       if (dtd.tableType != 1)
> +               return ERROR(GENERIC);
> +       return HUF_decompress1X4_usingDTable_internal(dst, dstSize, cSrc, 
> cSrcSize, DTable);
> +}
> +
> +size_t HUF_decompress1X4_DCtx_wksp(HUF_DTable *DCtx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize)
> +{
> +       const BYTE *ip = (const BYTE *)cSrc;
> +
> +       size_t const hSize = HUF_readDTableX4_wksp(DCtx, cSrc, cSrcSize, 
> workspace, workspaceSize);
> +       if (HUF_isError(hSize))
> +               return hSize;
> +       if (hSize >= cSrcSize)
> +               return ERROR(srcSize_wrong);
> +       ip += hSize;
> +       cSrcSize -= hSize;
> +
> +       return HUF_decompress1X4_usingDTable_internal(dst, dstSize, ip, 
> cSrcSize, DCtx);
> +}
> +
> +static size_t HUF_decompress4X4_usingDTable_internal(void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       if (cSrcSize < 10)
> +               return ERROR(corruption_detected); /* strict minimum : jump 
> table + 1 byte per stream */
> +
> +       {
> +               const BYTE *const istart = (const BYTE *)cSrc;
> +               BYTE *const ostart = (BYTE *)dst;
> +               BYTE *const oend = ostart + dstSize;
> +               const void *const dtPtr = DTable + 1;
> +               const HUF_DEltX4 *const dt = (const HUF_DEltX4 *)dtPtr;
> +
> +               /* Init */
> +               BIT_DStream_t bitD1;
> +               BIT_DStream_t bitD2;
> +               BIT_DStream_t bitD3;
> +               BIT_DStream_t bitD4;
> +               size_t const length1 = ZSTD_readLE16(istart);
> +               size_t const length2 = ZSTD_readLE16(istart + 2);
> +               size_t const length3 = ZSTD_readLE16(istart + 4);
> +               size_t const length4 = cSrcSize - (length1 + length2 + 
> length3 + 6);
> +               const BYTE *const istart1 = istart + 6; /* jumpTable */
> +               const BYTE *const istart2 = istart1 + length1;
> +               const BYTE *const istart3 = istart2 + length2;
> +               const BYTE *const istart4 = istart3 + length3;
> +               size_t const segmentSize = (dstSize + 3) / 4;
> +               BYTE *const opStart2 = ostart + segmentSize;
> +               BYTE *const opStart3 = opStart2 + segmentSize;
> +               BYTE *const opStart4 = opStart3 + segmentSize;
> +               BYTE *op1 = ostart;
> +               BYTE *op2 = opStart2;
> +               BYTE *op3 = opStart3;
> +               BYTE *op4 = opStart4;
> +               U32 endSignal;
> +               DTableDesc const dtd = HUF_getDTableDesc(DTable);
> +               U32 const dtLog = dtd.tableLog;
> +
> +               if (length4 > cSrcSize)
> +                       return ERROR(corruption_detected); /* overflow */
> +               {
> +                       size_t const errorCode = BIT_initDStream(&bitD1, 
> istart1, length1);
> +                       if (HUF_isError(errorCode))
> +                               return errorCode;
> +               }
> +               {
> +                       size_t const errorCode = BIT_initDStream(&bitD2, 
> istart2, length2);
> +                       if (HUF_isError(errorCode))
> +                               return errorCode;
> +               }
> +               {
> +                       size_t const errorCode = BIT_initDStream(&bitD3, 
> istart3, length3);
> +                       if (HUF_isError(errorCode))
> +                               return errorCode;
> +               }
> +               {
> +                       size_t const errorCode = BIT_initDStream(&bitD4, 
> istart4, length4);
> +                       if (HUF_isError(errorCode))
> +                               return errorCode;
> +               }
> +
> +               /* 16-32 symbols per loop (4-8 symbols per stream) */
> +               endSignal = BIT_reloadDStream(&bitD1) | 
> BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | 
> BIT_reloadDStream(&bitD4);
> +               for (; (endSignal == BIT_DStream_unfinished) & (op4 < (oend - 
> (sizeof(bitD4.bitContainer) - 1)));) {
> +                       HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
> +                       HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
> +                       HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
> +                       HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
> +                       HUF_DECODE_SYMBOLX4_1(op1, &bitD1);
> +                       HUF_DECODE_SYMBOLX4_1(op2, &bitD2);
> +                       HUF_DECODE_SYMBOLX4_1(op3, &bitD3);
> +                       HUF_DECODE_SYMBOLX4_1(op4, &bitD4);
> +                       HUF_DECODE_SYMBOLX4_2(op1, &bitD1);
> +                       HUF_DECODE_SYMBOLX4_2(op2, &bitD2);
> +                       HUF_DECODE_SYMBOLX4_2(op3, &bitD3);
> +                       HUF_DECODE_SYMBOLX4_2(op4, &bitD4);
> +                       HUF_DECODE_SYMBOLX4_0(op1, &bitD1);
> +                       HUF_DECODE_SYMBOLX4_0(op2, &bitD2);
> +                       HUF_DECODE_SYMBOLX4_0(op3, &bitD3);
> +                       HUF_DECODE_SYMBOLX4_0(op4, &bitD4);
> +
> +                       endSignal = BIT_reloadDStream(&bitD1) | 
> BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | 
> BIT_reloadDStream(&bitD4);
> +               }
> +
> +               /* check corruption */
> +               if (op1 > opStart2)
> +                       return ERROR(corruption_detected);
> +               if (op2 > opStart3)
> +                       return ERROR(corruption_detected);
> +               if (op3 > opStart4)
> +                       return ERROR(corruption_detected);
> +               /* note : op4 already verified within main loop */
> +
> +               /* finish bitStreams one by one */
> +               HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog);
> +               HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog);
> +               HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog);
> +               HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog);
> +
> +               /* check */
> +               {
> +                       U32 const endCheck = BIT_endOfDStream(&bitD1) & 
> BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & 
> BIT_endOfDStream(&bitD4);
> +                       if (!endCheck)
> +                               return ERROR(corruption_detected);
> +               }
> +
> +               /* decoded size */
> +               return dstSize;
> +       }
> +}
> +
> +size_t HUF_decompress4X4_usingDTable(void *dst, size_t dstSize, const void 
> *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       DTableDesc dtd = HUF_getDTableDesc(DTable);
> +       if (dtd.tableType != 1)
> +               return ERROR(GENERIC);
> +       return HUF_decompress4X4_usingDTable_internal(dst, dstSize, cSrc, 
> cSrcSize, DTable);
> +}
> +
> +size_t HUF_decompress4X4_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize)
> +{
> +       const BYTE *ip = (const BYTE *)cSrc;
> +
> +       size_t hSize = HUF_readDTableX4_wksp(dctx, cSrc, cSrcSize, workspace, 
> workspaceSize);
> +       if (HUF_isError(hSize))
> +               return hSize;
> +       if (hSize >= cSrcSize)
> +               return ERROR(srcSize_wrong);
> +       ip += hSize;
> +       cSrcSize -= hSize;
> +
> +       return HUF_decompress4X4_usingDTable_internal(dst, dstSize, ip, 
> cSrcSize, dctx);
> +}
> +
> +/* ********************************/
> +/* Generic decompression selector */
> +/* ********************************/
> +
> +size_t HUF_decompress1X_usingDTable(void *dst, size_t maxDstSize, const void 
> *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       DTableDesc const dtd = HUF_getDTableDesc(DTable);
> +       return dtd.tableType ? HUF_decompress1X4_usingDTable_internal(dst, 
> maxDstSize, cSrc, cSrcSize, DTable)
> +                            : HUF_decompress1X2_usingDTable_internal(dst, 
> maxDstSize, cSrc, cSrcSize, DTable);
> +}
> +
> +size_t HUF_decompress4X_usingDTable(void *dst, size_t maxDstSize, const void 
> *cSrc, size_t cSrcSize, const HUF_DTable *DTable)
> +{
> +       DTableDesc const dtd = HUF_getDTableDesc(DTable);
> +       return dtd.tableType ? HUF_decompress4X4_usingDTable_internal(dst, 
> maxDstSize, cSrc, cSrcSize, DTable)
> +                            : HUF_decompress4X2_usingDTable_internal(dst, 
> maxDstSize, cSrc, cSrcSize, DTable);
> +}
> +
> +typedef struct {
> +       U32 tableTime;
> +       U32 decode256Time;
> +} algo_time_t;
> +static const algo_time_t algoTime[16 /* Quantization */][3 /* single, 
> double, quad */] = {
> +    /* single, double, quad */
> +    {{0, 0}, {1, 1}, {2, 2}},               /* Q==0 : impossible */
> +    {{0, 0}, {1, 1}, {2, 2}},               /* Q==1 : impossible */
> +    {{38, 130}, {1313, 74}, {2151, 38}},     /* Q == 2 : 12-18% */
> +    {{448, 128}, {1353, 74}, {2238, 41}},    /* Q == 3 : 18-25% */
> +    {{556, 128}, {1353, 74}, {2238, 47}},    /* Q == 4 : 25-32% */
> +    {{714, 128}, {1418, 74}, {2436, 53}},    /* Q == 5 : 32-38% */
> +    {{883, 128}, {1437, 74}, {2464, 61}},    /* Q == 6 : 38-44% */
> +    {{897, 128}, {1515, 75}, {2622, 68}},    /* Q == 7 : 44-50% */
> +    {{926, 128}, {1613, 75}, {2730, 75}},    /* Q == 8 : 50-56% */
> +    {{947, 128}, {1729, 77}, {3359, 77}},    /* Q == 9 : 56-62% */
> +    {{1107, 128}, {2083, 81}, {4006, 84}},   /* Q ==10 : 62-69% */
> +    {{1177, 128}, {2379, 87}, {4785, 88}},   /* Q ==11 : 69-75% */
> +    {{1242, 128}, {2415, 93}, {5155, 84}},   /* Q ==12 : 75-81% */
> +    {{1349, 128}, {2644, 106}, {5260, 106}}, /* Q ==13 : 81-87% */
> +    {{1455, 128}, {2422, 124}, {4174, 124}}, /* Q ==14 : 87-93% */
> +    {{722, 128}, {1891, 145}, {1936, 146}},  /* Q ==15 : 93-99% */
> +};
> +
> +/** HUF_selectDecoder() :
> +*   Tells which decoder is likely to decode faster,
> +*   based on a set of pre-determined metrics.
> +*   @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
> +*   Assumption : 0 < cSrcSize < dstSize <= 128 KB */
> +U32 HUF_selectDecoder(size_t dstSize, size_t cSrcSize)
> +{
> +       /* decoder timing evaluation */
> +       U32 const Q = (U32)(cSrcSize * 16 / dstSize); /* Q < 16 since dstSize 
> > cSrcSize */
> +       U32 const D256 = (U32)(dstSize >> 8);
> +       U32 const DTime0 = algoTime[Q][0].tableTime + 
> (algoTime[Q][0].decode256Time * D256);
> +       U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time 
> * D256);
> +       DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, 
> for cache eviction */
> +
> +       return DTime1 < DTime0;
> +}
> +
> +typedef size_t (*decompressionAlgo)(void *dst, size_t dstSize, const void 
> *cSrc, size_t cSrcSize);
> +
> +size_t HUF_decompress4X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize)
> +{
> +       /* validation checks */
> +       if (dstSize == 0)
> +               return ERROR(dstSize_tooSmall);
> +       if (cSrcSize > dstSize)
> +               return ERROR(corruption_detected); /* invalid */
> +       if (cSrcSize == dstSize) {
> +               memcpy(dst, cSrc, dstSize);
> +               return dstSize;
> +       } /* not compressed */
> +       if (cSrcSize == 1) {
> +               memset(dst, *(const BYTE *)cSrc, dstSize);
> +               return dstSize;
> +       } /* RLE */
> +
> +       {
> +               U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
> +               return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, 
> dstSize, cSrc, cSrcSize, workspace, workspaceSize)
> +                             : HUF_decompress4X2_DCtx_wksp(dctx, dst, 
> dstSize, cSrc, cSrcSize, workspace, workspaceSize);
> +       }
> +}
> +
> +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize)
> +{
> +       /* validation checks */
> +       if (dstSize == 0)
> +               return ERROR(dstSize_tooSmall);
> +       if ((cSrcSize >= dstSize) || (cSrcSize <= 1))
> +               return ERROR(corruption_detected); /* invalid */
> +
> +       {
> +               U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
> +               return algoNb ? HUF_decompress4X4_DCtx_wksp(dctx, dst, 
> dstSize, cSrc, cSrcSize, workspace, workspaceSize)
> +                             : HUF_decompress4X2_DCtx_wksp(dctx, dst, 
> dstSize, cSrc, cSrcSize, workspace, workspaceSize);
> +       }
> +}
> +
> +size_t HUF_decompress1X_DCtx_wksp(HUF_DTable *dctx, void *dst, size_t 
> dstSize, const void *cSrc, size_t cSrcSize, void *workspace, size_t 
> workspaceSize)
> +{
> +       /* validation checks */
> +       if (dstSize == 0)
> +               return ERROR(dstSize_tooSmall);
> +       if (cSrcSize > dstSize)
> +               return ERROR(corruption_detected); /* invalid */
> +       if (cSrcSize == dstSize) {
> +               memcpy(dst, cSrc, dstSize);
> +               return dstSize;
> +       } /* not compressed */
> +       if (cSrcSize == 1) {
> +               memset(dst, *(const BYTE *)cSrc, dstSize);
> +               return dstSize;
> +       } /* RLE */
> +
> +       {
> +               U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize);
> +               return algoNb ? HUF_decompress1X4_DCtx_wksp(dctx, dst, 
> dstSize, cSrc, cSrcSize, workspace, workspaceSize)
> +                             : HUF_decompress1X2_DCtx_wksp(dctx, dst, 
> dstSize, cSrc, cSrcSize, workspace, workspaceSize);
> +       }
> +}
> diff --git a/grub-core/lib/zstd/mem.h b/grub-core/lib/zstd/mem.h
> new file mode 100644
> index 000000000..3a0f34c87
> --- /dev/null
> +++ b/grub-core/lib/zstd/mem.h
> @@ -0,0 +1,151 @@
> +/**
> + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
> + * All rights reserved.
> + *
> + * This source code is licensed under the BSD-style license found in the
> + * LICENSE file in the root directory of https://github.com/facebook/zstd.
> + * An additional grant of patent rights can be found in the PATENTS file in 
> the
> + * same directory.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + */
> +
> +#ifndef MEM_H_MODULE
> +#define MEM_H_MODULE
> +
> +/*-****************************************
> +*  Dependencies
> +******************************************/
> +#include <asm/unaligned.h>
> +#include <linux/string.h> /* memcpy */
> +#include <linux/types.h>  /* size_t, ptrdiff_t */
> +
> +/*-****************************************
> +*  Compiler specifics
> +******************************************/
> +#define ZSTD_STATIC static __inline __attribute__((unused))
> +
> +/*-**************************************************************
> +*  Basic Types
> +*****************************************************************/
> +typedef uint8_t BYTE;
> +typedef uint16_t U16;
> +typedef int16_t S16;
> +typedef uint32_t U32;
> +typedef int32_t S32;
> +typedef uint64_t U64;
> +typedef int64_t S64;
> +typedef ptrdiff_t iPtrDiff;
> +typedef uintptr_t uPtrDiff;
> +
> +/*-**************************************************************
> +*  Memory I/O
> +*****************************************************************/
> +ZSTD_STATIC unsigned ZSTD_32bits(void) { return sizeof(size_t) == 4; }
> +ZSTD_STATIC unsigned ZSTD_64bits(void) { return sizeof(size_t) == 8; }
> +
> +#if defined(__LITTLE_ENDIAN)
> +#define ZSTD_LITTLE_ENDIAN 1
> +#else
> +#define ZSTD_LITTLE_ENDIAN 0
> +#endif
> +
> +ZSTD_STATIC unsigned ZSTD_isLittleEndian(void) { return ZSTD_LITTLE_ENDIAN; }
> +
> +ZSTD_STATIC U16 ZSTD_read16(const void *memPtr) { return 
> get_unaligned((const U16 *)memPtr); }
> +
> +ZSTD_STATIC U32 ZSTD_read32(const void *memPtr) { return 
> get_unaligned((const U32 *)memPtr); }
> +
> +ZSTD_STATIC U64 ZSTD_read64(const void *memPtr) { return 
> get_unaligned((const U64 *)memPtr); }
> +
> +ZSTD_STATIC size_t ZSTD_readST(const void *memPtr) { return 
> get_unaligned((const size_t *)memPtr); }
> +
> +ZSTD_STATIC void ZSTD_write16(void *memPtr, U16 value) { 
> put_unaligned(value, (U16 *)memPtr); }
> +
> +ZSTD_STATIC void ZSTD_write32(void *memPtr, U32 value) { 
> put_unaligned(value, (U32 *)memPtr); }
> +
> +ZSTD_STATIC void ZSTD_write64(void *memPtr, U64 value) { 
> put_unaligned(value, (U64 *)memPtr); }
> +
> +/*=== Little endian r/w ===*/
> +
> +ZSTD_STATIC U16 ZSTD_readLE16(const void *memPtr) { return 
> get_unaligned_le16(memPtr); }
> +
> +ZSTD_STATIC void ZSTD_writeLE16(void *memPtr, U16 val) { 
> put_unaligned_le16(val, memPtr); }
> +
> +ZSTD_STATIC U32 ZSTD_readLE24(const void *memPtr) { return 
> ZSTD_readLE16(memPtr) + (((const BYTE *)memPtr)[2] << 16); }
> +
> +ZSTD_STATIC void ZSTD_writeLE24(void *memPtr, U32 val)
> +{
> +       ZSTD_writeLE16(memPtr, (U16)val);
> +       ((BYTE *)memPtr)[2] = (BYTE)(val >> 16);
> +}
> +
> +ZSTD_STATIC U32 ZSTD_readLE32(const void *memPtr) { return 
> get_unaligned_le32(memPtr); }
> +
> +ZSTD_STATIC void ZSTD_writeLE32(void *memPtr, U32 val32) { 
> put_unaligned_le32(val32, memPtr); }
> +
> +ZSTD_STATIC U64 ZSTD_readLE64(const void *memPtr) { return 
> get_unaligned_le64(memPtr); }
> +
> +ZSTD_STATIC void ZSTD_writeLE64(void *memPtr, U64 val64) { 
> put_unaligned_le64(val64, memPtr); }
> +
> +ZSTD_STATIC size_t ZSTD_readLEST(const void *memPtr)
> +{
> +       if (ZSTD_32bits())
> +               return (size_t)ZSTD_readLE32(memPtr);
> +       else
> +               return (size_t)ZSTD_readLE64(memPtr);
> +}
> +
> +ZSTD_STATIC void ZSTD_writeLEST(void *memPtr, size_t val)
> +{
> +       if (ZSTD_32bits())
> +               ZSTD_writeLE32(memPtr, (U32)val);
> +       else
> +               ZSTD_writeLE64(memPtr, (U64)val);
> +}
> +
> +/*=== Big endian r/w ===*/
> +
> +ZSTD_STATIC U32 ZSTD_readBE32(const void *memPtr) { return 
> get_unaligned_be32(memPtr); }
> +
> +ZSTD_STATIC void ZSTD_writeBE32(void *memPtr, U32 val32) { 
> put_unaligned_be32(val32, memPtr); }
> +
> +ZSTD_STATIC U64 ZSTD_readBE64(const void *memPtr) { return 
> get_unaligned_be64(memPtr); }
> +
> +ZSTD_STATIC void ZSTD_writeBE64(void *memPtr, U64 val64) { 
> put_unaligned_be64(val64, memPtr); }
> +
> +ZSTD_STATIC size_t ZSTD_readBEST(const void *memPtr)
> +{
> +       if (ZSTD_32bits())
> +               return (size_t)ZSTD_readBE32(memPtr);
> +       else
> +               return (size_t)ZSTD_readBE64(memPtr);
> +}
> +
> +ZSTD_STATIC void ZSTD_writeBEST(void *memPtr, size_t val)
> +{
> +       if (ZSTD_32bits())
> +               ZSTD_writeBE32(memPtr, (U32)val);
> +       else
> +               ZSTD_writeBE64(memPtr, (U64)val);
> +}
> +
> +/* function safe only for comparisons */
> +ZSTD_STATIC U32 ZSTD_readMINMATCH(const void *memPtr, U32 length)
> +{
> +       switch (length) {
> +       default:
> +       case 4: return ZSTD_read32(memPtr);
> +       case 3:
> +               if (ZSTD_isLittleEndian())
> +                       return ZSTD_read32(memPtr) << 8;
> +               else
> +                       return ZSTD_read32(memPtr) >> 8;
> +       }
> +}
> +
> +#endif /* MEM_H_MODULE */
> diff --git a/grub-core/lib/zstd/xxhash.c b/grub-core/lib/zstd/xxhash.c
> new file mode 100644
> index 000000000..aa61e2a38
> --- /dev/null
> +++ b/grub-core/lib/zstd/xxhash.c
> @@ -0,0 +1,500 @@
> +/*
> + * xxHash - Extremely Fast Hash algorithm
> + * Copyright (C) 2012-2016, Yann Collet.
> + *
> + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + *     notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the following disclaimer
> + *     in the documentation and/or other materials provided with the
> + *     distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + *
> + * You can contact the author at:
> + * - xxHash homepage: http://cyan4973.github.io/xxHash/
> + * - xxHash source repository: https://github.com/Cyan4973/xxHash
> + */
> +
> +#include <asm/unaligned.h>
> +#include <linux/errno.h>
> +#include <linux/compiler.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/string.h>
> +#include <linux/xxhash.h>
> +
> +/*-*************************************
> + * Macros
> + **************************************/
> +#define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
> +#define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
> +
> +#ifdef __LITTLE_ENDIAN
> +# define XXH_CPU_LITTLE_ENDIAN 1
> +#else
> +# define XXH_CPU_LITTLE_ENDIAN 0
> +#endif
> +
> +/*-*************************************
> + * Constants
> + **************************************/
> +static const uint32_t PRIME32_1 = 2654435761U;
> +static const uint32_t PRIME32_2 = 2246822519U;
> +static const uint32_t PRIME32_3 = 3266489917U;
> +static const uint32_t PRIME32_4 =  668265263U;
> +static const uint32_t PRIME32_5 =  374761393U;
> +
> +static const uint64_t PRIME64_1 = 11400714785074694791ULL;
> +static const uint64_t PRIME64_2 = 14029467366897019727ULL;
> +static const uint64_t PRIME64_3 =  1609587929392839161ULL;
> +static const uint64_t PRIME64_4 =  9650029242287828579ULL;
> +static const uint64_t PRIME64_5 =  2870177450012600261ULL;
> +
> +/*-**************************
> + *  Utils
> + ***************************/
> +void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
> +{
> +       memcpy(dst, src, sizeof(*dst));
> +}
> +EXPORT_SYMBOL(xxh32_copy_state);
> +
> +void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
> +{
> +       memcpy(dst, src, sizeof(*dst));
> +}
> +EXPORT_SYMBOL(xxh64_copy_state);
> +
> +/*-***************************
> + * Simple Hash Functions
> + ****************************/
> +static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
> +{
> +       seed += input * PRIME32_2;
> +       seed = xxh_rotl32(seed, 13);
> +       seed *= PRIME32_1;
> +       return seed;
> +}
> +
> +uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
> +{
> +       const uint8_t *p = (const uint8_t *)input;
> +       const uint8_t *b_end = p + len;
> +       uint32_t h32;
> +
> +       if (len >= 16) {
> +               const uint8_t *const limit = b_end - 16;
> +               uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
> +               uint32_t v2 = seed + PRIME32_2;
> +               uint32_t v3 = seed + 0;
> +               uint32_t v4 = seed - PRIME32_1;
> +
> +               do {
> +                       v1 = xxh32_round(v1, get_unaligned_le32(p));
> +                       p += 4;
> +                       v2 = xxh32_round(v2, get_unaligned_le32(p));
> +                       p += 4;
> +                       v3 = xxh32_round(v3, get_unaligned_le32(p));
> +                       p += 4;
> +                       v4 = xxh32_round(v4, get_unaligned_le32(p));
> +                       p += 4;
> +               } while (p <= limit);
> +
> +               h32 = xxh_rotl32(v1, 1) + xxh_rotl32(v2, 7) +
> +                       xxh_rotl32(v3, 12) + xxh_rotl32(v4, 18);
> +       } else {
> +               h32 = seed + PRIME32_5;
> +       }
> +
> +       h32 += (uint32_t)len;
> +
> +       while (p + 4 <= b_end) {
> +               h32 += get_unaligned_le32(p) * PRIME32_3;
> +               h32 = xxh_rotl32(h32, 17) * PRIME32_4;
> +               p += 4;
> +       }
> +
> +       while (p < b_end) {
> +               h32 += (*p) * PRIME32_5;
> +               h32 = xxh_rotl32(h32, 11) * PRIME32_1;
> +               p++;
> +       }
> +
> +       h32 ^= h32 >> 15;
> +       h32 *= PRIME32_2;
> +       h32 ^= h32 >> 13;
> +       h32 *= PRIME32_3;
> +       h32 ^= h32 >> 16;
> +
> +       return h32;
> +}
> +EXPORT_SYMBOL(xxh32);
> +
> +static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
> +{
> +       acc += input * PRIME64_2;
> +       acc = xxh_rotl64(acc, 31);
> +       acc *= PRIME64_1;
> +       return acc;
> +}
> +
> +static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
> +{
> +       val = xxh64_round(0, val);
> +       acc ^= val;
> +       acc = acc * PRIME64_1 + PRIME64_4;
> +       return acc;
> +}
> +
> +uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
> +{
> +       const uint8_t *p = (const uint8_t *)input;
> +       const uint8_t *const b_end = p + len;
> +       uint64_t h64;
> +
> +       if (len >= 32) {
> +               const uint8_t *const limit = b_end - 32;
> +               uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
> +               uint64_t v2 = seed + PRIME64_2;
> +               uint64_t v3 = seed + 0;
> +               uint64_t v4 = seed - PRIME64_1;
> +
> +               do {
> +                       v1 = xxh64_round(v1, get_unaligned_le64(p));
> +                       p += 8;
> +                       v2 = xxh64_round(v2, get_unaligned_le64(p));
> +                       p += 8;
> +                       v3 = xxh64_round(v3, get_unaligned_le64(p));
> +                       p += 8;
> +                       v4 = xxh64_round(v4, get_unaligned_le64(p));
> +                       p += 8;
> +               } while (p <= limit);
> +
> +               h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
> +                       xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
> +               h64 = xxh64_merge_round(h64, v1);
> +               h64 = xxh64_merge_round(h64, v2);
> +               h64 = xxh64_merge_round(h64, v3);
> +               h64 = xxh64_merge_round(h64, v4);
> +
> +       } else {
> +               h64  = seed + PRIME64_5;
> +       }
> +
> +       h64 += (uint64_t)len;
> +
> +       while (p + 8 <= b_end) {
> +               const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
> +
> +               h64 ^= k1;
> +               h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
> +               p += 8;
> +       }
> +
> +       if (p + 4 <= b_end) {
> +               h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
> +               h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
> +               p += 4;
> +       }
> +
> +       while (p < b_end) {
> +               h64 ^= (*p) * PRIME64_5;
> +               h64 = xxh_rotl64(h64, 11) * PRIME64_1;
> +               p++;
> +       }
> +
> +       h64 ^= h64 >> 33;
> +       h64 *= PRIME64_2;
> +       h64 ^= h64 >> 29;
> +       h64 *= PRIME64_3;
> +       h64 ^= h64 >> 32;
> +
> +       return h64;
> +}
> +EXPORT_SYMBOL(xxh64);
> +
> +/*-**************************************************
> + * Advanced Hash Functions
> + ***************************************************/
> +void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
> +{
> +       /* use a local state for memcpy() to avoid strict-aliasing warnings */
> +       struct xxh32_state state;
> +
> +       memset(&state, 0, sizeof(state));
> +       state.v1 = seed + PRIME32_1 + PRIME32_2;
> +       state.v2 = seed + PRIME32_2;
> +       state.v3 = seed + 0;
> +       state.v4 = seed - PRIME32_1;
> +       memcpy(statePtr, &state, sizeof(state));
> +}
> +EXPORT_SYMBOL(xxh32_reset);
> +
> +void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
> +{
> +       /* use a local state for memcpy() to avoid strict-aliasing warnings */
> +       struct xxh64_state state;
> +
> +       memset(&state, 0, sizeof(state));
> +       state.v1 = seed + PRIME64_1 + PRIME64_2;
> +       state.v2 = seed + PRIME64_2;
> +       state.v3 = seed + 0;
> +       state.v4 = seed - PRIME64_1;
> +       memcpy(statePtr, &state, sizeof(state));
> +}
> +EXPORT_SYMBOL(xxh64_reset);
> +
> +int xxh32_update(struct xxh32_state *state, const void *input, const size_t 
> len)
> +{
> +       const uint8_t *p = (const uint8_t *)input;
> +       const uint8_t *const b_end = p + len;
> +
> +       if (input == NULL)
> +               return -EINVAL;
> +
> +       state->total_len_32 += (uint32_t)len;
> +       state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
> +
> +       if (state->memsize + len < 16) { /* fill in tmp buffer */
> +               memcpy((uint8_t *)(state->mem32) + state->memsize, input, 
> len);
> +               state->memsize += (uint32_t)len;
> +               return 0;
> +       }
> +
> +       if (state->memsize) { /* some data left from previous update */
> +               const uint32_t *p32 = state->mem32;
> +
> +               memcpy((uint8_t *)(state->mem32) + state->memsize, input,
> +                       16 - state->memsize);
> +
> +               state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
> +               p32++;
> +               state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
> +               p32++;
> +               state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
> +               p32++;
> +               state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
> +               p32++;
> +
> +               p += 16-state->memsize;
> +               state->memsize = 0;
> +       }
> +
> +       if (p <= b_end - 16) {
> +               const uint8_t *const limit = b_end - 16;
> +               uint32_t v1 = state->v1;
> +               uint32_t v2 = state->v2;
> +               uint32_t v3 = state->v3;
> +               uint32_t v4 = state->v4;
> +
> +               do {
> +                       v1 = xxh32_round(v1, get_unaligned_le32(p));
> +                       p += 4;
> +                       v2 = xxh32_round(v2, get_unaligned_le32(p));
> +                       p += 4;
> +                       v3 = xxh32_round(v3, get_unaligned_le32(p));
> +                       p += 4;
> +                       v4 = xxh32_round(v4, get_unaligned_le32(p));
> +                       p += 4;
> +               } while (p <= limit);
> +
> +               state->v1 = v1;
> +               state->v2 = v2;
> +               state->v3 = v3;
> +               state->v4 = v4;
> +       }
> +
> +       if (p < b_end) {
> +               memcpy(state->mem32, p, (size_t)(b_end-p));
> +               state->memsize = (uint32_t)(b_end-p);
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(xxh32_update);
> +
> +uint32_t xxh32_digest(const struct xxh32_state *state)
> +{
> +       const uint8_t *p = (const uint8_t *)state->mem32;
> +       const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
> +               state->memsize;
> +       uint32_t h32;
> +
> +       if (state->large_len) {
> +               h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
> +                       xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
> +       } else {
> +               h32 = state->v3 /* == seed */ + PRIME32_5;
> +       }
> +
> +       h32 += state->total_len_32;
> +
> +       while (p + 4 <= b_end) {
> +               h32 += get_unaligned_le32(p) * PRIME32_3;
> +               h32 = xxh_rotl32(h32, 17) * PRIME32_4;
> +               p += 4;
> +       }
> +
> +       while (p < b_end) {
> +               h32 += (*p) * PRIME32_5;
> +               h32 = xxh_rotl32(h32, 11) * PRIME32_1;
> +               p++;
> +       }
> +
> +       h32 ^= h32 >> 15;
> +       h32 *= PRIME32_2;
> +       h32 ^= h32 >> 13;
> +       h32 *= PRIME32_3;
> +       h32 ^= h32 >> 16;
> +
> +       return h32;
> +}
> +EXPORT_SYMBOL(xxh32_digest);
> +
> +int xxh64_update(struct xxh64_state *state, const void *input, const size_t 
> len)
> +{
> +       const uint8_t *p = (const uint8_t *)input;
> +       const uint8_t *const b_end = p + len;
> +
> +       if (input == NULL)
> +               return -EINVAL;
> +
> +       state->total_len += len;
> +
> +       if (state->memsize + len < 32) { /* fill in tmp buffer */
> +               memcpy(((uint8_t *)state->mem64) + state->memsize, input, 
> len);
> +               state->memsize += (uint32_t)len;
> +               return 0;
> +       }
> +
> +       if (state->memsize) { /* tmp buffer is full */
> +               uint64_t *p64 = state->mem64;
> +
> +               memcpy(((uint8_t *)p64) + state->memsize, input,
> +                       32 - state->memsize);
> +
> +               state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
> +               p64++;
> +               state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
> +               p64++;
> +               state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
> +               p64++;
> +               state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
> +
> +               p += 32 - state->memsize;
> +               state->memsize = 0;
> +       }
> +
> +       if (p + 32 <= b_end) {
> +               const uint8_t *const limit = b_end - 32;
> +               uint64_t v1 = state->v1;
> +               uint64_t v2 = state->v2;
> +               uint64_t v3 = state->v3;
> +               uint64_t v4 = state->v4;
> +
> +               do {
> +                       v1 = xxh64_round(v1, get_unaligned_le64(p));
> +                       p += 8;
> +                       v2 = xxh64_round(v2, get_unaligned_le64(p));
> +                       p += 8;
> +                       v3 = xxh64_round(v3, get_unaligned_le64(p));
> +                       p += 8;
> +                       v4 = xxh64_round(v4, get_unaligned_le64(p));
> +                       p += 8;
> +               } while (p <= limit);
> +
> +               state->v1 = v1;
> +               state->v2 = v2;
> +               state->v3 = v3;
> +               state->v4 = v4;
> +       }
> +
> +       if (p < b_end) {
> +               memcpy(state->mem64, p, (size_t)(b_end-p));
> +               state->memsize = (uint32_t)(b_end - p);
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(xxh64_update);
> +
> +uint64_t xxh64_digest(const struct xxh64_state *state)
> +{
> +       const uint8_t *p = (const uint8_t *)state->mem64;
> +       const uint8_t *const b_end = (const uint8_t *)state->mem64 +
> +               state->memsize;
> +       uint64_t h64;
> +
> +       if (state->total_len >= 32) {
> +               const uint64_t v1 = state->v1;
> +               const uint64_t v2 = state->v2;
> +               const uint64_t v3 = state->v3;
> +               const uint64_t v4 = state->v4;
> +
> +               h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
> +                       xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
> +               h64 = xxh64_merge_round(h64, v1);
> +               h64 = xxh64_merge_round(h64, v2);
> +               h64 = xxh64_merge_round(h64, v3);
> +               h64 = xxh64_merge_round(h64, v4);
> +       } else {
> +               h64  = state->v3 + PRIME64_5;
> +       }
> +
> +       h64 += (uint64_t)state->total_len;
> +
> +       while (p + 8 <= b_end) {
> +               const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
> +
> +               h64 ^= k1;
> +               h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
> +               p += 8;
> +       }
> +
> +       if (p + 4 <= b_end) {
> +               h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
> +               h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
> +               p += 4;
> +       }
> +
> +       while (p < b_end) {
> +               h64 ^= (*p) * PRIME64_5;
> +               h64 = xxh_rotl64(h64, 11) * PRIME64_1;
> +               p++;
> +       }
> +
> +       h64 ^= h64 >> 33;
> +       h64 *= PRIME64_2;
> +       h64 ^= h64 >> 29;
> +       h64 *= PRIME64_3;
> +       h64 ^= h64 >> 32;
> +
> +       return h64;
> +}
> +EXPORT_SYMBOL(xxh64_digest);
> +
> +MODULE_LICENSE("Dual BSD/GPL");
> +MODULE_DESCRIPTION("xxHash");
> diff --git a/grub-core/lib/zstd/xxhash.h b/grub-core/lib/zstd/xxhash.h
> new file mode 100644
> index 000000000..9e1f42cb5
> --- /dev/null
> +++ b/grub-core/lib/zstd/xxhash.h
> @@ -0,0 +1,236 @@
> +/*
> + * xxHash - Extremely Fast Hash algorithm
> + * Copyright (C) 2012-2016, Yann Collet.
> + *
> + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + *     notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the following disclaimer
> + *     in the documentation and/or other materials provided with the
> + *     distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + *
> + * You can contact the author at:
> + * - xxHash homepage: http://cyan4973.github.io/xxHash/
> + * - xxHash source repository: https://github.com/Cyan4973/xxHash
> + */
> +
> +/*
> + * Notice extracted from xxHash homepage:
> + *
> + * xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
> + * It also successfully passes all tests from the SMHasher suite.
> + *
> + * Comparison (single thread, Windows Seven 32 bits, using SMHasher on a 
> Core 2
> + * Duo @3GHz)
> + *
> + * Name            Speed       Q.Score   Author
> + * xxHash          5.4 GB/s     10
> + * CrapWow         3.2 GB/s      2       Andrew
> + * MumurHash 3a    2.7 GB/s     10       Austin Appleby
> + * SpookyHash      2.0 GB/s     10       Bob Jenkins
> + * SBox            1.4 GB/s      9       Bret Mulvey
> + * Lookup3         1.2 GB/s      9       Bob Jenkins
> + * SuperFastHash   1.2 GB/s      1       Paul Hsieh
> + * CityHash64      1.05 GB/s    10       Pike & Alakuijala
> + * FNV             0.55 GB/s     5       Fowler, Noll, Vo
> + * CRC32           0.43 GB/s     9
> + * MD5-32          0.33 GB/s    10       Ronald L. Rivest
> + * SHA1-32         0.28 GB/s    10
> + *
> + * Q.Score is a measure of quality of the hash function.
> + * It depends on successfully passing SMHasher test set.
> + * 10 is a perfect score.
> + *
> + * A 64-bits version, named xxh64 offers much better speed,
> + * but for 64-bits applications only.
> + * Name     Speed on 64 bits    Speed on 32 bits
> + * xxh64       13.8 GB/s            1.9 GB/s
> + * xxh32        6.8 GB/s            6.0 GB/s
> + */
> +
> +#ifndef XXHASH_H
> +#define XXHASH_H
> +
> +#include <linux/types.h>
> +
> +/*-****************************
> + * Simple Hash Functions
> + *****************************/
> +
> +/**
> + * xxh32() - calculate the 32-bit hash of the input with a given seed.
> + *
> + * @input:  The data to hash.
> + * @length: The length of the data to hash.
> + * @seed:   The seed can be used to alter the result predictably.
> + *
> + * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
> + *
> + * Return:  The 32-bit hash of the data.
> + */
> +uint32_t xxh32(const void *input, size_t length, uint32_t seed);
> +
> +/**
> + * xxh64() - calculate the 64-bit hash of the input with a given seed.
> + *
> + * @input:  The data to hash.
> + * @length: The length of the data to hash.
> + * @seed:   The seed can be used to alter the result predictably.
> + *
> + * This function runs 2x faster on 64-bit systems, but slower on 32-bit 
> systems.
> + *
> + * Return:  The 64-bit hash of the data.
> + */
> +uint64_t xxh64(const void *input, size_t length, uint64_t seed);
> +
> +/*-****************************
> + * Streaming Hash Functions
> + *****************************/
> +
> +/*
> + * These definitions are only meant to allow allocation of XXH state
> + * statically, on stack, or in a struct for example.
> + * Do not use members directly.
> + */
> +
> +/**
> + * struct xxh32_state - private xxh32 state, do not use members directly
> + */
> +struct xxh32_state {
> +       uint32_t total_len_32;
> +       uint32_t large_len;
> +       uint32_t v1;
> +       uint32_t v2;
> +       uint32_t v3;
> +       uint32_t v4;
> +       uint32_t mem32[4];
> +       uint32_t memsize;
> +};
> +
> +/**
> + * struct xxh32_state - private xxh64 state, do not use members directly
> + */
> +struct xxh64_state {
> +       uint64_t total_len;
> +       uint64_t v1;
> +       uint64_t v2;
> +       uint64_t v3;
> +       uint64_t v4;
> +       uint64_t mem64[4];
> +       uint32_t memsize;
> +};
> +
> +/**
> + * xxh32_reset() - reset the xxh32 state to start a new hashing operation
> + *
> + * @state: The xxh32 state to reset.
> + * @seed:  Initialize the hash state with this seed.
> + *
> + * Call this function on any xxh32_state to prepare for a new hashing 
> operation.
> + */
> +void xxh32_reset(struct xxh32_state *state, uint32_t seed);
> +
> +/**
> + * xxh32_update() - hash the data given and update the xxh32 state
> + *
> + * @state:  The xxh32 state to update.
> + * @input:  The data to hash.
> + * @length: The length of the data to hash.
> + *
> + * After calling xxh32_reset() call xxh32_update() as many times as 
> necessary.
> + *
> + * Return:  Zero on success, otherwise an error code.
> + */
> +int xxh32_update(struct xxh32_state *state, const void *input, size_t 
> length);
> +
> +/**
> + * xxh32_digest() - produce the current xxh32 hash
> + *
> + * @state: Produce the current xxh32 hash of this state.
> + *
> + * A hash value can be produced at any time. It is still possible to continue
> + * inserting input into the hash state after a call to xxh32_digest(), and
> + * generate new hashes later on, by calling xxh32_digest() again.
> + *
> + * Return: The xxh32 hash stored in the state.
> + */
> +uint32_t xxh32_digest(const struct xxh32_state *state);
> +
> +/**
> + * xxh64_reset() - reset the xxh64 state to start a new hashing operation
> + *
> + * @state: The xxh64 state to reset.
> + * @seed:  Initialize the hash state with this seed.
> + */
> +void xxh64_reset(struct xxh64_state *state, uint64_t seed);
> +
> +/**
> + * xxh64_update() - hash the data given and update the xxh64 state
> + * @state:  The xxh64 state to update.
> + * @input:  The data to hash.
> + * @length: The length of the data to hash.
> + *
> + * After calling xxh64_reset() call xxh64_update() as many times as 
> necessary.
> + *
> + * Return:  Zero on success, otherwise an error code.
> + */
> +int xxh64_update(struct xxh64_state *state, const void *input, size_t 
> length);
> +
> +/**
> + * xxh64_digest() - produce the current xxh64 hash
> + *
> + * @state: Produce the current xxh64 hash of this state.
> + *
> + * A hash value can be produced at any time. It is still possible to continue
> + * inserting input into the hash state after a call to xxh64_digest(), and
> + * generate new hashes later on, by calling xxh64_digest() again.
> + *
> + * Return: The xxh64 hash stored in the state.
> + */
> +uint64_t xxh64_digest(const struct xxh64_state *state);
> +
> +/*-**************************
> + * Utils
> + ***************************/
> +
> +/**
> + * xxh32_copy_state() - copy the source state into the destination state
> + *
> + * @src: The source xxh32 state.
> + * @dst: The destination xxh32 state.
> + */
> +void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state 
> *src);
> +
> +/**
> + * xxh64_copy_state() - copy the source state into the destination state
> + *
> + * @src: The source xxh64 state.
> + * @dst: The destination xxh64 state.
> + */
> +void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state 
> *src);
> +
> +#endif /* XXHASH_H */
> diff --git a/grub-core/lib/zstd/zstd.h b/grub-core/lib/zstd/zstd.h
> new file mode 100644
> index 000000000..249575e24
> --- /dev/null
> +++ b/grub-core/lib/zstd/zstd.h
> @@ -0,0 +1,1157 @@
> +/*
> + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
> + * All rights reserved.
> + *
> + * This source code is licensed under the BSD-style license found in the
> + * LICENSE file in the root directory of https://github.com/facebook/zstd.
> + * An additional grant of patent rights can be found in the PATENTS file in 
> the
> + * same directory.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + */
> +
> +#ifndef ZSTD_H
> +#define ZSTD_H
> +
> +/* ======   Dependency   ======*/
> +#include <linux/types.h>   /* size_t */
> +
> +
> +/*-*****************************************************************************
> + * Introduction
> + *
> + * zstd, short for Zstandard, is a fast lossless compression algorithm,
> + * targeting real-time compression scenarios at zlib-level and better
> + * compression ratios. The zstd compression library provides in-memory
> + * compression and decompression functions. The library supports compression
> + * levels from 1 up to ZSTD_maxCLevel() which is 22. Levels >= 20, labeled
> + * ultra, should be used with caution, as they require more memory.
> + * Compression can be done in:
> + *  - a single step, reusing a context (described as Explicit memory 
> management)
> + *  - unbounded multiple steps (described as Streaming compression)
> + * The compression ratio achievable on small data can be highly improved 
> using
> + * compression with a dictionary in:
> + *  - a single step (described as Simple dictionary API)
> + *  - a single step, reusing a dictionary (described as Fast dictionary API)
> + 
> ******************************************************************************/
> +
> +/*======  Helper functions  ======*/
> +
> +/**
> + * enum ZSTD_ErrorCode - zstd error codes
> + *
> + * Functions that return size_t can be checked for errors using 
> ZSTD_isError()
> + * and the ZSTD_ErrorCode can be extracted using ZSTD_getErrorCode().
> + */
> +typedef enum {
> +       ZSTD_error_no_error,
> +       ZSTD_error_GENERIC,
> +       ZSTD_error_prefix_unknown,
> +       ZSTD_error_version_unsupported,
> +       ZSTD_error_parameter_unknown,
> +       ZSTD_error_frameParameter_unsupported,
> +       ZSTD_error_frameParameter_unsupportedBy32bits,
> +       ZSTD_error_frameParameter_windowTooLarge,
> +       ZSTD_error_compressionParameter_unsupported,
> +       ZSTD_error_init_missing,
> +       ZSTD_error_memory_allocation,
> +       ZSTD_error_stage_wrong,
> +       ZSTD_error_dstSize_tooSmall,
> +       ZSTD_error_srcSize_wrong,
> +       ZSTD_error_corruption_detected,
> +       ZSTD_error_checksum_wrong,
> +       ZSTD_error_tableLog_tooLarge,
> +       ZSTD_error_maxSymbolValue_tooLarge,
> +       ZSTD_error_maxSymbolValue_tooSmall,
> +       ZSTD_error_dictionary_corrupted,
> +       ZSTD_error_dictionary_wrong,
> +       ZSTD_error_dictionaryCreation_failed,
> +       ZSTD_error_maxCode
> +} ZSTD_ErrorCode;
> +
> +/**
> + * ZSTD_maxCLevel() - maximum compression level available
> + *
> + * Return: Maximum compression level available.
> + */
> +int ZSTD_maxCLevel(void);
> +/**
> + * ZSTD_compressBound() - maximum compressed size in worst case scenario
> + * @srcSize: The size of the data to compress.
> + *
> + * Return:   The maximum compressed size in the worst case scenario.
> + */
> +size_t ZSTD_compressBound(size_t srcSize);
> +/**
> + * ZSTD_isError() - tells if a size_t function result is an error code
> + * @code:  The function result to check for error.
> + *
> + * Return: Non-zero iff the code is an error.
> + */
> +static __attribute__((unused)) unsigned int ZSTD_isError(size_t code)
> +{
> +       return code > (size_t)-ZSTD_error_maxCode;
> +}
> +/**
> + * ZSTD_getErrorCode() - translates an error function result to a 
> ZSTD_ErrorCode
> + * @functionResult: The result of a function for which ZSTD_isError() is 
> true.
> + *
> + * Return:          The ZSTD_ErrorCode corresponding to the functionResult 
> or 0
> + *                  if the functionResult isn't an error.
> + */
> +static __attribute__((unused)) ZSTD_ErrorCode ZSTD_getErrorCode(
> +       size_t functionResult)
> +{
> +       if (!ZSTD_isError(functionResult))
> +               return (ZSTD_ErrorCode)0;
> +       return (ZSTD_ErrorCode)(0 - functionResult);
> +}
> +
> +/**
> + * enum ZSTD_strategy - zstd compression search strategy
> + *
> + * From faster to stronger.
> + */
> +typedef enum {
> +       ZSTD_fast,
> +       ZSTD_dfast,
> +       ZSTD_greedy,
> +       ZSTD_lazy,
> +       ZSTD_lazy2,
> +       ZSTD_btlazy2,
> +       ZSTD_btopt,
> +       ZSTD_btopt2
> +} ZSTD_strategy;
> +
> +/**
> + * struct ZSTD_compressionParameters - zstd compression parameters
> + * @windowLog:    Log of the largest match distance. Larger means more
> + *                compression, and more memory needed during decompression.
> + * @chainLog:     Fully searched segment. Larger means more compression, 
> slower,
> + *                and more memory (useless for fast).
> + * @hashLog:      Dispatch table. Larger means more compression,
> + *                slower, and more memory.
> + * @searchLog:    Number of searches. Larger means more compression and 
> slower.
> + * @searchLength: Match length searched. Larger means faster decompression,
> + *                sometimes less compression.
> + * @targetLength: Acceptable match size for optimal parser (only). Larger 
> means
> + *                more compression, and slower.
> + * @strategy:     The zstd compression strategy.
> + */
> +typedef struct {
> +       unsigned int windowLog;
> +       unsigned int chainLog;
> +       unsigned int hashLog;
> +       unsigned int searchLog;
> +       unsigned int searchLength;
> +       unsigned int targetLength;
> +       ZSTD_strategy strategy;
> +} ZSTD_compressionParameters;
> +
> +/**
> + * struct ZSTD_frameParameters - zstd frame parameters
> + * @contentSizeFlag: Controls whether content size will be present in the 
> frame
> + *                   header (when known).
> + * @checksumFlag:    Controls whether a 32-bit checksum is generated at the 
> end
> + *                   of the frame for error detection.
> + * @noDictIDFlag:    Controls whether dictID will be saved into the frame 
> header
> + *                   when using dictionary compression.
> + *
> + * The default value is all fields set to 0.
> + */
> +typedef struct {
> +       unsigned int contentSizeFlag;
> +       unsigned int checksumFlag;
> +       unsigned int noDictIDFlag;
> +} ZSTD_frameParameters;
> +
> +/**
> + * struct ZSTD_parameters - zstd parameters
> + * @cParams: The compression parameters.
> + * @fParams: The frame parameters.
> + */
> +typedef struct {
> +       ZSTD_compressionParameters cParams;
> +       ZSTD_frameParameters fParams;
> +} ZSTD_parameters;
> +
> +/**
> + * ZSTD_getCParams() - returns ZSTD_compressionParameters for selected level
> + * @compressionLevel: The compression level from 1 to ZSTD_maxCLevel().
> + * @estimatedSrcSize: The estimated source size to compress or 0 if unknown.
> + * @dictSize:         The dictionary size or 0 if a dictionary isn't being 
> used.
> + *
> + * Return:            The selected ZSTD_compressionParameters.
> + */
> +ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel,
> +       unsigned long long estimatedSrcSize, size_t dictSize);
> +
> +/**
> + * ZSTD_getParams() - returns ZSTD_parameters for selected level
> + * @compressionLevel: The compression level from 1 to ZSTD_maxCLevel().
> + * @estimatedSrcSize: The estimated source size to compress or 0 if unknown.
> + * @dictSize:         The dictionary size or 0 if a dictionary isn't being 
> used.
> + *
> + * The same as ZSTD_getCParams() except also selects the default frame
> + * parameters (all zero).
> + *
> + * Return:            The selected ZSTD_parameters.
> + */
> +ZSTD_parameters ZSTD_getParams(int compressionLevel,
> +       unsigned long long estimatedSrcSize, size_t dictSize);
> +
> +/*-*************************************
> + * Explicit memory management
> + **************************************/
> +
> +/**
> + * ZSTD_CCtxWorkspaceBound() - amount of memory needed to initialize a 
> ZSTD_CCtx
> + * @cParams: The compression parameters to be used for compression.
> + *
> + * If multiple compression parameters might be used, the caller must call
> + * ZSTD_CCtxWorkspaceBound() for each set of parameters and use the maximum
> + * size.
> + *
> + * Return:   A lower bound on the size of the workspace that is passed to
> + *           ZSTD_initCCtx().
> + */
> +size_t ZSTD_CCtxWorkspaceBound(ZSTD_compressionParameters cParams);
> +
> +/**
> + * struct ZSTD_CCtx - the zstd compression context
> + *
> + * When compressing many times it is recommended to allocate a context just 
> once
> + * and reuse it for each successive compression operation.
> + */
> +typedef struct ZSTD_CCtx_s ZSTD_CCtx;
> +/**
> + * ZSTD_initCCtx() - initialize a zstd compression context
> + * @workspace:     The workspace to emplace the context into. It must outlive
> + *                 the returned context.
> + * @workspaceSize: The size of workspace. Use ZSTD_CCtxWorkspaceBound() to
> + *                 determine how large the workspace must be.
> + *
> + * Return:         A compression context emplaced into workspace.
> + */
> +ZSTD_CCtx *ZSTD_initCCtx(void *workspace, size_t workspaceSize);
> +
> +/**
> + * ZSTD_compressCCtx() - compress src into dst
> + * @ctx:         The context. Must have been initialized with a workspace at
> + *               least as large as ZSTD_CCtxWorkspaceBound(params.cParams).
> + * @dst:         The buffer to compress src into.
> + * @dstCapacity: The size of the destination buffer. May be any size, but
> + *               ZSTD_compressBound(srcSize) is guaranteed to be large 
> enough.
> + * @src:         The data to compress.
> + * @srcSize:     The size of the data to compress.
> + * @params:      The parameters to use for compression. See ZSTD_getParams().
> + *
> + * Return:       The compressed size or an error, which can be checked using
> + *               ZSTD_isError().
> + */
> +size_t ZSTD_compressCCtx(ZSTD_CCtx *ctx, void *dst, size_t dstCapacity,
> +       const void *src, size_t srcSize, ZSTD_parameters params);
> +
> +/**
> + * ZSTD_DCtxWorkspaceBound() - amount of memory needed to initialize a 
> ZSTD_DCtx
> + *
> + * Return: A lower bound on the size of the workspace that is passed to
> + *         ZSTD_initDCtx().
> + */
> +size_t ZSTD_DCtxWorkspaceBound(void);
> +
> +/**
> + * struct ZSTD_DCtx - the zstd decompression context
> + *
> + * When decompressing many times it is recommended to allocate a context just
> + * once and reuse it for each successive decompression operation.
> + */
> +typedef struct ZSTD_DCtx_s ZSTD_DCtx;
> +/**
> + * ZSTD_initDCtx() - initialize a zstd decompression context
> + * @workspace:     The workspace to emplace the context into. It must outlive
> + *                 the returned context.
> + * @workspaceSize: The size of workspace. Use ZSTD_DCtxWorkspaceBound() to
> + *                 determine how large the workspace must be.
> + *
> + * Return:         A decompression context emplaced into workspace.
> + */
> +ZSTD_DCtx *ZSTD_initDCtx(void *workspace, size_t workspaceSize);
> +
> +/**
> + * ZSTD_decompressDCtx() - decompress zstd compressed src into dst
> + * @ctx:         The decompression context.
> + * @dst:         The buffer to decompress src into.
> + * @dstCapacity: The size of the destination buffer. Must be at least as 
> large
> + *               as the decompressed size. If the caller cannot upper bound 
> the
> + *               decompressed size, then it's better to use the streaming 
> API.
> + * @src:         The zstd compressed data to decompress. Multiple 
> concatenated
> + *               frames and skippable frames are allowed.
> + * @srcSize:     The exact size of the data to decompress.
> + *
> + * Return:       The decompressed size or an error, which can be checked 
> using
> + *               ZSTD_isError().
> + */
> +size_t ZSTD_decompressDCtx(ZSTD_DCtx *ctx, void *dst, size_t dstCapacity,
> +       const void *src, size_t srcSize);
> +
> +/*-************************
> + * Simple dictionary API
> + **************************/
> +
> +/**
> + * ZSTD_compress_usingDict() - compress src into dst using a dictionary
> + * @ctx:         The context. Must have been initialized with a workspace at
> + *               least as large as ZSTD_CCtxWorkspaceBound(params.cParams).
> + * @dst:         The buffer to compress src into.
> + * @dstCapacity: The size of the destination buffer. May be any size, but
> + *               ZSTD_compressBound(srcSize) is guaranteed to be large 
> enough.
> + * @src:         The data to compress.
> + * @srcSize:     The size of the data to compress.
> + * @dict:        The dictionary to use for compression.
> + * @dictSize:    The size of the dictionary.
> + * @params:      The parameters to use for compression. See ZSTD_getParams().
> + *
> + * Compression using a predefined dictionary. The same dictionary must be 
> used
> + * during decompression.
> + *
> + * Return:       The compressed size or an error, which can be checked using
> + *               ZSTD_isError().
> + */
> +size_t ZSTD_compress_usingDict(ZSTD_CCtx *ctx, void *dst, size_t dstCapacity,
> +       const void *src, size_t srcSize, const void *dict, size_t dictSize,
> +       ZSTD_parameters params);
> +
> +/**
> + * ZSTD_decompress_usingDict() - decompress src into dst using a dictionary
> + * @ctx:         The decompression context.
> + * @dst:         The buffer to decompress src into.
> + * @dstCapacity: The size of the destination buffer. Must be at least as 
> large
> + *               as the decompressed size. If the caller cannot upper bound 
> the
> + *               decompressed size, then it's better to use the streaming 
> API.
> + * @src:         The zstd compressed data to decompress. Multiple 
> concatenated
> + *               frames and skippable frames are allowed.
> + * @srcSize:     The exact size of the data to decompress.
> + * @dict:        The dictionary to use for decompression. The same dictionary
> + *               must've been used to compress the data.
> + * @dictSize:    The size of the dictionary.
> + *
> + * Return:       The decompressed size or an error, which can be checked 
> using
> + *               ZSTD_isError().
> + */
> +size_t ZSTD_decompress_usingDict(ZSTD_DCtx *ctx, void *dst, size_t 
> dstCapacity,
> +       const void *src, size_t srcSize, const void *dict, size_t dictSize);
> +
> +/*-**************************
> + * Fast dictionary API
> + ***************************/
> +
> +/**
> + * ZSTD_CDictWorkspaceBound() - memory needed to initialize a ZSTD_CDict
> + * @cParams: The compression parameters to be used for compression.
> + *
> + * Return:   A lower bound on the size of the workspace that is passed to
> + *           ZSTD_initCDict().
> + */
> +size_t ZSTD_CDictWorkspaceBound(ZSTD_compressionParameters cParams);
> +
> +/**
> + * struct ZSTD_CDict - a digested dictionary to be used for compression
> + */
> +typedef struct ZSTD_CDict_s ZSTD_CDict;
> +
> +/**
> + * ZSTD_initCDict() - initialize a digested dictionary for compression
> + * @dictBuffer:    The dictionary to digest. The buffer is referenced by the
> + *                 ZSTD_CDict so it must outlive the returned ZSTD_CDict.
> + * @dictSize:      The size of the dictionary.
> + * @params:        The parameters to use for compression. See 
> ZSTD_getParams().
> + * @workspace:     The workspace. It must outlive the returned ZSTD_CDict.
> + * @workspaceSize: The workspace size. Must be at least
> + *                 ZSTD_CDictWorkspaceBound(params.cParams).
> + *
> + * When compressing multiple messages / blocks with the same dictionary it is
> + * recommended to load it just once. The ZSTD_CDict merely references the
> + * dictBuffer, so it must outlive the returned ZSTD_CDict.
> + *
> + * Return:         The digested dictionary emplaced into workspace.
> + */
> +ZSTD_CDict *ZSTD_initCDict(const void *dictBuffer, size_t dictSize,
> +       ZSTD_parameters params, void *workspace, size_t workspaceSize);
> +
> +/**
> + * ZSTD_compress_usingCDict() - compress src into dst using a ZSTD_CDict
> + * @ctx:         The context. Must have been initialized with a workspace at
> + *               least as large as ZSTD_CCtxWorkspaceBound(cParams) where
> + *               cParams are the compression parameters used to initialize 
> the
> + *               cdict.
> + * @dst:         The buffer to compress src into.
> + * @dstCapacity: The size of the destination buffer. May be any size, but
> + *               ZSTD_compressBound(srcSize) is guaranteed to be large 
> enough.
> + * @src:         The data to compress.
> + * @srcSize:     The size of the data to compress.
> + * @cdict:       The digested dictionary to use for compression.
> + * @params:      The parameters to use for compression. See ZSTD_getParams().
> + *
> + * Compression using a digested dictionary. The same dictionary must be used
> + * during decompression.
> + *
> + * Return:       The compressed size or an error, which can be checked using
> + *               ZSTD_isError().
> + */
> +size_t ZSTD_compress_usingCDict(ZSTD_CCtx *cctx, void *dst, size_t 
> dstCapacity,
> +       const void *src, size_t srcSize, const ZSTD_CDict *cdict);
> +
> +
> +/**
> + * ZSTD_DDictWorkspaceBound() - memory needed to initialize a ZSTD_DDict
> + *
> + * Return:  A lower bound on the size of the workspace that is passed to
> + *          ZSTD_initDDict().
> + */
> +size_t ZSTD_DDictWorkspaceBound(void);
> +
> +/**
> + * struct ZSTD_DDict - a digested dictionary to be used for decompression
> + */
> +typedef struct ZSTD_DDict_s ZSTD_DDict;
> +
> +/**
> + * ZSTD_initDDict() - initialize a digested dictionary for decompression
> + * @dictBuffer:    The dictionary to digest. The buffer is referenced by the
> + *                 ZSTD_DDict so it must outlive the returned ZSTD_DDict.
> + * @dictSize:      The size of the dictionary.
> + * @workspace:     The workspace. It must outlive the returned ZSTD_DDict.
> + * @workspaceSize: The workspace size. Must be at least
> + *                 ZSTD_DDictWorkspaceBound().
> + *
> + * When decompressing multiple messages / blocks with the same dictionary it 
> is
> + * recommended to load it just once. The ZSTD_DDict merely references the
> + * dictBuffer, so it must outlive the returned ZSTD_DDict.
> + *
> + * Return:         The digested dictionary emplaced into workspace.
> + */
> +ZSTD_DDict *ZSTD_initDDict(const void *dictBuffer, size_t dictSize,
> +       void *workspace, size_t workspaceSize);
> +
> +/**
> + * ZSTD_decompress_usingDDict() - decompress src into dst using a ZSTD_DDict
> + * @ctx:         The decompression context.
> + * @dst:         The buffer to decompress src into.
> + * @dstCapacity: The size of the destination buffer. Must be at least as 
> large
> + *               as the decompressed size. If the caller cannot upper bound 
> the
> + *               decompressed size, then it's better to use the streaming 
> API.
> + * @src:         The zstd compressed data to decompress. Multiple 
> concatenated
> + *               frames and skippable frames are allowed.
> + * @srcSize:     The exact size of the data to decompress.
> + * @ddict:       The digested dictionary to use for decompression. The same
> + *               dictionary must've been used to compress the data.
> + *
> + * Return:       The decompressed size or an error, which can be checked 
> using
> + *               ZSTD_isError().
> + */
> +size_t ZSTD_decompress_usingDDict(ZSTD_DCtx *dctx, void *dst,
> +       size_t dstCapacity, const void *src, size_t srcSize,
> +       const ZSTD_DDict *ddict);
> +
> +
> +/*-**************************
> + * Streaming
> + ***************************/
> +
> +/**
> + * struct ZSTD_inBuffer - input buffer for streaming
> + * @src:  Start of the input buffer.
> + * @size: Size of the input buffer.
> + * @pos:  Position where reading stopped. Will be updated.
> + *        Necessarily 0 <= pos <= size.
> + */
> +typedef struct ZSTD_inBuffer_s {
> +       const void *src;
> +       size_t size;
> +       size_t pos;
> +} ZSTD_inBuffer;
> +
> +/**
> + * struct ZSTD_outBuffer - output buffer for streaming
> + * @dst:  Start of the output buffer.
> + * @size: Size of the output buffer.
> + * @pos:  Position where writing stopped. Will be updated.
> + *        Necessarily 0 <= pos <= size.
> + */
> +typedef struct ZSTD_outBuffer_s {
> +       void *dst;
> +       size_t size;
> +       size_t pos;
> +} ZSTD_outBuffer;
> +
> +
> +
> +/*-*****************************************************************************
> + * Streaming compression - HowTo
> + *
> + * A ZSTD_CStream object is required to track streaming operation.
> + * Use ZSTD_initCStream() to initialize a ZSTD_CStream object.
> + * ZSTD_CStream objects can be reused multiple times on consecutive 
> compression
> + * operations. It is recommended to re-use ZSTD_CStream in situations where 
> many
> + * streaming operations will be achieved consecutively. Use one separate
> + * ZSTD_CStream per thread for parallel execution.
> + *
> + * Use ZSTD_compressStream() repetitively to consume input stream.
> + * The function will automatically update both `pos` fields.
> + * Note that it may not consume the entire input, in which case `pos < size`,
> + * and it's up to the caller to present again remaining data.
> + * It returns a hint for the preferred number of bytes to use as an input for
> + * the next function call.
> + *
> + * At any moment, it's possible to flush whatever data remains within 
> internal
> + * buffer, using ZSTD_flushStream(). `output->pos` will be updated. There 
> might
> + * still be some content left within the internal buffer if `output->size` is
> + * too small. It returns the number of bytes left in the internal buffer and
> + * must be called until it returns 0.
> + *
> + * ZSTD_endStream() instructs to finish a frame. It will perform a flush and
> + * write frame epilogue. The epilogue is required for decoders to consider a
> + * frame completed. Similar to ZSTD_flushStream(), it may not be able to 
> flush
> + * the full content if `output->size` is too small. In which case, call again
> + * ZSTD_endStream() to complete the flush. It returns the number of bytes 
> left
> + * in the internal buffer and must be called until it returns 0.
> + 
> ******************************************************************************/
> +
> +/**
> + * ZSTD_CStreamWorkspaceBound() - memory needed to initialize a ZSTD_CStream
> + * @cParams: The compression parameters to be used for compression.
> + *
> + * Return:   A lower bound on the size of the workspace that is passed to
> + *           ZSTD_initCStream() and ZSTD_initCStream_usingCDict().
> + */
> +size_t ZSTD_CStreamWorkspaceBound(ZSTD_compressionParameters cParams);
> +
> +/**
> + * struct ZSTD_CStream - the zstd streaming compression context
> + */
> +typedef struct ZSTD_CStream_s ZSTD_CStream;
> +
> +/*===== ZSTD_CStream management functions =====*/
> +/**
> + * ZSTD_initCStream() - initialize a zstd streaming compression context
> + * @params:         The zstd compression parameters.
> + * @pledgedSrcSize: If params.fParams.contentSizeFlag == 1 then the caller 
> must
> + *                  pass the source size (zero means empty source). 
> Otherwise,
> + *                  the caller may optionally pass the source size, or zero 
> if
> + *                  unknown.
> + * @workspace:      The workspace to emplace the context into. It must 
> outlive
> + *                  the returned context.
> + * @workspaceSize:  The size of workspace.
> + *                  Use ZSTD_CStreamWorkspaceBound(params.cParams) to 
> determine
> + *                  how large the workspace must be.
> + *
> + * Return:          The zstd streaming compression context.
> + */
> +ZSTD_CStream *ZSTD_initCStream(ZSTD_parameters params,
> +       unsigned long long pledgedSrcSize, void *workspace,
> +       size_t workspaceSize);
> +
> +/**
> + * ZSTD_initCStream_usingCDict() - initialize a streaming compression context
> + * @cdict:          The digested dictionary to use for compression.
> + * @pledgedSrcSize: Optionally the source size, or zero if unknown.
> + * @workspace:      The workspace to emplace the context into. It must 
> outlive
> + *                  the returned context.
> + * @workspaceSize:  The size of workspace. Call ZSTD_CStreamWorkspaceBound()
> + *                  with the cParams used to initialize the cdict to 
> determine
> + *                  how large the workspace must be.
> + *
> + * Return:          The zstd streaming compression context.
> + */
> +ZSTD_CStream *ZSTD_initCStream_usingCDict(const ZSTD_CDict *cdict,
> +       unsigned long long pledgedSrcSize, void *workspace,
> +       size_t workspaceSize);
> +
> +/*===== Streaming compression functions =====*/
> +/**
> + * ZSTD_resetCStream() - reset the context using parameters from creation
> + * @zcs:            The zstd streaming compression context to reset.
> + * @pledgedSrcSize: Optionally the source size, or zero if unknown.
> + *
> + * Resets the context using the parameters from creation. Skips dictionary
> + * loading, since it can be reused. If `pledgedSrcSize` is non-zero the frame
> + * content size is always written into the frame header.
> + *
> + * Return:          Zero or an error, which can be checked using 
> ZSTD_isError().
> + */
> +size_t ZSTD_resetCStream(ZSTD_CStream *zcs, unsigned long long 
> pledgedSrcSize);
> +/**
> + * ZSTD_compressStream() - streaming compress some of input into output
> + * @zcs:    The zstd streaming compression context.
> + * @output: Destination buffer. `output->pos` is updated to indicate how much
> + *          compressed data was written.
> + * @input:  Source buffer. `input->pos` is updated to indicate how much data 
> was
> + *          read. Note that it may not consume the entire input, in which 
> case
> + *          `input->pos < input->size`, and it's up to the caller to present
> + *          remaining data again.
> + *
> + * The `input` and `output` buffers may be any size. Guaranteed to make some
> + * forward progress if `input` and `output` are not empty.
> + *
> + * Return:  A hint for the number of bytes to use as the input for the next
> + *          function call or an error, which can be checked using
> + *          ZSTD_isError().
> + */
> +size_t ZSTD_compressStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output,
> +       ZSTD_inBuffer *input);
> +/**
> + * ZSTD_flushStream() - flush internal buffers into output
> + * @zcs:    The zstd streaming compression context.
> + * @output: Destination buffer. `output->pos` is updated to indicate how much
> + *          compressed data was written.
> + *
> + * ZSTD_flushStream() must be called until it returns 0, meaning all the data
> + * has been flushed. Since ZSTD_flushStream() causes a block to be ended,
> + * calling it too often will degrade the compression ratio.
> + *
> + * Return:  The number of bytes still present within internal buffers or an
> + *          error, which can be checked using ZSTD_isError().
> + */
> +size_t ZSTD_flushStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output);
> +/**
> + * ZSTD_endStream() - flush internal buffers into output and end the frame
> + * @zcs:    The zstd streaming compression context.
> + * @output: Destination buffer. `output->pos` is updated to indicate how much
> + *          compressed data was written.
> + *
> + * ZSTD_endStream() must be called until it returns 0, meaning all the data 
> has
> + * been flushed and the frame epilogue has been written.
> + *
> + * Return:  The number of bytes still present within internal buffers or an
> + *          error, which can be checked using ZSTD_isError().
> + */
> +size_t ZSTD_endStream(ZSTD_CStream *zcs, ZSTD_outBuffer *output);
> +
> +/**
> + * ZSTD_CStreamInSize() - recommended size for the input buffer
> + *
> + * Return: The recommended size for the input buffer.
> + */
> +size_t ZSTD_CStreamInSize(void);
> +/**
> + * ZSTD_CStreamOutSize() - recommended size for the output buffer
> + *
> + * When the output buffer is at least this large, it is guaranteed to be 
> large
> + * enough to flush at least one complete compressed block.
> + *
> + * Return: The recommended size for the output buffer.
> + */
> +size_t ZSTD_CStreamOutSize(void);
> +
> +
> +
> +/*-*****************************************************************************
> + * Streaming decompression - HowTo
> + *
> + * A ZSTD_DStream object is required to track streaming operations.
> + * Use ZSTD_initDStream() to initialize a ZSTD_DStream object.
> + * ZSTD_DStream objects can be re-used multiple times.
> + *
> + * Use ZSTD_decompressStream() repetitively to consume your input.
> + * The function will update both `pos` fields.
> + * If `input->pos < input->size`, some input has not been consumed.
> + * It's up to the caller to present again remaining data.
> + * If `output->pos < output->size`, decoder has flushed everything it could.
> + * Returns 0 iff a frame is completely decoded and fully flushed.
> + * Otherwise it returns a suggested next input size that will never load more
> + * than the current frame.
> + 
> ******************************************************************************/
> +
> +/**
> + * ZSTD_DStreamWorkspaceBound() - memory needed to initialize a ZSTD_DStream
> + * @maxWindowSize: The maximum window size allowed for compressed frames.
> + *
> + * Return:         A lower bound on the size of the workspace that is passed 
> to
> + *                 ZSTD_initDStream() and ZSTD_initDStream_usingDDict().
> + */
> +size_t ZSTD_DStreamWorkspaceBound(size_t maxWindowSize);
> +
> +/**
> + * struct ZSTD_DStream - the zstd streaming decompression context
> + */
> +typedef struct ZSTD_DStream_s ZSTD_DStream;
> +/*===== ZSTD_DStream management functions =====*/
> +/**
> + * ZSTD_initDStream() - initialize a zstd streaming decompression context
> + * @maxWindowSize: The maximum window size allowed for compressed frames.
> + * @workspace:     The workspace to emplace the context into. It must outlive
> + *                 the returned context.
> + * @workspaceSize: The size of workspace.
> + *                 Use ZSTD_DStreamWorkspaceBound(maxWindowSize) to determine
> + *                 how large the workspace must be.
> + *
> + * Return:         The zstd streaming decompression context.
> + */
> +ZSTD_DStream *ZSTD_initDStream(size_t maxWindowSize, void *workspace,
> +       size_t workspaceSize);
> +/**
> + * ZSTD_initDStream_usingDDict() - initialize streaming decompression context
> + * @maxWindowSize: The maximum window size allowed for compressed frames.
> + * @ddict:         The digested dictionary to use for decompression.
> + * @workspace:     The workspace to emplace the context into. It must outlive
> + *                 the returned context.
> + * @workspaceSize: The size of workspace.
> + *                 Use ZSTD_DStreamWorkspaceBound(maxWindowSize) to determine
> + *                 how large the workspace must be.
> + *
> + * Return:         The zstd streaming decompression context.
> + */
> +ZSTD_DStream *ZSTD_initDStream_usingDDict(size_t maxWindowSize,
> +       const ZSTD_DDict *ddict, void *workspace, size_t workspaceSize);
> +
> +/*===== Streaming decompression functions =====*/
> +/**
> + * ZSTD_resetDStream() - reset the context using parameters from creation
> + * @zds:   The zstd streaming decompression context to reset.
> + *
> + * Resets the context using the parameters from creation. Skips dictionary
> + * loading, since it can be reused.
> + *
> + * Return: Zero or an error, which can be checked using ZSTD_isError().
> + */
> +size_t ZSTD_resetDStream(ZSTD_DStream *zds);
> +/**
> + * ZSTD_decompressStream() - streaming decompress some of input into output
> + * @zds:    The zstd streaming decompression context.
> + * @output: Destination buffer. `output.pos` is updated to indicate how much
> + *          decompressed data was written.
> + * @input:  Source buffer. `input.pos` is updated to indicate how much data 
> was
> + *          read. Note that it may not consume the entire input, in which 
> case
> + *          `input.pos < input.size`, and it's up to the caller to present
> + *          remaining data again.
> + *
> + * The `input` and `output` buffers may be any size. Guaranteed to make some
> + * forward progress if `input` and `output` are not empty.
> + * ZSTD_decompressStream() will not consume the last byte of the frame until
> + * the entire frame is flushed.
> + *
> + * Return:  Returns 0 iff a frame is completely decoded and fully flushed.
> + *          Otherwise returns a hint for the number of bytes to use as the 
> input
> + *          for the next function call or an error, which can be checked 
> using
> + *          ZSTD_isError(). The size hint will never load more than the 
> frame.
> + */
> +size_t ZSTD_decompressStream(ZSTD_DStream *zds, ZSTD_outBuffer *output,
> +       ZSTD_inBuffer *input);
> +
> +/**
> + * ZSTD_DStreamInSize() - recommended size for the input buffer
> + *
> + * Return: The recommended size for the input buffer.
> + */
> +size_t ZSTD_DStreamInSize(void);
> +/**
> + * ZSTD_DStreamOutSize() - recommended size for the output buffer
> + *
> + * When the output buffer is at least this large, it is guaranteed to be 
> large
> + * enough to flush at least one complete decompressed block.
> + *
> + * Return: The recommended size for the output buffer.
> + */
> +size_t ZSTD_DStreamOutSize(void);
> +
> +
> +/* --- Constants ---*/
> +#define ZSTD_MAGICNUMBER            0xFD2FB528   /* >= v0.8.0 */
> +#define ZSTD_MAGIC_SKIPPABLE_START  0x184D2A50U
> +
> +#define ZSTD_CONTENTSIZE_UNKNOWN (0ULL - 1)
> +#define ZSTD_CONTENTSIZE_ERROR   (0ULL - 2)
> +
> +#define ZSTD_WINDOWLOG_MAX_32  27
> +#define ZSTD_WINDOWLOG_MAX_64  27
> +#define ZSTD_WINDOWLOG_MAX \
> +       ((unsigned int)(sizeof(size_t) == 4 \
> +               ? ZSTD_WINDOWLOG_MAX_32 \
> +               : ZSTD_WINDOWLOG_MAX_64))
> +#define ZSTD_WINDOWLOG_MIN 10
> +#define ZSTD_HASHLOG_MAX ZSTD_WINDOWLOG_MAX
> +#define ZSTD_HASHLOG_MIN        6
> +#define ZSTD_CHAINLOG_MAX     (ZSTD_WINDOWLOG_MAX+1)
> +#define ZSTD_CHAINLOG_MIN      ZSTD_HASHLOG_MIN
> +#define ZSTD_HASHLOG3_MAX      17
> +#define ZSTD_SEARCHLOG_MAX    (ZSTD_WINDOWLOG_MAX-1)
> +#define ZSTD_SEARCHLOG_MIN      1
> +/* only for ZSTD_fast, other strategies are limited to 6 */
> +#define ZSTD_SEARCHLENGTH_MAX   7
> +/* only for ZSTD_btopt, other strategies are limited to 4 */
> +#define ZSTD_SEARCHLENGTH_MIN   3
> +#define ZSTD_TARGETLENGTH_MIN   4
> +#define ZSTD_TARGETLENGTH_MAX 999
> +
> +/* for static allocation */
> +#define ZSTD_FRAMEHEADERSIZE_MAX 18
> +#define ZSTD_FRAMEHEADERSIZE_MIN  6
> +static const size_t ZSTD_frameHeaderSize_prefix = 5;
> +static const size_t ZSTD_frameHeaderSize_min = ZSTD_FRAMEHEADERSIZE_MIN;
> +static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX;
> +/* magic number + skippable frame length */
> +static const size_t ZSTD_skippableHeaderSize = 8;
> +
> +
> +/*-*************************************
> + * Compressed size functions
> + **************************************/
> +
> +/**
> + * ZSTD_findFrameCompressedSize() - returns the size of a compressed frame
> + * @src:     Source buffer. It should point to the start of a zstd encoded 
> frame
> + *           or a skippable frame.
> + * @srcSize: The size of the source buffer. It must be at least as large as 
> the
> + *           size of the frame.
> + *
> + * Return:   The compressed size of the frame pointed to by `src` or an 
> error,
> + *           which can be check with ZSTD_isError().
> + *           Suitable to pass to ZSTD_decompress() or similar functions.
> + */
> +size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize);
> +
> +/*-*************************************
> + * Decompressed size functions
> + **************************************/
> +/**
> + * ZSTD_getFrameContentSize() - returns the content size in a zstd frame 
> header
> + * @src:     It should point to the start of a zstd encoded frame.
> + * @srcSize: The size of the source buffer. It must be at least as large as 
> the
> + *           frame header. `ZSTD_frameHeaderSize_max` is always large enough.
> + *
> + * Return:   The frame content size stored in the frame header if known.
> + *           `ZSTD_CONTENTSIZE_UNKNOWN` if the content size isn't stored in 
> the
> + *           frame header. `ZSTD_CONTENTSIZE_ERROR` on invalid input.
> + */
> +unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
> +
> +/**
> + * ZSTD_findDecompressedSize() - returns decompressed size of a series of 
> frames
> + * @src:     It should point to the start of a series of zstd encoded and/or
> + *           skippable frames.
> + * @srcSize: The exact size of the series of frames.
> + *
> + * If any zstd encoded frame in the series doesn't have the frame content 
> size
> + * set, `ZSTD_CONTENTSIZE_UNKNOWN` is returned. But frame content size is 
> always
> + * set when using ZSTD_compress(). The decompressed size can be very large.
> + * If the source is untrusted, the decompressed size could be wrong or
> + * intentionally modified. Always ensure the result fits within the
> + * application's authorized limits. ZSTD_findDecompressedSize() handles 
> multiple
> + * frames, and so it must traverse the input to read each frame header. This 
> is
> + * efficient as most of the data is skipped, however it does mean that all 
> frame
> + * data must be present and valid.
> + *
> + * Return:   Decompressed size of all the data contained in the frames if 
> known.
> + *           `ZSTD_CONTENTSIZE_UNKNOWN` if the decompressed size is unknown.
> + *           `ZSTD_CONTENTSIZE_ERROR` if an error occurred.
> + */
> +unsigned long long ZSTD_findDecompressedSize(const void *src, size_t 
> srcSize);
> +
> +/*-*************************************
> + * Advanced compression functions
> + **************************************/
> +/**
> + * ZSTD_checkCParams() - ensure parameter values remain within authorized 
> range
> + * @cParams: The zstd compression parameters.
> + *
> + * Return:   Zero or an error, which can be checked using ZSTD_isError().
> + */
> +size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams);
> +
> +/**
> + * ZSTD_adjustCParams() - optimize parameters for a given srcSize and 
> dictSize
> + * @srcSize:  Optionally the estimated source size, or zero if unknown.
> + * @dictSize: Optionally the estimated dictionary size, or zero if unknown.
> + *
> + * Return:    The optimized parameters.
> + */
> +ZSTD_compressionParameters ZSTD_adjustCParams(
> +       ZSTD_compressionParameters cParams, unsigned long long srcSize,
> +       size_t dictSize);
> +
> +/*--- Advanced decompression functions ---*/
> +
> +/**
> + * ZSTD_isFrame() - returns true iff the buffer starts with a valid frame
> + * @buffer: The source buffer to check.
> + * @size:   The size of the source buffer, must be at least 4 bytes.
> + *
> + * Return: True iff the buffer starts with a zstd or skippable frame 
> identifier.
> + */
> +unsigned int ZSTD_isFrame(const void *buffer, size_t size);
> +
> +/**
> + * ZSTD_getDictID_fromDict() - returns the dictionary id stored in a 
> dictionary
> + * @dict:     The dictionary buffer.
> + * @dictSize: The size of the dictionary buffer.
> + *
> + * Return:    The dictionary id stored within the dictionary or 0 if the
> + *            dictionary is not a zstd dictionary. If it returns 0 the
> + *            dictionary can still be loaded as a content-only dictionary.
> + */
> +unsigned int ZSTD_getDictID_fromDict(const void *dict, size_t dictSize);
> +
> +/**
> + * ZSTD_getDictID_fromDDict() - returns the dictionary id stored in a 
> ZSTD_DDict
> + * @ddict: The ddict to find the id of.
> + *
> + * Return: The dictionary id stored within `ddict` or 0 if the dictionary is 
> not
> + *         a zstd dictionary. If it returns 0 `ddict` will be loaded as a
> + *         content-only dictionary.
> + */
> +unsigned int ZSTD_getDictID_fromDDict(const ZSTD_DDict *ddict);
> +
> +/**
> + * ZSTD_getDictID_fromFrame() - returns the dictionary id stored in a zstd 
> frame
> + * @src:     Source buffer. It must be a zstd encoded frame.
> + * @srcSize: The size of the source buffer. It must be at least as large as 
> the
> + *           frame header. `ZSTD_frameHeaderSize_max` is always large enough.
> + *
> + * Return:   The dictionary id required to decompress the frame stored within
> + *           `src` or 0 if the dictionary id could not be decoded. It can 
> return
> + *           0 if the frame does not require a dictionary, the dictionary id
> + *           wasn't stored in the frame, `src` is not a zstd frame, or 
> `srcSize`
> + *           is too small.
> + */
> +unsigned int ZSTD_getDictID_fromFrame(const void *src, size_t srcSize);
> +
> +/**
> + * struct ZSTD_frameParams - zstd frame parameters stored in the frame header
> + * @frameContentSize: The frame content size, or 0 if not present.
> + * @windowSize:       The window size, or 0 if the frame is a skippable 
> frame.
> + * @dictID:           The dictionary id, or 0 if not present.
> + * @checksumFlag:     Whether a checksum was used.
> + */
> +typedef struct {
> +       unsigned long long frameContentSize;
> +       unsigned int windowSize;
> +       unsigned int dictID;
> +       unsigned int checksumFlag;
> +} ZSTD_frameParams;
> +
> +/**
> + * ZSTD_getFrameParams() - extracts parameters from a zstd or skippable frame
> + * @fparamsPtr: On success the frame parameters are written here.
> + * @src:        The source buffer. It must point to a zstd or skippable 
> frame.
> + * @srcSize:    The size of the source buffer. `ZSTD_frameHeaderSize_max` is
> + *              always large enough to succeed.
> + *
> + * Return:      0 on success. If more data is required it returns how many 
> bytes
> + *              must be provided to make forward progress. Otherwise it 
> returns
> + *              an error, which can be checked using ZSTD_isError().
> + */
> +size_t ZSTD_getFrameParams(ZSTD_frameParams *fparamsPtr, const void *src,
> +       size_t srcSize);
> +
> +/*-*****************************************************************************
> + * Buffer-less and synchronous inner streaming functions
> + *
> + * This is an advanced API, giving full control over buffer management, for
> + * users which need direct control over memory.
> + * But it's also a complex one, with many restrictions (documented below).
> + * Prefer using normal streaming API for an easier experience
> + 
> ******************************************************************************/
> +
> +/*-*****************************************************************************
> + * Buffer-less streaming compression (synchronous mode)
> + *
> + * A ZSTD_CCtx object is required to track streaming operations.
> + * Use ZSTD_initCCtx() to initialize a context.
> + * ZSTD_CCtx object can be re-used multiple times within successive 
> compression
> + * operations.
> + *
> + * Start by initializing a context.
> + * Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary
> + * compression,
> + * or ZSTD_compressBegin_advanced(), for finer parameter control.
> + * It's also possible to duplicate a reference context which has already been
> + * initialized, using ZSTD_copyCCtx()
> + *
> + * Then, consume your input using ZSTD_compressContinue().
> + * There are some important considerations to keep in mind when using this
> + * advanced function :
> + * - ZSTD_compressContinue() has no internal buffer. It uses externally 
> provided
> + *   buffer only.
> + * - Interface is synchronous : input is consumed entirely and produce 1+
> + *   (or more) compressed blocks.
> + * - Caller must ensure there is enough space in `dst` to store compressed 
> data
> + *   under worst case scenario. Worst case evaluation is provided by
> + *   ZSTD_compressBound().
> + *   ZSTD_compressContinue() doesn't guarantee recover after a failed
> + *   compression.
> + * - ZSTD_compressContinue() presumes prior input ***is still accessible and
> + *   unmodified*** (up to maximum distance size, see WindowLog).
> + *   It remembers all previous contiguous blocks, plus one separated memory
> + *   segment (which can itself consists of multiple contiguous blocks)
> + * - ZSTD_compressContinue() detects that prior input has been overwritten 
> when
> + *   `src` buffer overlaps. In which case, it will "discard" the relevant 
> memory
> + *   section from its history.
> + *
> + * Finish a frame with ZSTD_compressEnd(), which will write the last block(s)
> + * and optional checksum. It's possible to use srcSize==0, in which case, it
> + * will write a final empty block to end the frame. Without last block mark,
> + * frames will be considered unfinished (corrupted) by decoders.
> + *
> + * `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress some 
> new
> + * frame.
> + 
> ******************************************************************************/
> +
> +/*=====   Buffer-less streaming compression functions  =====*/
> +size_t ZSTD_compressBegin(ZSTD_CCtx *cctx, int compressionLevel);
> +size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx *cctx, const void *dict,
> +       size_t dictSize, int compressionLevel);
> +size_t ZSTD_compressBegin_advanced(ZSTD_CCtx *cctx, const void *dict,
> +       size_t dictSize, ZSTD_parameters params,
> +       unsigned long long pledgedSrcSize);
> +size_t ZSTD_copyCCtx(ZSTD_CCtx *cctx, const ZSTD_CCtx *preparedCCtx,
> +       unsigned long long pledgedSrcSize);
> +size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx *cctx, const ZSTD_CDict 
> *cdict,
> +       unsigned long long pledgedSrcSize);
> +size_t ZSTD_compressContinue(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity,
> +       const void *src, size_t srcSize);
> +size_t ZSTD_compressEnd(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity,
> +       const void *src, size_t srcSize);
> +
> +
> +
> +/*-*****************************************************************************
> + * Buffer-less streaming decompression (synchronous mode)
> + *
> + * A ZSTD_DCtx object is required to track streaming operations.
> + * Use ZSTD_initDCtx() to initialize a context.
> + * A ZSTD_DCtx object can be re-used multiple times.
> + *
> + * First typical operation is to retrieve frame parameters, using
> + * ZSTD_getFrameParams(). It fills a ZSTD_frameParams structure which provide
> + * important information to correctly decode the frame, such as the minimum
> + * rolling buffer size to allocate to decompress data (`windowSize`), and the
> + * dictionary ID used.
> + * Note: content size is optional, it may not be present. 0 means unknown.
> + * Note that these values could be wrong, either because of data 
> malformation,
> + * or because an attacker is spoofing deliberate false information. As a
> + * consequence, check that values remain within valid application range,
> + * especially `windowSize`, before allocation. Each application can set its 
> own
> + * limit, depending on local restrictions. For extended interoperability, it 
> is
> + * recommended to support at least 8 MB.
> + * Frame parameters are extracted from the beginning of the compressed frame.
> + * Data fragment must be large enough to ensure successful decoding, 
> typically
> + * `ZSTD_frameHeaderSize_max` bytes.
> + * Result: 0: successful decoding, the `ZSTD_frameParams` structure is 
> filled.
> + *        >0: `srcSize` is too small, provide at least this many bytes.
> + *        errorCode, which can be tested using ZSTD_isError().
> + *
> + * Start decompression, with ZSTD_decompressBegin() or
> + * ZSTD_decompressBegin_usingDict(). Alternatively, you can copy a prepared
> + * context, using ZSTD_copyDCtx().
> + *
> + * Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue()
> + * alternatively.
> + * ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 
> 'srcSize'
> + * to ZSTD_decompressContinue().
> + * ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it 
> will
> + * fail.
> + *
> + * The result of ZSTD_decompressContinue() is the number of bytes regenerated
> + * within 'dst' (necessarily <= dstCapacity). It can be zero, which is not an
> + * error; it just means ZSTD_decompressContinue() has decoded some metadata
> + * item. It can also be an error code, which can be tested with 
> ZSTD_isError().
> + *
> + * ZSTD_decompressContinue() needs previous data blocks during 
> decompression, up
> + * to `windowSize`. They should preferably be located contiguously, prior to
> + * current block. Alternatively, a round buffer of sufficient size is also
> + * possible. Sufficient size is determined by frame parameters.
> + * ZSTD_decompressContinue() is very sensitive to contiguity, if 2 blocks 
> don't
> + * follow each other, make sure that either the compressor breaks contiguity 
> at
> + * the same place, or that previous contiguous segment is large enough to
> + * properly handle maximum back-reference.
> + *
> + * A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero.
> + * Context can then be reset to start a new decompression.
> + *
> + * Note: it's possible to know if next input to present is a header or a 
> block,
> + * using ZSTD_nextInputType(). This information is not required to properly
> + * decode a frame.
> + *
> + * == Special case: skippable frames ==
> + *
> + * Skippable frames allow integration of user-defined data into a flow of
> + * concatenated frames. Skippable frames will be ignored (skipped) by a
> + * decompressor. The format of skippable frames is as follows:
> + * a) Skippable frame ID - 4 Bytes, Little endian format, any value from
> + *    0x184D2A50 to 0x184D2A5F
> + * b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits
> + * c) Frame Content - any content (User Data) of length equal to Frame Size
> + * For skippable frames ZSTD_decompressContinue() always returns 0.
> + * For skippable frames ZSTD_getFrameParams() returns 
> fparamsPtr->windowLog==0
> + * what means that a frame is skippable.
> + * Note: If fparamsPtr->frameContentSize==0, it is ambiguous: the frame might
> + *       actually be a zstd encoded frame with no content. For purposes of
> + *       decompression, it is valid in both cases to skip the frame using
> + *       ZSTD_findFrameCompressedSize() to find its size in bytes.
> + * It also returns frame size as fparamsPtr->frameContentSize.
> + 
> ******************************************************************************/
> +
> +/*=====   Buffer-less streaming decompression functions  =====*/
> +size_t ZSTD_decompressBegin(ZSTD_DCtx *dctx);
> +size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx *dctx, const void *dict,
> +       size_t dictSize);
> +void   ZSTD_copyDCtx(ZSTD_DCtx *dctx, const ZSTD_DCtx *preparedDCtx);
> +size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx *dctx);
> +size_t ZSTD_decompressContinue(ZSTD_DCtx *dctx, void *dst, size_t 
> dstCapacity,
> +       const void *src, size_t srcSize);
> +typedef enum {
> +       ZSTDnit_frameHeader,
> +       ZSTDnit_blockHeader,
> +       ZSTDnit_block,
> +       ZSTDnit_lastBlock,
> +       ZSTDnit_checksum,
> +       ZSTDnit_skippableFrame
> +} ZSTD_nextInputType_e;
> +ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx *dctx);
> +
> +/*-*****************************************************************************
> + * Block functions
> + *
> + * Block functions produce and decode raw zstd blocks, without frame 
> metadata.
> + * Frame metadata cost is typically ~18 bytes, which can be non-negligible 
> for
> + * very small blocks (< 100 bytes). User will have to take in charge required
> + * information to regenerate data, such as compressed and content sizes.
> + *
> + * A few rules to respect:
> + * - Compressing and decompressing require a context structure
> + *   + Use ZSTD_initCCtx() and ZSTD_initDCtx()
> + * - It is necessary to init context before starting
> + *   + compression : ZSTD_compressBegin()
> + *   + decompression : ZSTD_decompressBegin()
> + *   + variants _usingDict() are also allowed
> + *   + copyCCtx() and copyDCtx() work too
> + * - Block size is limited, it must be <= ZSTD_getBlockSizeMax()
> + *   + If you need to compress more, cut data into multiple blocks
> + *   + Consider using the regular ZSTD_compress() instead, as frame metadata
> + *     costs become negligible when source size is large.
> + * - When a block is considered not compressible enough, ZSTD_compressBlock()
> + *   result will be zero. In which case, nothing is produced into `dst`.
> + *   + User must test for such outcome and deal directly with uncompressed 
> data
> + *   + ZSTD_decompressBlock() doesn't accept uncompressed data as input!!!
> + *   + In case of multiple successive blocks, decoder must be informed of
> + *     uncompressed block existence to follow proper history. Use
> + *     ZSTD_insertBlock() in such a case.
> + 
> ******************************************************************************/
> +
> +/* Define for static allocation */
> +#define ZSTD_BLOCKSIZE_ABSOLUTEMAX (128 * 1024)
> +/*=====   Raw zstd block functions  =====*/
> +size_t ZSTD_getBlockSizeMax(ZSTD_CCtx *cctx);
> +size_t ZSTD_compressBlock(ZSTD_CCtx *cctx, void *dst, size_t dstCapacity,
> +       const void *src, size_t srcSize);
> +size_t ZSTD_decompressBlock(ZSTD_DCtx *dctx, void *dst, size_t dstCapacity,
> +       const void *src, size_t srcSize);
> +size_t ZSTD_insertBlock(ZSTD_DCtx *dctx, const void *blockStart,
> +       size_t blockSize);
> +
> +#endif  /* ZSTD_H */
> diff --git a/grub-core/lib/zstd/zstd_common.c 
> b/grub-core/lib/zstd/zstd_common.c
> new file mode 100644
> index 000000000..a282624ee
> --- /dev/null
> +++ b/grub-core/lib/zstd/zstd_common.c
> @@ -0,0 +1,75 @@
> +/**
> + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
> + * All rights reserved.
> + *
> + * This source code is licensed under the BSD-style license found in the
> + * LICENSE file in the root directory of https://github.com/facebook/zstd.
> + * An additional grant of patent rights can be found in the PATENTS file in 
> the
> + * same directory.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + */
> +
> +/*-*************************************
> +*  Dependencies
> +***************************************/
> +#include "error_private.h"
> +#include "zstd_internal.h" /* declaration of ZSTD_isError, 
> ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber 
> */
> +#include <linux/kernel.h>
> +
> +/*=**************************************************************
> +*  Custom allocator
> +****************************************************************/
> +
> +#define stack_push(stack, size)                                 \
> +       ({                                                      \
> +               void *const ptr = ZSTD_PTR_ALIGN((stack)->ptr); \
> +               (stack)->ptr = (char *)ptr + (size);            \
> +               (stack)->ptr <= (stack)->end ? ptr : NULL;      \
> +       })
> +
> +ZSTD_customMem ZSTD_initStack(void *workspace, size_t workspaceSize)
> +{
> +       ZSTD_customMem stackMem = {ZSTD_stackAlloc, ZSTD_stackFree, 
> workspace};
> +       ZSTD_stack *stack = (ZSTD_stack *)workspace;
> +       /* Verify preconditions */
> +       if (!workspace || workspaceSize < sizeof(ZSTD_stack) || workspace != 
> ZSTD_PTR_ALIGN(workspace)) {
> +               ZSTD_customMem error = {NULL, NULL, NULL};
> +               return error;
> +       }
> +       /* Initialize the stack */
> +       stack->ptr = workspace;
> +       stack->end = (char *)workspace + workspaceSize;
> +       stack_push(stack, sizeof(ZSTD_stack));
> +       return stackMem;
> +}
> +
> +void *ZSTD_stackAllocAll(void *opaque, size_t *size)
> +{
> +       ZSTD_stack *stack = (ZSTD_stack *)opaque;
> +       *size = (BYTE const *)stack->end - (BYTE *)ZSTD_PTR_ALIGN(stack->ptr);
> +       return stack_push(stack, *size);
> +}
> +
> +void *ZSTD_stackAlloc(void *opaque, size_t size)
> +{
> +       ZSTD_stack *stack = (ZSTD_stack *)opaque;
> +       return stack_push(stack, size);
> +}
> +void ZSTD_stackFree(void *opaque, void *address)
> +{
> +       (void)opaque;
> +       (void)address;
> +}
> +
> +void *ZSTD_malloc(size_t size, ZSTD_customMem customMem) { return 
> customMem.customAlloc(customMem.opaque, size); }
> +
> +void ZSTD_free(void *ptr, ZSTD_customMem customMem)
> +{
> +       if (ptr != NULL)
> +               customMem.customFree(customMem.opaque, ptr);
> +}
> diff --git a/grub-core/lib/zstd/zstd_internal.h 
> b/grub-core/lib/zstd/zstd_internal.h
> new file mode 100644
> index 000000000..1a79fab9e
> --- /dev/null
> +++ b/grub-core/lib/zstd/zstd_internal.h
> @@ -0,0 +1,263 @@
> +/**
> + * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
> + * All rights reserved.
> + *
> + * This source code is licensed under the BSD-style license found in the
> + * LICENSE file in the root directory of https://github.com/facebook/zstd.
> + * An additional grant of patent rights can be found in the PATENTS file in 
> the
> + * same directory.
> + *
> + * This program is free software; you can redistribute it and/or modify it 
> under
> + * the terms of the GNU General Public License version 2 as published by the
> + * Free Software Foundation. This program is dual-licensed; you may select
> + * either version 2 of the GNU General Public License ("GPL") or BSD license
> + * ("BSD").
> + */
> +
> +#ifndef ZSTD_CCOMMON_H_MODULE
> +#define ZSTD_CCOMMON_H_MODULE
> +
> +/*-*******************************************************
> +*  Compiler specifics
> +*********************************************************/
> +#define FORCE_INLINE static __always_inline
> +#define FORCE_NOINLINE static noinline
> +
> +/*-*************************************
> +*  Dependencies
> +***************************************/
> +#include "error_private.h"
> +#include "mem.h"
> +#include <linux/compiler.h>
> +#include <linux/kernel.h>
> +#include <linux/xxhash.h>
> +#include <linux/zstd.h>
> +
> +/*-*************************************
> +*  shared macros
> +***************************************/
> +#define MIN(a, b) ((a) < (b) ? (a) : (b))
> +#define MAX(a, b) ((a) > (b) ? (a) : (b))
> +#define CHECK_F(f)                       \
> +       {                                \
> +               size_t const errcod = f; \
> +               if (ERR_isError(errcod)) \
> +                       return errcod;   \
> +       } /* check and Forward error code */
> +#define CHECK_E(f, e)                    \
> +       {                                \
> +               size_t const errcod = f; \
> +               if (ERR_isError(errcod)) \
> +                       return ERROR(e); \
> +       } /* check and send Error code */
> +#define ZSTD_STATIC_ASSERT(c)                                   \
> +       {                                                       \
> +               enum { ZSTD_static_assert = 1 / (int)(!!(c)) }; \
> +       }
> +
> +/*-*************************************
> +*  Common constants
> +***************************************/
> +#define ZSTD_OPT_NUM (1 << 12)
> +#define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */
> +
> +#define ZSTD_REP_NUM 3               /* number of repcodes */
> +#define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the 
> optimal parser */
> +#define ZSTD_REP_MOVE (ZSTD_REP_NUM - 1)
> +#define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM)
> +static const U32 repStartValue[ZSTD_REP_NUM] = {1, 4, 8};
> +
> +#define KB *(1 << 10)
> +#define MB *(1 << 20)
> +#define GB *(1U << 30)
> +
> +#define BIT7 128
> +#define BIT6 64
> +#define BIT5 32
> +#define BIT4 16
> +#define BIT1 2
> +#define BIT0 1
> +
> +#define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
> +static const size_t ZSTD_fcs_fieldSize[4] = {0, 2, 4, 8};
> +static const size_t ZSTD_did_fieldSize[4] = {0, 1, 2, 4};
> +
> +#define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` 
> variable to be init using another `static const` variable */
> +static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
> +typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
> +
> +#define MIN_SEQUENCES_SIZE 1                                                 
>                     /* nbSeq==0 */
> +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + 
> MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
> +
> +#define HufLog 12
> +typedef enum { set_basic, set_rle, set_compressed, set_repeat } 
> symbolEncodingType_e;
> +
> +#define LONGNBSEQ 0x7F00
> +
> +#define MINMATCH 3
> +#define EQUAL_READ32 4
> +
> +#define Litbits 8
> +#define MaxLit ((1 << Litbits) - 1)
> +#define MaxML 52
> +#define MaxLL 35
> +#define MaxOff 28
> +#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
> +#define MLFSELog 9
> +#define LLFSELog 9
> +#define OffFSELog 8
> +
> +static const U32 LL_bits[MaxLL + 1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
> 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 
> 16};
> +static const S16 LL_defaultNorm[MaxLL + 1] = {4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 
> 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, -1, -1, -1, 
> -1};
> +#define LL_DEFAULTNORMLOG 6 /* for static allocation */
> +static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
> +
> +static const U32 ML_bits[MaxML + 1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
> 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0, 0,
> +                                      0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 
> 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
> +static const S16 ML_defaultNorm[MaxML + 1] = {1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 
> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  1,  1,  1,  1,  1,  1, 1,
> +                                             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
> 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1};
> +#define ML_DEFAULTNORMLOG 6 /* for static allocation */
> +static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
> +
> +static const S16 OF_defaultNorm[MaxOff + 1] = {1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 
> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1};
> +#define OF_DEFAULTNORMLOG 5 /* for static allocation */
> +static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
> +
> +/*-*******************************************
> +*  Shared functions to include for inlining
> +*********************************************/
> +ZSTD_STATIC void ZSTD_copy8(void *dst, const void *src) {
> +       memcpy(dst, src, 8);
> +}
> +/*! ZSTD_wildcopy() :
> +*   custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if 
> length==0) */
> +#define WILDCOPY_OVERLENGTH 8
> +ZSTD_STATIC void ZSTD_wildcopy(void *dst, const void *src, ptrdiff_t length)
> +{
> +       const BYTE* ip = (const BYTE*)src;
> +       BYTE* op = (BYTE*)dst;
> +       BYTE* const oend = op + length;
> +       /* Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81388.
> +        * Avoid the bad case where the loop only runs once by handling the
> +        * special case separately. This doesn't trigger the bug because it
> +        * doesn't involve pointer/integer overflow.
> +        */
> +       if (length <= 8)
> +               return ZSTD_copy8(dst, src);
> +       do {
> +               ZSTD_copy8(op, ip);
> +               op += 8;
> +               ip += 8;
> +       } while (op < oend);
> +}
> +
> +/*-*******************************************
> +*  Private interfaces
> +*********************************************/
> +typedef struct ZSTD_stats_s ZSTD_stats_t;
> +
> +typedef struct {
> +       U32 off;
> +       U32 len;
> +} ZSTD_match_t;
> +
> +typedef struct {
> +       U32 price;
> +       U32 off;
> +       U32 mlen;
> +       U32 litlen;
> +       U32 rep[ZSTD_REP_NUM];
> +} ZSTD_optimal_t;
> +
> +typedef struct seqDef_s {
> +       U32 offset;
> +       U16 litLength;
> +       U16 matchLength;
> +} seqDef;
> +
> +typedef struct {
> +       seqDef *sequencesStart;
> +       seqDef *sequences;
> +       BYTE *litStart;
> +       BYTE *lit;
> +       BYTE *llCode;
> +       BYTE *mlCode;
> +       BYTE *ofCode;
> +       U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == 
> Match.longLength; */
> +       U32 longLengthPos;
> +       /* opt */
> +       ZSTD_optimal_t *priceTable;
> +       ZSTD_match_t *matchTable;
> +       U32 *matchLengthFreq;
> +       U32 *litLengthFreq;
> +       U32 *litFreq;
> +       U32 *offCodeFreq;
> +       U32 matchLengthSum;
> +       U32 matchSum;
> +       U32 litLengthSum;
> +       U32 litSum;
> +       U32 offCodeSum;
> +       U32 log2matchLengthSum;
> +       U32 log2matchSum;
> +       U32 log2litLengthSum;
> +       U32 log2litSum;
> +       U32 log2offCodeSum;
> +       U32 factor;
> +       U32 staticPrices;
> +       U32 cachedPrice;
> +       U32 cachedLitLength;
> +       const BYTE *cachedLiterals;
> +} seqStore_t;
> +
> +const seqStore_t *ZSTD_getSeqStore(const ZSTD_CCtx *ctx);
> +void ZSTD_seqToCodes(const seqStore_t *seqStorePtr);
> +int ZSTD_isSkipFrame(ZSTD_DCtx *dctx);
> +
> +/*= Custom memory allocation functions */
> +typedef void *(*ZSTD_allocFunction)(void *opaque, size_t size);
> +typedef void (*ZSTD_freeFunction)(void *opaque, void *address);
> +typedef struct {
> +       ZSTD_allocFunction customAlloc;
> +       ZSTD_freeFunction customFree;
> +       void *opaque;
> +} ZSTD_customMem;
> +
> +void *ZSTD_malloc(size_t size, ZSTD_customMem customMem);
> +void ZSTD_free(void *ptr, ZSTD_customMem customMem);
> +
> +/*====== stack allocation  ======*/
> +
> +typedef struct {
> +       void *ptr;
> +       const void *end;
> +} ZSTD_stack;
> +
> +#define ZSTD_ALIGN(x) ALIGN(x, sizeof(size_t))
> +#define ZSTD_PTR_ALIGN(p) PTR_ALIGN(p, sizeof(size_t))
> +
> +ZSTD_customMem ZSTD_initStack(void *workspace, size_t workspaceSize);
> +
> +void *ZSTD_stackAllocAll(void *opaque, size_t *size);
> +void *ZSTD_stackAlloc(void *opaque, size_t size);
> +void ZSTD_stackFree(void *opaque, void *address);
> +
> +/*======  common function  ======*/
> +
> +ZSTD_STATIC U32 ZSTD_highbit32(U32 val) { return 31 - __builtin_clz(val); }
> +
> +/* hidden functions */
> +
> +/* ZSTD_invalidateRepCodes() :
> + * ensures next compression will not use repcodes from previous block.
> + * Note : only works with regular variant;
> + *        do not use with extDict variant ! */
> +void ZSTD_invalidateRepCodes(ZSTD_CCtx *cctx);
> +
> +size_t ZSTD_freeCCtx(ZSTD_CCtx *cctx);
> +size_t ZSTD_freeDCtx(ZSTD_DCtx *dctx);
> +size_t ZSTD_freeCDict(ZSTD_CDict *cdict);
> +size_t ZSTD_freeDDict(ZSTD_DDict *cdict);
> +size_t ZSTD_freeCStream(ZSTD_CStream *zcs);
> +size_t ZSTD_freeDStream(ZSTD_DStream *zds);
> +
> +#endif /* ZSTD_CCOMMON_H_MODULE */
> --
> 2.16.2
>
> _______________________________________________
> Grub-devel mailing list
> address@hidden
> https://lists.gnu.org/mailman/listinfo/grub-devel



reply via email to

[Prev in Thread] Current Thread [Next in Thread]