2017-08-18 23:52:05 +00:00
/*
2020-03-26 22:19:05 +00:00
* Copyright ( c ) 2016 - 2020 , Yann Collet , Facebook , Inc .
2016-08-30 17:04:33 +00:00
* All rights reserved .
*
2017-08-18 23:52:05 +00:00
* This source code is licensed under both the BSD - style license ( found in the
* LICENSE file in the root directory of this source tree ) and the GPLv2 ( found
* in the COPYING file in the root directory of this source tree ) .
2017-09-08 07:09:23 +00:00
* You may select , at your option , one of the above - listed licenses .
2016-08-30 17:04:33 +00:00
*/
2015-11-11 12:43:58 +00:00
/* ***************************************************************
* Tuning parameters
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*!
* HEAPMODE :
2018-03-20 20:40:29 +00:00
* Select how default decompression function ZSTD_decompress ( ) allocates its context ,
* on stack ( 0 ) , or into heap ( 1 , default ; requires malloc ( ) ) .
* Note that functions with explicit context such as ZSTD_decompressDCtx ( ) are unaffected .
2015-11-11 12:43:58 +00:00
*/
# ifndef ZSTD_HEAPMODE
# define ZSTD_HEAPMODE 1
2016-01-11 11:56:11 +00:00
# endif
2015-11-11 12:43:58 +00:00
/*!
* LEGACY_SUPPORT :
faster decoding in 32-bits mode for long offsets (tentative)
On my laptop:
Before:
./zstd32 -b --zstd=wlog=27 silesia.tar enwik8 -S
3#silesia.tar : 211984896 -> 66683478 (3.179), 97.6 MB/s , 400.7 MB/s
3#enwik8 : 100000000 -> 35643153 (2.806), 76.5 MB/s , 303.2 MB/s
After:
./zstd32 -b --zstd=wlog=27 silesia.tar enwik8 -S
3#silesia.tar : 211984896 -> 66683478 (3.179), 97.4 MB/s , 435.0 MB/s
3#enwik8 : 100000000 -> 35643153 (2.806), 76.2 MB/s , 338.1 MB/s
Mileage vary, depending on file, and cpu type.
But a generic rule is : x86 benefits less from "long-offset mode" than x64,
maybe due to register pressure.
On "entropy", long-mode is _never_ a win for x86.
On my laptop though, it may, depending on file and compression level
(enwik8 benefits more from "long-mode" than silesia).
2018-02-04 07:54:10 +00:00
* if set to 1 + , ZSTD_decompress ( ) can decode older formats ( v0 .1 + )
2015-11-11 12:43:58 +00:00
*/
# ifndef ZSTD_LEGACY_SUPPORT
2016-01-18 11:03:27 +00:00
# define ZSTD_LEGACY_SUPPORT 0
2015-11-11 12:43:58 +00:00
# endif
2016-08-22 23:34:34 +00:00
/*!
2018-03-20 20:40:29 +00:00
* MAXWINDOWSIZE_DEFAULT :
* maximum window size accepted by DStream __by default__ .
* Frames requiring more memory will be rejected .
* It ' s possible to set a different limit using ZSTD_DCtx_setMaxWindowSize ( ) .
*/
2016-08-23 14:58:10 +00:00
# ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
2018-11-14 02:09:03 +00:00
# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
2016-08-22 23:34:34 +00:00
# endif
error on no forward progress
streaming decoders, such as ZSTD_decompressStream() or ZSTD_decompress_generic(),
may end up making no forward progress,
(aka no byte read from input __and__ no byte written to output),
due to unusual parameters conditions,
such as providing an output buffer already full.
In such case, the caller may be caught in an infinite loop,
calling the streaming decompression function again and again,
without making any progress.
This version detects such situation, and generates an error instead :
ZSTD_error_dstSize_tooSmall when output buffer is full,
ZSTD_error_srcSize_wrong when input buffer is empty.
The detection tolerates a number of attempts before triggering an error,
controlled by ZSTD_NO_FORWARD_PROGRESS_MAX macro constant,
which is set to 16 by default, and can be re-defined at compilation time.
This behavior tolerates potentially existing implementations
where such cases happen sporadically, like once or twice,
which is not dangerous (only infinite loops are),
without generating an error, hence without breaking these implementations.
2018-06-23 00:58:21 +00:00
/*!
* NO_FORWARD_PROGRESS_MAX :
2018-12-04 18:28:36 +00:00
* maximum allowed nb of calls to ZSTD_decompressStream ( )
error on no forward progress
streaming decoders, such as ZSTD_decompressStream() or ZSTD_decompress_generic(),
may end up making no forward progress,
(aka no byte read from input __and__ no byte written to output),
due to unusual parameters conditions,
such as providing an output buffer already full.
In such case, the caller may be caught in an infinite loop,
calling the streaming decompression function again and again,
without making any progress.
This version detects such situation, and generates an error instead :
ZSTD_error_dstSize_tooSmall when output buffer is full,
ZSTD_error_srcSize_wrong when input buffer is empty.
The detection tolerates a number of attempts before triggering an error,
controlled by ZSTD_NO_FORWARD_PROGRESS_MAX macro constant,
which is set to 16 by default, and can be re-defined at compilation time.
This behavior tolerates potentially existing implementations
where such cases happen sporadically, like once or twice,
which is not dangerous (only infinite loops are),
without generating an error, hence without breaking these implementations.
2018-06-23 00:58:21 +00:00
* without any forward progress
* ( defined as : no byte read from input , and no byte flushed to output )
* before triggering an error .
*/
# ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
# define ZSTD_NO_FORWARD_PROGRESS_MAX 16
# endif
2018-09-12 00:23:44 +00:00
2016-01-27 23:18:06 +00:00
/*-*******************************************************
2016-02-04 14:28:14 +00:00
* Dependencies
2015-11-11 12:43:58 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-08-10 19:46:38 +00:00
# include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
2020-05-01 20:07:57 +00:00
# include "../common/cpu.h" /* bmi2 */
# include "../common/mem.h" /* low level memory routines */
2016-06-04 22:58:01 +00:00
# define FSE_STATIC_LINKING_ONLY
2020-05-01 20:07:57 +00:00
# include "../common/fse.h"
2016-06-04 22:42:28 +00:00
# define HUF_STATIC_LINKING_ONLY
2020-05-01 20:07:57 +00:00
# include "../common/huf.h"
# include "../common/zstd_internal.h" /* blockProperties_t */
2018-10-24 00:25:49 +00:00
# include "zstd_decompress_internal.h" /* ZSTD_DCtx */
# include "zstd_ddict.h" /* ZSTD_DDictDictContent */
2018-10-25 23:28:41 +00:00
# include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
2015-11-11 12:43:58 +00:00
2016-06-05 22:26:38 +00:00
# if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
2020-05-01 20:07:57 +00:00
# include ".. / legacy / zstd_legacy.h"
2015-11-11 12:43:58 +00:00
# endif
2016-05-12 13:55:26 +00:00
2016-03-12 00:25:40 +00:00
/*-*************************************************************
2015-11-12 14:36:05 +00:00
* Context management
2015-11-11 12:43:58 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-05-23 23:19:43 +00:00
size_t ZSTD_sizeof_DCtx ( const ZSTD_DCtx * dctx )
{
if ( dctx = = NULL ) return 0 ; /* support sizeof NULL */
return sizeof ( * dctx )
+ ZSTD_sizeof_DDict ( dctx - > ddictLocal )
+ dctx - > inBuffSize + dctx - > outBuffSize ;
}
2016-01-27 23:18:06 +00:00
2016-07-11 11:46:25 +00:00
size_t ZSTD_estimateDCtxSize ( void ) { return sizeof ( ZSTD_DCtx ) ; }
2017-09-26 22:36:14 +00:00
static size_t ZSTD_startingInputLength ( ZSTD_format_e format )
{
2019-10-22 02:42:14 +00:00
size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX ( format ) ;
2017-09-26 22:36:57 +00:00
/* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
assert ( ( format = = ZSTD_f_zstd1 ) | | ( format = = ZSTD_f_zstd1_magicless ) ) ;
2017-09-26 22:36:14 +00:00
return startingInputLength ;
}
2020-09-29 23:25:03 +00:00
static void ZSTD_DCtx_resetParameters ( ZSTD_DCtx * dctx )
{
assert ( dctx - > streamStage = = zdss_init ) ;
dctx - > format = ZSTD_f_zstd1 ;
dctx - > maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT ;
2020-10-12 20:15:39 +00:00
dctx - > outBufferMode = ZSTD_bm_buffered ;
2020-09-29 23:25:03 +00:00
dctx - > forceIgnoreChecksum = ZSTD_d_validateChecksum ;
}
2017-05-25 00:41:41 +00:00
static void ZSTD_initDCtx_internal ( ZSTD_DCtx * dctx )
2016-05-23 14:24:52 +00:00
{
2017-09-09 21:37:28 +00:00
dctx - > staticSize = 0 ;
dctx - > ddict = NULL ;
dctx - > ddictLocal = NULL ;
2018-09-13 19:29:52 +00:00
dctx - > dictEnd = NULL ;
2018-09-12 00:23:44 +00:00
dctx - > ddictIsCold = 0 ;
2019-04-10 23:50:35 +00:00
dctx - > dictUses = ZSTD_dont_use ;
2017-09-09 21:37:28 +00:00
dctx - > inBuff = NULL ;
dctx - > inBuffSize = 0 ;
dctx - > outBuffSize = 0 ;
2017-05-25 00:41:41 +00:00
dctx - > streamStage = zdss_init ;
2018-06-14 14:22:24 +00:00
dctx - > legacyContext = NULL ;
dctx - > previousLegacyVersion = 0 ;
error on no forward progress
streaming decoders, such as ZSTD_decompressStream() or ZSTD_decompress_generic(),
may end up making no forward progress,
(aka no byte read from input __and__ no byte written to output),
due to unusual parameters conditions,
such as providing an output buffer already full.
In such case, the caller may be caught in an infinite loop,
calling the streaming decompression function again and again,
without making any progress.
This version detects such situation, and generates an error instead :
ZSTD_error_dstSize_tooSmall when output buffer is full,
ZSTD_error_srcSize_wrong when input buffer is empty.
The detection tolerates a number of attempts before triggering an error,
controlled by ZSTD_NO_FORWARD_PROGRESS_MAX macro constant,
which is set to 16 by default, and can be re-defined at compilation time.
This behavior tolerates potentially existing implementations
where such cases happen sporadically, like once or twice,
which is not dangerous (only infinite loops are),
without generating an error, hence without breaking these implementations.
2018-06-23 00:58:21 +00:00
dctx - > noForwardProgress = 0 ;
2020-04-03 19:40:31 +00:00
dctx - > oversizedDuration = 0 ;
2018-02-03 02:03:09 +00:00
dctx - > bmi2 = ZSTD_cpuid_bmi2 ( ZSTD_cpuid ( ) ) ;
2020-09-29 23:25:03 +00:00
ZSTD_DCtx_resetParameters ( dctx ) ;
2020-08-24 21:28:00 +00:00
dctx - > validateChecksum = 1 ;
2020-05-12 02:05:42 +00:00
# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
dctx - > dictContentEndForFuzzing = NULL ;
# endif
2017-09-27 01:26:09 +00:00
}
ZSTD_DCtx * ZSTD_initStaticDCtx ( void * workspace , size_t workspaceSize )
{
ZSTD_DCtx * const dctx = ( ZSTD_DCtx * ) workspace ;
if ( ( size_t ) workspace & 7 ) return NULL ; /* 8-aligned */
if ( workspaceSize < sizeof ( ZSTD_DCtx ) ) return NULL ; /* minimum size */
ZSTD_initDCtx_internal ( dctx ) ;
dctx - > staticSize = workspaceSize ;
dctx - > inBuff = ( char * ) ( dctx + 1 ) ;
return dctx ;
2017-05-25 00:41:41 +00:00
}
2016-05-23 14:24:52 +00:00
ZSTD_DCtx * ZSTD_createDCtx_advanced ( ZSTD_customMem customMem )
{
2020-09-24 03:34:44 +00:00
if ( ( ! customMem . customAlloc ) ^ ( ! customMem . customFree ) ) return NULL ;
2016-05-23 14:24:52 +00:00
2020-08-10 19:42:03 +00:00
{ ZSTD_DCtx * const dctx = ( ZSTD_DCtx * ) ZSTD_customMalloc ( sizeof ( * dctx ) , customMem ) ;
2017-06-02 21:24:58 +00:00
if ( ! dctx ) return NULL ;
dctx - > customMem = customMem ;
ZSTD_initDCtx_internal ( dctx ) ;
return dctx ;
}
2017-05-25 00:41:41 +00:00
}
2016-05-31 22:18:28 +00:00
ZSTD_DCtx * ZSTD_createDCtx ( void )
{
2017-12-30 14:12:59 +00:00
DEBUGLOG ( 3 , " ZSTD_createDCtx " ) ;
2017-05-31 00:11:39 +00:00
return ZSTD_createDCtx_advanced ( ZSTD_defaultCMem ) ;
2016-05-31 22:18:28 +00:00
}
2019-04-10 19:34:21 +00:00
static void ZSTD_clearDict ( ZSTD_DCtx * dctx )
{
ZSTD_freeDDict ( dctx - > ddictLocal ) ;
dctx - > ddictLocal = NULL ;
dctx - > ddict = NULL ;
2019-04-10 23:50:35 +00:00
dctx - > dictUses = ZSTD_dont_use ;
2019-04-10 19:34:21 +00:00
}
2015-11-12 14:36:05 +00:00
size_t ZSTD_freeDCtx ( ZSTD_DCtx * dctx )
{
2016-06-03 14:36:50 +00:00
if ( dctx = = NULL ) return 0 ; /* support free on NULL */
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( dctx - > staticSize , memory_allocation , " not compatible with static DCtx " ) ;
2017-05-23 23:19:43 +00:00
{ ZSTD_customMem const cMem = dctx - > customMem ;
2019-04-10 19:34:21 +00:00
ZSTD_clearDict ( dctx ) ;
2020-08-10 19:42:03 +00:00
ZSTD_customFree ( dctx - > inBuff , cMem ) ;
2017-05-23 23:19:43 +00:00
dctx - > inBuff = NULL ;
# if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
if ( dctx - > legacyContext )
ZSTD_freeLegacyStreamContext ( dctx - > legacyContext , dctx - > previousLegacyVersion ) ;
# endif
2020-08-10 19:42:03 +00:00
ZSTD_customFree ( dctx , cMem ) ;
2017-05-23 23:19:43 +00:00
return 0 ;
}
2015-11-12 14:36:05 +00:00
}
2017-06-21 20:26:10 +00:00
/* no longer useful */
2016-01-26 14:58:49 +00:00
void ZSTD_copyDCtx ( ZSTD_DCtx * dstDCtx , const ZSTD_DCtx * srcDCtx )
{
2017-05-25 00:41:41 +00:00
size_t const toCopy = ( size_t ) ( ( char * ) ( & dstDCtx - > inBuff ) - ( char * ) dstDCtx ) ;
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( dstDCtx , srcDCtx , toCopy ) ; /* no need to copy workspace */
2016-01-26 14:58:49 +00:00
}
2015-11-12 14:36:05 +00:00
2016-03-12 00:25:40 +00:00
/*-*************************************************************
faster decoding in 32-bits mode for long offsets (tentative)
On my laptop:
Before:
./zstd32 -b --zstd=wlog=27 silesia.tar enwik8 -S
3#silesia.tar : 211984896 -> 66683478 (3.179), 97.6 MB/s , 400.7 MB/s
3#enwik8 : 100000000 -> 35643153 (2.806), 76.5 MB/s , 303.2 MB/s
After:
./zstd32 -b --zstd=wlog=27 silesia.tar enwik8 -S
3#silesia.tar : 211984896 -> 66683478 (3.179), 97.4 MB/s , 435.0 MB/s
3#enwik8 : 100000000 -> 35643153 (2.806), 76.2 MB/s , 338.1 MB/s
Mileage vary, depending on file, and cpu type.
But a generic rule is : x86 benefits less from "long-offset mode" than x64,
maybe due to register pressure.
On "entropy", long-mode is _never_ a win for x86.
On my laptop though, it may, depending on file and compression level
(enwik8 benefits more from "long-mode" than silesia).
2018-02-04 07:54:10 +00:00
* Frame header decoding
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-01-23 18:28:41 +00:00
2016-11-03 00:30:49 +00:00
/*! 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 )
{
2018-08-14 19:56:21 +00:00
if ( size < ZSTD_FRAMEIDSIZE ) return 0 ;
2016-11-03 00:30:49 +00:00
{ U32 const magic = MEM_readLE32 ( buffer ) ;
if ( magic = = ZSTD_MAGICNUMBER ) return 1 ;
2018-11-14 01:36:35 +00:00
if ( ( magic & ZSTD_MAGIC_SKIPPABLE_MASK ) = = ZSTD_MAGIC_SKIPPABLE_START ) return 1 ;
2016-11-03 00:30:49 +00:00
}
# if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
if ( ZSTD_isLegacy ( buffer , size ) ) return 1 ;
# endif
return 0 ;
}
2017-09-25 21:26:26 +00:00
/** ZSTD_frameHeaderSize_internal() :
* srcSize must be large enough to reach header size fields .
faster decoding in 32-bits mode for long offsets (tentative)
On my laptop:
Before:
./zstd32 -b --zstd=wlog=27 silesia.tar enwik8 -S
3#silesia.tar : 211984896 -> 66683478 (3.179), 97.6 MB/s , 400.7 MB/s
3#enwik8 : 100000000 -> 35643153 (2.806), 76.5 MB/s , 303.2 MB/s
After:
./zstd32 -b --zstd=wlog=27 silesia.tar enwik8 -S
3#silesia.tar : 211984896 -> 66683478 (3.179), 97.4 MB/s , 435.0 MB/s
3#enwik8 : 100000000 -> 35643153 (2.806), 76.2 MB/s , 338.1 MB/s
Mileage vary, depending on file, and cpu type.
But a generic rule is : x86 benefits less from "long-offset mode" than x64,
maybe due to register pressure.
On "entropy", long-mode is _never_ a win for x86.
On my laptop though, it may, depending on file and compression level
(enwik8 benefits more from "long-mode" than silesia).
2018-02-04 07:54:10 +00:00
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless .
2017-09-25 21:26:26 +00:00
* @ return : size of the Frame Header
* or an error code , which can be tested with ZSTD_isError ( ) */
static size_t ZSTD_frameHeaderSize_internal ( const void * src , size_t srcSize , ZSTD_format_e format )
2015-11-25 13:42:45 +00:00
{
2017-09-26 22:36:14 +00:00
size_t const minInputSize = ZSTD_startingInputLength ( format ) ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( srcSize < minInputSize , srcSize_wrong , " " ) ;
2017-09-25 21:26:26 +00:00
{ BYTE const fhd = ( ( const BYTE * ) src ) [ minInputSize - 1 ] ;
2016-06-05 22:26:38 +00:00
U32 const dictID = fhd & 3 ;
2016-07-26 17:42:19 +00:00
U32 const singleSegment = ( fhd > > 5 ) & 1 ;
2016-06-05 22:26:38 +00:00
U32 const fcsId = fhd > > 6 ;
2017-09-25 21:26:26 +00:00
return minInputSize + ! singleSegment
+ ZSTD_did_fieldSize [ dictID ] + ZSTD_fcs_fieldSize [ fcsId ]
+ ( singleSegment & & ! fcsId ) ;
2016-05-29 03:01:04 +00:00
}
2015-11-25 13:42:45 +00:00
}
2017-09-25 21:26:26 +00:00
/** ZSTD_frameHeaderSize() :
* srcSize must be > = ZSTD_frameHeaderSize_prefix .
2018-03-31 03:09:27 +00:00
* @ return : size of the Frame Header ,
* or an error code ( if srcSize is too small ) */
2017-09-25 21:26:26 +00:00
size_t ZSTD_frameHeaderSize ( const void * src , size_t srcSize )
{
return ZSTD_frameHeaderSize_internal ( src , srcSize , ZSTD_f_zstd1 ) ;
}
2015-11-25 13:42:45 +00:00
2017-09-25 21:26:26 +00:00
2018-03-31 03:09:27 +00:00
/** ZSTD_getFrameHeader_advanced() :
2017-09-25 21:26:26 +00:00
* decode Frame Header , or require larger ` srcSize ` .
* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
* @ return : 0 , ` zfhPtr ` is correctly filled ,
* > 0 , ` srcSize ` is too small , value is wanted ` srcSize ` amount ,
* or an error code , which can be tested using ZSTD_isError ( ) */
2018-03-29 23:51:08 +00:00
size_t ZSTD_getFrameHeader_advanced ( ZSTD_frameHeader * zfhPtr , const void * src , size_t srcSize , ZSTD_format_e format )
2015-11-25 13:42:45 +00:00
{
2016-03-12 00:25:40 +00:00
const BYTE * ip = ( const BYTE * ) src ;
2017-09-26 22:36:14 +00:00
size_t const minInputSize = ZSTD_startingInputLength ( format ) ;
2017-05-09 23:18:17 +00:00
2020-08-10 19:46:38 +00:00
ZSTD_memset ( zfhPtr , 0 , sizeof ( * zfhPtr ) ) ; /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
2017-09-25 21:26:26 +00:00
if ( srcSize < minInputSize ) return minInputSize ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( src = = NULL , GENERIC , " invalid parameter " ) ;
2017-09-25 21:26:26 +00:00
2017-09-26 22:06:30 +00:00
if ( ( format ! = ZSTD_f_zstd1_magicless )
& & ( MEM_readLE32 ( src ) ! = ZSTD_MAGICNUMBER ) ) {
2018-11-14 01:36:35 +00:00
if ( ( MEM_readLE32 ( src ) & ZSTD_MAGIC_SKIPPABLE_MASK ) = = ZSTD_MAGIC_SKIPPABLE_START ) {
2017-05-09 23:18:17 +00:00
/* skippable frame */
2018-11-14 00:56:32 +00:00
if ( srcSize < ZSTD_SKIPPABLEHEADERSIZE )
return ZSTD_SKIPPABLEHEADERSIZE ; /* magic number + frame length */
2020-08-10 19:46:38 +00:00
ZSTD_memset ( zfhPtr , 0 , sizeof ( * zfhPtr ) ) ;
2018-08-14 19:56:21 +00:00
zfhPtr - > frameContentSize = MEM_readLE32 ( ( const char * ) src + ZSTD_FRAMEIDSIZE ) ;
2017-07-07 22:21:35 +00:00
zfhPtr - > frameType = ZSTD_skippableFrame ;
2016-05-31 10:43:46 +00:00
return 0 ;
}
2020-04-30 16:24:56 +00:00
RETURN_ERROR ( prefix_unknown , " " ) ;
2016-05-31 10:43:46 +00:00
}
2016-03-12 00:25:40 +00:00
2016-03-15 00:33:36 +00:00
/* ensure there is enough `srcSize` to fully read/decode frame header */
2017-09-25 21:26:26 +00:00
{ size_t const fhsize = ZSTD_frameHeaderSize_internal ( src , srcSize , format ) ;
2017-07-07 22:51:24 +00:00
if ( srcSize < fhsize ) return fhsize ;
zfhPtr - > headerSize = ( U32 ) fhsize ;
}
2016-03-12 00:25:40 +00:00
2017-09-25 21:26:26 +00:00
{ BYTE const fhdByte = ip [ minInputSize - 1 ] ;
size_t pos = minInputSize ;
2016-06-05 22:26:38 +00:00
U32 const dictIDSizeCode = fhdByte & 3 ;
U32 const checksumFlag = ( fhdByte > > 2 ) & 1 ;
2016-07-26 17:42:19 +00:00
U32 const singleSegment = ( fhdByte > > 5 ) & 1 ;
2016-06-05 22:26:38 +00:00
U32 const fcsID = fhdByte > > 6 ;
2017-07-07 22:21:35 +00:00
U64 windowSize = 0 ;
2016-06-05 22:26:38 +00:00
U32 dictID = 0 ;
2017-07-07 22:21:35 +00:00
U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( ( fhdByte & 0x08 ) ! = 0 , frameParameter_unsupported ,
" reserved bits, must be zero " ) ;
2017-07-07 22:21:35 +00:00
2016-07-26 17:42:19 +00:00
if ( ! singleSegment ) {
2016-06-05 22:26:38 +00:00
BYTE const wlByte = ip [ pos + + ] ;
U32 const windowLog = ( wlByte > > 3 ) + ZSTD_WINDOWLOG_ABSOLUTEMIN ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( windowLog > ZSTD_WINDOWLOG_MAX , frameParameter_windowTooLarge , " " ) ;
2017-07-07 23:09:47 +00:00
windowSize = ( 1ULL < < windowLog ) ;
2016-06-05 22:26:38 +00:00
windowSize + = ( windowSize > > 3 ) * ( wlByte & 7 ) ;
}
switch ( dictIDSizeCode )
2016-05-29 03:01:04 +00:00
{
2017-07-07 22:21:35 +00:00
default : assert ( 0 ) ; /* impossible */
2016-06-05 22:26:38 +00:00
case 0 : break ;
case 1 : dictID = ip [ pos ] ; pos + + ; break ;
case 2 : dictID = MEM_readLE16 ( ip + pos ) ; pos + = 2 ; break ;
case 3 : dictID = MEM_readLE32 ( ip + pos ) ; pos + = 4 ; break ;
2016-05-29 03:01:04 +00:00
}
2016-06-05 22:26:38 +00:00
switch ( fcsID )
2016-03-15 00:33:36 +00:00
{
2017-07-07 22:21:35 +00:00
default : assert ( 0 ) ; /* impossible */
2016-07-26 17:42:19 +00:00
case 0 : if ( singleSegment ) frameContentSize = ip [ pos ] ; break ;
2016-06-05 22:26:38 +00:00
case 1 : frameContentSize = MEM_readLE16 ( ip + pos ) + 256 ; break ;
case 2 : frameContentSize = MEM_readLE32 ( ip + pos ) ; break ;
case 3 : frameContentSize = MEM_readLE64 ( ip + pos ) ; break ;
}
2017-07-07 22:21:35 +00:00
if ( singleSegment ) windowSize = frameContentSize ;
zfhPtr - > frameType = ZSTD_frame ;
2017-05-10 18:14:08 +00:00
zfhPtr - > frameContentSize = frameContentSize ;
zfhPtr - > windowSize = windowSize ;
2017-09-09 08:03:29 +00:00
zfhPtr - > blockSizeMax = ( unsigned ) MIN ( windowSize , ZSTD_BLOCKSIZE_MAX ) ;
2017-05-10 18:14:08 +00:00
zfhPtr - > dictID = dictID ;
zfhPtr - > checksumFlag = checksumFlag ;
2016-06-05 22:26:38 +00:00
}
2015-11-25 13:42:45 +00:00
return 0 ;
}
2017-09-25 21:26:26 +00:00
/** ZSTD_getFrameHeader() :
* decode Frame Header , or require larger ` srcSize ` .
* note : this function does not consume input , it only reads it .
* @ return : 0 , ` zfhPtr ` is correctly filled ,
* > 0 , ` srcSize ` is too small , value is wanted ` srcSize ` amount ,
* or an error code , which can be tested using ZSTD_isError ( ) */
size_t ZSTD_getFrameHeader ( ZSTD_frameHeader * zfhPtr , const void * src , size_t srcSize )
{
2018-03-29 23:51:08 +00:00
return ZSTD_getFrameHeader_advanced ( zfhPtr , src , srcSize , ZSTD_f_zstd1 ) ;
2017-09-25 21:26:26 +00:00
}
2017-02-07 21:50:09 +00:00
/** ZSTD_getFrameContentSize() :
2017-07-07 22:21:35 +00:00
* 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 ) */
2017-02-07 21:50:09 +00:00
unsigned long long ZSTD_getFrameContentSize ( const void * src , size_t srcSize )
{
2017-03-13 21:32:30 +00:00
# if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
2017-02-07 21:50:09 +00:00
if ( ZSTD_isLegacy ( src , srcSize ) ) {
unsigned long long const ret = ZSTD_getDecompressedSize_legacy ( src , srcSize ) ;
return ret = = 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret ;
}
# endif
2017-07-07 22:21:35 +00:00
{ ZSTD_frameHeader zfh ;
if ( ZSTD_getFrameHeader ( & zfh , src , srcSize ) ! = 0 )
2017-07-07 21:19:01 +00:00
return ZSTD_CONTENTSIZE_ERROR ;
2017-07-07 22:21:35 +00:00
if ( zfh . frameType = = ZSTD_skippableFrame ) {
2017-02-07 21:50:09 +00:00
return 0 ;
} else {
2017-07-07 22:21:35 +00:00
return zfh . frameContentSize ;
} }
2017-02-07 21:50:09 +00:00
}
2018-12-12 23:26:35 +00:00
static size_t readSkippableFrameSize ( void const * src , size_t srcSize )
{
size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE ;
U32 sizeU32 ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( srcSize < ZSTD_SKIPPABLEHEADERSIZE , srcSize_wrong , " " ) ;
2018-12-12 23:26:35 +00:00
sizeU32 = MEM_readLE32 ( ( BYTE const * ) src + ZSTD_FRAMEIDSIZE ) ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( ( U32 ) ( sizeU32 + ZSTD_SKIPPABLEHEADERSIZE ) < sizeU32 ,
2020-04-30 16:24:56 +00:00
frameParameter_unsupported , " " ) ;
2019-04-17 18:41:55 +00:00
{
size_t const skippableSize = skippableHeaderSize + sizeU32 ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( skippableSize > srcSize , srcSize_wrong , " " ) ;
2019-04-17 18:41:55 +00:00
return skippableSize ;
}
2018-12-12 23:26:35 +00:00
}
2017-02-07 21:50:09 +00:00
/** 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 )
{
2017-05-23 23:19:43 +00:00
unsigned long long totalDstSize = 0 ;
2017-02-07 21:50:09 +00:00
2019-10-22 02:42:14 +00:00
while ( srcSize > = ZSTD_startingInputLength ( ZSTD_f_zstd1 ) ) {
2017-09-25 21:26:26 +00:00
U32 const magicNumber = MEM_readLE32 ( src ) ;
2017-05-23 23:19:43 +00:00
2018-11-14 01:36:35 +00:00
if ( ( magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK ) = = ZSTD_MAGIC_SKIPPABLE_START ) {
2018-12-12 23:26:35 +00:00
size_t const skippableSize = readSkippableFrameSize ( src , srcSize ) ;
2019-04-17 18:41:55 +00:00
if ( ZSTD_isError ( skippableSize ) ) {
2017-05-23 23:19:43 +00:00
return ZSTD_CONTENTSIZE_ERROR ;
2017-02-07 21:50:09 +00:00
}
2019-04-17 18:41:55 +00:00
assert ( skippableSize < = srcSize ) ;
2017-02-07 21:50:09 +00:00
2017-05-23 23:19:43 +00:00
src = ( const BYTE * ) src + skippableSize ;
srcSize - = skippableSize ;
continue ;
}
2017-02-07 21:50:09 +00:00
2017-05-23 23:19:43 +00:00
{ unsigned long long const ret = ZSTD_getFrameContentSize ( src , srcSize ) ;
if ( ret > = ZSTD_CONTENTSIZE_ERROR ) return ret ;
2017-02-07 21:50:09 +00:00
2017-05-23 23:19:43 +00:00
/* check for overflow */
if ( totalDstSize + ret < totalDstSize ) return ZSTD_CONTENTSIZE_ERROR ;
totalDstSize + = ret ;
2017-02-07 21:50:09 +00:00
}
2017-05-23 23:19:43 +00:00
{ size_t const frameSrcSize = ZSTD_findFrameCompressedSize ( src , srcSize ) ;
if ( ZSTD_isError ( frameSrcSize ) ) {
return ZSTD_CONTENTSIZE_ERROR ;
}
2017-02-07 21:50:09 +00:00
2017-05-23 23:19:43 +00:00
src = ( const BYTE * ) src + frameSrcSize ;
srcSize - = frameSrcSize ;
2017-02-07 21:50:09 +00:00
}
2017-09-25 21:26:26 +00:00
} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
2017-02-07 21:50:09 +00:00
2017-09-25 21:26:26 +00:00
if ( srcSize ) return ZSTD_CONTENTSIZE_ERROR ;
2017-05-23 23:19:43 +00:00
return totalDstSize ;
2017-02-07 21:50:09 +00:00
}
2016-03-12 00:25:40 +00:00
2016-07-07 11:14:21 +00:00
/** ZSTD_getDecompressedSize() :
2018-10-24 23:34:35 +00:00
* compatible with legacy mode
* @ return : decompressed size if known , 0 otherwise
note : 0 can mean any of the following :
2017-07-07 21:19:01 +00:00
- frame content is empty
- decompressed size field is not present in frame header
2016-07-07 11:14:21 +00:00
- frame header unknown / not supported
2016-07-20 18:12:24 +00:00
- frame header not complete ( ` srcSize ` too small ) */
2016-07-07 12:40:13 +00:00
unsigned long long ZSTD_getDecompressedSize ( const void * src , size_t srcSize )
{
2017-02-07 21:50:09 +00:00
unsigned long long const ret = ZSTD_getFrameContentSize ( src , srcSize ) ;
2017-09-25 21:26:26 +00:00
ZSTD_STATIC_ASSERT ( ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN ) ;
return ( ret > = ZSTD_CONTENTSIZE_ERROR ) ? 0 : ret ;
2016-07-07 11:14:21 +00:00
}
2016-03-12 00:25:40 +00:00
/** ZSTD_decodeFrameHeader() :
2018-10-24 23:34:35 +00:00
* ` headerSize ` must be the size provided by ZSTD_frameHeaderSize ( ) .
* @ return : 0 if success , or an error code , which can be tested using ZSTD_isError ( ) */
2016-10-21 03:11:00 +00:00
static size_t ZSTD_decodeFrameHeader ( ZSTD_DCtx * dctx , const void * src , size_t headerSize )
2015-11-26 11:43:28 +00:00
{
2018-03-29 23:51:08 +00:00
size_t const result = ZSTD_getFrameHeader_advanced ( & ( dctx - > fParams ) , src , headerSize , dctx - > format ) ;
2017-09-25 21:26:26 +00:00
if ( ZSTD_isError ( result ) ) return result ; /* invalid header */
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( result > 0 , srcSize_wrong , " headerSize too small " ) ;
2019-04-09 02:57:41 +00:00
# ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
/* Skip the dictID check in fuzzing mode, because it makes the search
* harder .
*/
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( dctx - > fParams . dictID & & ( dctx - > dictID ! = dctx - > fParams . dictID ) ,
2020-04-30 16:24:56 +00:00
dictionary_wrong , " " ) ;
2019-04-09 02:57:41 +00:00
# endif
2020-08-24 21:28:00 +00:00
dctx - > validateChecksum = ( dctx - > fParams . checksumFlag & & ! dctx - > forceIgnoreChecksum ) ? 1 : 0 ;
if ( dctx - > validateChecksum ) XXH64_reset ( & dctx - > xxhState , 0 ) ;
2016-10-21 03:11:00 +00:00
return 0 ;
2015-11-26 11:43:28 +00:00
}
2019-03-02 02:29:35 +00:00
static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo ( size_t ret )
{
ZSTD_frameSizeInfo frameSizeInfo ;
frameSizeInfo . compressedSize = ret ;
2019-03-13 08:23:07 +00:00
frameSizeInfo . decompressedBound = ZSTD_CONTENTSIZE_ERROR ;
2019-03-02 02:29:35 +00:00
return frameSizeInfo ;
}
2019-03-01 06:55:18 +00:00
static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo ( const void * src , size_t srcSize )
2017-02-07 21:50:09 +00:00
{
2019-03-01 06:55:18 +00:00
ZSTD_frameSizeInfo frameSizeInfo ;
2020-08-10 19:46:38 +00:00
ZSTD_memset ( & frameSizeInfo , 0 , sizeof ( ZSTD_frameSizeInfo ) ) ;
2019-03-01 06:55:18 +00:00
2017-03-13 21:32:30 +00:00
# if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
2019-03-18 02:35:43 +00:00
if ( ZSTD_isLegacy ( src , srcSize ) )
2019-03-15 23:10:37 +00:00
return ZSTD_findFrameSizeInfoLegacy ( src , srcSize ) ;
2017-02-10 19:38:57 +00:00
# endif
2019-03-01 06:55:18 +00:00
if ( ( srcSize > = ZSTD_SKIPPABLEHEADERSIZE )
& & ( MEM_readLE32 ( src ) & ZSTD_MAGIC_SKIPPABLE_MASK ) = = ZSTD_MAGIC_SKIPPABLE_START ) {
frameSizeInfo . compressedSize = readSkippableFrameSize ( src , srcSize ) ;
2019-04-17 18:41:55 +00:00
assert ( ZSTD_isError ( frameSizeInfo . compressedSize ) | |
frameSizeInfo . compressedSize < = srcSize ) ;
2019-03-01 06:55:18 +00:00
return frameSizeInfo ;
2017-02-22 20:12:32 +00:00
} else {
2017-02-10 19:38:57 +00:00
const BYTE * ip = ( const BYTE * ) src ;
const BYTE * const ipstart = ip ;
size_t remainingSize = srcSize ;
2019-03-01 08:05:59 +00:00
size_t nbBlocks = 0 ;
2019-03-01 06:55:18 +00:00
ZSTD_frameHeader zfh ;
2017-02-07 21:50:09 +00:00
2017-07-07 22:51:24 +00:00
/* Extract Frame Header */
2019-03-02 07:11:15 +00:00
{ size_t const ret = ZSTD_getFrameHeader ( & zfh , src , srcSize ) ;
2019-03-02 02:29:35 +00:00
if ( ZSTD_isError ( ret ) )
return ZSTD_errorFrameSizeInfo ( ret ) ;
if ( ret > 0 )
return ZSTD_errorFrameSizeInfo ( ERROR ( srcSize_wrong ) ) ;
2017-02-10 19:38:57 +00:00
}
2017-02-07 21:50:09 +00:00
2017-07-07 22:51:24 +00:00
ip + = zfh . headerSize ;
remainingSize - = zfh . headerSize ;
2017-02-07 21:50:09 +00:00
2019-03-01 06:55:18 +00:00
/* Iterate over each block */
2017-02-10 19:38:57 +00:00
while ( 1 ) {
blockProperties_t blockProperties ;
size_t const cBlockSize = ZSTD_getcBlockSize ( ip , remainingSize , & blockProperties ) ;
2019-03-02 02:29:35 +00:00
if ( ZSTD_isError ( cBlockSize ) )
return ZSTD_errorFrameSizeInfo ( cBlockSize ) ;
2017-02-07 21:50:09 +00:00
2019-03-02 02:29:35 +00:00
if ( ZSTD_blockHeaderSize + cBlockSize > remainingSize )
return ZSTD_errorFrameSizeInfo ( ERROR ( srcSize_wrong ) ) ;
2017-02-07 21:50:09 +00:00
2017-02-10 19:38:57 +00:00
ip + = ZSTD_blockHeaderSize + cBlockSize ;
remainingSize - = ZSTD_blockHeaderSize + cBlockSize ;
2019-02-28 08:42:49 +00:00
nbBlocks + + ;
2017-02-07 21:50:09 +00:00
2017-02-10 19:38:57 +00:00
if ( blockProperties . lastBlock ) break ;
}
2017-02-07 21:50:09 +00:00
2019-03-01 06:55:18 +00:00
/* Final frame content checksum */
if ( zfh . checksumFlag ) {
2019-03-02 02:29:35 +00:00
if ( remainingSize < 4 )
return ZSTD_errorFrameSizeInfo ( ERROR ( srcSize_wrong ) ) ;
2017-02-10 19:38:57 +00:00
ip + = 4 ;
}
2017-02-07 21:50:09 +00:00
2019-03-01 06:55:18 +00:00
frameSizeInfo . compressedSize = ip - ipstart ;
frameSizeInfo . decompressedBound = ( zfh . frameContentSize ! = ZSTD_CONTENTSIZE_UNKNOWN )
? zfh . frameContentSize
: nbBlocks * zfh . blockSizeMax ;
return frameSizeInfo ;
2017-02-10 19:38:57 +00:00
}
2017-02-07 21:50:09 +00:00
}
2016-06-06 17:52:35 +00:00
2019-02-28 08:42:49 +00:00
/** 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 )
{
2019-03-02 02:29:35 +00:00
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo ( src , srcSize ) ;
2019-03-01 06:55:18 +00:00
return frameSizeInfo . compressedSize ;
2019-02-28 08:42:49 +00:00
}
/** ZSTD_decompressBound() :
2019-03-19 03:33:15 +00:00
* compatible with legacy mode
2019-02-28 08:42:49 +00:00
* ` src ` must point to the start of a ZSTD frame or a skippeable frame
* ` srcSize ` must be at least as large as the frame contained
2019-03-01 08:03:50 +00:00
* @ return : the maximum decompressed size of the compressed source
2019-02-28 08:42:49 +00:00
*/
2019-03-01 08:03:50 +00:00
unsigned long long ZSTD_decompressBound ( const void * src , size_t srcSize )
2019-02-28 08:42:49 +00:00
{
2019-03-01 08:03:50 +00:00
unsigned long long bound = 0 ;
2019-03-01 06:55:18 +00:00
/* Iterate over each frame */
while ( srcSize > 0 ) {
2019-03-02 02:29:35 +00:00
ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo ( src , srcSize ) ;
size_t const compressedSize = frameSizeInfo . compressedSize ;
unsigned long long const decompressedBound = frameSizeInfo . decompressedBound ;
2019-03-02 07:11:15 +00:00
if ( ZSTD_isError ( compressedSize ) | | decompressedBound = = ZSTD_CONTENTSIZE_ERROR )
2019-03-01 08:03:50 +00:00
return ZSTD_CONTENTSIZE_ERROR ;
2019-04-17 18:14:49 +00:00
assert ( srcSize > = compressedSize ) ;
2019-03-01 06:55:18 +00:00
src = ( const BYTE * ) src + compressedSize ;
srcSize - = compressedSize ;
bound + = decompressedBound ;
}
return bound ;
2019-02-28 08:42:49 +00:00
}
2018-10-25 23:28:41 +00:00
/*-*************************************************************
* Frame decoding
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/** ZSTD_insertBlock() :
2019-08-03 14:43:34 +00:00
* insert ` src ` block into ` dctx ` history . Useful to track uncompressed blocks . */
2018-10-25 23:28:41 +00:00
size_t ZSTD_insertBlock ( ZSTD_DCtx * dctx , const void * blockStart , size_t blockSize )
{
2019-08-03 14:43:34 +00:00
DEBUGLOG ( 5 , " ZSTD_insertBlock: %u bytes " , ( unsigned ) blockSize ) ;
2018-10-25 23:28:41 +00:00
ZSTD_checkContinuity ( dctx , blockStart ) ;
dctx - > previousDstEnd = ( const char * ) blockStart + blockSize ;
return blockSize ;
}
static size_t ZSTD_copyRawBlock ( void * dst , size_t dstCapacity ,
const void * src , size_t srcSize )
{
2018-10-26 22:00:00 +00:00
DEBUGLOG ( 5 , " ZSTD_copyRawBlock " ) ;
2020-08-15 19:32:57 +00:00
RETURN_ERROR_IF ( srcSize > dstCapacity , dstSize_tooSmall , " " ) ;
2018-10-29 20:57:37 +00:00
if ( dst = = NULL ) {
if ( srcSize = = 0 ) return 0 ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR ( dstBuffer_null , " " ) ;
2018-10-29 20:57:37 +00:00
}
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( dst , src , srcSize ) ;
2018-10-25 23:28:41 +00:00
return srcSize ;
}
static size_t ZSTD_setRleBlock ( void * dst , size_t dstCapacity ,
BYTE b ,
size_t regenSize )
{
2020-08-15 19:32:57 +00:00
RETURN_ERROR_IF ( regenSize > dstCapacity , dstSize_tooSmall , " " ) ;
2018-10-29 22:03:57 +00:00
if ( dst = = NULL ) {
if ( regenSize = = 0 ) return 0 ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR ( dstBuffer_null , " " ) ;
2018-10-29 22:03:57 +00:00
}
2020-08-10 19:46:38 +00:00
ZSTD_memset ( dst , b , regenSize ) ;
2018-10-25 23:28:41 +00:00
return regenSize ;
}
2016-05-06 14:43:23 +00:00
/*! ZSTD_decompressFrame() :
2018-10-24 23:34:35 +00:00
* @ dctx must be properly initialized
* will update * srcPtr and * srcSizePtr ,
* to make * srcPtr progress by one frame . */
2016-03-11 20:58:04 +00:00
static size_t ZSTD_decompressFrame ( ZSTD_DCtx * dctx ,
2017-07-06 01:10:07 +00:00
void * dst , size_t dstCapacity ,
const void * * srcPtr , size_t * srcSizePtr )
2015-11-11 12:43:58 +00:00
{
2017-02-08 00:16:55 +00:00
const BYTE * ip = ( const BYTE * ) ( * srcPtr ) ;
2015-11-11 12:43:58 +00:00
BYTE * const ostart = ( BYTE * const ) dst ;
2019-11-21 02:21:51 +00:00
BYTE * const oend = dstCapacity ! = 0 ? ostart + dstCapacity : ostart ;
2016-06-03 13:41:51 +00:00
BYTE * op = ostart ;
2018-10-24 23:34:35 +00:00
size_t remainingSrcSize = * srcSizePtr ;
DEBUGLOG ( 4 , " ZSTD_decompressFrame (srcSize:%i) " , ( int ) * srcSizePtr ) ;
2015-11-11 12:43:58 +00:00
2016-03-19 13:14:31 +00:00
/* check */
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF (
2019-10-22 02:42:14 +00:00
remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN ( dctx - > format ) + ZSTD_blockHeaderSize ,
2020-04-30 16:24:56 +00:00
srcSize_wrong , " " ) ;
2016-03-19 13:14:31 +00:00
/* Frame Header */
2019-10-22 02:42:14 +00:00
{ size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal (
ip , ZSTD_FRAMEHEADERSIZE_PREFIX ( dctx - > format ) , dctx - > format ) ;
2015-11-25 13:42:45 +00:00
if ( ZSTD_isError ( frameHeaderSize ) ) return frameHeaderSize ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( remainingSrcSize < frameHeaderSize + ZSTD_blockHeaderSize ,
2020-04-30 16:24:56 +00:00
srcSize_wrong , " " ) ;
FORWARD_IF_ERROR ( ZSTD_decodeFrameHeader ( dctx , ip , frameHeaderSize ) , " " ) ;
2018-10-24 23:34:35 +00:00
ip + = frameHeaderSize ; remainingSrcSize - = frameHeaderSize ;
2015-11-25 13:42:45 +00:00
}
2015-11-11 12:43:58 +00:00
/* Loop on each block */
2016-03-19 13:14:31 +00:00
while ( 1 ) {
2016-06-10 22:23:43 +00:00
size_t decodedSize ;
2016-06-03 13:41:51 +00:00
blockProperties_t blockProperties ;
2018-10-24 23:34:35 +00:00
size_t const cBlockSize = ZSTD_getcBlockSize ( ip , remainingSrcSize , & blockProperties ) ;
2015-11-11 12:43:58 +00:00
if ( ZSTD_isError ( cBlockSize ) ) return cBlockSize ;
ip + = ZSTD_blockHeaderSize ;
2018-10-24 23:34:35 +00:00
remainingSrcSize - = ZSTD_blockHeaderSize ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( cBlockSize > remainingSrcSize , srcSize_wrong , " " ) ;
2015-11-11 12:43:58 +00:00
switch ( blockProperties . blockType )
{
case bt_compressed :
2017-09-16 00:22:38 +00:00
decodedSize = ZSTD_decompressBlock_internal ( dctx , op , oend - op , ip , cBlockSize , /* frame */ 1 ) ;
2015-11-11 12:43:58 +00:00
break ;
case bt_raw :
2015-11-12 15:19:30 +00:00
decodedSize = ZSTD_copyRawBlock ( op , oend - op , ip , cBlockSize ) ;
2015-11-11 12:43:58 +00:00
break ;
case bt_rle :
2018-10-25 23:28:41 +00:00
decodedSize = ZSTD_setRleBlock ( op , oend - op , * ip , blockProperties . origSize ) ;
2015-11-11 12:43:58 +00:00
break ;
2016-07-27 22:55:43 +00:00
case bt_reserved :
2015-11-11 12:43:58 +00:00
default :
2020-04-30 16:24:56 +00:00
RETURN_ERROR ( corruption_detected , " invalid block type " ) ;
2015-11-11 12:43:58 +00:00
}
if ( ZSTD_isError ( decodedSize ) ) return decodedSize ;
2020-08-24 21:28:00 +00:00
if ( dctx - > validateChecksum )
2017-07-06 01:10:07 +00:00
XXH64_update ( & dctx - > xxhState , op , decodedSize ) ;
2019-11-21 02:21:51 +00:00
if ( decodedSize ! = 0 )
op + = decodedSize ;
assert ( ip ! = NULL ) ;
2015-11-11 12:43:58 +00:00
ip + = cBlockSize ;
2018-10-24 23:34:35 +00:00
remainingSrcSize - = cBlockSize ;
2016-07-27 22:55:43 +00:00
if ( blockProperties . lastBlock ) break ;
2015-11-11 12:43:58 +00:00
}
2017-09-21 23:21:10 +00:00
if ( dctx - > fParams . frameContentSize ! = ZSTD_CONTENTSIZE_UNKNOWN ) {
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( ( U64 ) ( op - ostart ) ! = dctx - > fParams . frameContentSize ,
2020-04-30 16:24:56 +00:00
corruption_detected , " " ) ;
2019-01-28 17:22:52 +00:00
}
2017-07-06 01:10:07 +00:00
if ( dctx - > fParams . checksumFlag ) { /* Frame content checksum verification */
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( remainingSrcSize < 4 , checksum_wrong , " " ) ;
2020-08-22 17:26:33 +00:00
if ( ! dctx - > forceIgnoreChecksum ) {
U32 const checkCalc = ( U32 ) XXH64_digest ( & dctx - > xxhState ) ;
U32 checkRead ;
checkRead = MEM_readLE32 ( ip ) ;
RETURN_ERROR_IF ( checkRead ! = checkCalc , checksum_wrong , " " ) ;
}
2017-02-08 00:16:55 +00:00
ip + = 4 ;
2018-10-24 23:34:35 +00:00
remainingSrcSize - = 4 ;
2016-07-27 22:55:43 +00:00
}
2017-02-28 09:15:28 +00:00
/* Allow caller to get size read */
2017-02-08 00:16:55 +00:00
* srcPtr = ip ;
2018-10-24 23:34:35 +00:00
* srcSizePtr = remainingSrcSize ;
2015-11-11 12:43:58 +00:00
return op - ostart ;
}
2017-02-08 00:16:55 +00:00
static size_t ZSTD_decompressMultiFrame ( ZSTD_DCtx * dctx ,
void * dst , size_t dstCapacity ,
const void * src , size_t srcSize ,
2017-07-06 01:10:07 +00:00
const void * dict , size_t dictSize ,
2017-02-26 22:43:07 +00:00
const ZSTD_DDict * ddict )
2017-02-08 00:16:55 +00:00
{
void * const dststart = dst ;
decompress: changed error code when input is too large
ZSTD_decompress() can decompress multiple frames sent as a single input.
But the input size must be the exact sum of all compressed frames, no more.
In the case of a mistake on srcSize, being larger than required,
ZSTD_decompress() will try to decompress a new frame after current one, and fail.
As a consequence, it will issue an error code, ERROR(prefix_unknown).
While the error is technically correct
(the decoder could not recognise the header of _next_ frame),
it's confusing, as users will believe that the first header of the first frame is wrong,
which is not the case (it's correct).
It makes it more difficult to understand that the error is in the source size, which is too large.
This patch changes the error code provided in such a scenario.
If (at least) a first frame was successfully decoded,
and then following bytes are garbage values,
the decoder assumes the provided input size is wrong (too large),
and issue the error code ERROR(srcSize_wrong).
2018-05-14 22:32:28 +00:00
int moreThan1Frame = 0 ;
2018-09-12 22:35:21 +00:00
DEBUGLOG ( 5 , " ZSTD_decompressMultiFrame " ) ;
2017-07-06 01:10:07 +00:00
assert ( dict = = NULL | | ddict = = NULL ) ; /* either dict or ddict set, not both */
2017-02-28 23:28:29 +00:00
if ( ddict ) {
2018-10-24 00:25:49 +00:00
dict = ZSTD_DDict_dictContent ( ddict ) ;
dictSize = ZSTD_DDict_dictSize ( ddict ) ;
2017-02-28 23:28:29 +00:00
}
2019-10-22 02:42:14 +00:00
while ( srcSize > = ZSTD_startingInputLength ( dctx - > format ) ) {
2017-02-08 00:16:55 +00:00
# if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
if ( ZSTD_isLegacy ( src , srcSize ) ) {
size_t decodedSize ;
2017-02-25 18:11:15 +00:00
size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy ( src , srcSize ) ;
2017-02-08 00:16:55 +00:00
if ( ZSTD_isError ( frameSize ) ) return frameSize ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( dctx - > staticSize , memory_allocation ,
" legacy support is not compatible with static dctx " ) ;
2017-02-08 00:16:55 +00:00
decodedSize = ZSTD_decompressLegacy ( dst , dstCapacity , src , frameSize , dict , dictSize ) ;
2018-10-24 23:34:35 +00:00
if ( ZSTD_isError ( decodedSize ) ) return decodedSize ;
2017-02-08 00:16:55 +00:00
2018-10-24 23:34:35 +00:00
assert ( decodedSize < = - dstCapacity ) ;
2017-02-08 00:16:55 +00:00
dst = ( BYTE * ) dst + decodedSize ;
dstCapacity - = decodedSize ;
src = ( const BYTE * ) src + frameSize ;
srcSize - = frameSize ;
continue ;
}
# endif
decompress: changed error code when input is too large
ZSTD_decompress() can decompress multiple frames sent as a single input.
But the input size must be the exact sum of all compressed frames, no more.
In the case of a mistake on srcSize, being larger than required,
ZSTD_decompress() will try to decompress a new frame after current one, and fail.
As a consequence, it will issue an error code, ERROR(prefix_unknown).
While the error is technically correct
(the decoder could not recognise the header of _next_ frame),
it's confusing, as users will believe that the first header of the first frame is wrong,
which is not the case (it's correct).
It makes it more difficult to understand that the error is in the source size, which is too large.
This patch changes the error code provided in such a scenario.
If (at least) a first frame was successfully decoded,
and then following bytes are garbage values,
the decoder assumes the provided input size is wrong (too large),
and issue the error code ERROR(srcSize_wrong).
2018-05-14 22:32:28 +00:00
{ U32 const magicNumber = MEM_readLE32 ( src ) ;
DEBUGLOG ( 4 , " reading magic number %08X (expecting %08X) " ,
fix confusion between unsigned <-> U32
as suggested in #1441.
generally U32 and unsigned are the same thing,
except when they are not ...
case : 32-bit compilation for MIPS (uint32_t == unsigned long)
A vast majority of transformation consists in transforming U32 into unsigned.
In rare cases, it's the other way around (typically for internal code, such as seeds).
Among a few issues this patches solves :
- some parameters were declared with type `unsigned` in *.h,
but with type `U32` in their implementation *.c .
- some parameters have type unsigned*,
but the caller user a pointer to U32 instead.
These fixes are useful.
However, the bulk of changes is about %u formating,
which requires unsigned type,
but generally receives U32 values instead,
often just for brevity (U32 is shorter than unsigned).
These changes are generally minor, or even annoying.
As a consequence, the amount of code changed is larger than I would expect for such a patch.
Testing is also a pain :
it requires manually modifying `mem.h`,
in order to lie about `U32`
and force it to be an `unsigned long` typically.
On a 64-bit system, this will break the equivalence unsigned == U32.
Unfortunately, it will also break a few static_assert(), controlling structure sizes.
So it also requires modifying `debug.h` to make `static_assert()` a noop.
And then reverting these changes.
So it's inconvenient, and as a consequence,
this property is currently not checked during CI tests.
Therefore, these problems can emerge again in the future.
I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests.
It's another restriction for coding, adding more frustration during merge tests,
since most platforms don't need this distinction (hence contributor will not see it),
and while this can matter in theory, the number of platforms impacted seems minimal.
Thoughts ?
2018-12-22 00:19:44 +00:00
( unsigned ) magicNumber , ZSTD_MAGICNUMBER ) ;
2018-11-14 01:36:35 +00:00
if ( ( magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK ) = = ZSTD_MAGIC_SKIPPABLE_START ) {
2018-12-12 23:26:35 +00:00
size_t const skippableSize = readSkippableFrameSize ( src , srcSize ) ;
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( skippableSize , " readSkippableFrameSize failed " ) ;
2019-04-17 18:41:55 +00:00
assert ( skippableSize < = srcSize ) ;
2017-02-08 00:16:55 +00:00
src = ( const BYTE * ) src + skippableSize ;
srcSize - = skippableSize ;
continue ;
decompress: changed error code when input is too large
ZSTD_decompress() can decompress multiple frames sent as a single input.
But the input size must be the exact sum of all compressed frames, no more.
In the case of a mistake on srcSize, being larger than required,
ZSTD_decompress() will try to decompress a new frame after current one, and fail.
As a consequence, it will issue an error code, ERROR(prefix_unknown).
While the error is technically correct
(the decoder could not recognise the header of _next_ frame),
it's confusing, as users will believe that the first header of the first frame is wrong,
which is not the case (it's correct).
It makes it more difficult to understand that the error is in the source size, which is too large.
This patch changes the error code provided in such a scenario.
If (at least) a first frame was successfully decoded,
and then following bytes are garbage values,
the decoder assumes the provided input size is wrong (too large),
and issue the error code ERROR(srcSize_wrong).
2018-05-14 22:32:28 +00:00
} }
2017-02-08 00:16:55 +00:00
2017-02-26 22:43:07 +00:00
if ( ddict ) {
2017-02-08 00:16:55 +00:00
/* we were called from ZSTD_decompress_usingDDict */
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decompressBegin_usingDDict ( dctx , ddict ) , " " ) ;
2017-02-08 00:16:55 +00:00
} else {
/* this will initialize correctly with no dict if dict == NULL, so
* use this in all cases but ddict */
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decompressBegin_usingDict ( dctx , dict , dictSize ) , " " ) ;
2017-02-08 00:16:55 +00:00
}
ZSTD_checkContinuity ( dctx , dst ) ;
2017-02-25 18:11:15 +00:00
{ const size_t res = ZSTD_decompressFrame ( dctx , dst , dstCapacity ,
2017-02-08 00:16:55 +00:00
& src , & srcSize ) ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF (
( ZSTD_getErrorCode ( res ) = = ZSTD_error_prefix_unknown )
& & ( moreThan1Frame = = 1 ) ,
srcSize_wrong ,
" at least one frame successfully completed, but following "
" bytes are garbage: it's more likely to be a srcSize error, "
" specifying more bytes than compressed size of frame(s). This "
" error message replaces ERROR(prefix_unknown), which would be "
" confusing, as the first header is actually correct. Note that "
" one could be unlucky, it might be a corruption error instead, "
" happening right at the place where we expect zstd magic "
" bytes. But this is _much_ less likely than a srcSize field "
" error. " ) ;
2017-02-08 00:16:55 +00:00
if ( ZSTD_isError ( res ) ) return res ;
2018-10-24 23:34:35 +00:00
assert ( res < = dstCapacity ) ;
2019-11-21 02:21:51 +00:00
if ( res ! = 0 )
dst = ( BYTE * ) dst + res ;
2017-02-08 00:16:55 +00:00
dstCapacity - = res ;
}
decompress: changed error code when input is too large
ZSTD_decompress() can decompress multiple frames sent as a single input.
But the input size must be the exact sum of all compressed frames, no more.
In the case of a mistake on srcSize, being larger than required,
ZSTD_decompress() will try to decompress a new frame after current one, and fail.
As a consequence, it will issue an error code, ERROR(prefix_unknown).
While the error is technically correct
(the decoder could not recognise the header of _next_ frame),
it's confusing, as users will believe that the first header of the first frame is wrong,
which is not the case (it's correct).
It makes it more difficult to understand that the error is in the source size, which is too large.
This patch changes the error code provided in such a scenario.
If (at least) a first frame was successfully decoded,
and then following bytes are garbage values,
the decoder assumes the provided input size is wrong (too large),
and issue the error code ERROR(srcSize_wrong).
2018-05-14 22:32:28 +00:00
moreThan1Frame = 1 ;
2017-07-06 01:10:07 +00:00
} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
2017-02-08 00:16:55 +00:00
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( srcSize , srcSize_wrong , " input not entirely consumed " ) ;
2017-02-08 00:16:55 +00:00
return ( BYTE * ) dst - ( BYTE * ) dststart ;
}
2015-12-18 00:26:48 +00:00
2016-01-26 14:58:49 +00:00
size_t ZSTD_decompress_usingDict ( ZSTD_DCtx * dctx ,
2016-03-19 13:14:31 +00:00
void * dst , size_t dstCapacity ,
2016-09-13 14:52:16 +00:00
const void * src , size_t srcSize ,
const void * dict , size_t dictSize )
2016-01-26 14:58:49 +00:00
{
2017-02-08 00:16:55 +00:00
return ZSTD_decompressMultiFrame ( dctx , dst , dstCapacity , src , srcSize , dict , dictSize , NULL ) ;
2016-01-26 14:58:49 +00:00
}
2019-04-10 19:34:21 +00:00
static ZSTD_DDict const * ZSTD_getDDict ( ZSTD_DCtx * dctx )
{
2019-04-10 23:50:35 +00:00
switch ( dctx - > dictUses ) {
default :
assert ( 0 /* Impossible */ ) ;
/* fall-through */
case ZSTD_dont_use :
2019-04-10 19:34:21 +00:00
ZSTD_clearDict ( dctx ) ;
return NULL ;
2019-04-10 23:50:35 +00:00
case ZSTD_use_indefinitely :
return dctx - > ddict ;
case ZSTD_use_once :
dctx - > dictUses = ZSTD_dont_use ;
2019-04-10 19:34:21 +00:00
return dctx - > ddict ;
}
}
2016-03-19 13:14:31 +00:00
size_t ZSTD_decompressDCtx ( ZSTD_DCtx * dctx , void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2015-12-18 00:26:48 +00:00
{
2019-04-10 19:34:21 +00:00
return ZSTD_decompress_usingDDict ( dctx , dst , dstCapacity , src , srcSize , ZSTD_getDDict ( dctx ) ) ;
2015-12-18 00:26:48 +00:00
}
2016-03-11 20:58:04 +00:00
2016-03-19 13:14:31 +00:00
size_t ZSTD_decompress ( void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2015-11-11 12:43:58 +00:00
{
2017-06-03 00:10:49 +00:00
# if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
2016-01-11 11:56:11 +00:00
size_t regenSize ;
2016-06-03 13:41:51 +00:00
ZSTD_DCtx * const dctx = ZSTD_createDCtx ( ) ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dctx = = NULL , memory_allocation , " NULL pointer! " ) ;
2016-03-19 13:14:31 +00:00
regenSize = ZSTD_decompressDCtx ( dctx , dst , dstCapacity , src , srcSize ) ;
2016-01-11 11:56:11 +00:00
ZSTD_freeDCtx ( dctx ) ;
return regenSize ;
2016-05-06 14:43:23 +00:00
# else /* stack mode */
2015-12-18 00:26:48 +00:00
ZSTD_DCtx dctx ;
2018-06-14 14:22:24 +00:00
ZSTD_initDCtx_internal ( & dctx ) ;
2016-03-19 13:14:31 +00:00
return ZSTD_decompressDCtx ( & dctx , dst , dstCapacity , src , srcSize ) ;
2016-01-21 15:04:35 +00:00
# endif
2015-11-11 12:43:58 +00:00
}
2016-08-22 22:30:31 +00:00
/*-**************************************
* Advanced Streaming Decompression API
* Bufferless and synchronous
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-07-28 17:55:09 +00:00
size_t ZSTD_nextSrcSizeToDecompress ( ZSTD_DCtx * dctx ) { return dctx - > expected ; }
2015-11-11 12:43:58 +00:00
2020-01-11 02:02:11 +00:00
/**
* Similar to ZSTD_nextSrcSizeToDecompress ( ) , but when when a block input can be streamed ,
* we allow taking a partial block as the input . Currently only raw uncompressed blocks can
* be streamed .
*
* For blocks that can be streamed , this allows us to reduce the latency until we produce
* output , and avoid copying the input .
*
* @ param inputSize - The total amount of input that the caller currently has .
*/
static size_t ZSTD_nextSrcSizeToDecompressWithInputSize ( ZSTD_DCtx * dctx , size_t inputSize ) {
if ( ! ( dctx - > stage = = ZSTDds_decompressBlock | | dctx - > stage = = ZSTDds_decompressLastBlock ) )
return dctx - > expected ;
if ( dctx - > bType ! = bt_raw )
return dctx - > expected ;
return MIN ( MAX ( inputSize , 1 ) , dctx - > expected ) ;
}
2016-07-28 18:30:25 +00:00
ZSTD_nextInputType_e ZSTD_nextInputType ( ZSTD_DCtx * dctx ) {
switch ( dctx - > stage )
{
default : /* should not happen */
2017-07-03 19:31:55 +00:00
assert ( 0 ) ;
2016-07-28 18:30:25 +00:00
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 ;
}
}
2017-06-20 23:09:11 +00:00
static int ZSTD_isSkipFrame ( ZSTD_DCtx * dctx ) { return dctx - > stage = = ZSTDds_skipFrame ; }
2016-05-31 10:43:46 +00:00
2016-05-31 16:13:56 +00:00
/** ZSTD_decompressContinue() :
2017-06-20 23:09:11 +00:00
* srcSize : must be the exact nb of bytes expected ( see ZSTD_nextSrcSizeToDecompress ( ) )
* @ return : nb of bytes generated into ` dst ` ( necessarily < = ` dstCapacity )
* or an error code , which can be tested using ZSTD_isError ( ) */
2016-05-10 12:14:19 +00:00
size_t ZSTD_decompressContinue ( ZSTD_DCtx * dctx , void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2015-11-11 12:43:58 +00:00
{
fix confusion between unsigned <-> U32
as suggested in #1441.
generally U32 and unsigned are the same thing,
except when they are not ...
case : 32-bit compilation for MIPS (uint32_t == unsigned long)
A vast majority of transformation consists in transforming U32 into unsigned.
In rare cases, it's the other way around (typically for internal code, such as seeds).
Among a few issues this patches solves :
- some parameters were declared with type `unsigned` in *.h,
but with type `U32` in their implementation *.c .
- some parameters have type unsigned*,
but the caller user a pointer to U32 instead.
These fixes are useful.
However, the bulk of changes is about %u formating,
which requires unsigned type,
but generally receives U32 values instead,
often just for brevity (U32 is shorter than unsigned).
These changes are generally minor, or even annoying.
As a consequence, the amount of code changed is larger than I would expect for such a patch.
Testing is also a pain :
it requires manually modifying `mem.h`,
in order to lie about `U32`
and force it to be an `unsigned long` typically.
On a 64-bit system, this will break the equivalence unsigned == U32.
Unfortunately, it will also break a few static_assert(), controlling structure sizes.
So it also requires modifying `debug.h` to make `static_assert()` a noop.
And then reverting these changes.
So it's inconvenient, and as a consequence,
this property is currently not checked during CI tests.
Therefore, these problems can emerge again in the future.
I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests.
It's another restriction for coding, adding more frustration during merge tests,
since most platforms don't need this distinction (hence contributor will not see it),
and while this can matter in theory, the number of platforms impacted seems minimal.
Thoughts ?
2018-12-22 00:19:44 +00:00
DEBUGLOG ( 5 , " ZSTD_decompressContinue (srcSize:%u) " , ( unsigned ) srcSize ) ;
2015-11-11 12:43:58 +00:00
/* Sanity check */
2020-01-11 02:02:11 +00:00
RETURN_ERROR_IF ( srcSize ! = ZSTD_nextSrcSizeToDecompressWithInputSize ( dctx , srcSize ) , srcSize_wrong , " not allowed " ) ;
2016-05-10 12:14:19 +00:00
if ( dstCapacity ) ZSTD_checkContinuity ( dctx , dst ) ;
2015-11-11 12:43:58 +00:00
2016-01-25 15:54:05 +00:00
switch ( dctx - > stage )
2015-11-11 12:43:58 +00:00
{
2015-11-25 13:42:45 +00:00
case ZSTDds_getFrameHeaderSize :
2017-07-03 19:31:55 +00:00
assert ( src ! = NULL ) ;
2017-09-25 22:12:09 +00:00
if ( dctx - > format = = ZSTD_f_zstd1 ) { /* allows header */
2018-08-14 19:56:21 +00:00
assert ( srcSize > = ZSTD_FRAMEIDSIZE ) ; /* to read skippable magic number */
2018-11-14 01:36:35 +00:00
if ( ( MEM_readLE32 ( src ) & ZSTD_MAGIC_SKIPPABLE_MASK ) = = ZSTD_MAGIC_SKIPPABLE_START ) { /* skippable frame */
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( dctx - > headerBuffer , src , srcSize ) ;
2018-11-14 00:56:32 +00:00
dctx - > expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize ; /* remaining to load to get full skippable frame header */
2017-09-25 22:12:09 +00:00
dctx - > stage = ZSTDds_decodeSkippableHeader ;
return 0 ;
} }
dctx - > headerSize = ZSTD_frameHeaderSize_internal ( src , srcSize , dctx - > format ) ;
2016-05-10 12:14:19 +00:00
if ( ZSTD_isError ( dctx - > headerSize ) ) return dctx - > headerSize ;
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( dctx - > headerBuffer , src , srcSize ) ;
2017-09-25 22:12:09 +00:00
dctx - > expected = dctx - > headerSize - srcSize ;
dctx - > stage = ZSTDds_decodeFrameHeader ;
return 0 ;
2015-11-25 13:42:45 +00:00
case ZSTDds_decodeFrameHeader :
2017-07-03 19:31:55 +00:00
assert ( src ! = NULL ) ;
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( dctx - > headerBuffer + ( dctx - > headerSize - srcSize ) , src , srcSize ) ;
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decodeFrameHeader ( dctx , dctx - > headerBuffer , dctx - > headerSize ) , " " ) ;
2016-09-06 13:36:19 +00:00
dctx - > expected = ZSTD_blockHeaderSize ;
dctx - > stage = ZSTDds_decodeBlockHeader ;
return 0 ;
2015-11-25 13:42:45 +00:00
case ZSTDds_decodeBlockHeader :
2016-05-10 12:14:19 +00:00
{ blockProperties_t bp ;
2016-03-24 00:27:55 +00:00
size_t const cBlockSize = ZSTD_getcBlockSize ( src , ZSTD_blockHeaderSize , & bp ) ;
if ( ZSTD_isError ( cBlockSize ) ) return cBlockSize ;
2019-07-17 19:53:15 +00:00
RETURN_ERROR_IF ( cBlockSize > dctx - > fParams . blockSizeMax , corruption_detected , " Block Size Exceeds Maximum " ) ;
2016-07-27 22:55:43 +00:00
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 ) {
2016-05-31 22:18:28 +00:00
if ( dctx - > fParams . checksumFlag ) {
2016-07-27 22:55:43 +00:00
dctx - > expected = 4 ;
dctx - > stage = ZSTDds_checkChecksum ;
} else {
dctx - > expected = 0 ; /* end of frame */
dctx - > stage = ZSTDds_getFrameHeaderSize ;
2016-05-31 22:18:28 +00:00
}
2016-03-24 00:27:55 +00:00
} else {
2017-06-20 23:09:11 +00:00
dctx - > expected = ZSTD_blockHeaderSize ; /* jump to next header */
2016-07-27 22:55:43 +00:00
dctx - > stage = ZSTDds_decodeBlockHeader ;
2015-11-25 13:42:45 +00:00
}
return 0 ;
}
2017-09-25 22:12:09 +00:00
2016-07-27 22:55:43 +00:00
case ZSTDds_decompressLastBlock :
2015-12-04 16:16:37 +00:00
case ZSTDds_decompressBlock :
2018-01-16 23:28:43 +00:00
DEBUGLOG ( 5 , " ZSTD_decompressContinue: case ZSTDds_decompressBlock " ) ;
2016-05-10 12:14:19 +00:00
{ size_t rSize ;
2016-01-25 15:54:05 +00:00
switch ( dctx - > bType )
2015-11-25 13:42:45 +00:00
{
case bt_compressed :
2018-01-16 23:28:43 +00:00
DEBUGLOG ( 5 , " ZSTD_decompressContinue: case bt_compressed " ) ;
2017-09-16 00:22:38 +00:00
rSize = ZSTD_decompressBlock_internal ( dctx , dst , dstCapacity , src , srcSize , /* frame */ 1 ) ;
2020-01-11 02:02:11 +00:00
dctx - > expected = 0 ; /* Streaming not supported */
2015-11-25 13:42:45 +00:00
break ;
case bt_raw :
2020-01-11 02:02:11 +00:00
assert ( srcSize < = dctx - > expected ) ;
2016-05-10 12:14:19 +00:00
rSize = ZSTD_copyRawBlock ( dst , dstCapacity , src , srcSize ) ;
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( rSize , " ZSTD_copyRawBlock failed " ) ;
2020-01-11 02:02:11 +00:00
assert ( rSize = = srcSize ) ;
dctx - > expected - = rSize ;
2015-11-25 13:42:45 +00:00
break ;
case bt_rle :
2018-10-25 23:28:41 +00:00
rSize = ZSTD_setRleBlock ( dst , dstCapacity , * ( const BYTE * ) src , dctx - > rleSize ) ;
2020-01-11 02:02:11 +00:00
dctx - > expected = 0 ; /* Streaming not supported */
2015-11-25 13:42:45 +00:00
break ;
2016-07-27 22:55:43 +00:00
case bt_reserved : /* should never happen */
2015-11-25 13:42:45 +00:00
default :
2020-04-30 16:24:56 +00:00
RETURN_ERROR ( corruption_detected , " invalid block type " ) ;
2015-11-25 13:42:45 +00:00
}
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( rSize , " " ) ;
2019-07-17 19:53:15 +00:00
RETURN_ERROR_IF ( rSize > dctx - > fParams . blockSizeMax , corruption_detected , " Decompressed Block Size Exceeds Maximum " ) ;
fix confusion between unsigned <-> U32
as suggested in #1441.
generally U32 and unsigned are the same thing,
except when they are not ...
case : 32-bit compilation for MIPS (uint32_t == unsigned long)
A vast majority of transformation consists in transforming U32 into unsigned.
In rare cases, it's the other way around (typically for internal code, such as seeds).
Among a few issues this patches solves :
- some parameters were declared with type `unsigned` in *.h,
but with type `U32` in their implementation *.c .
- some parameters have type unsigned*,
but the caller user a pointer to U32 instead.
These fixes are useful.
However, the bulk of changes is about %u formating,
which requires unsigned type,
but generally receives U32 values instead,
often just for brevity (U32 is shorter than unsigned).
These changes are generally minor, or even annoying.
As a consequence, the amount of code changed is larger than I would expect for such a patch.
Testing is also a pain :
it requires manually modifying `mem.h`,
in order to lie about `U32`
and force it to be an `unsigned long` typically.
On a 64-bit system, this will break the equivalence unsigned == U32.
Unfortunately, it will also break a few static_assert(), controlling structure sizes.
So it also requires modifying `debug.h` to make `static_assert()` a noop.
And then reverting these changes.
So it's inconvenient, and as a consequence,
this property is currently not checked during CI tests.
Therefore, these problems can emerge again in the future.
I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests.
It's another restriction for coding, adding more frustration during merge tests,
since most platforms don't need this distinction (hence contributor will not see it),
and while this can matter in theory, the number of platforms impacted seems minimal.
Thoughts ?
2018-12-22 00:19:44 +00:00
DEBUGLOG ( 5 , " ZSTD_decompressContinue: decoded size from block : %u " , ( unsigned ) rSize ) ;
2017-09-09 21:37:28 +00:00
dctx - > decodedSize + = rSize ;
2020-08-24 21:28:00 +00:00
if ( dctx - > validateChecksum ) XXH64_update ( & dctx - > xxhState , dst , rSize ) ;
2020-01-11 02:02:11 +00:00
dctx - > previousDstEnd = ( char * ) dst + rSize ;
/* Stay on the same stage until we are finished streaming the block. */
if ( dctx - > expected > 0 ) {
return rSize ;
}
2016-07-27 22:55:43 +00:00
if ( dctx - > stage = = ZSTDds_decompressLastBlock ) { /* end of frame */
fix confusion between unsigned <-> U32
as suggested in #1441.
generally U32 and unsigned are the same thing,
except when they are not ...
case : 32-bit compilation for MIPS (uint32_t == unsigned long)
A vast majority of transformation consists in transforming U32 into unsigned.
In rare cases, it's the other way around (typically for internal code, such as seeds).
Among a few issues this patches solves :
- some parameters were declared with type `unsigned` in *.h,
but with type `U32` in their implementation *.c .
- some parameters have type unsigned*,
but the caller user a pointer to U32 instead.
These fixes are useful.
However, the bulk of changes is about %u formating,
which requires unsigned type,
but generally receives U32 values instead,
often just for brevity (U32 is shorter than unsigned).
These changes are generally minor, or even annoying.
As a consequence, the amount of code changed is larger than I would expect for such a patch.
Testing is also a pain :
it requires manually modifying `mem.h`,
in order to lie about `U32`
and force it to be an `unsigned long` typically.
On a 64-bit system, this will break the equivalence unsigned == U32.
Unfortunately, it will also break a few static_assert(), controlling structure sizes.
So it also requires modifying `debug.h` to make `static_assert()` a noop.
And then reverting these changes.
So it's inconvenient, and as a consequence,
this property is currently not checked during CI tests.
Therefore, these problems can emerge again in the future.
I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests.
It's another restriction for coding, adding more frustration during merge tests,
since most platforms don't need this distinction (hence contributor will not see it),
and while this can matter in theory, the number of platforms impacted seems minimal.
Thoughts ?
2018-12-22 00:19:44 +00:00
DEBUGLOG ( 4 , " ZSTD_decompressContinue: decoded size from frame : %u " , ( unsigned ) dctx - > decodedSize ) ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF (
dctx - > fParams . frameContentSize ! = ZSTD_CONTENTSIZE_UNKNOWN
& & dctx - > decodedSize ! = dctx - > fParams . frameContentSize ,
2020-04-30 16:24:56 +00:00
corruption_detected , " " ) ;
2016-07-27 22:55:43 +00:00
if ( dctx - > fParams . checksumFlag ) { /* another round for frame checksum */
2016-07-28 17:55:09 +00:00
dctx - > expected = 4 ;
2016-07-27 22:55:43 +00:00
dctx - > stage = ZSTDds_checkChecksum ;
2016-07-28 17:55:09 +00:00
} else {
dctx - > expected = 0 ; /* ends here */
dctx - > stage = ZSTDds_getFrameHeaderSize ;
2016-07-27 22:55:43 +00:00
}
} else {
dctx - > stage = ZSTDds_decodeBlockHeader ;
dctx - > expected = ZSTD_blockHeaderSize ;
}
2015-11-25 13:42:45 +00:00
return rSize ;
2015-11-11 12:43:58 +00:00
}
2017-09-25 22:12:09 +00:00
2016-07-27 22:55:43 +00:00
case ZSTDds_checkChecksum :
2017-09-09 21:37:28 +00:00
assert ( srcSize = = 4 ) ; /* guaranteed by dctx->expected */
2020-08-22 20:05:40 +00:00
{
2020-08-24 21:28:00 +00:00
if ( dctx - > validateChecksum ) {
2020-08-22 20:05:40 +00:00
U32 const h32 = ( U32 ) XXH64_digest ( & dctx - > xxhState ) ;
U32 const check32 = MEM_readLE32 ( src ) ;
DEBUGLOG ( 4 , " ZSTD_decompressContinue: checksum : calculated %08X :: %08X read " , ( unsigned ) h32 , ( unsigned ) check32 ) ;
RETURN_ERROR_IF ( check32 ! = h32 , checksum_wrong , " " ) ;
}
2016-07-27 22:55:43 +00:00
dctx - > expected = 0 ;
dctx - > stage = ZSTDds_getFrameHeaderSize ;
return 0 ;
}
2017-09-25 22:12:09 +00:00
2016-05-31 10:43:46 +00:00
case ZSTDds_decodeSkippableHeader :
2017-09-25 22:25:07 +00:00
assert ( src ! = NULL ) ;
2018-11-14 00:56:32 +00:00
assert ( srcSize < = ZSTD_SKIPPABLEHEADERSIZE ) ;
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( dctx - > headerBuffer + ( ZSTD_SKIPPABLEHEADERSIZE - srcSize ) , src , srcSize ) ; /* complete skippable header */
2018-08-14 19:56:21 +00:00
dctx - > expected = MEM_readLE32 ( dctx - > headerBuffer + ZSTD_FRAMEIDSIZE ) ; /* note : dctx->expected can grow seriously large, beyond local buffer size */
2017-09-25 22:25:07 +00:00
dctx - > stage = ZSTDds_skipFrame ;
return 0 ;
2017-09-25 22:12:09 +00:00
2016-05-31 10:43:46 +00:00
case ZSTDds_skipFrame :
2017-09-25 22:25:07 +00:00
dctx - > expected = 0 ;
dctx - > stage = ZSTDds_getFrameHeaderSize ;
return 0 ;
2017-09-25 22:12:09 +00:00
2015-11-25 13:42:45 +00:00
default :
2018-10-29 22:03:57 +00:00
assert ( 0 ) ; /* impossible */
2020-04-30 16:24:56 +00:00
RETURN_ERROR ( GENERIC , " impossible to reach " ) ; /* some compiler require default to do something */
2015-11-11 12:43:58 +00:00
}
}
2016-06-19 21:06:54 +00:00
static size_t ZSTD_refDictContent ( ZSTD_DCtx * dctx , const void * dict , size_t dictSize )
2015-12-04 16:16:37 +00:00
{
2016-01-25 15:54:05 +00:00
dctx - > dictEnd = dctx - > previousDstEnd ;
2018-06-01 22:18:32 +00:00
dctx - > virtualStart = ( const char * ) dict - ( ( const char * ) ( dctx - > previousDstEnd ) - ( const char * ) ( dctx - > prefixStart ) ) ;
dctx - > prefixStart = dict ;
2016-01-25 15:54:05 +00:00
dctx - > previousDstEnd = ( const char * ) dict + dictSize ;
2020-05-12 02:05:42 +00:00
# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2020-05-12 21:33:59 +00:00
dctx - > dictContentBeginForFuzzing = dctx - > prefixStart ;
2020-05-12 02:05:42 +00:00
dctx - > dictContentEndForFuzzing = dctx - > previousDstEnd ;
# endif
2016-06-19 21:06:54 +00:00
return 0 ;
2015-12-04 16:16:37 +00:00
}
2016-01-26 02:14:20 +00:00
2018-10-24 00:25:49 +00:00
/*! ZSTD_loadDEntropy() :
2018-09-12 00:23:44 +00:00
* dict : must point at beginning of a valid zstd dictionary .
2017-02-25 18:11:15 +00:00
* @ return : size of entropy tables read */
2018-10-24 00:25:49 +00:00
size_t
ZSTD_loadDEntropy ( ZSTD_entropyDTables_t * entropy ,
const void * const dict , size_t const dictSize )
2016-01-26 02:14:20 +00:00
{
2016-06-15 12:05:07 +00:00
const BYTE * dictPtr = ( const BYTE * ) dict ;
2016-06-15 23:41:50 +00:00
const BYTE * const dictEnd = dictPtr + dictSize ;
2016-01-27 23:18:06 +00:00
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dictSize < = 8 , dictionary_corrupted , " dict is too small " ) ;
2018-09-07 00:54:13 +00:00
assert ( MEM_readLE32 ( dict ) = = ZSTD_MAGIC_DICTIONARY ) ; /* dict must be valid */
2017-02-25 18:11:15 +00:00
dictPtr + = 8 ; /* skip header = magic + dictID */
2018-09-12 00:23:44 +00:00
ZSTD_STATIC_ASSERT ( offsetof ( ZSTD_entropyDTables_t , OFTable ) = = offsetof ( ZSTD_entropyDTables_t , LLTable ) + sizeof ( entropy - > LLTable ) ) ;
ZSTD_STATIC_ASSERT ( offsetof ( ZSTD_entropyDTables_t , MLTable ) = = offsetof ( ZSTD_entropyDTables_t , OFTable ) + sizeof ( entropy - > OFTable ) ) ;
ZSTD_STATIC_ASSERT ( sizeof ( entropy - > LLTable ) + sizeof ( entropy - > OFTable ) + sizeof ( entropy - > MLTable ) > = HUF_DECOMPRESS_WORKSPACE_SIZE ) ;
{ void * const workspace = & entropy - > LLTable ; /* use fse tables as temporary workspace; implies fse tables are grouped together */
size_t const workspaceSize = sizeof ( entropy - > LLTable ) + sizeof ( entropy - > OFTable ) + sizeof ( entropy - > MLTable ) ;
2018-12-04 18:01:58 +00:00
# ifdef HUF_FORCE_DECOMPRESS_X1
2018-11-16 23:28:53 +00:00
/* in minimal huffman, we always use X1 variants */
size_t const hSize = HUF_readDTableX1_wksp ( entropy - > hufTable ,
dictPtr , dictEnd - dictPtr ,
workspace , workspaceSize ) ;
# else
2018-09-07 00:07:53 +00:00
size_t const hSize = HUF_readDTableX2_wksp ( entropy - > hufTable ,
dictPtr , dictEnd - dictPtr ,
workspace , workspaceSize ) ;
2018-11-16 23:28:53 +00:00
# endif
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( HUF_isError ( hSize ) , dictionary_corrupted , " " ) ;
2016-06-15 12:05:07 +00:00
dictPtr + = hSize ;
2016-05-31 22:18:28 +00:00
}
2016-01-27 23:18:06 +00:00
2016-05-06 14:43:23 +00:00
{ short offcodeNCount [ MaxOff + 1 ] ;
fix confusion between unsigned <-> U32
as suggested in #1441.
generally U32 and unsigned are the same thing,
except when they are not ...
case : 32-bit compilation for MIPS (uint32_t == unsigned long)
A vast majority of transformation consists in transforming U32 into unsigned.
In rare cases, it's the other way around (typically for internal code, such as seeds).
Among a few issues this patches solves :
- some parameters were declared with type `unsigned` in *.h,
but with type `U32` in their implementation *.c .
- some parameters have type unsigned*,
but the caller user a pointer to U32 instead.
These fixes are useful.
However, the bulk of changes is about %u formating,
which requires unsigned type,
but generally receives U32 values instead,
often just for brevity (U32 is shorter than unsigned).
These changes are generally minor, or even annoying.
As a consequence, the amount of code changed is larger than I would expect for such a patch.
Testing is also a pain :
it requires manually modifying `mem.h`,
in order to lie about `U32`
and force it to be an `unsigned long` typically.
On a 64-bit system, this will break the equivalence unsigned == U32.
Unfortunately, it will also break a few static_assert(), controlling structure sizes.
So it also requires modifying `debug.h` to make `static_assert()` a noop.
And then reverting these changes.
So it's inconvenient, and as a consequence,
this property is currently not checked during CI tests.
Therefore, these problems can emerge again in the future.
I wonder if it is worth ensuring proper distinction of U32 != unsigned in CI tests.
It's another restriction for coding, adding more frustration during merge tests,
since most platforms don't need this distinction (hence contributor will not see it),
and while this can matter in theory, the number of platforms impacted seems minimal.
Thoughts ?
2018-12-22 00:19:44 +00:00
unsigned offcodeMaxValue = MaxOff , offcodeLog ;
2016-06-15 12:05:07 +00:00
size_t const offcodeHeaderSize = FSE_readNCount ( offcodeNCount , & offcodeMaxValue , & offcodeLog , dictPtr , dictEnd - dictPtr ) ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( FSE_isError ( offcodeHeaderSize ) , dictionary_corrupted , " " ) ;
RETURN_ERROR_IF ( offcodeMaxValue > MaxOff , dictionary_corrupted , " " ) ;
RETURN_ERROR_IF ( offcodeLog > OffFSELog , dictionary_corrupted , " " ) ;
2018-09-07 00:07:53 +00:00
ZSTD_buildFSETable ( entropy - > OFTable ,
2018-02-09 12:25:15 +00:00
offcodeNCount , offcodeMaxValue ,
OF_base , OF_bits ,
2020-08-14 22:28:59 +00:00
offcodeLog ,
2020-08-17 20:44:49 +00:00
entropy - > workspace , sizeof ( entropy - > workspace ) ,
/* bmi2 */ 0 ) ;
2016-06-15 12:05:07 +00:00
dictPtr + = offcodeHeaderSize ;
2016-05-06 14:43:23 +00:00
}
{ short matchlengthNCount [ MaxML + 1 ] ;
Fix buffer overrun in ZSTD_loadEntropy()
The table log set by `FSE_readNCount()` was not checked in
`ZSTD_loadEntropy()`. This caused `FSE_buildDTable(dctx->MLTable, ...)`
to overwrite the beginning of `dctx->hufTable`.
The benchmarks look good, there is no obvious performance regression:
> ./zstds/zstd.opt.0 -i10 -b1 -e5 ~/bench/silesia.tar
1#silesia.tar : 211988480 -> 73656930 (2.878), 268.2 MB/s , 701.0 MB/s
2#silesia.tar : 211988480 -> 70162842 (3.021), 199.5 MB/s , 666.9 MB/s
3#silesia.tar : 211988480 -> 66997986 (3.164), 154.9 MB/s , 655.6 MB/s
4#silesia.tar : 211988480 -> 66002591 (3.212), 128.9 MB/s , 648.4 MB/s
5#silesia.tar : 211988480 -> 65008480 (3.261), 98.4 MB/s , 633.4 MB/s
> ./zstds/zstd.opt.2 -i10 -b1 -e5 ~/bench/silesia.tar
1#silesia.tar : 211988480 -> 73656930 (2.878), 266.1 MB/s , 703.7 MB/s
2#silesia.tar : 211988480 -> 70162842 (3.021), 199.0 MB/s , 666.6 MB/s
3#silesia.tar : 211988480 -> 66997986 (3.164), 156.2 MB/s , 656.2 MB/s
4#silesia.tar : 211988480 -> 66002591 (3.212), 133.2 MB/s , 647.4 MB/s
5#silesia.tar : 211988480 -> 65008480 (3.261), 96.3 MB/s , 633.3 MB/s
2016-10-17 22:49:50 +00:00
unsigned matchlengthMaxValue = MaxML , matchlengthLog ;
2016-06-15 12:05:07 +00:00
size_t const matchlengthHeaderSize = FSE_readNCount ( matchlengthNCount , & matchlengthMaxValue , & matchlengthLog , dictPtr , dictEnd - dictPtr ) ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( FSE_isError ( matchlengthHeaderSize ) , dictionary_corrupted , " " ) ;
RETURN_ERROR_IF ( matchlengthMaxValue > MaxML , dictionary_corrupted , " " ) ;
RETURN_ERROR_IF ( matchlengthLog > MLFSELog , dictionary_corrupted , " " ) ;
2018-09-07 00:07:53 +00:00
ZSTD_buildFSETable ( entropy - > MLTable ,
2018-02-09 12:25:15 +00:00
matchlengthNCount , matchlengthMaxValue ,
ML_base , ML_bits ,
2020-08-14 22:28:59 +00:00
matchlengthLog ,
2020-08-17 20:44:49 +00:00
entropy - > workspace , sizeof ( entropy - > workspace ) ,
/* bmi2 */ 0 ) ;
2016-06-15 12:05:07 +00:00
dictPtr + = matchlengthHeaderSize ;
2016-05-06 14:43:23 +00:00
}
{ short litlengthNCount [ MaxLL + 1 ] ;
Fix buffer overrun in ZSTD_loadEntropy()
The table log set by `FSE_readNCount()` was not checked in
`ZSTD_loadEntropy()`. This caused `FSE_buildDTable(dctx->MLTable, ...)`
to overwrite the beginning of `dctx->hufTable`.
The benchmarks look good, there is no obvious performance regression:
> ./zstds/zstd.opt.0 -i10 -b1 -e5 ~/bench/silesia.tar
1#silesia.tar : 211988480 -> 73656930 (2.878), 268.2 MB/s , 701.0 MB/s
2#silesia.tar : 211988480 -> 70162842 (3.021), 199.5 MB/s , 666.9 MB/s
3#silesia.tar : 211988480 -> 66997986 (3.164), 154.9 MB/s , 655.6 MB/s
4#silesia.tar : 211988480 -> 66002591 (3.212), 128.9 MB/s , 648.4 MB/s
5#silesia.tar : 211988480 -> 65008480 (3.261), 98.4 MB/s , 633.4 MB/s
> ./zstds/zstd.opt.2 -i10 -b1 -e5 ~/bench/silesia.tar
1#silesia.tar : 211988480 -> 73656930 (2.878), 266.1 MB/s , 703.7 MB/s
2#silesia.tar : 211988480 -> 70162842 (3.021), 199.0 MB/s , 666.6 MB/s
3#silesia.tar : 211988480 -> 66997986 (3.164), 156.2 MB/s , 656.2 MB/s
4#silesia.tar : 211988480 -> 66002591 (3.212), 133.2 MB/s , 647.4 MB/s
5#silesia.tar : 211988480 -> 65008480 (3.261), 96.3 MB/s , 633.3 MB/s
2016-10-17 22:49:50 +00:00
unsigned litlengthMaxValue = MaxLL , litlengthLog ;
2016-06-15 12:05:07 +00:00
size_t const litlengthHeaderSize = FSE_readNCount ( litlengthNCount , & litlengthMaxValue , & litlengthLog , dictPtr , dictEnd - dictPtr ) ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( FSE_isError ( litlengthHeaderSize ) , dictionary_corrupted , " " ) ;
RETURN_ERROR_IF ( litlengthMaxValue > MaxLL , dictionary_corrupted , " " ) ;
RETURN_ERROR_IF ( litlengthLog > LLFSELog , dictionary_corrupted , " " ) ;
2018-09-07 00:07:53 +00:00
ZSTD_buildFSETable ( entropy - > LLTable ,
2018-02-09 12:25:15 +00:00
litlengthNCount , litlengthMaxValue ,
LL_base , LL_bits ,
2020-08-14 22:28:59 +00:00
litlengthLog ,
2020-08-17 20:44:49 +00:00
entropy - > workspace , sizeof ( entropy - > workspace ) ,
/* bmi2 */ 0 ) ;
2016-06-15 12:05:07 +00:00
dictPtr + = litlengthHeaderSize ;
2016-05-06 14:43:23 +00:00
}
2016-01-27 23:18:06 +00:00
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dictPtr + 12 > dictEnd , dictionary_corrupted , " " ) ;
2017-02-26 02:33:31 +00:00
{ int i ;
2017-02-26 22:43:07 +00:00
size_t const dictContentSize = ( size_t ) ( dictEnd - ( dictPtr + 12 ) ) ;
2017-02-26 02:33:31 +00:00
for ( i = 0 ; i < 3 ; i + + ) {
U32 const rep = MEM_readLE32 ( dictPtr ) ; dictPtr + = 4 ;
2019-11-01 22:33:39 +00:00
RETURN_ERROR_IF ( rep = = 0 | | rep > dictContentSize ,
2020-04-30 16:24:56 +00:00
dictionary_corrupted , " " ) ;
2017-02-26 18:16:42 +00:00
entropy - > rep [ i ] = rep ;
2017-02-26 02:33:31 +00:00
} }
2016-06-15 12:05:07 +00:00
return dictPtr - ( const BYTE * ) dict ;
2016-01-26 02:14:20 +00:00
}
2016-01-26 14:58:49 +00:00
static size_t ZSTD_decompress_insertDictionary ( ZSTD_DCtx * dctx , const void * dict , size_t dictSize )
2016-01-26 02:14:20 +00:00
{
2016-06-19 21:06:54 +00:00
if ( dictSize < 8 ) return ZSTD_refDictContent ( dctx , dict , dictSize ) ;
2016-05-29 03:01:04 +00:00
{ U32 const magic = MEM_readLE32 ( dict ) ;
2017-06-27 20:50:34 +00:00
if ( magic ! = ZSTD_MAGIC_DICTIONARY ) {
2016-06-19 21:06:54 +00:00
return ZSTD_refDictContent ( dctx , dict , dictSize ) ; /* pure content mode */
} }
2018-08-14 19:56:21 +00:00
dctx - > dictID = MEM_readLE32 ( ( const char * ) dict + ZSTD_FRAMEIDSIZE ) ;
2016-06-19 21:06:54 +00:00
/* load entropy tables */
2018-10-24 00:25:49 +00:00
{ size_t const eSize = ZSTD_loadDEntropy ( & dctx - > entropy , dict , dictSize ) ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( ZSTD_isError ( eSize ) , dictionary_corrupted , " " ) ;
2016-06-19 21:06:54 +00:00
dict = ( const char * ) dict + eSize ;
dictSize - = eSize ;
2016-01-26 02:14:20 +00:00
}
2017-02-26 02:33:31 +00:00
dctx - > litEntropy = dctx - > fseEntropy = 1 ;
2016-06-19 21:06:54 +00:00
/* reference dictionary content */
return ZSTD_refDictContent ( dctx , dict , dictSize ) ;
2016-01-26 02:14:20 +00:00
}
2017-09-27 20:51:05 +00:00
size_t ZSTD_decompressBegin ( ZSTD_DCtx * dctx )
{
assert ( dctx ! = NULL ) ;
dctx - > expected = ZSTD_startingInputLength ( dctx - > format ) ; /* dctx->format must be properly set */
dctx - > stage = ZSTDds_getFrameHeaderSize ;
dctx - > decodedSize = 0 ;
dctx - > previousDstEnd = NULL ;
2018-06-01 22:18:32 +00:00
dctx - > prefixStart = NULL ;
dctx - > virtualStart = NULL ;
2017-09-27 20:51:05 +00:00
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 ;
2020-01-24 01:54:48 +00:00
dctx - > bType = bt_reserved ;
2017-09-27 20:51:05 +00:00
ZSTD_STATIC_ASSERT ( sizeof ( dctx - > entropy . rep ) = = sizeof ( repStartValue ) ) ;
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( dctx - > entropy . rep , repStartValue , sizeof ( repStartValue ) ) ; /* initial repcodes */
2017-09-27 20:51:05 +00:00
dctx - > LLTptr = dctx - > entropy . LLTable ;
dctx - > MLTptr = dctx - > entropy . MLTable ;
dctx - > OFTptr = dctx - > entropy . OFTable ;
dctx - > HUFptr = dctx - > entropy . hufTable ;
return 0 ;
}
2016-01-26 14:58:49 +00:00
size_t ZSTD_decompressBegin_usingDict ( ZSTD_DCtx * dctx , const void * dict , size_t dictSize )
{
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decompressBegin ( dctx ) , " " ) ;
2017-07-06 01:10:07 +00:00
if ( dict & & dictSize )
2019-01-28 22:27:29 +00:00
RETURN_ERROR_IF (
ZSTD_isError ( ZSTD_decompress_insertDictionary ( dctx , dict , dictSize ) ) ,
2020-04-30 16:24:56 +00:00
dictionary_corrupted , " " ) ;
2016-01-26 14:58:49 +00:00
return 0 ;
}
2016-06-06 22:51:51 +00:00
2016-09-14 14:55:44 +00:00
/* ====== ZSTD_DDict ====== */
2018-09-12 00:23:44 +00:00
size_t ZSTD_decompressBegin_usingDDict ( ZSTD_DCtx * dctx , const ZSTD_DDict * ddict )
2017-02-26 22:43:07 +00:00
{
2018-09-12 00:23:44 +00:00
DEBUGLOG ( 4 , " ZSTD_decompressBegin_usingDDict " ) ;
assert ( dctx ! = NULL ) ;
if ( ddict ) {
2018-10-24 00:25:49 +00:00
const char * const dictStart = ( const char * ) ZSTD_DDict_dictContent ( ddict ) ;
size_t const dictSize = ZSTD_DDict_dictSize ( ddict ) ;
const void * const dictEnd = dictStart + dictSize ;
dctx - > ddictIsCold = ( dctx - > dictEnd ! = dictEnd ) ;
2018-09-12 23:40:28 +00:00
DEBUGLOG ( 4 , " DDict is %s " ,
2018-09-12 00:23:44 +00:00
dctx - > ddictIsCold ? " ~cold~ " : " hot! " ) ;
}
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decompressBegin ( dctx ) , " " ) ;
2018-09-12 00:23:44 +00:00
if ( ddict ) { /* NULL ddict is equivalent to no dictionary */
2018-10-24 00:25:49 +00:00
ZSTD_copyDDictParameters ( dctx , ddict ) ;
2017-05-25 22:44:06 +00:00
}
return 0 ;
}
2016-12-06 00:21:06 +00:00
/*! 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 ;
2017-06-27 20:50:34 +00:00
if ( MEM_readLE32 ( dict ) ! = ZSTD_MAGIC_DICTIONARY ) return 0 ;
2018-08-14 19:56:21 +00:00
return MEM_readLE32 ( ( const char * ) dict + ZSTD_FRAMEIDSIZE ) ;
2016-12-06 00:21:06 +00:00
}
/*! ZSTD_getDictID_fromFrame() :
2019-04-12 18:18:11 +00:00
* Provides the dictID required to decompress frame stored within ` src ` .
2016-12-06 00:21:06 +00:00
* If @ return = = 0 , the dictID could not be decoded .
* This could for one of the following reasons :
2017-05-01 18:22:24 +00:00
* - The frame does not require a dictionary ( most common case ) .
* - The frame was built with dictID intentionally removed .
* Needed dictionary is a hidden information .
2016-12-06 00:21:06 +00:00
* Note : this use case also happens when using a non - conformant dictionary .
2017-05-01 18:22:24 +00:00
* - ` srcSize ` is too small , and as a result , frame header could not be decoded .
* Note : possible if ` srcSize < ZSTD_FRAMEHEADERSIZE_MAX ` .
2016-12-06 00:21:06 +00:00
* - This is not a Zstandard frame .
2017-05-01 18:22:24 +00:00
* When identifying the exact failure cause , it ' s possible to use
2017-05-09 22:46:07 +00:00
* ZSTD_getFrameHeader ( ) , which will provide a more precise error code . */
2016-12-06 00:21:06 +00:00
unsigned ZSTD_getDictID_fromFrame ( const void * src , size_t srcSize )
{
2017-09-09 08:03:29 +00:00
ZSTD_frameHeader zfp = { 0 , 0 , 0 , ZSTD_frame , 0 , 0 , 0 } ;
2017-05-09 22:46:07 +00:00
size_t const hError = ZSTD_getFrameHeader ( & zfp , src , srcSize ) ;
2016-12-06 00:21:06 +00:00
if ( ZSTD_isError ( hError ) ) return 0 ;
return zfp . dictID ;
}
2016-09-14 14:55:44 +00:00
2016-06-06 22:51:51 +00:00
/*! ZSTD_decompress_usingDDict() :
* Decompression using a pre - digested Dictionary
2016-06-09 22:12:26 +00:00
* Use dictionary without significant overhead . */
2016-09-14 14:55:44 +00:00
size_t ZSTD_decompress_usingDDict ( ZSTD_DCtx * dctx ,
void * dst , size_t dstCapacity ,
const void * src , size_t srcSize ,
const ZSTD_DDict * ddict )
2016-06-06 22:51:51 +00:00
{
2017-02-08 00:16:55 +00:00
/* pass content and size in case legacy frames are encountered */
return ZSTD_decompressMultiFrame ( dctx , dst , dstCapacity , src , srcSize ,
2017-02-28 08:14:28 +00:00
NULL , 0 ,
2017-02-26 22:43:07 +00:00
ddict ) ;
2016-06-06 22:51:51 +00:00
}
2016-08-12 11:04:27 +00:00
/*=====================================
* Streaming decompression
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
ZSTD_DStream * ZSTD_createDStream ( void )
{
2017-12-30 14:12:59 +00:00
DEBUGLOG ( 3 , " ZSTD_createDStream " ) ;
2017-05-31 00:11:39 +00:00
return ZSTD_createDStream_advanced ( ZSTD_defaultCMem ) ;
2016-08-12 11:04:27 +00:00
}
2017-06-27 00:44:26 +00:00
ZSTD_DStream * ZSTD_initStaticDStream ( void * workspace , size_t workspaceSize )
{
return ZSTD_initStaticDCtx ( workspace , workspaceSize ) ;
}
2016-08-12 11:04:27 +00:00
ZSTD_DStream * ZSTD_createDStream_advanced ( ZSTD_customMem customMem )
{
2017-05-23 23:19:43 +00:00
return ZSTD_createDCtx_advanced ( customMem ) ;
2016-08-12 11:04:27 +00:00
}
size_t ZSTD_freeDStream ( ZSTD_DStream * zds )
{
2017-05-23 23:19:43 +00:00
return ZSTD_freeDCtx ( zds ) ;
2016-08-12 11:04:27 +00:00
}
2018-09-12 00:23:44 +00:00
/* *** Initialization *** */
2016-08-12 11:04:27 +00:00
2017-05-19 17:51:30 +00:00
size_t ZSTD_DStreamInSize ( void ) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize ; }
size_t ZSTD_DStreamOutSize ( void ) { return ZSTD_BLOCKSIZE_MAX ; }
2016-08-12 11:04:27 +00:00
2018-09-12 00:23:44 +00:00
size_t ZSTD_DCtx_loadDictionary_advanced ( ZSTD_DCtx * dctx ,
const void * dict , size_t dictSize ,
ZSTD_dictLoadMethod_e dictLoadMethod ,
ZSTD_dictContentType_e dictContentType )
2018-03-20 20:40:29 +00:00
{
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dctx - > streamStage ! = zdss_init , stage_wrong , " " ) ;
2019-04-10 19:34:21 +00:00
ZSTD_clearDict ( dctx ) ;
2019-11-01 22:33:39 +00:00
if ( dict & & dictSize ! = 0 ) {
2018-03-20 22:13:14 +00:00
dctx - > ddictLocal = ZSTD_createDDict_advanced ( dict , dictSize , dictLoadMethod , dictContentType , dctx - > customMem ) ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dctx - > ddictLocal = = NULL , memory_allocation , " NULL pointer! " ) ;
2019-04-10 19:34:21 +00:00
dctx - > ddict = dctx - > ddictLocal ;
2019-04-10 23:50:35 +00:00
dctx - > dictUses = ZSTD_use_indefinitely ;
2018-03-20 20:40:29 +00:00
}
return 0 ;
}
size_t ZSTD_DCtx_loadDictionary_byReference ( ZSTD_DCtx * dctx , const void * dict , size_t dictSize )
{
2018-03-20 22:13:14 +00:00
return ZSTD_DCtx_loadDictionary_advanced ( dctx , dict , dictSize , ZSTD_dlm_byRef , ZSTD_dct_auto ) ;
2018-03-20 20:40:29 +00:00
}
size_t ZSTD_DCtx_loadDictionary ( ZSTD_DCtx * dctx , const void * dict , size_t dictSize )
{
2018-03-20 22:13:14 +00:00
return ZSTD_DCtx_loadDictionary_advanced ( dctx , dict , dictSize , ZSTD_dlm_byCopy , ZSTD_dct_auto ) ;
2018-03-20 20:40:29 +00:00
}
2018-03-20 22:45:56 +00:00
size_t ZSTD_DCtx_refPrefix_advanced ( ZSTD_DCtx * dctx , const void * prefix , size_t prefixSize , ZSTD_dictContentType_e dictContentType )
{
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_DCtx_loadDictionary_advanced ( dctx , prefix , prefixSize , ZSTD_dlm_byRef , dictContentType ) , " " ) ;
2019-04-10 23:50:35 +00:00
dctx - > dictUses = ZSTD_use_once ;
2019-04-10 19:34:21 +00:00
return 0 ;
2018-03-20 22:45:56 +00:00
}
size_t ZSTD_DCtx_refPrefix ( ZSTD_DCtx * dctx , const void * prefix , size_t prefixSize )
{
return ZSTD_DCtx_refPrefix_advanced ( dctx , prefix , prefixSize , ZSTD_dct_rawContent ) ;
}
2018-03-20 22:43:49 +00:00
/* ZSTD_initDStream_usingDict() :
2019-10-22 02:42:14 +00:00
* return : expected size , aka ZSTD_startingInputLength ( ) .
2018-03-20 22:43:49 +00:00
* this function cannot fail */
2016-08-12 11:04:27 +00:00
size_t ZSTD_initDStream_usingDict ( ZSTD_DStream * zds , const void * dict , size_t dictSize )
{
2017-12-30 14:12:59 +00:00
DEBUGLOG ( 4 , " ZSTD_initDStream_usingDict " ) ;
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_DCtx_reset ( zds , ZSTD_reset_session_only ) , " " ) ;
FORWARD_IF_ERROR ( ZSTD_DCtx_loadDictionary ( zds , dict , dictSize ) , " " ) ;
2019-10-22 02:42:14 +00:00
return ZSTD_startingInputLength ( zds - > format ) ;
2016-08-12 11:04:27 +00:00
}
2017-09-25 23:21:17 +00:00
/* note : this variant can't fail */
2016-08-12 11:04:27 +00:00
size_t ZSTD_initDStream ( ZSTD_DStream * zds )
{
2017-12-30 14:12:59 +00:00
DEBUGLOG ( 4 , " ZSTD_initDStream " ) ;
2019-04-10 19:34:21 +00:00
return ZSTD_initDStream_usingDDict ( zds , NULL ) ;
2016-08-12 11:04:27 +00:00
}
2017-05-01 18:22:24 +00:00
/* ZSTD_initDStream_usingDDict() :
2017-09-25 23:21:17 +00:00
* ddict will just be referenced , and must outlive decompression session
* this function cannot fail */
2018-03-20 23:16:13 +00:00
size_t ZSTD_initDStream_usingDDict ( ZSTD_DStream * dctx , const ZSTD_DDict * ddict )
2016-10-26 00:47:02 +00:00
{
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_DCtx_reset ( dctx , ZSTD_reset_session_only ) , " " ) ;
FORWARD_IF_ERROR ( ZSTD_DCtx_refDDict ( dctx , ddict ) , " " ) ;
2019-10-22 02:42:14 +00:00
return ZSTD_startingInputLength ( dctx - > format ) ;
2016-10-26 00:47:02 +00:00
}
2018-03-20 22:43:49 +00:00
/* ZSTD_resetDStream() :
2019-10-22 02:42:14 +00:00
* return : expected size , aka ZSTD_startingInputLength ( ) .
2018-03-20 22:43:49 +00:00
* this function cannot fail */
2018-03-20 23:16:13 +00:00
size_t ZSTD_resetDStream ( ZSTD_DStream * dctx )
2016-09-14 14:55:44 +00:00
{
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_DCtx_reset ( dctx , ZSTD_reset_session_only ) , " " ) ;
2019-10-22 02:42:14 +00:00
return ZSTD_startingInputLength ( dctx - > format ) ;
2016-09-14 14:55:44 +00:00
}
2016-08-23 14:58:10 +00:00
2018-09-12 00:23:44 +00:00
size_t ZSTD_DCtx_refDDict ( ZSTD_DCtx * dctx , const ZSTD_DDict * ddict )
{
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dctx - > streamStage ! = zdss_init , stage_wrong , " " ) ;
2019-04-10 19:34:21 +00:00
ZSTD_clearDict ( dctx ) ;
if ( ddict ) {
dctx - > ddict = ddict ;
2019-04-10 23:50:35 +00:00
dctx - > dictUses = ZSTD_use_indefinitely ;
2019-04-10 19:34:21 +00:00
}
2018-09-12 00:23:44 +00:00
return 0 ;
}
2018-12-05 01:06:48 +00:00
/* ZSTD_DCtx_setMaxWindowSize() :
* note : no direct equivalence in ZSTD_DCtx_setParameter ,
* since this version sets windowSize , and the other sets windowLog */
2017-09-25 21:26:26 +00:00
size_t ZSTD_DCtx_setMaxWindowSize ( ZSTD_DCtx * dctx , size_t maxWindowSize )
{
2018-12-05 01:06:48 +00:00
ZSTD_bounds const bounds = ZSTD_dParam_getBounds ( ZSTD_d_windowLogMax ) ;
size_t const min = ( size_t ) 1 < < bounds . lowerBound ;
size_t const max = ( size_t ) 1 < < bounds . upperBound ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dctx - > streamStage ! = zdss_init , stage_wrong , " " ) ;
RETURN_ERROR_IF ( maxWindowSize < min , parameter_outOfBound , " " ) ;
RETURN_ERROR_IF ( maxWindowSize > max , parameter_outOfBound , " " ) ;
2017-09-25 21:26:26 +00:00
dctx - > maxWindowSize = maxWindowSize ;
return 0 ;
}
size_t ZSTD_DCtx_setFormat ( ZSTD_DCtx * dctx , ZSTD_format_e format )
{
2018-12-05 01:06:48 +00:00
return ZSTD_DCtx_setParameter ( dctx , ZSTD_d_format , format ) ;
2017-09-25 21:26:26 +00:00
}
2018-12-04 23:35:37 +00:00
ZSTD_bounds ZSTD_dParam_getBounds ( ZSTD_dParameter dParam )
{
ZSTD_bounds bounds = { 0 , 0 , 0 } ;
switch ( dParam ) {
case ZSTD_d_windowLogMax :
bounds . lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN ;
bounds . upperBound = ZSTD_WINDOWLOG_MAX ;
return bounds ;
case ZSTD_d_format :
bounds . lowerBound = ( int ) ZSTD_f_zstd1 ;
bounds . upperBound = ( int ) ZSTD_f_zstd1_magicless ;
ZSTD_STATIC_ASSERT ( ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless ) ;
return bounds ;
2020-04-28 00:42:03 +00:00
case ZSTD_d_stableOutBuffer :
2020-10-12 20:15:39 +00:00
bounds . lowerBound = ( int ) ZSTD_bm_buffered ;
bounds . upperBound = ( int ) ZSTD_bm_stable ;
2020-04-28 00:42:03 +00:00
return bounds ;
2020-08-21 20:23:39 +00:00
case ZSTD_d_forceIgnoreChecksum :
bounds . lowerBound = ( int ) ZSTD_d_validateChecksum ;
bounds . upperBound = ( int ) ZSTD_d_ignoreChecksum ;
2020-08-21 22:18:53 +00:00
return bounds ;
2018-12-05 00:59:26 +00:00
default : ;
2018-12-04 23:35:37 +00:00
}
bounds . error = ERROR ( parameter_unsupported ) ;
return bounds ;
}
/* ZSTD_dParam_withinBounds:
* @ return 1 if value is within dParam bounds ,
* 0 otherwise */
static int ZSTD_dParam_withinBounds ( ZSTD_dParameter dParam , int value )
{
ZSTD_bounds const bounds = ZSTD_dParam_getBounds ( dParam ) ;
if ( ZSTD_isError ( bounds . error ) ) return 0 ;
if ( value < bounds . lowerBound ) return 0 ;
if ( value > bounds . upperBound ) return 0 ;
return 1 ;
}
# define CHECK_DBOUNDS(p,v) { \
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( ! ZSTD_dParam_withinBounds ( p , v ) , parameter_outOfBound , " " ) ; \
2018-12-04 23:35:37 +00:00
}
2020-09-29 23:25:03 +00:00
size_t ZSTD_DCtx_getParameter ( ZSTD_DCtx * dctx , ZSTD_dParameter param , int * value )
{
switch ( param ) {
case ZSTD_d_windowLogMax :
* value = ZSTD_highbit32 ( ( U32 ) dctx - > maxWindowSize ) ;
return 0 ;
case ZSTD_d_format :
* value = dctx - > format ;
return 0 ;
case ZSTD_d_stableOutBuffer :
* value = dctx - > outBufferMode ;
return 0 ;
case ZSTD_d_forceIgnoreChecksum :
* value = dctx - > forceIgnoreChecksum ;
return 0 ;
default : ;
}
RETURN_ERROR ( parameter_unsupported , " " ) ;
}
2018-12-04 23:35:37 +00:00
size_t ZSTD_DCtx_setParameter ( ZSTD_DCtx * dctx , ZSTD_dParameter dParam , int value )
{
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dctx - > streamStage ! = zdss_init , stage_wrong , " " ) ;
2018-12-04 23:35:37 +00:00
switch ( dParam ) {
case ZSTD_d_windowLogMax :
2019-04-03 02:20:52 +00:00
if ( value = = 0 ) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT ;
2018-12-04 23:35:37 +00:00
CHECK_DBOUNDS ( ZSTD_d_windowLogMax , value ) ;
2018-12-04 23:57:16 +00:00
dctx - > maxWindowSize = ( ( size_t ) 1 ) < < value ;
2018-12-04 23:35:37 +00:00
return 0 ;
case ZSTD_d_format :
CHECK_DBOUNDS ( ZSTD_d_format , value ) ;
dctx - > format = ( ZSTD_format_e ) value ;
return 0 ;
2020-04-28 00:42:03 +00:00
case ZSTD_d_stableOutBuffer :
CHECK_DBOUNDS ( ZSTD_d_stableOutBuffer , value ) ;
2020-10-12 20:15:39 +00:00
dctx - > outBufferMode = ( ZSTD_bufferMode_e ) value ;
2020-04-28 00:42:03 +00:00
return 0 ;
2020-08-21 20:23:39 +00:00
case ZSTD_d_forceIgnoreChecksum :
CHECK_DBOUNDS ( ZSTD_d_forceIgnoreChecksum , value ) ;
2020-08-21 20:46:46 +00:00
dctx - > forceIgnoreChecksum = ( ZSTD_forceIgnoreChecksum_e ) value ;
2020-08-21 22:18:53 +00:00
return 0 ;
2018-12-05 00:59:26 +00:00
default : ;
2018-12-04 23:35:37 +00:00
}
2020-04-30 16:24:56 +00:00
RETURN_ERROR ( parameter_unsupported , " " ) ;
2018-12-04 23:35:37 +00:00
}
size_t ZSTD_DCtx_reset ( ZSTD_DCtx * dctx , ZSTD_ResetDirective reset )
{
if ( ( reset = = ZSTD_reset_session_only )
| | ( reset = = ZSTD_reset_session_and_parameters ) ) {
2019-04-10 19:34:21 +00:00
dctx - > streamStage = zdss_init ;
dctx - > noForwardProgress = 0 ;
2018-12-04 23:35:37 +00:00
}
if ( ( reset = = ZSTD_reset_parameters )
| | ( reset = = ZSTD_reset_session_and_parameters ) ) {
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( dctx - > streamStage ! = zdss_init , stage_wrong , " " ) ;
2019-04-10 19:34:21 +00:00
ZSTD_clearDict ( dctx ) ;
2020-09-29 23:25:03 +00:00
ZSTD_DCtx_resetParameters ( dctx ) ;
2018-12-04 23:35:37 +00:00
}
return 0 ;
}
2016-08-23 14:58:10 +00:00
2018-03-20 23:16:13 +00:00
size_t ZSTD_sizeof_DStream ( const ZSTD_DStream * dctx )
2016-08-22 22:30:31 +00:00
{
2018-03-20 23:16:13 +00:00
return ZSTD_sizeof_DCtx ( dctx ) ;
2016-08-22 22:30:31 +00:00
}
2017-09-09 08:03:29 +00:00
size_t ZSTD_decodingBufferSize_min ( unsigned long long windowSize , unsigned long long frameContentSize )
{
size_t const blockSize = ( size_t ) MIN ( windowSize , ZSTD_BLOCKSIZE_MAX ) ;
unsigned long long const neededRBSize = windowSize + blockSize + ( WILDCOPY_OVERLENGTH * 2 ) ;
unsigned long long const neededSize = MIN ( frameContentSize , neededRBSize ) ;
size_t const minRBSize = ( size_t ) neededSize ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( ( unsigned long long ) minRBSize ! = neededSize ,
2020-04-30 16:24:56 +00:00
frameParameter_windowTooLarge , " " ) ;
2017-09-09 08:03:29 +00:00
return minRBSize ;
}
2017-06-27 00:44:26 +00:00
size_t ZSTD_estimateDStreamSize ( size_t windowSize )
2017-05-09 23:18:17 +00:00
{
2017-05-19 17:51:30 +00:00
size_t const blockSize = MIN ( windowSize , ZSTD_BLOCKSIZE_MAX ) ;
2017-05-09 23:18:17 +00:00
size_t const inBuffSize = blockSize ; /* no block can be larger */
2017-09-09 08:03:29 +00:00
size_t const outBuffSize = ZSTD_decodingBufferSize_min ( windowSize , ZSTD_CONTENTSIZE_UNKNOWN ) ;
2017-08-13 10:29:42 +00:00
return ZSTD_estimateDCtxSize ( ) + inBuffSize + outBuffSize ;
2017-05-09 23:18:17 +00:00
}
2017-09-25 21:26:26 +00:00
size_t ZSTD_estimateDStreamSize_fromFrame ( const void * src , size_t srcSize )
2017-06-27 00:44:26 +00:00
{
2018-11-14 02:09:03 +00:00
U32 const windowSizeMax = 1U < < ZSTD_WINDOWLOG_MAX ; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
2017-07-07 22:21:35 +00:00
ZSTD_frameHeader zfh ;
size_t const err = ZSTD_getFrameHeader ( & zfh , src , srcSize ) ;
2017-06-27 00:44:26 +00:00
if ( ZSTD_isError ( err ) ) return err ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( err > 0 , srcSize_wrong , " " ) ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( zfh . windowSize > windowSizeMax ,
2020-04-30 16:24:56 +00:00
frameParameter_windowTooLarge , " " ) ;
2017-07-08 00:13:12 +00:00
return ZSTD_estimateDStreamSize ( ( size_t ) zfh . windowSize ) ;
2017-06-27 00:44:26 +00:00
}
2016-08-12 11:04:27 +00:00
2016-09-09 14:44:16 +00:00
/* ***** Decompression ***** */
2016-08-12 11:04:27 +00:00
2020-04-03 21:14:46 +00:00
static int ZSTD_DCtx_isOverflow ( ZSTD_DStream * zds , size_t const neededInBuffSize , size_t const neededOutBuffSize )
2020-04-03 20:20:22 +00:00
{
2020-04-03 21:26:15 +00:00
return ( zds - > inBuffSize + zds - > outBuffSize ) > = ( neededInBuffSize + neededOutBuffSize ) * ZSTD_WORKSPACETOOLARGE_FACTOR ;
2020-04-03 20:20:22 +00:00
}
2020-04-03 21:14:46 +00:00
static void ZSTD_DCtx_updateOversizedDuration ( ZSTD_DStream * zds , size_t const neededInBuffSize , size_t const neededOutBuffSize )
2020-04-03 20:20:22 +00:00
{
2020-04-03 21:21:24 +00:00
if ( ZSTD_DCtx_isOverflow ( zds , neededInBuffSize , neededOutBuffSize ) )
zds - > oversizedDuration + + ;
else
zds - > oversizedDuration = 0 ;
2020-04-03 20:20:22 +00:00
}
2020-04-03 21:14:46 +00:00
static int ZSTD_DCtx_isOversizedTooLong ( ZSTD_DStream * zds )
2020-04-03 20:20:22 +00:00
{
2020-04-03 21:26:15 +00:00
return zds - > oversizedDuration > = ZSTD_WORKSPACETOOLARGE_MAXDURATION ;
2020-04-03 20:20:22 +00:00
}
2016-08-12 11:04:27 +00:00
2020-04-28 01:25:30 +00:00
/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */
2020-04-28 00:42:03 +00:00
static size_t ZSTD_checkOutBuffer ( ZSTD_DStream const * zds , ZSTD_outBuffer const * output )
{
ZSTD_outBuffer const expect = zds - > expectedOutBuffer ;
/* No requirement when ZSTD_obm_stable is not enabled. */
2020-10-12 20:15:39 +00:00
if ( zds - > outBufferMode ! = ZSTD_bm_stable )
2020-04-28 00:42:03 +00:00
return 0 ;
/* Any buffer is allowed in zdss_init, this must be the same for every other call until
* the context is reset .
*/
if ( zds - > streamStage = = zdss_init )
return 0 ;
/* The buffer must match our expectation exactly. */
if ( expect . dst = = output - > dst & & expect . pos = = output - > pos & & expect . size = = output - > size )
return 0 ;
2020-10-12 20:15:39 +00:00
RETURN_ERROR ( dstBuffer_wrong , " ZSTD_d_stableOutBuffer enabled but output differs! " ) ;
2020-04-28 00:42:03 +00:00
}
2020-04-28 01:25:30 +00:00
/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()
* and updates the stage and the output buffer state . This call is extracted so it can be
* used both when reading directly from the ZSTD_inBuffer , and in buffered input mode .
* NOTE : You must break after calling this function since the streamStage is modified .
*/
2020-04-28 00:42:03 +00:00
static size_t ZSTD_decompressContinueStream (
ZSTD_DStream * zds , char * * op , char * oend ,
void const * src , size_t srcSize ) {
int const isSkipFrame = ZSTD_isSkipFrame ( zds ) ;
2020-10-12 20:15:39 +00:00
if ( zds - > outBufferMode = = ZSTD_bm_buffered ) {
2020-04-28 00:42:03 +00:00
size_t const dstSize = isSkipFrame ? 0 : zds - > outBuffSize - zds - > outStart ;
size_t const decodedSize = ZSTD_decompressContinue ( zds ,
zds - > outBuff + zds - > outStart , dstSize , src , srcSize ) ;
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( decodedSize , " " ) ;
2020-04-28 00:42:03 +00:00
if ( ! decodedSize & & ! isSkipFrame ) {
zds - > streamStage = zdss_read ;
} else {
zds - > outEnd = zds - > outStart + decodedSize ;
zds - > streamStage = zdss_flush ;
}
} else {
2020-04-28 01:25:30 +00:00
/* Write directly into the output buffer */
2020-04-28 00:42:03 +00:00
size_t const dstSize = isSkipFrame ? 0 : oend - * op ;
size_t const decodedSize = ZSTD_decompressContinue ( zds , * op , dstSize , src , srcSize ) ;
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( decodedSize , " " ) ;
2020-04-28 00:42:03 +00:00
* op + = decodedSize ;
2020-04-28 01:25:30 +00:00
/* Flushing is not needed. */
2020-04-28 00:42:03 +00:00
zds - > streamStage = zdss_read ;
assert ( * op < = oend ) ;
2020-10-12 20:15:39 +00:00
assert ( zds - > outBufferMode = = ZSTD_bm_stable ) ;
2020-04-28 00:42:03 +00:00
}
return 0 ;
}
2016-08-16 23:39:22 +00:00
size_t ZSTD_decompressStream ( ZSTD_DStream * zds , ZSTD_outBuffer * output , ZSTD_inBuffer * input )
2016-08-12 11:04:27 +00:00
{
2019-11-21 02:21:51 +00:00
const char * const src = ( const char * ) input - > src ;
const char * const istart = input - > pos ! = 0 ? src + input - > pos : src ;
const char * const iend = input - > size ! = 0 ? src + input - > size : src ;
2016-08-12 11:04:27 +00:00
const char * ip = istart ;
2019-11-21 02:21:51 +00:00
char * const dst = ( char * ) output - > dst ;
char * const ostart = output - > pos ! = 0 ? dst + output - > pos : dst ;
char * const oend = output - > size ! = 0 ? dst + output - > size : dst ;
2016-08-12 11:04:27 +00:00
char * op = ostart ;
U32 someMoreWork = 1 ;
2017-06-21 22:53:42 +00:00
DEBUGLOG ( 5 , " ZSTD_decompressStream " ) ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF (
input - > pos > input - > size ,
srcSize_wrong ,
" forbidden. in: pos: %u vs size: %u " ,
( U32 ) input - > pos , ( U32 ) input - > size ) ;
RETURN_ERROR_IF (
output - > pos > output - > size ,
dstSize_tooSmall ,
" forbidden. out: pos: %u vs size: %u " ,
( U32 ) output - > pos , ( U32 ) output - > size ) ;
2017-06-21 22:53:42 +00:00
DEBUGLOG ( 5 , " input size : %u " , ( U32 ) ( input - > size - input - > pos ) ) ;
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_checkOutBuffer ( zds , output ) , " " ) ;
2017-09-25 22:41:48 +00:00
2016-08-12 11:04:27 +00:00
while ( someMoreWork ) {
2017-05-23 23:19:43 +00:00
switch ( zds - > streamStage )
2016-08-12 11:04:27 +00:00
{
case zdss_init :
2018-03-21 00:48:22 +00:00
DEBUGLOG ( 5 , " stage zdss_init => transparent reset " ) ;
2019-04-10 19:34:21 +00:00
zds - > streamStage = zdss_loadHeader ;
zds - > lhSize = zds - > inPos = zds - > outStart = zds - > outEnd = 0 ;
zds - > legacyVersion = 0 ;
zds - > hostageByte = 0 ;
2020-04-28 00:42:03 +00:00
zds - > expectedOutBuffer = * output ;
2016-12-03 02:37:38 +00:00
/* fall-through */
2016-08-12 11:04:27 +00:00
case zdss_loadHeader :
2017-09-25 22:12:09 +00:00
DEBUGLOG ( 5 , " stage zdss_loadHeader (srcSize : %u) " , ( U32 ) ( iend - ip ) ) ;
2018-03-21 00:48:22 +00:00
# if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
if ( zds - > legacyVersion ) {
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( zds - > staticSize , memory_allocation ,
" legacy support is incompatible with static dctx " ) ;
2018-03-21 00:48:22 +00:00
{ size_t const hint = ZSTD_decompressLegacyStream ( zds - > legacyContext , zds - > legacyVersion , output , input ) ;
if ( hint = = 0 ) zds - > streamStage = zdss_init ;
return hint ;
} }
# endif
2018-03-29 23:51:08 +00:00
{ size_t const hSize = ZSTD_getFrameHeader_advanced ( & zds - > fParams , zds - > headerBuffer , zds - > lhSize , zds - > format ) ;
2017-09-25 22:12:09 +00:00
DEBUGLOG ( 5 , " header size : %u " , ( U32 ) hSize ) ;
2017-05-24 22:42:24 +00:00
if ( ZSTD_isError ( hSize ) ) {
2016-08-28 14:43:34 +00:00
# if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
2017-05-24 22:42:24 +00:00
U32 const legacyVersion = ZSTD_isLegacy ( istart , iend - istart ) ;
2016-08-28 14:43:34 +00:00
if ( legacyVersion ) {
2019-04-10 19:34:21 +00:00
ZSTD_DDict const * const ddict = ZSTD_getDDict ( zds ) ;
const void * const dict = ddict ? ZSTD_DDict_dictContent ( ddict ) : NULL ;
size_t const dictSize = ddict ? ZSTD_DDict_dictSize ( ddict ) : 0 ;
2018-03-21 00:48:22 +00:00
DEBUGLOG ( 5 , " ZSTD_decompressStream: detected legacy version v0.%u " , legacyVersion ) ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( zds - > staticSize , memory_allocation ,
" legacy support is incompatible with static dctx " ) ;
2019-01-29 17:56:07 +00:00
FORWARD_IF_ERROR ( ZSTD_initLegacyStream ( & zds - > legacyContext ,
2017-07-07 22:21:35 +00:00
zds - > previousLegacyVersion , legacyVersion ,
2020-04-30 16:24:56 +00:00
dict , dictSize ) , " " ) ;
2016-08-28 15:19:47 +00:00
zds - > legacyVersion = zds - > previousLegacyVersion = legacyVersion ;
2018-03-21 00:48:22 +00:00
{ size_t const hint = ZSTD_decompressLegacyStream ( zds - > legacyContext , legacyVersion , output , input ) ;
if ( hint = = 0 ) zds - > streamStage = zdss_init ; /* or stay in stage zdss_loadHeader */
return hint ;
} }
2016-08-28 14:43:34 +00:00
# endif
2017-12-12 22:01:54 +00:00
return hSize ; /* error */
2017-05-24 22:42:24 +00:00
}
2016-08-12 11:04:27 +00:00
if ( hSize ! = 0 ) { /* need more input */
size_t const toLoad = hSize - zds - > lhSize ; /* if hSize!=0, hSize > zds->lhSize */
2017-12-12 22:01:54 +00:00
size_t const remainingInput = ( size_t ) ( iend - ip ) ;
assert ( iend > = ip ) ;
if ( toLoad > remainingInput ) { /* not enough input to load full header */
if ( remainingInput > 0 ) {
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( zds - > headerBuffer + zds - > lhSize , ip , remainingInput ) ;
2017-12-12 22:01:54 +00:00
zds - > lhSize + = remainingInput ;
2017-07-03 19:31:55 +00:00
}
2016-08-16 23:39:22 +00:00
input - > pos = input - > size ;
2019-10-22 02:42:14 +00:00
return ( MAX ( ( size_t ) ZSTD_FRAMEHEADERSIZE_MIN ( zds - > format ) , hSize ) - zds - > lhSize ) + ZSTD_blockHeaderSize ; /* remaining header bytes + next block header */
2016-08-12 11:04:27 +00:00
}
2017-07-03 19:31:55 +00:00
assert ( ip ! = NULL ) ;
2020-08-10 19:46:38 +00:00
ZSTD_memcpy ( zds - > headerBuffer + zds - > lhSize , ip , toLoad ) ; zds - > lhSize = hSize ; ip + = toLoad ;
2016-08-12 11:04:27 +00:00
break ;
} }
2017-05-24 20:50:10 +00:00
2017-02-28 08:14:28 +00:00
/* check for single-pass mode opportunity */
2020-04-28 01:10:45 +00:00
if ( zds - > fParams . frameContentSize ! = ZSTD_CONTENTSIZE_UNKNOWN
& & zds - > fParams . frameType ! = ZSTD_skippableFrame
2017-02-28 08:14:28 +00:00
& & ( U64 ) ( size_t ) ( oend - op ) > = zds - > fParams . frameContentSize ) {
size_t const cSize = ZSTD_findFrameCompressedSize ( istart , iend - istart ) ;
if ( cSize < = ( size_t ) ( iend - istart ) ) {
2017-12-12 22:01:54 +00:00
/* shortcut : using single-pass mode */
2019-04-10 19:34:21 +00:00
size_t const decompressedSize = ZSTD_decompress_usingDDict ( zds , op , oend - op , istart , cSize , ZSTD_getDDict ( zds ) ) ;
2017-02-28 08:14:28 +00:00
if ( ZSTD_isError ( decompressedSize ) ) return decompressedSize ;
2017-12-12 22:01:54 +00:00
DEBUGLOG ( 4 , " shortcut to single-pass ZSTD_decompress_usingDDict() " )
2017-02-28 10:12:42 +00:00
ip = istart + cSize ;
2017-02-28 08:14:28 +00:00
op + = decompressedSize ;
2017-05-23 23:19:43 +00:00
zds - > expected = 0 ;
zds - > streamStage = zdss_init ;
2017-02-28 08:14:28 +00:00
someMoreWork = 0 ;
break ;
} }
2020-04-28 00:42:03 +00:00
/* Check output buffer is large enough for ZSTD_odm_stable. */
2020-10-12 20:15:39 +00:00
if ( zds - > outBufferMode = = ZSTD_bm_stable
2020-04-28 00:42:03 +00:00
& & zds - > fParams . frameType ! = ZSTD_skippableFrame
& & zds - > fParams . frameContentSize ! = ZSTD_CONTENTSIZE_UNKNOWN
& & ( U64 ) ( size_t ) ( oend - op ) < zds - > fParams . frameContentSize ) {
RETURN_ERROR ( dstSize_tooSmall , " ZSTD_obm_stable passed but ZSTD_outBuffer is too small " ) ;
}
2017-06-21 00:44:55 +00:00
/* Consume header (see ZSTDds_decodeFrameHeader) */
2017-06-28 18:09:43 +00:00
DEBUGLOG ( 4 , " Consume header " ) ;
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decompressBegin_usingDDict ( zds , ZSTD_getDDict ( zds ) ) , " " ) ;
2017-06-21 22:53:42 +00:00
2018-11-14 01:36:35 +00:00
if ( ( MEM_readLE32 ( zds - > headerBuffer ) & ZSTD_MAGIC_SKIPPABLE_MASK ) = = ZSTD_MAGIC_SKIPPABLE_START ) { /* skippable frame */
2018-08-14 19:56:21 +00:00
zds - > expected = MEM_readLE32 ( zds - > headerBuffer + ZSTD_FRAMEIDSIZE ) ;
2017-06-21 22:53:42 +00:00
zds - > stage = ZSTDds_skipFrame ;
} else {
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decodeFrameHeader ( zds , zds - > headerBuffer , zds - > lhSize ) , " " ) ;
2017-06-21 22:53:42 +00:00
zds - > expected = ZSTD_blockHeaderSize ;
zds - > stage = ZSTDds_decodeBlockHeader ;
}
2016-08-12 11:04:27 +00:00
2017-06-21 00:44:55 +00:00
/* control buffer memory usage */
2017-12-12 22:01:54 +00:00
DEBUGLOG ( 4 , " Control max memory usage (%u KB <= max %u KB) " ,
( U32 ) ( zds - > fParams . windowSize > > 10 ) ,
( U32 ) ( zds - > maxWindowSize > > 10 ) ) ;
2016-08-12 11:04:27 +00:00
zds - > fParams . windowSize = MAX ( zds - > fParams . windowSize , 1U < < ZSTD_WINDOWLOG_ABSOLUTEMIN ) ;
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( zds - > fParams . windowSize > zds - > maxWindowSize ,
2020-04-30 16:24:56 +00:00
frameParameter_windowTooLarge , " " ) ;
2016-08-12 11:04:27 +00:00
2016-09-09 14:44:16 +00:00
/* Adapt buffer sizes to frame header instructions */
2017-09-09 21:37:28 +00:00
{ size_t const neededInBuffSize = MAX ( zds - > fParams . blockSizeMax , 4 /* frame checksum */ ) ;
2020-10-12 20:15:39 +00:00
size_t const neededOutBuffSize = zds - > outBufferMode = = ZSTD_bm_buffered
2020-04-28 00:42:03 +00:00
? ZSTD_decodingBufferSize_min ( zds - > fParams . windowSize , zds - > fParams . frameContentSize )
: 0 ;
2020-04-03 20:20:22 +00:00
2020-04-03 21:14:46 +00:00
ZSTD_DCtx_updateOversizedDuration ( zds , neededInBuffSize , neededOutBuffSize ) ;
2020-04-03 21:12:23 +00:00
{ int const tooSmall = ( zds - > inBuffSize < neededInBuffSize ) | | ( zds - > outBuffSize < neededOutBuffSize ) ;
2020-04-03 21:14:46 +00:00
int const tooLarge = ZSTD_DCtx_isOversizedTooLong ( zds ) ;
2020-04-03 21:12:23 +00:00
if ( tooSmall | | tooLarge ) {
size_t const bufferSize = neededInBuffSize + neededOutBuffSize ;
DEBUGLOG ( 4 , " inBuff : from %u to %u " ,
( U32 ) zds - > inBuffSize , ( U32 ) neededInBuffSize ) ;
DEBUGLOG ( 4 , " outBuff : from %u to %u " ,
( U32 ) zds - > outBuffSize , ( U32 ) neededOutBuffSize ) ;
if ( zds - > staticSize ) { /* static DCtx */
DEBUGLOG ( 4 , " staticSize : %u " , ( U32 ) zds - > staticSize ) ;
assert ( zds - > staticSize > = sizeof ( ZSTD_DCtx ) ) ; /* controlled at init */
RETURN_ERROR_IF (
bufferSize > zds - > staticSize - sizeof ( ZSTD_DCtx ) ,
2020-04-30 16:24:56 +00:00
memory_allocation , " " ) ;
2020-04-03 21:12:23 +00:00
} else {
2020-08-10 19:42:03 +00:00
ZSTD_customFree ( zds - > inBuff , zds - > customMem ) ;
2020-04-03 21:12:23 +00:00
zds - > inBuffSize = 0 ;
zds - > outBuffSize = 0 ;
2020-08-10 19:42:03 +00:00
zds - > inBuff = ( char * ) ZSTD_customMalloc ( bufferSize , zds - > customMem ) ;
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( zds - > inBuff = = NULL , memory_allocation , " " ) ;
2020-04-03 21:12:23 +00:00
}
zds - > inBuffSize = neededInBuffSize ;
zds - > outBuff = zds - > inBuff + zds - > inBuffSize ;
zds - > outBuffSize = neededOutBuffSize ;
} } }
2017-05-23 23:19:43 +00:00
zds - > streamStage = zdss_read ;
2017-08-08 19:32:26 +00:00
/* fall-through */
2016-08-12 11:04:27 +00:00
case zdss_read :
2017-06-21 22:53:42 +00:00
DEBUGLOG ( 5 , " stage zdss_read " ) ;
2020-01-11 02:02:11 +00:00
{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize ( zds , iend - ip ) ;
2017-06-21 22:53:42 +00:00
DEBUGLOG ( 5 , " neededInSize = %u " , ( U32 ) neededInSize ) ;
2016-08-12 11:04:27 +00:00
if ( neededInSize = = 0 ) { /* end of frame */
2017-05-23 23:19:43 +00:00
zds - > streamStage = zdss_init ;
2016-08-12 11:04:27 +00:00
someMoreWork = 0 ;
break ;
}
if ( ( size_t ) ( iend - ip ) > = neededInSize ) { /* decode directly from src */
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decompressContinueStream ( zds , & op , oend , ip , neededInSize ) , " " ) ;
2016-08-12 11:04:27 +00:00
ip + = neededInSize ;
2020-04-28 00:42:03 +00:00
/* Function modifies the stage so we must break */
2016-08-12 11:04:27 +00:00
break ;
2017-05-25 00:41:41 +00:00
} }
if ( ip = = iend ) { someMoreWork = 0 ; break ; } /* no more input */
zds - > streamStage = zdss_load ;
2017-08-08 19:32:26 +00:00
/* fall-through */
2018-03-21 00:48:22 +00:00
2016-08-12 11:04:27 +00:00
case zdss_load :
2017-05-23 23:19:43 +00:00
{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress ( zds ) ;
2017-11-01 19:49:51 +00:00
size_t const toLoad = neededInSize - zds - > inPos ;
int const isSkipFrame = ZSTD_isSkipFrame ( zds ) ;
2016-08-12 11:04:27 +00:00
size_t loadedSize ;
2020-01-11 02:02:11 +00:00
/* At this point we shouldn't be decompressing a block that we can stream. */
assert ( neededInSize = = ZSTD_nextSrcSizeToDecompressWithInputSize ( zds , iend - ip ) ) ;
2017-11-01 19:49:51 +00:00
if ( isSkipFrame ) {
loadedSize = MIN ( toLoad , ( size_t ) ( iend - ip ) ) ;
} else {
2019-01-28 17:22:52 +00:00
RETURN_ERROR_IF ( toLoad > zds - > inBuffSize - zds - > inPos ,
corruption_detected ,
" should never happen " ) ;
2017-11-01 19:49:51 +00:00
loadedSize = ZSTD_limitCopy ( zds - > inBuff + zds - > inPos , toLoad , ip , iend - ip ) ;
}
2016-08-12 11:04:27 +00:00
ip + = loadedSize ;
zds - > inPos + = loadedSize ;
if ( loadedSize < toLoad ) { someMoreWork = 0 ; break ; } /* not enough input, wait for more */
/* decode loaded input */
2020-04-28 00:42:03 +00:00
zds - > inPos = 0 ; /* input is consumed */
2020-04-30 16:24:56 +00:00
FORWARD_IF_ERROR ( ZSTD_decompressContinueStream ( zds , & op , oend , zds - > inBuff , neededInSize ) , " " ) ;
2020-04-28 00:42:03 +00:00
/* Function modifies the stage so we must break */
break ;
}
2016-08-12 11:04:27 +00:00
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 */
2017-05-23 23:19:43 +00:00
zds - > streamStage = zdss_read ;
2017-09-09 21:37:28 +00:00
if ( ( zds - > outBuffSize < zds - > fParams . frameContentSize )
& & ( zds - > outStart + zds - > fParams . blockSizeMax > zds - > outBuffSize ) ) {
DEBUGLOG ( 5 , " restart filling outBuff from beginning (left:%i, needed:%u) " ,
( int ) ( zds - > outBuffSize - zds - > outStart ) ,
( U32 ) zds - > fParams . blockSizeMax ) ;
2016-08-12 11:04:27 +00:00
zds - > outStart = zds - > outEnd = 0 ;
2017-09-09 21:37:28 +00:00
}
2016-08-12 11:04:27 +00:00
break ;
2017-05-25 00:41:41 +00:00
} }
/* cannot complete flush */
someMoreWork = 0 ;
break ;
2018-10-29 22:03:57 +00:00
default :
assert ( 0 ) ; /* impossible */
2020-04-30 16:24:56 +00:00
RETURN_ERROR ( GENERIC , " impossible to reach " ) ; /* some compiler require default to do something */
2016-08-12 11:04:27 +00:00
} }
/* result */
error on no forward progress
streaming decoders, such as ZSTD_decompressStream() or ZSTD_decompress_generic(),
may end up making no forward progress,
(aka no byte read from input __and__ no byte written to output),
due to unusual parameters conditions,
such as providing an output buffer already full.
In such case, the caller may be caught in an infinite loop,
calling the streaming decompression function again and again,
without making any progress.
This version detects such situation, and generates an error instead :
ZSTD_error_dstSize_tooSmall when output buffer is full,
ZSTD_error_srcSize_wrong when input buffer is empty.
The detection tolerates a number of attempts before triggering an error,
controlled by ZSTD_NO_FORWARD_PROGRESS_MAX macro constant,
which is set to 16 by default, and can be re-defined at compilation time.
This behavior tolerates potentially existing implementations
where such cases happen sporadically, like once or twice,
which is not dangerous (only infinite loops are),
without generating an error, hence without breaking these implementations.
2018-06-23 00:58:21 +00:00
input - > pos = ( size_t ) ( ip - ( const char * ) ( input - > src ) ) ;
output - > pos = ( size_t ) ( op - ( char * ) ( output - > dst ) ) ;
2020-04-28 00:42:03 +00:00
/* Update the expected output buffer for ZSTD_obm_stable. */
zds - > expectedOutBuffer = * output ;
error on no forward progress
streaming decoders, such as ZSTD_decompressStream() or ZSTD_decompress_generic(),
may end up making no forward progress,
(aka no byte read from input __and__ no byte written to output),
due to unusual parameters conditions,
such as providing an output buffer already full.
In such case, the caller may be caught in an infinite loop,
calling the streaming decompression function again and again,
without making any progress.
This version detects such situation, and generates an error instead :
ZSTD_error_dstSize_tooSmall when output buffer is full,
ZSTD_error_srcSize_wrong when input buffer is empty.
The detection tolerates a number of attempts before triggering an error,
controlled by ZSTD_NO_FORWARD_PROGRESS_MAX macro constant,
which is set to 16 by default, and can be re-defined at compilation time.
This behavior tolerates potentially existing implementations
where such cases happen sporadically, like once or twice,
which is not dangerous (only infinite loops are),
without generating an error, hence without breaking these implementations.
2018-06-23 00:58:21 +00:00
if ( ( ip = = istart ) & & ( op = = ostart ) ) { /* no forward progress */
zds - > noForwardProgress + + ;
if ( zds - > noForwardProgress > = ZSTD_NO_FORWARD_PROGRESS_MAX ) {
2020-04-30 16:24:56 +00:00
RETURN_ERROR_IF ( op = = oend , dstSize_tooSmall , " " ) ;
RETURN_ERROR_IF ( ip = = iend , srcSize_wrong , " " ) ;
error on no forward progress
streaming decoders, such as ZSTD_decompressStream() or ZSTD_decompress_generic(),
may end up making no forward progress,
(aka no byte read from input __and__ no byte written to output),
due to unusual parameters conditions,
such as providing an output buffer already full.
In such case, the caller may be caught in an infinite loop,
calling the streaming decompression function again and again,
without making any progress.
This version detects such situation, and generates an error instead :
ZSTD_error_dstSize_tooSmall when output buffer is full,
ZSTD_error_srcSize_wrong when input buffer is empty.
The detection tolerates a number of attempts before triggering an error,
controlled by ZSTD_NO_FORWARD_PROGRESS_MAX macro constant,
which is set to 16 by default, and can be re-defined at compilation time.
This behavior tolerates potentially existing implementations
where such cases happen sporadically, like once or twice,
which is not dangerous (only infinite loops are),
without generating an error, hence without breaking these implementations.
2018-06-23 00:58:21 +00:00
assert ( 0 ) ;
}
} else {
zds - > noForwardProgress = 0 ;
}
2017-05-23 23:19:43 +00:00
{ size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress ( zds ) ;
2016-09-09 14:44:16 +00:00
if ( ! nextSrcSizeHint ) { /* frame fully decoded */
if ( zds - > outEnd = = zds - > outStart ) { /* output fully flushed */
if ( zds - > hostageByte ) {
2017-05-23 23:19:43 +00:00
if ( input - > pos > = input - > size ) {
/* can't release hostage (not present) */
zds - > streamStage = zdss_read ;
return 1 ;
}
2016-09-09 14:44:16 +00:00
input - > pos + + ; /* release hostage */
2017-05-25 00:41:41 +00:00
} /* zds->hostageByte */
2016-09-09 14:44:16 +00:00
return 0 ;
2017-05-25 00:41:41 +00:00
} /* zds->outEnd == zds->outStart */
2016-09-09 14:44:16 +00:00
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 ;
2017-05-25 00:41:41 +00:00
} /* nextSrcSizeHint==0 */
2017-05-23 23:19:43 +00:00
nextSrcSizeHint + = ZSTD_blockHeaderSize * ( ZSTD_nextInputType ( zds ) = = ZSTDnit_block ) ; /* preload header of next block */
2018-03-20 23:16:13 +00:00
assert ( zds - > inPos < = nextSrcSizeHint ) ;
nextSrcSizeHint - = zds - > inPos ; /* part already loaded*/
2016-08-12 11:04:27 +00:00
return nextSrcSizeHint ;
}
}
2017-09-25 22:41:48 +00:00
2018-12-04 18:28:36 +00:00
size_t ZSTD_decompressStream_simpleArgs (
2017-09-25 22:44:48 +00:00
ZSTD_DCtx * dctx ,
void * dst , size_t dstCapacity , size_t * dstPos ,
const void * src , size_t srcSize , size_t * srcPos )
{
ZSTD_outBuffer output = { dst , dstCapacity , * dstPos } ;
ZSTD_inBuffer input = { src , srcSize , * srcPos } ;
/* ZSTD_compress_generic() will check validity of dstPos and srcPos */
2018-12-04 18:28:36 +00:00
size_t const cErr = ZSTD_decompressStream ( dctx , & output , & input ) ;
2017-09-25 22:44:48 +00:00
* dstPos = output . pos ;
* srcPos = input . pos ;
return cErr ;
}