2015-11-25 13:42:45 +00:00
/*
Buffered version of Zstd compression library
2016-01-28 16:56:33 +00:00
Copyright ( C ) 2015 - 2016 , Yann Collet .
2015-11-25 13:42:45 +00:00
BSD 2 - Clause License ( http : //www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are
met :
* Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the following disclaimer
in the documentation and / or other materials provided with the
distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
You can contact the author at :
- zstd source repository : https : //github.com/Cyan4973/zstd
- ztsd public forum : https : //groups.google.com/forum/#!forum/lz4c
*/
/* The objects defined into this file should be considered experimental.
* They are not labelled stable , as their prototype may change in the future .
* You can use them for tests , provide feedback , or if you can endure risk of future changes .
*/
/* *************************************
2016-02-03 01:46:46 +00:00
* Dependencies
2015-11-25 13:42:45 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdlib.h>
2016-01-21 14:38:47 +00:00
# include "error_private.h"
2016-03-16 14:26:51 +00:00
# include "zstd_internal.h" /* MIN, ZSTD_blockHeaderSize */
# include "zstd_static.h" /* ZSTD_BLOCKSIZE_MAX */
2016-02-12 17:59:11 +00:00
# include "zbuff_static.h"
2015-11-25 13:42:45 +00:00
2016-02-03 01:46:46 +00:00
/* *************************************
* Constants
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-03-16 14:26:51 +00:00
static size_t const ZBUFF_endFrameSize = ZSTD_BLOCKHEADERSIZE ;
2016-02-03 01:46:46 +00:00
2016-03-15 11:56:03 +00:00
/*_**************************************************
2015-11-25 13:42:45 +00:00
* Streaming compression
*
* A ZBUFF_CCtx object is required to track streaming operation .
* Use ZBUFF_createCCtx ( ) and ZBUFF_freeCCtx ( ) to create / release resources .
* Use ZBUFF_compressInit ( ) to start a new compression operation .
* ZBUFF_CCtx objects can be reused multiple times .
*
* Use ZBUFF_compressContinue ( ) repetitively to consume your input .
2016-03-16 14:26:51 +00:00
* * srcSizePtr and * dstCapacityPtr can be any size .
* The function will report how many bytes were read or written by modifying * srcSizePtr and * dstCapacityPtr .
2015-11-25 13:42:45 +00:00
* Note that it may not consume the entire input , in which case it ' s up to the caller to call again the function with remaining input .
2016-03-16 14:26:51 +00:00
* The content of dst will be overwritten ( up to * dstCapacityPtr ) at each function call , so save its content if it matters or change dst .
2015-11-25 13:42:45 +00:00
* @ return : a hint to preferred nb of bytes to use as input for next function call ( it ' s only a hint , to improve latency )
* or an error code , which can be tested using ZBUFF_isError ( ) .
*
* ZBUFF_compressFlush ( ) can be used to instruct ZBUFF to compress and output whatever remains within its buffer .
2016-03-16 14:26:51 +00:00
* Note that it will not output more than * dstCapacityPtr .
2015-11-25 13:42:45 +00:00
* Therefore , some content might still be left into its internal buffer if dst buffer is too small .
* @ return : nb of bytes still present into internal buffer ( 0 if it ' s empty )
* or an error code , which can be tested using ZBUFF_isError ( ) .
*
* ZBUFF_compressEnd ( ) instructs to finish a frame .
* It will perform a flush and write frame epilogue .
2016-03-16 14:26:51 +00:00
* Similar to ZBUFF_compressFlush ( ) , it may not be able to output the entire internal buffer content if * dstCapacityPtr is too small .
2015-11-25 13:42:45 +00:00
* @ return : nb of bytes still present into internal buffer ( 0 if it ' s empty )
* or an error code , which can be tested using ZBUFF_isError ( ) .
*
* Hint : recommended buffer sizes ( not compulsory )
2016-03-16 14:26:51 +00:00
* input : ZSTD_BLOCKSIZE_MAX ( 128 KB ) , internal unit size , it improves latency to use this value .
* output : ZSTD_compressBound ( ZSTD_BLOCKSIZE_MAX ) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it ' s always possible to write / flush / end a full block at best speed .
2015-11-25 13:42:45 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
typedef enum { ZBUFFcs_init , ZBUFFcs_load , ZBUFFcs_flush } ZBUFF_cStage ;
/* *** Ressources *** */
struct ZBUFF_CCtx_s {
ZSTD_CCtx * zc ;
2016-03-15 11:56:03 +00:00
char * inBuff ;
2015-11-25 13:42:45 +00:00
size_t inBuffSize ;
size_t inToCompress ;
size_t inBuffPos ;
size_t inBuffTarget ;
size_t blockSize ;
2016-03-15 11:56:03 +00:00
char * outBuff ;
2015-11-25 13:42:45 +00:00
size_t outBuffSize ;
size_t outBuffContentSize ;
size_t outBuffFlushedSize ;
ZBUFF_cStage stage ;
} ; /* typedef'd tp ZBUFF_CCtx within "zstd_buffered.h" */
ZBUFF_CCtx * ZBUFF_createCCtx ( void )
{
ZBUFF_CCtx * zbc = ( ZBUFF_CCtx * ) malloc ( sizeof ( ZBUFF_CCtx ) ) ;
2015-11-25 14:04:37 +00:00
if ( zbc = = NULL ) return NULL ;
2015-11-25 13:42:45 +00:00
memset ( zbc , 0 , sizeof ( * zbc ) ) ;
zbc - > zc = ZSTD_createCCtx ( ) ;
return zbc ;
}
size_t ZBUFF_freeCCtx ( ZBUFF_CCtx * zbc )
{
if ( zbc = = NULL ) return 0 ; /* support free on NULL */
ZSTD_freeCCtx ( zbc - > zc ) ;
2015-11-25 14:26:55 +00:00
free ( zbc - > inBuff ) ;
free ( zbc - > outBuff ) ;
2015-11-25 13:42:45 +00:00
free ( zbc ) ;
return 0 ;
}
/* *** Initialization *** */
2016-01-26 15:31:22 +00:00
size_t ZBUFF_compressInit_advanced ( ZBUFF_CCtx * zbc , const void * dict , size_t dictSize , ZSTD_parameters params )
2015-11-25 13:42:45 +00:00
{
size_t neededInBuffSize ;
2016-03-30 14:50:44 +00:00
{ size_t const errorCode = ZSTD_checkParams ( params ) ;
if ( ZSTD_isError ( errorCode ) ) return errorCode ; }
ZSTD_adjustParams ( & params , 0 , dictSize ) ;
2015-11-25 13:42:45 +00:00
neededInBuffSize = ( size_t ) 1 < < params . windowLog ;
/* allocate buffers */
2016-01-28 16:56:33 +00:00
if ( zbc - > inBuffSize < neededInBuffSize ) {
2015-11-25 13:42:45 +00:00
zbc - > inBuffSize = neededInBuffSize ;
free ( zbc - > inBuff ) ; /* should not be necessary */
zbc - > inBuff = ( char * ) malloc ( neededInBuffSize ) ;
if ( zbc - > inBuff = = NULL ) return ERROR ( memory_allocation ) ;
}
2016-03-16 14:26:51 +00:00
zbc - > blockSize = MIN ( ZSTD_BLOCKSIZE_MAX , zbc - > inBuffSize ) ;
2016-01-28 16:56:33 +00:00
if ( zbc - > outBuffSize < ZSTD_compressBound ( zbc - > blockSize ) + 1 ) {
2015-11-25 13:42:45 +00:00
zbc - > outBuffSize = ZSTD_compressBound ( zbc - > blockSize ) + 1 ;
free ( zbc - > outBuff ) ; /* should not be necessary */
zbc - > outBuff = ( char * ) malloc ( zbc - > outBuffSize ) ;
if ( zbc - > outBuff = = NULL ) return ERROR ( memory_allocation ) ;
}
2016-01-26 15:31:22 +00:00
zbc - > outBuffContentSize = ZSTD_compressBegin_advanced ( zbc - > zc , dict , dictSize , params ) ;
2015-11-25 13:42:45 +00:00
if ( ZSTD_isError ( zbc - > outBuffContentSize ) ) return zbc - > outBuffContentSize ;
zbc - > inToCompress = 0 ;
zbc - > inBuffPos = 0 ;
zbc - > inBuffTarget = zbc - > blockSize ;
zbc - > outBuffFlushedSize = 0 ;
zbc - > stage = ZBUFFcs_flush ; /* starts by flushing the header */
return 0 ; /* ready to go */
}
2016-03-30 14:50:44 +00:00
2015-11-25 13:42:45 +00:00
size_t ZBUFF_compressInit ( ZBUFF_CCtx * zbc , int compressionLevel )
{
2016-01-26 15:31:22 +00:00
return ZBUFF_compressInit_advanced ( zbc , NULL , 0 , ZSTD_getParams ( compressionLevel , 0 ) ) ;
2015-11-25 13:42:45 +00:00
}
2016-01-26 15:31:22 +00:00
ZSTDLIB_API size_t ZBUFF_compressInitDictionary ( ZBUFF_CCtx * zbc , const void * dict , size_t dictSize , int compressionLevel )
2015-12-12 10:17:42 +00:00
{
2016-01-26 15:31:22 +00:00
return ZBUFF_compressInit_advanced ( zbc , dict , dictSize , ZSTD_getParams ( compressionLevel , 0 ) ) ;
2015-12-12 10:17:42 +00:00
}
2015-11-25 13:42:45 +00:00
/* *** Compression *** */
2016-03-15 11:56:03 +00:00
static size_t ZBUFF_limitCopy ( void * dst , size_t dstCapacity , const void * src , size_t srcSize )
2015-11-25 13:42:45 +00:00
{
2016-03-15 11:56:03 +00:00
size_t length = MIN ( dstCapacity , srcSize ) ;
2015-11-25 13:42:45 +00:00
memcpy ( dst , src , length ) ;
return length ;
}
static size_t ZBUFF_compressContinue_generic ( ZBUFF_CCtx * zbc ,
2016-03-16 14:26:51 +00:00
void * dst , size_t * dstCapacityPtr ,
2015-11-25 13:42:45 +00:00
const void * src , size_t * srcSizePtr ,
int flush ) /* aggregate : wait for full block before compressing */
{
U32 notDone = 1 ;
const char * const istart = ( const char * ) src ;
const char * ip = istart ;
const char * const iend = istart + * srcSizePtr ;
char * const ostart = ( char * ) dst ;
char * op = ostart ;
2016-03-16 14:26:51 +00:00
char * const oend = ostart + * dstCapacityPtr ;
2015-11-25 13:42:45 +00:00
2016-01-28 16:56:33 +00:00
while ( notDone ) {
2015-11-25 13:42:45 +00:00
switch ( zbc - > stage )
{
case ZBUFFcs_init : return ERROR ( init_missing ) ; /* call ZBUFF_compressInit() first ! */
case ZBUFFcs_load :
/* complete inBuffer */
{
size_t toLoad = zbc - > inBuffTarget - zbc - > inBuffPos ;
size_t loaded = ZBUFF_limitCopy ( zbc - > inBuff + zbc - > inBuffPos , toLoad , ip , iend - ip ) ;
zbc - > inBuffPos + = loaded ;
ip + = loaded ;
2016-01-28 16:56:33 +00:00
if ( ( zbc - > inBuffPos = = zbc - > inToCompress ) | | ( ! flush & & ( toLoad ! = loaded ) ) ) {
notDone = 0 ; break ; /* not enough input to get a full block : stop there, wait for more */
} }
2015-11-25 13:42:45 +00:00
/* compress current block (note : this stage cannot be stopped in the middle) */
{
void * cDst ;
size_t cSize ;
size_t iSize = zbc - > inBuffPos - zbc - > inToCompress ;
2015-11-27 13:07:36 +00:00
size_t oSize = oend - op ;
if ( oSize > = ZSTD_compressBound ( iSize ) )
2015-11-25 13:42:45 +00:00
cDst = op ; /* compress directly into output buffer (avoid flush stage) */
else
2015-11-27 13:07:36 +00:00
cDst = zbc - > outBuff , oSize = zbc - > outBuffSize ;
cSize = ZSTD_compressContinue ( zbc - > zc , cDst , oSize , zbc - > inBuff + zbc - > inToCompress , iSize ) ;
2015-11-25 13:42:45 +00:00
if ( ZSTD_isError ( cSize ) ) return cSize ;
/* prepare next block */
zbc - > inBuffTarget = zbc - > inBuffPos + zbc - > blockSize ;
if ( zbc - > inBuffTarget > zbc - > inBuffSize )
2015-11-26 10:43:00 +00:00
{ zbc - > inBuffPos = 0 ; zbc - > inBuffTarget = zbc - > blockSize ; } /* note : inBuffSize >= blockSize */
2015-11-25 13:42:45 +00:00
zbc - > inToCompress = zbc - > inBuffPos ;
if ( cDst = = op ) { op + = cSize ; break ; } /* no need to flush */
zbc - > outBuffContentSize = cSize ;
zbc - > outBuffFlushedSize = 0 ;
zbc - > stage = ZBUFFcs_flush ;
// break; /* flush stage follows */
}
case ZBUFFcs_flush :
/* flush into dst */
{
size_t toFlush = zbc - > outBuffContentSize - zbc - > outBuffFlushedSize ;
size_t flushed = ZBUFF_limitCopy ( op , oend - op , zbc - > outBuff + zbc - > outBuffFlushedSize , toFlush ) ;
op + = flushed ;
zbc - > outBuffFlushedSize + = flushed ;
2016-01-28 16:56:33 +00:00
if ( toFlush ! = flushed ) { notDone = 0 ; break ; } /* not enough space within dst to store compressed block : stop there */
2015-11-25 13:42:45 +00:00
zbc - > outBuffContentSize = 0 ;
zbc - > outBuffFlushedSize = 0 ;
zbc - > stage = ZBUFFcs_load ;
break ;
}
2016-01-21 14:38:47 +00:00
default :
return ERROR ( GENERIC ) ; /* impossible */
2015-11-25 13:42:45 +00:00
}
}
* srcSizePtr = ip - istart ;
2016-03-16 14:26:51 +00:00
* dstCapacityPtr = op - ostart ;
2015-11-25 13:42:45 +00:00
{
size_t hintInSize = zbc - > inBuffTarget - zbc - > inBuffPos ;
if ( hintInSize = = 0 ) hintInSize = zbc - > blockSize ;
return hintInSize ;
}
}
size_t ZBUFF_compressContinue ( ZBUFF_CCtx * zbc ,
2016-03-16 14:26:51 +00:00
void * dst , size_t * dstCapacityPtr ,
2015-11-25 13:42:45 +00:00
const void * src , size_t * srcSizePtr )
2016-01-28 16:56:33 +00:00
{
2016-03-16 14:26:51 +00:00
return ZBUFF_compressContinue_generic ( zbc , dst , dstCapacityPtr , src , srcSizePtr , 0 ) ;
2016-01-28 16:56:33 +00:00
}
2015-11-25 13:42:45 +00:00
/* *** Finalize *** */
2016-03-16 14:26:51 +00:00
size_t ZBUFF_compressFlush ( ZBUFF_CCtx * zbc , void * dst , size_t * dstCapacityPtr )
2015-11-25 13:42:45 +00:00
{
size_t srcSize = 0 ;
2016-03-16 14:26:51 +00:00
ZBUFF_compressContinue_generic ( zbc , dst , dstCapacityPtr , & srcSize , & srcSize , 1 ) ; /* use a valid src address instead of NULL, as some sanitizer don't like it */
2015-11-25 13:42:45 +00:00
return zbc - > outBuffContentSize - zbc - > outBuffFlushedSize ;
}
2016-03-16 14:26:51 +00:00
size_t ZBUFF_compressEnd ( ZBUFF_CCtx * zbc , void * dst , size_t * dstCapacityPtr )
2015-11-25 13:42:45 +00:00
{
BYTE * const ostart = ( BYTE * ) dst ;
BYTE * op = ostart ;
2016-03-16 14:26:51 +00:00
BYTE * const oend = ostart + * dstCapacityPtr ;
size_t outSize = * dstCapacityPtr ;
2015-11-25 13:42:45 +00:00
size_t epilogueSize , remaining ;
ZBUFF_compressFlush ( zbc , dst , & outSize ) ; /* flush any remaining inBuff */
op + = outSize ;
epilogueSize = ZSTD_compressEnd ( zbc - > zc , zbc - > outBuff + zbc - > outBuffContentSize , zbc - > outBuffSize - zbc - > outBuffContentSize ) ; /* epilogue into outBuff */
zbc - > outBuffContentSize + = epilogueSize ;
outSize = oend - op ;
zbc - > stage = ZBUFFcs_flush ;
remaining = ZBUFF_compressFlush ( zbc , op , & outSize ) ; /* attempt to flush epilogue into dst */
op + = outSize ;
if ( ! remaining ) zbc - > stage = ZBUFFcs_init ; /* close only if nothing left to flush */
2016-03-16 14:26:51 +00:00
* dstCapacityPtr = op - ostart ; /* tells how many bytes were written */
2015-11-25 13:42:45 +00:00
return remaining ;
}
2016-03-11 20:58:04 +00:00
/*-***************************************************************************
* Streaming decompression howto
2015-11-25 13:42:45 +00:00
*
2016-03-11 20:58:04 +00:00
* A ZBUFF_DCtx object is required to track streaming operations .
2015-11-25 13:42:45 +00:00
* Use ZBUFF_createDCtx ( ) and ZBUFF_freeDCtx ( ) to create / release resources .
2016-03-11 20:58:04 +00:00
* Use ZBUFF_decompressInit ( ) to start a new decompression operation ,
* or ZBUFF_decompressInitDictionary ( ) if decompression requires a dictionary .
* Note that ZBUFF_DCtx objects can be re - init multiple times .
2015-11-25 13:42:45 +00:00
*
* Use ZBUFF_decompressContinue ( ) repetitively to consume your input .
2016-03-11 20:58:04 +00:00
* * srcSizePtr and * dstCapacityPtr can be any size .
* The function will report how many bytes were read or written by modifying * srcSizePtr and * dstCapacityPtr .
* Note that it may not consume the entire input , in which case it ' s up to the caller to present remaining input again .
* The content of @ dst will be overwritten ( up to * dstCapacityPtr ) at each function call , so save its content if it matters , or change @ dst .
* @ return : a hint to preferred nb of bytes to use as input for next function call ( it ' s only a hint , to help latency ) ,
* or 0 when a frame is completely decoded ,
2015-11-25 13:42:45 +00:00
* or an error code , which can be tested using ZBUFF_isError ( ) .
*
2016-03-11 20:58:04 +00:00
* Hint : recommended buffer sizes ( not compulsory ) : ZBUFF_recommendedDInSize ( ) and ZBUFF_recommendedDOutSize ( )
* output : ZBUFF_recommendedDOutSize = = 128 KB block size is the internal unit , it ensures it ' s always possible to write a full block when decoded .
* input : ZBUFF_recommendedDInSize = = 128 KB + 3 ;
* just follow indications from ZBUFF_decompressContinue ( ) to minimize latency . It should always be < = 128 KB + 3 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-11-25 13:42:45 +00:00
2016-03-15 11:56:03 +00:00
typedef enum { ZBUFFds_init , ZBUFFds_readHeader ,
2015-11-25 13:42:45 +00:00
ZBUFFds_read , ZBUFFds_load , ZBUFFds_flush } ZBUFF_dStage ;
/* *** Resource management *** */
struct ZBUFF_DCtx_s {
ZSTD_DCtx * zc ;
2016-03-11 20:58:04 +00:00
ZSTD_frameParams fParams ;
2015-11-25 13:42:45 +00:00
char * inBuff ;
size_t inBuffSize ;
size_t inPos ;
char * outBuff ;
size_t outBuffSize ;
size_t outStart ;
size_t outEnd ;
ZBUFF_dStage stage ;
} ; /* typedef'd to ZBUFF_DCtx within "zstd_buffered.h" */
ZBUFF_DCtx * ZBUFF_createDCtx ( void )
{
ZBUFF_DCtx * zbc = ( ZBUFF_DCtx * ) malloc ( sizeof ( ZBUFF_DCtx ) ) ;
2015-11-25 14:02:46 +00:00
if ( zbc = = NULL ) return NULL ;
2015-11-25 13:42:45 +00:00
memset ( zbc , 0 , sizeof ( * zbc ) ) ;
zbc - > zc = ZSTD_createDCtx ( ) ;
zbc - > stage = ZBUFFds_init ;
return zbc ;
}
size_t ZBUFF_freeDCtx ( ZBUFF_DCtx * zbc )
{
if ( zbc = = NULL ) return 0 ; /* support free on null */
ZSTD_freeDCtx ( zbc - > zc ) ;
2015-11-26 11:43:28 +00:00
free ( zbc - > inBuff ) ;
free ( zbc - > outBuff ) ;
2015-11-25 13:42:45 +00:00
free ( zbc ) ;
return 0 ;
}
/* *** Initialization *** */
2016-01-26 14:58:49 +00:00
size_t ZBUFF_decompressInitDictionary ( ZBUFF_DCtx * zbc , const void * dict , size_t dictSize )
2015-11-25 13:42:45 +00:00
{
zbc - > stage = ZBUFFds_readHeader ;
2016-03-15 11:56:03 +00:00
zbc - > inPos = zbc - > outStart = zbc - > outEnd = 0 ;
2016-01-26 14:58:49 +00:00
return ZSTD_decompressBegin_usingDict ( zbc - > zc , dict , dictSize ) ;
2015-11-25 13:42:45 +00:00
}
2016-01-26 14:58:49 +00:00
size_t ZBUFF_decompressInit ( ZBUFF_DCtx * zbc )
2015-12-12 10:17:42 +00:00
{
2016-01-26 14:58:49 +00:00
return ZBUFF_decompressInitDictionary ( zbc , NULL , 0 ) ;
2015-12-12 10:17:42 +00:00
}
2015-11-25 13:42:45 +00:00
/* *** Decompression *** */
2016-03-11 20:58:04 +00:00
size_t ZBUFF_decompressContinue ( ZBUFF_DCtx * zbc ,
void * dst , size_t * dstCapacityPtr ,
const void * src , size_t * srcSizePtr )
2015-11-25 13:42:45 +00:00
{
const char * const istart = ( const char * ) src ;
const char * ip = istart ;
const char * const iend = istart + * srcSizePtr ;
char * const ostart = ( char * ) dst ;
char * op = ostart ;
2016-03-11 20:58:04 +00:00
char * const oend = ostart + * dstCapacityPtr ;
2015-11-25 13:42:45 +00:00
U32 notDone = 1 ;
2016-01-28 16:56:33 +00:00
while ( notDone ) {
2015-11-25 13:42:45 +00:00
switch ( zbc - > stage )
{
case ZBUFFds_init :
return ERROR ( init_missing ) ;
case ZBUFFds_readHeader :
/* read header from src */
2016-03-15 11:56:03 +00:00
{ size_t const headerSize = ZSTD_getFrameParams ( & ( zbc - > fParams ) , src , * srcSizePtr ) ;
2015-11-25 13:42:45 +00:00
if ( ZSTD_isError ( headerSize ) ) return headerSize ;
2016-01-28 16:56:33 +00:00
if ( headerSize ) {
2016-03-15 11:56:03 +00:00
/* not enough input to decode header : needs headerSize > *srcSizePtr */
2016-03-11 20:58:04 +00:00
* dstCapacityPtr = 0 ;
2016-03-15 11:56:03 +00:00
* srcSizePtr = 0 ;
return headerSize ;
} }
2015-11-25 13:42:45 +00:00
2016-03-15 11:56:03 +00:00
/* Frame header provides buffer sizes */
2016-03-16 14:26:51 +00:00
{ size_t const neededInSize = ZSTD_BLOCKSIZE_MAX ; /* a block is never > ZSTD_BLOCKSIZE_MAX */
2016-03-15 11:56:03 +00:00
if ( zbc - > inBuffSize < neededInSize ) {
free ( zbc - > inBuff ) ;
zbc - > inBuffSize = neededInSize ;
zbc - > inBuff = ( char * ) malloc ( neededInSize ) ;
if ( zbc - > inBuff = = NULL ) return ERROR ( memory_allocation ) ;
} }
2015-11-25 13:42:45 +00:00
{
2016-03-15 11:56:03 +00:00
size_t const neededOutSize = ( size_t ) 1 < < zbc - > fParams . windowLog ;
if ( zbc - > outBuffSize < neededOutSize ) {
free ( zbc - > outBuff ) ;
zbc - > outBuffSize = neededOutSize ;
zbc - > outBuff = ( char * ) malloc ( neededOutSize ) ;
if ( zbc - > outBuff = = NULL ) return ERROR ( memory_allocation ) ;
} }
zbc - > stage = ZBUFFds_read ;
2015-11-25 13:42:45 +00:00
case ZBUFFds_read :
{
2016-03-15 11:56:03 +00:00
size_t const neededInSize = ZSTD_nextSrcSizeToDecompress ( zbc - > zc ) ;
2016-01-28 16:56:33 +00:00
if ( neededInSize = = 0 ) { /* end of frame */
2015-11-25 13:42:45 +00:00
zbc - > stage = ZBUFFds_init ;
notDone = 0 ;
break ;
}
2016-01-28 16:56:33 +00:00
if ( ( size_t ) ( iend - ip ) > = neededInSize ) {
2015-11-25 13:42:45 +00:00
/* directly decode from src */
2016-03-15 11:56:03 +00:00
size_t const decodedSize = ZSTD_decompressContinue ( zbc - > zc ,
2015-11-25 13:42:45 +00:00
zbc - > outBuff + zbc - > outStart , zbc - > outBuffSize - zbc - > outStart ,
ip , neededInSize ) ;
if ( ZSTD_isError ( decodedSize ) ) return decodedSize ;
ip + = neededInSize ;
if ( ! decodedSize ) break ; /* this was just a header */
zbc - > outEnd = zbc - > outStart + decodedSize ;
zbc - > stage = ZBUFFds_flush ;
break ;
}
if ( ip = = iend ) { notDone = 0 ; break ; } /* no more input */
zbc - > stage = ZBUFFds_load ;
}
case ZBUFFds_load :
{
2016-03-15 11:56:03 +00:00
size_t const neededInSize = ZSTD_nextSrcSizeToDecompress ( zbc - > zc ) ;
size_t const toLoad = neededInSize - zbc - > inPos ; /* should always be <= remaining space within inBuff */
2015-11-25 13:42:45 +00:00
size_t loadedSize ;
if ( toLoad > zbc - > inBuffSize - zbc - > inPos ) return ERROR ( corruption_detected ) ; /* should never happen */
2015-11-26 09:32:17 +00:00
loadedSize = ZBUFF_limitCopy ( zbc - > inBuff + zbc - > inPos , toLoad , ip , iend - ip ) ;
2015-11-25 13:42:45 +00:00
ip + = loadedSize ;
zbc - > inPos + = loadedSize ;
if ( loadedSize < toLoad ) { notDone = 0 ; break ; } /* not enough input, wait for more */
{
2016-03-15 11:56:03 +00:00
size_t const decodedSize = ZSTD_decompressContinue ( zbc - > zc ,
2015-11-25 13:42:45 +00:00
zbc - > outBuff + zbc - > outStart , zbc - > outBuffSize - zbc - > outStart ,
zbc - > inBuff , neededInSize ) ;
if ( ZSTD_isError ( decodedSize ) ) return decodedSize ;
zbc - > inPos = 0 ; /* input is consumed */
if ( ! decodedSize ) { zbc - > stage = ZBUFFds_read ; break ; } /* this was just a header */
zbc - > outEnd = zbc - > outStart + decodedSize ;
zbc - > stage = ZBUFFds_flush ;
// break; /* ZBUFFds_flush follows */
2016-01-28 16:56:33 +00:00
} }
2015-11-25 13:42:45 +00:00
case ZBUFFds_flush :
{
2016-03-15 11:56:03 +00:00
size_t const toFlushSize = zbc - > outEnd - zbc - > outStart ;
size_t const flushedSize = ZBUFF_limitCopy ( op , oend - op , zbc - > outBuff + zbc - > outStart , toFlushSize ) ;
2015-11-25 13:42:45 +00:00
op + = flushedSize ;
zbc - > outStart + = flushedSize ;
2016-01-28 16:56:33 +00:00
if ( flushedSize = = toFlushSize ) {
2015-11-25 13:42:45 +00:00
zbc - > stage = ZBUFFds_read ;
2016-03-16 14:26:51 +00:00
if ( zbc - > outStart + ZSTD_BLOCKSIZE_MAX > zbc - > outBuffSize )
2015-11-25 13:42:45 +00:00
zbc - > outStart = zbc - > outEnd = 0 ;
2015-11-26 21:39:29 +00:00
break ;
2015-11-25 13:42:45 +00:00
}
2015-11-26 21:39:29 +00:00
/* cannot flush everything */
notDone = 0 ;
2015-11-25 13:42:45 +00:00
break ;
}
2016-01-21 14:38:47 +00:00
default : return ERROR ( GENERIC ) ; /* impossible */
2016-01-28 16:56:33 +00:00
} }
2015-11-25 13:42:45 +00:00
2016-03-15 11:56:03 +00:00
/* result */
2015-11-25 13:42:45 +00:00
* srcSizePtr = ip - istart ;
2016-03-11 20:58:04 +00:00
* dstCapacityPtr = op - ostart ;
2015-11-27 12:26:38 +00:00
{
size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress ( zbc - > zc ) ;
2016-03-16 14:26:51 +00:00
if ( nextSrcSizeHint > ZSTD_blockHeaderSize ) nextSrcSizeHint + = ZSTD_blockHeaderSize ; /* get following block header too */
2015-11-27 12:26:38 +00:00
nextSrcSizeHint - = zbc - > inPos ; /* already loaded*/
return nextSrcSizeHint ;
}
2015-11-25 13:42:45 +00:00
}
/* *************************************
* Tool functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
unsigned ZBUFF_isError ( size_t errorCode ) { return ERR_isError ( errorCode ) ; }
const char * ZBUFF_getErrorName ( size_t errorCode ) { return ERR_getErrorName ( errorCode ) ; }
2016-03-16 14:26:51 +00:00
size_t ZBUFF_recommendedCInSize ( void ) { return ZSTD_BLOCKSIZE_MAX ; }
size_t ZBUFF_recommendedCOutSize ( void ) { return ZSTD_compressBound ( ZSTD_BLOCKSIZE_MAX ) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize ; }
size_t ZBUFF_recommendedDInSize ( void ) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize /* block header size*/ ; }
size_t ZBUFF_recommendedDOutSize ( void ) { return ZSTD_BLOCKSIZE_MAX ; }