2014-08-29 15:35:13 +00:00
/*
LZ4 auto - framing library
Copyright ( C ) 2011 - 2014 , Yann Collet .
BSD 2 - Clause License ( http : //www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are
met :
* Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the following disclaimer
in the documentation and / or other materials provided with the
distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
You can contact the author at :
- LZ4 source repository : http : //code.google.com/p/lz4/
- LZ4 public forum : https : //groups.google.com/forum/#!forum/lz4c
*/
/* LZ4F is a stand-alone API to create LZ4-compressed frames
* fully conformant to specification v1 .4 .1 .
* All related operations , including memory management , are handled by the library .
* You don ' t need lz4 . h when using lz4frame . h .
* */
/**************************************
Compiler Options
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef _MSC_VER /* Visual Studio */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
# endif
# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
2014-08-30 17:14:44 +00:00
# ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
# endif
2014-08-29 15:35:13 +00:00
/**************************************
Memory routines
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdlib.h> /* malloc, calloc, free */
2014-09-03 18:49:59 +00:00
# define ALLOCATOR(s) calloc(1,s)
2014-08-29 15:35:13 +00:00
# define FREEMEM free
2014-09-10 21:17:03 +00:00
# include <string.h> /* memset, memcpy, memmove */
2014-08-29 15:35:13 +00:00
# define MEM_INIT memset
/**************************************
Includes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "lz4frame.h"
# include "lz4.h"
# include "lz4hc.h"
# include "xxhash.h"
/**************************************
Basic Types
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
# include <stdint.h>
typedef uint8_t BYTE ;
typedef uint16_t U16 ;
typedef uint32_t U32 ;
typedef int32_t S32 ;
typedef uint64_t U64 ;
# else
typedef unsigned char BYTE ;
typedef unsigned short U16 ;
typedef unsigned int U32 ;
typedef signed int S32 ;
typedef unsigned long long U64 ;
# endif
/**************************************
Constants
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define KB *(1<<10)
# define MB *(1<<20)
# define GB *(1<<30)
2014-08-30 17:14:44 +00:00
# define _1BIT 0x01
# define _2BITS 0x03
# define _3BITS 0x07
# define _4BITS 0x0F
# define _8BITS 0xFF
# define LZ4F_MAGICNUMBER 0x184D2204U
# define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U
2014-09-05 15:32:04 +00:00
# define LZ4F_MAXHEADERFRAME_SIZE 7
2014-08-29 15:38:26 +00:00
# define LZ4F_BLOCKSIZEID_DEFAULT 4
2014-08-29 15:35:13 +00:00
/**************************************
Structures and local types
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-08-30 17:14:44 +00:00
typedef struct {
LZ4F_preferences_t prefs ;
unsigned version ;
unsigned cStage ;
size_t maxBlockSize ;
2014-09-07 11:57:09 +00:00
size_t maxBufferSize ;
2014-09-09 22:54:22 +00:00
BYTE * tmpBuff ;
BYTE * tmpIn ;
2014-09-03 18:49:59 +00:00
size_t tmpInSize ;
2014-09-09 22:54:22 +00:00
XXH32_stateSpace_t xxh ;
LZ4_stream_t lz4ctx ;
2014-08-30 17:14:44 +00:00
} LZ4F_cctx_internal_t ;
2014-08-29 15:35:13 +00:00
2014-09-05 14:50:06 +00:00
typedef struct {
LZ4F_frameInfo_t frameInfo ;
unsigned version ;
unsigned dStage ;
size_t maxBlockSize ;
2014-09-09 22:54:22 +00:00
size_t maxBufferSize ;
2014-09-05 14:50:06 +00:00
size_t sizeToDecode ;
const BYTE * srcExpect ;
BYTE * tmpIn ;
size_t tmpInSize ;
size_t tmpInTarget ;
2014-09-09 22:54:22 +00:00
BYTE * tmpOutBuffer ;
BYTE * dict ;
size_t dictSize ;
2014-09-05 14:50:06 +00:00
BYTE * tmpOut ;
size_t tmpOutSize ;
size_t tmpOutStart ;
2014-09-09 22:54:22 +00:00
XXH32_stateSpace_t xxh ;
BYTE header [ 8 ] ;
2014-09-05 14:50:06 +00:00
} LZ4F_dctx_internal_t ;
2014-08-29 15:35:13 +00:00
/**************************************
Macros
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**************************************
Private functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static size_t LZ4F_getBlockSize ( unsigned blockSizeID )
{
static const size_t blockSizes [ 4 ] = { 64 KB , 256 KB , 1 MB , 4 MB } ;
2014-08-30 17:14:44 +00:00
2014-08-29 15:38:26 +00:00
if ( blockSizeID = = 0 ) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT ;
2014-08-29 15:35:13 +00:00
blockSizeID - = 4 ;
2014-08-30 17:14:44 +00:00
if ( blockSizeID > 3 ) return - ERROR_maxBlockSize_invalid ;
2014-08-29 15:35:13 +00:00
return blockSizes [ blockSizeID ] ;
}
2014-08-30 17:14:44 +00:00
/* unoptimized version; solves endianess & alignment issues */
static void LZ4F_writeLE32 ( BYTE * dstPtr , U32 value32 )
{
dstPtr [ 0 ] = ( BYTE ) value32 ;
dstPtr [ 1 ] = ( BYTE ) ( value32 > > 8 ) ;
dstPtr [ 2 ] = ( BYTE ) ( value32 > > 16 ) ;
dstPtr [ 3 ] = ( BYTE ) ( value32 > > 24 ) ;
}
2014-09-01 21:44:02 +00:00
static U32 LZ4F_readLE32 ( const BYTE * srcPtr )
{
U32 value32 = srcPtr [ 0 ] ;
value32 + = ( srcPtr [ 1 ] < < 8 ) ;
value32 + = ( srcPtr [ 2 ] < < 16 ) ;
value32 + = ( srcPtr [ 3 ] < < 24 ) ;
return value32 ;
}
2014-08-30 17:14:44 +00:00
2014-09-01 21:44:02 +00:00
static BYTE LZ4F_headerChecksum ( const BYTE * header , size_t length )
2014-08-30 17:14:44 +00:00
{
U32 xxh = XXH32 ( header , length , 0 ) ;
return ( BYTE ) ( xxh > > 8 ) ;
}
2014-08-29 15:35:13 +00:00
/**************************************
Error management
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int LZ4F_isError ( LZ4F_errorCode_t code )
{
return ( code > ( LZ4F_errorCode_t ) ( - ERROR_maxCode ) ) ;
}
/**************************************
2014-08-30 17:14:44 +00:00
Simple compression functions
2014-08-29 15:35:13 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
size_t LZ4F_compressFrameBound ( size_t srcSize , const LZ4F_frameInfo_t * frameInfoPtr )
{
2014-09-10 21:17:03 +00:00
LZ4F_preferences_t prefs = { 0 } ;
2014-08-29 15:35:13 +00:00
size_t headerSize ;
2014-09-10 21:17:03 +00:00
size_t streamSize ;
2014-08-30 17:14:44 +00:00
2014-09-10 21:17:03 +00:00
if ( frameInfoPtr ! = NULL ) prefs . frameInfo = * frameInfoPtr ;
2014-08-30 17:14:44 +00:00
2014-08-29 15:35:13 +00:00
headerSize = 7 ; /* basic header size (no option) including magic number */
2014-09-10 21:17:03 +00:00
streamSize = LZ4F_compressBound ( srcSize , & prefs ) ;
2014-08-30 17:14:44 +00:00
2014-09-10 21:17:03 +00:00
return headerSize + streamSize ;
2014-08-29 15:35:13 +00:00
}
/* LZ4F_compressFrame()
* Compress an entire srcBuffer into a valid LZ4 frame , as defined by specification v1 .4 .1 , in a single step .
* The most important rule is that dstBuffer MUST be large enough ( dstMaxSize ) to ensure compression completion even in worst case .
* You can get the minimum value of dstMaxSize by using LZ4F_compressFrameBound ( )
* If this condition is not respected , LZ4F_compressFrame ( ) will fail ( result is an errorCode )
* The LZ4F_preferences_t structure is optional : you can provide NULL as argument . All preferences will be set to default .
* The result of the function is the number of bytes written into dstBuffer .
* The function outputs an error code if it fails ( can be tested using LZ4F_isError ( ) )
*/
size_t LZ4F_compressFrame ( void * dstBuffer , size_t dstMaxSize , const void * srcBuffer , size_t srcSize , const LZ4F_preferences_t * preferencesPtr )
{
const LZ4F_frameInfo_t frameInfoNull = { 0 } ;
const LZ4F_frameInfo_t * const frameInfoPtr = ( preferencesPtr = = NULL ) ? & frameInfoNull : & ( preferencesPtr - > frameInfo ) ;
2014-08-30 17:14:44 +00:00
LZ4F_compressionContext_t cctx = NULL ;
2014-08-29 15:35:13 +00:00
LZ4F_errorCode_t errorCode ;
BYTE * const dstStart = ( BYTE * ) dstBuffer ;
BYTE * dstPtr = dstStart ;
2014-09-10 21:17:03 +00:00
BYTE * const dstEnd = dstStart + dstMaxSize ;
2014-08-30 17:14:44 +00:00
2014-08-29 15:35:13 +00:00
if ( dstMaxSize < LZ4F_compressFrameBound ( srcSize , frameInfoPtr ) )
2014-08-30 17:14:44 +00:00
return - ERROR_dstMaxSize_tooSmall ;
2014-09-07 11:57:09 +00:00
errorCode = LZ4F_createCompressionContext ( & cctx , LZ4F_VERSION ) ;
2014-08-29 15:35:13 +00:00
if ( LZ4F_isError ( errorCode ) ) return errorCode ;
2014-08-30 17:14:44 +00:00
2014-09-07 11:57:09 +00:00
errorCode = LZ4F_compressBegin ( cctx , dstBuffer , dstMaxSize , preferencesPtr ) ; /* write header */
2014-08-29 15:35:13 +00:00
if ( LZ4F_isError ( errorCode ) ) return errorCode ;
dstPtr + = errorCode ; /* header size */
2014-08-30 17:14:44 +00:00
2014-09-10 21:17:03 +00:00
dstMaxSize - = errorCode ;
errorCode = LZ4F_compress ( cctx , dstPtr , dstMaxSize , srcBuffer , srcSize , NULL ) ;
if ( LZ4F_isError ( errorCode ) ) return errorCode ;
dstPtr + = errorCode ;
2014-08-30 17:14:44 +00:00
2014-09-10 21:17:03 +00:00
errorCode = LZ4F_compressEnd ( cctx , dstPtr , dstEnd - dstPtr , NULL ) ; /* flush last block, and generate suffix */
2014-08-29 15:35:13 +00:00
if ( LZ4F_isError ( errorCode ) ) return errorCode ;
dstPtr + = errorCode ;
errorCode = LZ4F_freeCompressionContext ( cctx ) ;
if ( LZ4F_isError ( errorCode ) ) return errorCode ;
return ( dstPtr - dstStart ) ;
}
2014-08-30 17:14:44 +00:00
2014-09-03 18:49:59 +00:00
/***********************************
2014-08-30 17:14:44 +00:00
* Advanced compression functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* LZ4F_createCompressionContext() :
* The first thing to do is to create a compressionContext object , which will be used in all compression operations .
* This is achieved using LZ4F_createCompressionContext ( ) , which takes as argument a version and an LZ4F_preferences_t structure .
* The version provided MUST be LZ4F_VERSION . It is intended to track potential version differences between different binaries .
2014-09-07 11:57:09 +00:00
* The function will provide a pointer to an allocated LZ4F_compressionContext_t object .
* If the result LZ4F_errorCode_t is not OK_NoError , there was an error during context creation .
2014-08-30 17:14:44 +00:00
* Object can release its memory using LZ4F_freeCompressionContext ( ) ;
*/
2014-09-07 11:57:09 +00:00
LZ4F_errorCode_t LZ4F_createCompressionContext ( LZ4F_compressionContext_t * LZ4F_compressionContextPtr , unsigned version )
2014-08-30 17:14:44 +00:00
{
LZ4F_cctx_internal_t * cctxPtr ;
2014-09-03 18:49:59 +00:00
cctxPtr = ALLOCATOR ( sizeof ( LZ4F_cctx_internal_t ) ) ;
2014-08-30 17:14:44 +00:00
if ( cctxPtr = = NULL ) return - ERROR_allocation_failed ;
cctxPtr - > version = version ;
cctxPtr - > cStage = 0 ; /* Next stage : write header */
* LZ4F_compressionContextPtr = ( LZ4F_compressionContext_t ) cctxPtr ;
return OK_NoError ;
}
LZ4F_errorCode_t LZ4F_freeCompressionContext ( LZ4F_compressionContext_t LZ4F_compressionContext )
{
LZ4F_cctx_internal_t * cctxPtr = ( LZ4F_cctx_internal_t * ) LZ4F_compressionContext ;
2014-09-09 22:54:22 +00:00
FREEMEM ( cctxPtr - > tmpBuff ) ;
2014-09-03 18:49:59 +00:00
FREEMEM ( LZ4F_compressionContext ) ;
2014-08-30 17:14:44 +00:00
return OK_NoError ;
}
/* LZ4F_compressBegin() :
* will write the frame header into dstBuffer .
2014-09-10 21:17:03 +00:00
* dstBuffer must be large enough to accommodate a header ( dstMaxSize ) . Maximum header size is LZ4F_MAXHEADERFRAME_SIZE bytes .
2014-08-30 17:14:44 +00:00
* The result of the function is the number of bytes written into dstBuffer for the header
* or an error code ( can be tested using LZ4F_isError ( ) )
*/
2014-09-07 11:57:09 +00:00
size_t LZ4F_compressBegin ( LZ4F_compressionContext_t compressionContext , void * dstBuffer , size_t dstMaxSize , const LZ4F_preferences_t * preferencesPtr )
2014-08-30 17:14:44 +00:00
{
2014-09-07 11:57:09 +00:00
LZ4F_preferences_t prefNull = { 0 } ;
2014-08-30 17:14:44 +00:00
LZ4F_cctx_internal_t * cctxPtr = ( LZ4F_cctx_internal_t * ) compressionContext ;
BYTE * const dstStart = ( BYTE * ) dstBuffer ;
BYTE * dstPtr = dstStart ;
BYTE * headerStart ;
2014-09-11 21:27:14 +00:00
size_t requiredBuffSize ;
2014-08-30 17:14:44 +00:00
if ( dstMaxSize < LZ4F_MAXHEADERFRAME_SIZE ) return - ERROR_dstMaxSize_tooSmall ;
if ( cctxPtr - > cStage ! = 0 ) return - ERROR_GENERIC ;
2014-09-07 11:57:09 +00:00
if ( preferencesPtr = = NULL ) preferencesPtr = & prefNull ;
/* Buffer Management */
cctxPtr - > prefs = * preferencesPtr ;
if ( cctxPtr - > prefs . frameInfo . blockSizeID = = 0 ) cctxPtr - > prefs . frameInfo . blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT ;
cctxPtr - > maxBlockSize = LZ4F_getBlockSize ( cctxPtr - > prefs . frameInfo . blockSizeID ) ;
2014-09-11 21:27:14 +00:00
requiredBuffSize = cctxPtr - > maxBlockSize + ( ( cctxPtr - > prefs . frameInfo . blockMode = = blockLinked ) * 128 KB ) ;
if ( cctxPtr - > maxBufferSize < requiredBuffSize )
2014-09-07 11:57:09 +00:00
{
2014-09-11 21:27:14 +00:00
cctxPtr - > maxBufferSize = requiredBuffSize ;
2014-09-09 22:54:22 +00:00
FREEMEM ( cctxPtr - > tmpBuff ) ;
cctxPtr - > tmpBuff = ALLOCATOR ( cctxPtr - > maxBufferSize ) ;
if ( cctxPtr - > tmpBuff = = NULL ) return - ERROR_allocation_failed ;
2014-09-07 11:57:09 +00:00
}
2014-09-11 21:27:14 +00:00
cctxPtr - > tmpIn = cctxPtr - > tmpBuff ;
2014-09-07 11:57:09 +00:00
cctxPtr - > tmpInSize = 0 ;
XXH32_resetState ( & ( cctxPtr - > xxh ) , 0 ) ;
2014-09-09 22:54:22 +00:00
LZ4_resetStream ( & ( cctxPtr - > lz4ctx ) ) ;
2014-08-30 17:14:44 +00:00
/* Magic Number */
LZ4F_writeLE32 ( dstPtr , LZ4F_MAGICNUMBER ) ;
dstPtr + = 4 ;
headerStart = dstPtr ;
/* FLG Byte */
2014-09-09 22:54:22 +00:00
//cctxPtr->prefs.frameInfo.blockMode = 1; // <============ debug
* dstPtr + + = ( ( 1 & _2BITS ) < < 6 ) /* Version('01') */
+ ( ( cctxPtr - > prefs . frameInfo . blockMode & _1BIT ) < < 5 ) /* Block mode */
+ ( char ) ( ( cctxPtr - > prefs . frameInfo . contentChecksumFlag & _1BIT ) < < 2 ) ; /* Stream checksum */
2014-08-30 17:14:44 +00:00
/* BD Byte */
2014-09-09 22:54:22 +00:00
* dstPtr + + = ( char ) ( ( cctxPtr - > prefs . frameInfo . blockSizeID & _3BITS ) < < 4 ) ;
2014-08-30 17:14:44 +00:00
/* CRC Byte */
2014-09-09 22:54:22 +00:00
* dstPtr + + = LZ4F_headerChecksum ( headerStart , 2 ) ;
2014-08-30 17:14:44 +00:00
2014-09-09 22:54:22 +00:00
cctxPtr - > cStage = 1 ; /* header written, wait for data block */
2014-08-30 17:14:44 +00:00
return ( dstPtr - dstStart ) ;
}
/* LZ4F_compressBound() : gives the size of Dst buffer given a srcSize to handle worst case situations.
* The LZ4F_frameInfo_t structure is optional :
* you can provide NULL as argument , all preferences will then be set to default .
* */
2014-09-10 21:17:03 +00:00
size_t LZ4F_compressBound ( size_t srcSize , const LZ4F_preferences_t * preferencesPtr )
2014-08-30 17:14:44 +00:00
{
2014-09-10 21:17:03 +00:00
LZ4F_frameInfo_t * frameInfoPtr = ( LZ4F_frameInfo_t * ) preferencesPtr ; /* works because prefs starts with frameInfo */
2014-08-30 17:14:44 +00:00
blockSizeID_t bid = ( frameInfoPtr = = NULL ) ? LZ4F_BLOCKSIZEID_DEFAULT : frameInfoPtr - > blockSizeID ;
size_t blockSize = LZ4F_getBlockSize ( bid ) ;
2014-09-10 21:17:03 +00:00
unsigned bufferize = ! ( preferencesPtr - > autoFlush ) ;
unsigned nbBlocks = ( srcSize / blockSize ) + 1 ;
size_t lastBlockSize = bufferize ? blockSize : srcSize % blockSize ;
2014-08-30 17:14:44 +00:00
size_t blockInfo = 4 ; /* default, without block CRC option */
2014-09-10 21:17:03 +00:00
size_t frameEnd = 4 + ( frameInfoPtr - > contentChecksumFlag * 4 ) ;
size_t result = ( blockInfo * nbBlocks ) + ( blockSize * ( nbBlocks - 1 ) ) + lastBlockSize + frameEnd ;
2014-08-30 17:14:44 +00:00
2014-09-03 18:49:59 +00:00
return result ;
2014-08-30 17:14:44 +00:00
}
/* LZ4F_compress()
* You can then call LZ4F_compress ( ) repetitively to compress as much data as necessary .
* The most important rule is that dstBuffer MUST be large enough ( dstMaxSize ) to ensure compression completion even in worst case .
* You can get the minimum value of dstMaxSize by using LZ4F_compressBound ( )
* Conversely , given a fixed dstMaxSize value , you can know the maximum srcSize authorized using LZ4F_getMaxSrcSize ( )
* If this condition is not respected , LZ4F_compress ( ) will fail ( result is an errorCode )
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument .
* The result of the function is the number of bytes written into dstBuffer ( it can be zero , meaning input data is just stored within compressionContext for a future block to complete )
* The function outputs an error code if it fails ( can be tested using LZ4F_isError ( ) )
*/
size_t LZ4F_compress ( LZ4F_compressionContext_t compressionContext , void * dstBuffer , size_t dstMaxSize , const void * srcBuffer , size_t srcSize , const LZ4F_compressOptions_t * compressOptionsPtr )
{
LZ4F_compressOptions_t cOptionsNull = { 0 } ;
LZ4F_cctx_internal_t * cctxPtr = ( LZ4F_cctx_internal_t * ) compressionContext ;
size_t blockSize = cctxPtr - > maxBlockSize ;
const BYTE * srcPtr = ( const BYTE * ) srcBuffer ;
const BYTE * const srcEnd = srcPtr + srcSize ;
BYTE * const dstStart = ( BYTE * ) dstBuffer ;
BYTE * dstPtr = dstStart ;
2014-09-09 22:54:22 +00:00
U32 lastBlockCompressed = 0 ;
int ( * compress ) ( void * , const char * , char * , int , int ) ;
2014-08-30 17:14:44 +00:00
if ( cctxPtr - > cStage ! = 1 ) return - ERROR_GENERIC ;
2014-09-10 21:17:03 +00:00
if ( dstMaxSize < LZ4F_compressBound ( srcSize , & ( cctxPtr - > prefs ) ) ) return - ERROR_dstMaxSize_tooSmall ;
2014-08-30 17:14:44 +00:00
if ( compressOptionsPtr = = NULL ) compressOptionsPtr = & cOptionsNull ;
2014-09-09 22:54:22 +00:00
/* select compression function */
compress = ( cctxPtr - > prefs . frameInfo . blockMode = = blockLinked ) ?
( int ( * ) ( void * , const char * , char * , int , int ) ) LZ4_compress_limitedOutput_continue :
LZ4_compress_limitedOutput_withState ;
2014-08-30 17:14:44 +00:00
/* complete tmp buffer */
2014-09-09 22:54:22 +00:00
if ( cctxPtr - > tmpInSize > 0 ) /* some data already within tmp buffer */
2014-08-30 17:14:44 +00:00
{
2014-09-03 18:49:59 +00:00
size_t sizeToCopy = blockSize - cctxPtr - > tmpInSize ;
2014-08-30 17:14:44 +00:00
if ( sizeToCopy > srcSize )
{
2014-09-09 22:54:22 +00:00
/* add src to tmpIn buffer */
2014-09-03 18:49:59 +00:00
memcpy ( cctxPtr - > tmpIn + cctxPtr - > tmpInSize , srcBuffer , srcSize ) ;
2014-08-30 17:14:44 +00:00
srcPtr = srcEnd ;
2014-09-03 18:49:59 +00:00
cctxPtr - > tmpInSize + = srcSize ;
2014-08-30 17:14:44 +00:00
}
else
{
2014-09-09 22:54:22 +00:00
/* complete tmpIn block and then compress it */
2014-08-30 17:14:44 +00:00
BYTE * cSizePtr = dstPtr ;
U32 cSize ;
2014-09-10 12:00:39 +00:00
lastBlockCompressed = 1 ;
2014-09-03 18:49:59 +00:00
memcpy ( cctxPtr - > tmpIn + cctxPtr - > tmpInSize , srcBuffer , sizeToCopy ) ;
2014-08-30 17:14:44 +00:00
srcPtr + = sizeToCopy ;
2014-09-09 22:54:22 +00:00
dstPtr + = 4 ; /* space for cSize */
cSize = ( U32 ) compress ( & ( cctxPtr - > lz4ctx ) , ( const char * ) cctxPtr - > tmpIn , ( char * ) dstPtr , ( int ) ( blockSize ) , ( int ) ( blockSize - 1 ) ) ;
2014-08-30 17:14:44 +00:00
dstPtr + = cSize ;
LZ4F_writeLE32 ( cSizePtr , cSize ) ;
2014-09-09 22:54:22 +00:00
if ( cSize = = 0 ) /* compression failed : non compressible assumed */
2014-08-30 17:14:44 +00:00
{
cSize = blockSize + LZ4F_BLOCKUNCOMPRESSED_FLAG ;
LZ4F_writeLE32 ( cSizePtr , cSize ) ;
2014-09-03 18:49:59 +00:00
memcpy ( dstPtr , cctxPtr - > tmpIn , blockSize ) ;
2014-08-30 17:14:44 +00:00
dstPtr + = blockSize ;
}
2014-09-11 21:27:14 +00:00
if ( cctxPtr - > prefs . frameInfo . blockMode = = blockLinked ) cctxPtr - > tmpIn + = blockSize ;
2014-09-03 18:49:59 +00:00
cctxPtr - > tmpInSize = 0 ;
2014-08-30 17:14:44 +00:00
}
}
while ( ( size_t ) ( srcEnd - srcPtr ) > = blockSize )
{
/* compress one block */
BYTE * cSizePtr = dstPtr ;
U32 cSize ;
2014-09-10 21:17:03 +00:00
lastBlockCompressed = 2 ;
2014-08-30 17:14:44 +00:00
dstPtr + = 4 ; /* space for cSizePtr */
2014-09-09 22:54:22 +00:00
cSize = ( U32 ) compress ( & ( cctxPtr - > lz4ctx ) , ( const char * ) srcPtr , ( char * ) dstPtr , ( int ) ( blockSize ) , ( int ) ( blockSize - 1 ) ) ;
2014-08-30 17:14:44 +00:00
dstPtr + = cSize ;
LZ4F_writeLE32 ( cSizePtr , cSize ) ;
if ( cSize = = 0 ) /* compression failed */
{
cSize = blockSize + LZ4F_BLOCKUNCOMPRESSED_FLAG ;
LZ4F_writeLE32 ( cSizePtr , cSize ) ;
memcpy ( dstPtr , srcPtr , blockSize ) ;
dstPtr + = blockSize ;
}
srcPtr + = blockSize ;
}
2014-09-09 22:54:22 +00:00
if ( ( cctxPtr - > prefs . frameInfo . blockMode = = blockLinked ) & & ( lastBlockCompressed ) )
{
2014-09-10 21:17:03 +00:00
/* last compressed input up to 64 KB become dictionary */
2014-09-11 21:27:14 +00:00
if ( ( lastBlockCompressed = = 2 ) | |
( ( cctxPtr - > tmpBuff + cctxPtr - > maxBufferSize ) < ( cctxPtr - > tmpIn + cctxPtr - > maxBlockSize ) ) )
2014-09-10 21:17:03 +00:00
{
int result ;
result = LZ4_saveDict ( & ( cctxPtr - > lz4ctx ) , ( char * ) ( cctxPtr - > tmpBuff ) , 64 KB ) ;
if ( result = = 0 ) return - ERROR_GENERIC ;
cctxPtr - > tmpIn = cctxPtr - > tmpBuff + result ;
}
2014-09-09 22:54:22 +00:00
}
2014-09-11 21:27:14 +00:00
if ( srcPtr < srcEnd ) /* some input data left, necessarily < blockSize */
2014-08-30 17:14:44 +00:00
{
/* fill tmp buffer */
size_t sizeToCopy = srcEnd - srcPtr ;
2014-09-03 18:49:59 +00:00
memcpy ( cctxPtr - > tmpIn , srcPtr , sizeToCopy ) ;
cctxPtr - > tmpInSize = sizeToCopy ;
2014-08-30 17:14:44 +00:00
}
if ( cctxPtr - > prefs . frameInfo . contentChecksumFlag = = contentChecksumEnabled )
XXH32_update ( & ( cctxPtr - > xxh ) , srcBuffer , ( unsigned ) srcSize ) ;
return dstPtr - dstStart ;
}
/* LZ4F_flush()
* Should you need to create compressed data immediately , without waiting for a block to be filled ,
* you can call LZ4_flush ( ) , which will immediately compress any remaining data stored within compressionContext .
* The result of the function is the number of bytes written into dstBuffer
* ( it can be zero , this means there was no data left within compressionContext )
* The function outputs an error code if it fails ( can be tested using LZ4F_isError ( ) )
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument .
*/
size_t LZ4F_flush ( LZ4F_compressionContext_t compressionContext , void * dstBuffer , size_t dstMaxSize , const LZ4F_compressOptions_t * compressOptionsPtr )
{
LZ4F_compressOptions_t cOptionsNull = { 0 } ;
LZ4F_cctx_internal_t * cctxPtr = ( LZ4F_cctx_internal_t * ) compressionContext ;
BYTE * const dstStart = ( BYTE * ) dstBuffer ;
BYTE * dstPtr = dstStart ;
2014-09-09 22:54:22 +00:00
int ( * compress ) ( void * , const char * , char * , int , int ) ;
2014-08-30 17:14:44 +00:00
2014-09-03 18:49:59 +00:00
if ( cctxPtr - > tmpInSize = = 0 ) return 0 ; /* nothing to flush */
2014-08-30 17:14:44 +00:00
if ( cctxPtr - > cStage ! = 1 ) return - ERROR_GENERIC ;
2014-09-10 21:17:03 +00:00
if ( dstMaxSize < ( cctxPtr - > tmpInSize + 16 ) ) return - ERROR_dstMaxSize_tooSmall ;
2014-08-30 17:14:44 +00:00
if ( compressOptionsPtr = = NULL ) compressOptionsPtr = & cOptionsNull ;
2014-09-09 22:54:22 +00:00
/* select compression function */
compress = ( cctxPtr - > prefs . frameInfo . blockMode = = blockLinked ) ?
( int ( * ) ( void * , const char * , char * , int , int ) ) LZ4_compress_limitedOutput_continue :
LZ4_compress_limitedOutput_withState ;
2014-08-30 17:14:44 +00:00
{
BYTE * cSizePtr = dstPtr ;
U32 cSize ;
dstPtr + = 4 ; /* space for cSizePtr */
2014-09-09 22:54:22 +00:00
cSize = ( U32 ) compress ( & ( cctxPtr - > lz4ctx ) , ( const char * ) cctxPtr - > tmpIn , ( char * ) dstPtr , ( int ) ( cctxPtr - > tmpInSize ) , ( int ) ( cctxPtr - > tmpInSize - 1 ) ) ;
2014-08-30 17:14:44 +00:00
dstPtr + = cSize ;
LZ4F_writeLE32 ( cSizePtr , cSize ) ;
if ( cSize = = 0 ) /* compression failed */
{
2014-09-03 18:49:59 +00:00
cSize = cctxPtr - > tmpInSize + LZ4F_BLOCKUNCOMPRESSED_FLAG ;
2014-08-30 17:14:44 +00:00
LZ4F_writeLE32 ( cSizePtr , cSize ) ;
2014-09-03 18:49:59 +00:00
memcpy ( dstPtr , cctxPtr - > tmpIn , cctxPtr - > tmpInSize ) ;
dstPtr + = cctxPtr - > tmpInSize ;
2014-08-30 17:14:44 +00:00
}
2014-09-11 21:27:14 +00:00
if ( cctxPtr - > prefs . frameInfo . blockMode = = blockLinked ) cctxPtr - > tmpIn + = cctxPtr - > tmpInSize ;
2014-09-03 18:49:59 +00:00
cctxPtr - > tmpInSize = 0 ;
2014-08-30 17:14:44 +00:00
}
2014-09-10 21:17:03 +00:00
if ( ( cctxPtr - > prefs . frameInfo . blockMode = = blockLinked )
2014-09-11 21:27:14 +00:00
& & ( ( cctxPtr - > tmpBuff + cctxPtr - > maxBufferSize ) < ( cctxPtr - > tmpIn + cctxPtr - > maxBlockSize ) ) )
2014-09-09 22:54:22 +00:00
{
/* last 64 KB of input become dictionary */
2014-09-10 21:17:03 +00:00
int result = LZ4_saveDict ( & ( cctxPtr - > lz4ctx ) , ( char * ) ( cctxPtr - > tmpBuff ) , 64 KB ) ;
2014-09-09 22:54:22 +00:00
if ( ! result ) return ERROR_GENERIC ;
2014-09-10 21:17:03 +00:00
cctxPtr - > tmpIn = cctxPtr - > tmpBuff + result ;
2014-09-09 22:54:22 +00:00
}
2014-08-30 17:14:44 +00:00
return dstPtr - dstStart ;
}
/* LZ4F_compressEnd()
* When you want to properly finish the compressed frame , just call LZ4F_compressEnd ( ) .
* It will flush whatever data remained within compressionContext ( like LZ4_flush ( ) )
* but also properly finalize the frame , with an endMark and a checksum .
* The result of the function is the number of bytes written into dstBuffer ( necessarily > = 4 ( endMark size ) )
* The function outputs an error code if it fails ( can be tested using LZ4F_isError ( ) )
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument .
* compressionContext can then be used again , starting with LZ4F_compressBegin ( ) . The preferences will remain the same .
*/
size_t LZ4F_compressEnd ( LZ4F_compressionContext_t compressionContext , void * dstBuffer , size_t dstMaxSize , const LZ4F_compressOptions_t * compressOptionsPtr )
{
LZ4F_cctx_internal_t * cctxPtr = ( LZ4F_cctx_internal_t * ) compressionContext ;
BYTE * const dstStart = ( BYTE * ) dstBuffer ;
BYTE * dstPtr = dstStart ;
size_t errorCode ;
errorCode = LZ4F_flush ( compressionContext , dstBuffer , dstMaxSize , compressOptionsPtr ) ;
if ( LZ4F_isError ( errorCode ) ) return errorCode ;
dstPtr + = errorCode ;
LZ4F_writeLE32 ( dstPtr , 0 ) ; dstPtr + = 4 ; /* endMark */
if ( cctxPtr - > prefs . frameInfo . contentChecksumFlag = = contentChecksumEnabled )
{
U32 xxh = XXH32_intermediateDigest ( & ( cctxPtr - > xxh ) ) ;
LZ4F_writeLE32 ( dstPtr , xxh ) ;
dstPtr + = 4 ; /* content Checksum */
}
cctxPtr - > cStage = 0 ; /* state is now re-usable (with identical preferences) */
return dstPtr - dstStart ;
}
2014-09-01 21:44:02 +00:00
/***********************************
* Decompression functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Resource management */
/* LZ4F_createDecompressionContext() :
* The first thing to do is to create a decompressionContext object , which will be used in all decompression operations .
* This is achieved using LZ4F_createDecompressionContext ( ) .
2014-09-03 18:49:59 +00:00
* The function will provide a pointer to a fully allocated and initialized LZ4F_decompressionContext object .
2014-09-01 21:44:02 +00:00
* If the result LZ4F_errorCode_t is not zero , there was an error during context creation .
* Object can release its memory using LZ4F_freeDecompressionContext ( ) ;
*/
2014-09-05 14:50:06 +00:00
LZ4F_errorCode_t LZ4F_createDecompressionContext ( LZ4F_compressionContext_t * LZ4F_decompressionContextPtr , unsigned versionNumber )
2014-09-03 18:49:59 +00:00
{
LZ4F_dctx_internal_t * dctxPtr ;
dctxPtr = ALLOCATOR ( sizeof ( LZ4F_dctx_internal_t ) ) ;
if ( dctxPtr = = NULL ) return - ERROR_GENERIC ;
2014-09-05 14:50:06 +00:00
dctxPtr - > version = versionNumber ;
2014-09-03 18:49:59 +00:00
* LZ4F_decompressionContextPtr = ( LZ4F_compressionContext_t ) dctxPtr ;
return OK_NoError ;
}
LZ4F_errorCode_t LZ4F_freeDecompressionContext ( LZ4F_compressionContext_t LZ4F_decompressionContext )
{
LZ4F_dctx_internal_t * dctxPtr = ( LZ4F_dctx_internal_t * ) LZ4F_decompressionContext ;
FREEMEM ( dctxPtr - > tmpIn ) ;
2014-09-09 22:54:22 +00:00
FREEMEM ( dctxPtr - > tmpOutBuffer ) ;
2014-09-03 18:49:59 +00:00
FREEMEM ( dctxPtr ) ;
return OK_NoError ;
}
2014-09-01 21:44:02 +00:00
/* Decompression */
2014-09-05 14:50:06 +00:00
static size_t LZ4F_decodeHeader ( LZ4F_dctx_internal_t * dctxPtr , const BYTE * srcPtr , size_t srcSize )
2014-09-01 21:44:02 +00:00
{
BYTE FLG , BD , HC ;
unsigned version , blockMode , blockChecksumFlag , contentSizeFlag , contentChecksumFlag , dictFlag , blockSizeID ;
2014-09-10 21:17:03 +00:00
size_t bufferNeeded ;
2014-09-01 21:44:02 +00:00
/* need to decode header to get frameInfo */
2014-09-03 18:49:59 +00:00
if ( srcSize < 7 ) return - ERROR_GENERIC ; /* minimal header size */
2014-09-01 21:44:02 +00:00
/* control magic number */
if ( LZ4F_readLE32 ( srcPtr ) ! = LZ4F_MAGICNUMBER ) return - ERROR_GENERIC ;
srcPtr + = 4 ;
/* Flags */
FLG = srcPtr [ 0 ] ;
version = ( FLG > > 6 ) & _2BITS ;
blockMode = ( FLG > > 5 ) & _1BIT ;
blockChecksumFlag = ( FLG > > 4 ) & _1BIT ;
contentSizeFlag = ( FLG > > 3 ) & _1BIT ;
contentChecksumFlag = ( FLG > > 2 ) & _1BIT ;
dictFlag = ( FLG > > 0 ) & _1BIT ;
BD = srcPtr [ 1 ] ;
blockSizeID = ( BD > > 4 ) & _3BITS ;
/* check */
HC = LZ4F_headerChecksum ( srcPtr , 2 ) ;
if ( HC ! = srcPtr [ 2 ] ) return - ERROR_GENERIC ; /* Bad header checksum error */
/* validate */
if ( version ! = 1 ) return - ERROR_GENERIC ; /* Version Number, only supported value */
2014-09-09 22:54:22 +00:00
//if (blockMode != blockIndependent) return -ERROR_GENERIC; /* Only supported blockMode for the time being */
2014-09-01 21:44:02 +00:00
if ( blockChecksumFlag ! = 0 ) return - ERROR_GENERIC ; /* Only supported value for the time being */
if ( contentSizeFlag ! = 0 ) return - ERROR_GENERIC ; /* Only supported value for the time being */
if ( ( ( FLG > > 1 ) & _1BIT ) ! = 0 ) return - ERROR_GENERIC ; /* Reserved bit */
if ( dictFlag ! = 0 ) return - ERROR_GENERIC ; /* Only supported value for the time being */
if ( ( ( BD > > 7 ) & _1BIT ) ! = 0 ) return - ERROR_GENERIC ; /* Reserved bit */
if ( blockSizeID < 4 ) return - ERROR_GENERIC ; /* Only supported values for the time being */
if ( ( ( BD > > 0 ) & _4BITS ) ! = 0 ) return - ERROR_GENERIC ; /* Reserved bits */
/* save */
2014-09-05 14:50:06 +00:00
dctxPtr - > frameInfo . blockMode = blockMode ;
dctxPtr - > frameInfo . contentChecksumFlag = contentChecksumFlag ;
dctxPtr - > frameInfo . blockSizeID = blockSizeID ;
2014-09-10 12:00:39 +00:00
dctxPtr - > maxBlockSize = LZ4F_getBlockSize ( blockSizeID ) ;
2014-09-01 21:44:02 +00:00
2014-09-05 14:50:06 +00:00
/* init */
if ( contentChecksumFlag ) XXH32_resetState ( & ( dctxPtr - > xxh ) , 0 ) ;
2014-09-01 21:44:02 +00:00
2014-09-10 12:00:39 +00:00
/* alloc */
2014-09-10 21:17:03 +00:00
bufferNeeded = dctxPtr - > maxBlockSize + ( ( dctxPtr - > frameInfo . blockMode = = blockLinked ) * 64 KB ) ;
if ( bufferNeeded > dctxPtr - > maxBufferSize ) /* tmp buffers too small */
2014-09-03 18:49:59 +00:00
{
FREEMEM ( dctxPtr - > tmpIn ) ;
2014-09-09 22:54:22 +00:00
FREEMEM ( dctxPtr - > tmpOutBuffer ) ;
2014-09-10 21:17:03 +00:00
dctxPtr - > maxBufferSize = bufferNeeded ;
2014-09-09 22:54:22 +00:00
dctxPtr - > tmpIn = ALLOCATOR ( dctxPtr - > maxBlockSize ) ;
if ( dctxPtr - > tmpIn = = NULL ) return - ERROR_GENERIC ;
dctxPtr - > tmpOutBuffer = ALLOCATOR ( dctxPtr - > maxBufferSize ) ;
if ( dctxPtr - > tmpOutBuffer = = NULL ) return - ERROR_GENERIC ;
2014-09-03 18:49:59 +00:00
}
2014-09-10 12:00:39 +00:00
dctxPtr - > tmpOut = dctxPtr - > tmpOutBuffer ;
if ( dctxPtr - > frameInfo . blockMode = = blockLinked ) dctxPtr - > tmpOut + = 64 KB ;
dctxPtr - > dictSize = 0 ;
dctxPtr - > dict = dctxPtr - > tmpOut ;
2014-09-05 14:50:06 +00:00
return 7 ;
2014-09-03 18:49:59 +00:00
}
2014-09-04 21:56:51 +00:00
typedef enum { dstage_getHeader = 0 , dstage_storeHeader , dstage_decodeHeader ,
2014-09-03 18:49:59 +00:00
dstage_getCBlockSize , dstage_storeCBlockSize , dstage_decodeCBlockSize ,
dstage_copyDirect ,
dstage_getCBlock , dstage_storeCBlock , dstage_decodeCBlock , dstage_flushOut ,
dstage_getSuffix , dstage_storeSuffix , dstage_checkSuffix } dStage_t ;
2014-09-01 21:44:02 +00:00
/* LZ4F_getFrameInfo()
* This function decodes frame header information , such as blockSize .
* It is optional : you could start by calling directly LZ4F_decompress ( ) instead .
* The objective is to extract header information without starting decompression , typically for allocation purposes .
* LZ4F_getFrameInfo ( ) can also be used * after * starting decompression , on a valid LZ4F_decompressionContext_t .
* The number of bytes read from srcBuffer will be provided within * srcSize ( necessarily < = original value ) .
* The function result is an error code which can be tested using LZ4F_isError ( ) .
*/
LZ4F_errorCode_t LZ4F_getFrameInfo ( LZ4F_decompressionContext_t decompressionContext , LZ4F_frameInfo_t * frameInfoPtr , const void * srcBuffer , size_t * srcSize )
{
LZ4F_dctx_internal_t * dctxPtr = ( LZ4F_dctx_internal_t * ) decompressionContext ;
if ( dctxPtr - > dStage = = 0 )
{
2014-09-05 14:50:06 +00:00
LZ4F_errorCode_t errorCode = LZ4F_decodeHeader ( dctxPtr , srcBuffer , * srcSize ) ;
2014-09-01 21:44:02 +00:00
if ( LZ4F_isError ( errorCode ) ) return errorCode ;
* srcSize = errorCode ;
2014-09-03 18:49:59 +00:00
dctxPtr - > dStage = dstage_getCBlockSize ;
2014-09-01 21:44:02 +00:00
return OK_NoError ;
}
/* frameInfo already decoded */
* srcSize = 0 ;
* frameInfoPtr = dctxPtr - > frameInfo ;
return OK_NoError ;
}
2014-09-03 18:49:59 +00:00
2014-09-10 12:00:39 +00:00
static void LZ4F_saveDict ( LZ4F_dctx_internal_t * dctxPtr , const BYTE * decoded , size_t decodedSize )
2014-09-09 22:54:22 +00:00
{
size_t newDictSize = decodedSize ;
size_t preserveDictSize ;
if ( newDictSize > 64 KB ) newDictSize = 64 KB ;
preserveDictSize = 64 KB - newDictSize ;
memmove ( dctxPtr - > tmpOutBuffer , dctxPtr - > tmpOutBuffer + newDictSize , preserveDictSize ) ;
memcpy ( dctxPtr - > tmpOutBuffer + preserveDictSize , decoded + decodedSize - newDictSize , newDictSize ) ;
dctxPtr - > dictSize + = newDictSize ;
if ( dctxPtr - > dictSize > 64 KB ) dctxPtr - > dictSize = 64 KB ;
dctxPtr - > dict = dctxPtr - > tmpOut - dctxPtr - > dictSize ;
}
static int LZ4F_decompress_safe ( const char * source , char * dest , int compressedSize , int maxDecompressedSize , const char * dictStart , int dictSize )
{
( void ) dictStart ; ( void ) dictSize ;
return LZ4_decompress_safe ( source , dest , compressedSize , maxDecompressedSize ) ;
}
2014-09-01 21:44:02 +00:00
/* LZ4F_decompress()
* Call this function repetitively to regenerate data compressed within srcBuffer .
* The function will attempt to decode * srcSize from srcBuffer , into dstBuffer of maximum size * dstSize .
*
* The number of bytes generated into dstBuffer will be provided within * dstSize ( necessarily < = original value ) .
*
* The number of bytes effectively read from srcBuffer will be provided within * srcSize ( necessarily < = original value ) .
* If the number of bytes read is < number of bytes provided , then the decompression operation is not complete .
* You will have to call it again , using the same src arguments ( but eventually different dst arguments ) .
*
* The function result is an error code which can be tested using LZ4F_isError ( ) .
* When the frame is fully decoded , the function result will be OK_FrameEnd ( = 1 ) .
*/
LZ4F_errorCode_t LZ4F_decompress ( LZ4F_decompressionContext_t decompressionContext , void * dstBuffer , size_t * dstSize , const void * srcBuffer , size_t * srcSize , const LZ4F_decompressOptions_t * decompressOptionsPtr )
{
LZ4F_dctx_internal_t * dctxPtr = ( LZ4F_dctx_internal_t * ) decompressionContext ;
LZ4F_decompressOptions_t optionsNull = { 0 } ;
const BYTE * const srcStart = ( const BYTE * ) srcBuffer ;
const BYTE * const srcEnd = srcStart + * srcSize ;
const BYTE * srcPtr = srcStart ;
BYTE * const dstStart = ( BYTE * ) dstBuffer ;
BYTE * const dstEnd = dstStart + * dstSize ;
BYTE * dstPtr = dstStart ;
size_t nextCBlockSize = 0 ;
2014-09-04 21:56:51 +00:00
const BYTE * selectedIn = NULL ;
2014-09-03 18:49:59 +00:00
LZ4F_errorCode_t goodResult = OK_NoError ;
2014-09-09 22:54:22 +00:00
int ( * decoder ) ( const char * , char * , int , int , const char * , int ) ;
2014-09-03 18:49:59 +00:00
2014-09-01 21:44:02 +00:00
if ( decompressOptionsPtr = = NULL ) decompressOptionsPtr = & optionsNull ;
2014-09-03 18:49:59 +00:00
* srcSize = 0 ; * dstSize = 0 ;
2014-09-01 21:44:02 +00:00
2014-09-04 21:56:51 +00:00
/* expect to continue decoding src buffer where it left previously */
2014-09-03 18:49:59 +00:00
if ( dctxPtr - > srcExpect ! = NULL )
2014-09-01 21:44:02 +00:00
{
2014-09-03 18:49:59 +00:00
if ( srcStart ! = dctxPtr - > srcExpect ) return - ERROR_GENERIC ;
2014-09-01 21:44:02 +00:00
}
2014-09-03 18:49:59 +00:00
while ( srcPtr < srcEnd )
2014-09-01 21:44:02 +00:00
{
2014-09-03 18:49:59 +00:00
switch ( dctxPtr - > dStage )
2014-09-01 21:44:02 +00:00
{
2014-09-04 21:56:51 +00:00
case dstage_getHeader :
2014-09-01 21:44:02 +00:00
{
2014-09-05 14:50:06 +00:00
if ( srcEnd - srcPtr > = 7 )
2014-09-04 21:56:51 +00:00
{
selectedIn = srcPtr ;
srcPtr + = 7 ;
dctxPtr - > dStage = dstage_decodeHeader ;
goto goto_decodeHeader ; /* break would risk leaving the while loop */
}
dctxPtr - > tmpInSize = 0 ;
dctxPtr - > dStage = dstage_storeHeader ;
/* break; break is useles, since storeHeader follows */
}
case dstage_storeHeader :
{
size_t sizeToCopy = 7 - dctxPtr - > tmpInSize ;
if ( sizeToCopy > ( size_t ) ( srcEnd - srcPtr ) ) sizeToCopy = srcEnd - srcPtr ;
2014-09-05 14:50:06 +00:00
memcpy ( dctxPtr - > header + dctxPtr - > tmpInSize , srcPtr , sizeToCopy ) ;
2014-09-04 21:56:51 +00:00
dctxPtr - > tmpInSize + = sizeToCopy ;
srcPtr + = sizeToCopy ;
if ( dctxPtr - > tmpInSize < 7 ) break ; /* src completed; come back later for more */
2014-09-05 14:50:06 +00:00
selectedIn = dctxPtr - > header ;
2014-09-04 21:56:51 +00:00
dctxPtr - > dStage = dstage_decodeHeader ;
/* break; useless because it follows */
}
case dstage_decodeHeader :
goto_decodeHeader :
{
2014-09-05 14:50:06 +00:00
LZ4F_errorCode_t errorCode = LZ4F_decodeHeader ( dctxPtr , selectedIn , 7 ) ;
2014-09-03 18:49:59 +00:00
if ( LZ4F_isError ( errorCode ) ) return errorCode ;
2014-09-04 21:56:51 +00:00
/* dctxPtr->dStage = dstage_getCBlockSize; break; no need to change stage nor break : dstage_getCBlockSize is next stage, and stage will be modified */
2014-09-01 21:44:02 +00:00
}
2014-09-03 18:49:59 +00:00
case dstage_getCBlockSize :
2014-09-01 21:44:02 +00:00
{
2014-09-04 21:56:51 +00:00
if ( ( srcEnd - srcPtr ) > = 4 )
2014-09-03 18:49:59 +00:00
{
2014-09-04 21:56:51 +00:00
selectedIn = srcPtr ;
srcPtr + = 4 ;
dctxPtr - > dStage = dstage_decodeCBlockSize ;
goto goto_decodeCBlockSize ; /* required : a break could leave while loop */
2014-09-03 18:49:59 +00:00
}
2014-09-04 21:56:51 +00:00
/* not enough input to read cBlockSize */
dctxPtr - > tmpInSize = 0 ;
dctxPtr - > dStage = dstage_storeCBlockSize ;
/* break; No need to break : dstage_storeCBlockSize is next block */
2014-09-01 21:44:02 +00:00
}
2014-09-03 18:49:59 +00:00
case dstage_storeCBlockSize :
2014-09-01 21:44:02 +00:00
{
2014-09-03 18:49:59 +00:00
size_t sizeToCopy = 4 - dctxPtr - > tmpInSize ;
2014-09-04 21:56:51 +00:00
if ( sizeToCopy > ( size_t ) ( srcEnd - srcPtr ) ) sizeToCopy = srcEnd - srcPtr ;
2014-09-03 18:49:59 +00:00
memcpy ( dctxPtr - > tmpIn + dctxPtr - > tmpInSize , srcPtr , sizeToCopy ) ;
srcPtr + = sizeToCopy ;
dctxPtr - > tmpInSize + = sizeToCopy ;
if ( dctxPtr - > tmpInSize < 4 ) break ; /* not enough input to read CBlockSize */
2014-09-04 21:56:51 +00:00
selectedIn = dctxPtr - > tmpIn ;
2014-09-03 18:49:59 +00:00
dctxPtr - > dStage = dstage_decodeCBlockSize ;
2014-09-04 21:56:51 +00:00
/* break; No need to break : dstage_decodeCBlockSize is next block */
2014-09-01 21:44:02 +00:00
}
2014-09-03 18:49:59 +00:00
case dstage_decodeCBlockSize :
2014-09-04 21:56:51 +00:00
goto_decodeCBlockSize :
2014-09-01 21:44:02 +00:00
{
2014-09-04 21:56:51 +00:00
nextCBlockSize = LZ4F_readLE32 ( selectedIn ) & 0x7FFFFFFFU ;
2014-09-03 18:49:59 +00:00
if ( nextCBlockSize = = 0 ) /* no more CBlock */
{
dctxPtr - > dStage = dstage_getSuffix ;
2014-09-04 21:56:51 +00:00
goto goto_getSuffix ; /* required : a break could leave the while loop */
2014-09-03 18:49:59 +00:00
}
if ( nextCBlockSize > dctxPtr - > maxBlockSize ) return - ERROR_GENERIC ;
dctxPtr - > sizeToDecode = nextCBlockSize ;
2014-09-04 21:56:51 +00:00
if ( LZ4F_readLE32 ( selectedIn ) & 0x80000000U ) /* uncompressed flag */
2014-09-03 18:49:59 +00:00
{
dctxPtr - > dStage = dstage_copyDirect ;
break ;
}
dctxPtr - > dStage = dstage_getCBlock ;
2014-09-04 21:56:51 +00:00
goto goto_getCBlock ; /* break risk leaving while loop */
2014-09-01 21:44:02 +00:00
}
2014-09-03 18:49:59 +00:00
case dstage_copyDirect :
2014-09-01 21:44:02 +00:00
{
2014-09-03 18:49:59 +00:00
size_t sizeToCopy = dctxPtr - > sizeToDecode ;
if ( ( size_t ) ( srcEnd - srcPtr ) < sizeToCopy ) sizeToCopy = srcEnd - srcPtr ; /* not enough input to read full block */
if ( ( size_t ) ( dstEnd - dstPtr ) < sizeToCopy ) sizeToCopy = dstEnd - dstPtr ;
memcpy ( dstPtr , srcPtr , sizeToCopy ) ;
2014-09-06 08:47:28 +00:00
if ( dctxPtr - > frameInfo . contentChecksumFlag ) XXH32_update ( & ( dctxPtr - > xxh ) , srcPtr , sizeToCopy ) ;
2014-09-10 12:00:39 +00:00
if ( dctxPtr - > frameInfo . blockMode = = blockLinked )
LZ4F_saveDict ( dctxPtr , srcPtr , sizeToCopy ) ;
2014-09-03 18:49:59 +00:00
srcPtr + = sizeToCopy ;
dstPtr + = sizeToCopy ;
if ( sizeToCopy = = dctxPtr - > sizeToDecode ) /* all copied */
{
dctxPtr - > dStage = dstage_getCBlockSize ;
break ;
}
dctxPtr - > sizeToDecode - = sizeToCopy ; /* still need to copy more */
goto _end ; /* either In or Out have reached end */
2014-09-01 21:44:02 +00:00
}
2014-09-03 18:49:59 +00:00
case dstage_getCBlock :
2014-09-04 21:56:51 +00:00
goto_getCBlock :
2014-09-01 21:44:02 +00:00
{
2014-09-03 18:49:59 +00:00
if ( ( size_t ) ( srcEnd - srcPtr ) < nextCBlockSize )
{
dctxPtr - > tmpInTarget = nextCBlockSize ;
dctxPtr - > tmpInSize = 0 ;
dctxPtr - > dStage = dstage_storeCBlock ;
break ;
}
2014-09-04 21:56:51 +00:00
selectedIn = srcPtr ;
2014-09-01 21:44:02 +00:00
srcPtr + = nextCBlockSize ;
2014-09-03 18:49:59 +00:00
dctxPtr - > dStage = dstage_decodeCBlock ;
2014-09-06 21:48:03 +00:00
goto goto_decodeCBlock ; /* break risks leaving the while loop */
2014-09-03 18:49:59 +00:00
}
case dstage_storeCBlock :
{
size_t sizeToCopy = dctxPtr - > tmpInTarget - dctxPtr - > tmpInSize ;
if ( sizeToCopy > ( size_t ) ( srcEnd - srcPtr ) ) sizeToCopy = srcEnd - srcPtr ;
memcpy ( dctxPtr - > tmpIn + dctxPtr - > tmpInSize , srcPtr , sizeToCopy ) ;
dctxPtr - > tmpInSize + = sizeToCopy ;
srcPtr + = sizeToCopy ;
if ( dctxPtr - > tmpInSize < dctxPtr - > tmpInTarget ) break ; /* need to read more */
2014-09-04 21:56:51 +00:00
selectedIn = dctxPtr - > tmpIn ;
2014-09-03 18:49:59 +00:00
dctxPtr - > dStage = dstage_decodeCBlock ;
2014-09-04 21:56:51 +00:00
/* break; break unnecessary because it follows */
2014-09-03 18:49:59 +00:00
}
case dstage_decodeCBlock :
2014-09-06 21:48:03 +00:00
goto_decodeCBlock :
2014-09-03 18:49:59 +00:00
{
int decodedSize ;
2014-09-09 22:54:22 +00:00
if ( dctxPtr - > frameInfo . blockMode = = blockLinked )
decoder = LZ4_decompress_safe_usingDict ;
else
decoder = LZ4F_decompress_safe ;
2014-09-03 18:49:59 +00:00
if ( ( size_t ) ( dstEnd - dstPtr ) < dctxPtr - > maxBlockSize ) /* not enough room : decode into tmpOut */
{
2014-09-09 22:54:22 +00:00
decodedSize = decoder ( ( const char * ) selectedIn , ( char * ) dctxPtr - > tmpOut , ( int ) dctxPtr - > sizeToDecode , ( int ) dctxPtr - > maxBlockSize , ( const char * ) dctxPtr - > dict , ( int ) dctxPtr - > dictSize ) ;
2014-09-03 18:49:59 +00:00
if ( decodedSize < 0 ) return - ERROR_GENERIC ; /* decompression failed */
2014-09-05 14:50:06 +00:00
if ( dctxPtr - > frameInfo . contentChecksumFlag )
XXH32_update ( & ( dctxPtr - > xxh ) , dctxPtr - > tmpOut , decodedSize ) ;
2014-09-09 22:54:22 +00:00
if ( dctxPtr - > frameInfo . blockMode = = blockLinked )
LZ4F_saveDict ( dctxPtr , dctxPtr - > tmpOut , decodedSize ) ;
2014-09-03 18:49:59 +00:00
dctxPtr - > tmpOutSize = decodedSize ;
dctxPtr - > tmpOutStart = 0 ;
dctxPtr - > dStage = dstage_flushOut ;
break ;
}
2014-09-09 22:54:22 +00:00
decodedSize = decoder ( ( const char * ) selectedIn , ( char * ) dstPtr , ( int ) dctxPtr - > sizeToDecode , ( int ) dctxPtr - > maxBlockSize , ( const char * ) dctxPtr - > dict , ( int ) dctxPtr - > dictSize ) ;
2014-09-03 18:49:59 +00:00
if ( decodedSize < 0 ) return - ERROR_GENERIC ; /* decompression failed */
2014-09-05 14:50:06 +00:00
if ( dctxPtr - > frameInfo . contentChecksumFlag )
XXH32_update ( & ( dctxPtr - > xxh ) , dstPtr , decodedSize ) ;
2014-09-09 22:54:22 +00:00
if ( dctxPtr - > frameInfo . blockMode = = blockLinked )
LZ4F_saveDict ( dctxPtr , dstPtr , decodedSize ) ;
2014-09-03 18:49:59 +00:00
dstPtr + = decodedSize ;
dctxPtr - > dStage = dstage_getCBlockSize ;
break ;
}
case dstage_flushOut :
{
size_t sizeToCopy = dctxPtr - > tmpOutSize - dctxPtr - > tmpOutStart ;
if ( sizeToCopy > ( size_t ) ( dstEnd - dstPtr ) ) sizeToCopy = dstEnd - dstPtr ;
memcpy ( dstPtr , dctxPtr - > tmpOut + dctxPtr - > tmpOutStart , sizeToCopy ) ;
dctxPtr - > tmpOutStart + = sizeToCopy ;
dstPtr + = sizeToCopy ;
if ( dctxPtr - > tmpOutStart < dctxPtr - > tmpOutSize ) goto _end ; /* need to write more */
dctxPtr - > dStage = dstage_getCBlockSize ;
break ;
}
case dstage_getSuffix :
2014-09-04 21:56:51 +00:00
goto_getSuffix :
2014-09-03 18:49:59 +00:00
{
size_t suffixSize = dctxPtr - > frameInfo . contentChecksumFlag * 4 ;
if ( suffixSize = = 0 ) /* frame completed */
{
goodResult = OK_FrameEnd ;
2014-09-04 21:56:51 +00:00
dctxPtr - > dStage = dstage_getHeader ;
2014-09-03 18:49:59 +00:00
goto _end ;
}
if ( ( srcEnd - srcPtr ) > = 4 ) /* CRC present */
{
2014-09-04 21:56:51 +00:00
selectedIn = srcPtr ;
2014-09-03 18:49:59 +00:00
srcPtr + = 4 ;
dctxPtr - > dStage = dstage_checkSuffix ;
2014-09-05 14:50:06 +00:00
goto goto_checkSuffix ; /* break risks leaving the while loop */
2014-09-03 18:49:59 +00:00
}
dctxPtr - > tmpInSize = 0 ;
dctxPtr - > dStage = dstage_storeSuffix ;
2014-09-10 12:00:39 +00:00
/* break; useless, it follows */
2014-09-03 18:49:59 +00:00
}
case dstage_storeSuffix :
{
size_t sizeToCopy = 4 - dctxPtr - > tmpInSize ;
2014-09-06 21:48:03 +00:00
if ( sizeToCopy > ( size_t ) ( srcEnd - srcPtr ) ) sizeToCopy = srcEnd - srcPtr ;
2014-09-03 18:49:59 +00:00
memcpy ( dctxPtr - > tmpIn + dctxPtr - > tmpInSize , srcPtr , sizeToCopy ) ;
srcPtr + = sizeToCopy ;
dctxPtr - > tmpInSize + = sizeToCopy ;
if ( dctxPtr - > tmpInSize < 4 ) break ; /* not enough input to read suffix */
2014-09-04 21:56:51 +00:00
selectedIn = dctxPtr - > tmpIn ;
2014-09-03 18:49:59 +00:00
dctxPtr - > dStage = dstage_checkSuffix ;
2014-09-06 21:48:03 +00:00
/* break; useless, it follows; would need a goto anyway */
2014-09-03 18:49:59 +00:00
}
case dstage_checkSuffix :
2014-09-05 14:50:06 +00:00
goto_checkSuffix :
2014-09-03 18:49:59 +00:00
{
2014-09-05 14:50:06 +00:00
U32 readCRC = LZ4F_readLE32 ( selectedIn ) ;
U32 resultCRC = XXH32_intermediateDigest ( & ( dctxPtr - > xxh ) ) ;
2014-09-10 12:00:39 +00:00
if ( readCRC ! = resultCRC ) return - ERROR_checksum_invalid ;
2014-09-03 18:49:59 +00:00
goodResult = OK_FrameEnd ;
2014-09-04 21:56:51 +00:00
dctxPtr - > dStage = dstage_getHeader ;
2014-09-03 18:49:59 +00:00
goto _end ;
2014-09-01 21:44:02 +00:00
}
}
}
2014-09-03 18:49:59 +00:00
/* input fully read */
2014-09-01 21:44:02 +00:00
_end :
2014-09-03 18:49:59 +00:00
2014-09-04 21:56:51 +00:00
if ( srcPtr < srcEnd ) /* function must be called again with following source data */
2014-09-03 18:49:59 +00:00
{
2014-09-04 21:56:51 +00:00
dctxPtr - > srcExpect = srcPtr ;
2014-09-03 18:49:59 +00:00
}
else
{
dctxPtr - > srcExpect = NULL ;
}
2014-09-01 21:44:02 +00:00
* srcSize = ( srcPtr - srcStart ) ;
* dstSize = ( dstPtr - dstStart ) ;
2014-09-03 18:49:59 +00:00
return goodResult ;
2014-09-01 21:44:02 +00:00
}