2016-08-30 10:04:33 -07:00
/**
* Copyright ( c ) 2016 - present , Yann Collet , Facebook , Inc .
* All rights reserved .
*
* This source code is licensed under the BSD - style license found in the
* LICENSE file in the root directory of this source tree . An additional grant
* of patent rights can be found in the PATENTS file in the same directory .
*/
2015-01-23 16:58:16 -08:00
2017-01-25 17:01:13 -08:00
2015-10-22 08:55:40 -07:00
/* *************************************
2015-01-23 16:58:16 -08:00
* Compiler Options
2015-10-22 08:55:40 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-08-13 16:19:12 -07:00
# ifdef _MSC_VER /* Visual */
2016-12-21 04:47:11 -08:00
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
2016-08-13 16:19:12 -07:00
# pragma warning(disable : 4204) /* non-constant aggregate initializer */
# endif
2016-12-21 04:23:34 -08:00
# if defined(__MINGW32__) && !defined(_POSIX_SOURCE)
# define _POSIX_SOURCE 1 /* disable %llu warnings with MinGW on Windows */
# endif
2015-01-23 16:58:16 -08:00
2016-11-02 17:30:49 -07:00
2016-02-12 11:19:48 -08:00
/*-*************************************
2015-01-23 16:58:16 -08:00
* Includes
2015-10-22 08:55:40 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-12-21 06:08:44 -08:00
# include "platform.h" /* Large Files support, SET_BINARY_MODE */
# include "util.h" /* UTIL_getFileSize */
2015-11-09 08:42:17 -08:00
# include <stdio.h> /* fprintf, fopen, fread, _fileno, stdin, stdout */
# include <stdlib.h> /* malloc, free */
# include <string.h> /* strcmp, strlen */
# include <time.h> /* clock */
# include <errno.h> /* errno */
2016-04-28 05:40:45 -07:00
2017-04-06 12:56:40 -07:00
# if defined (_MSC_VER)
# include <sys / stat.h>
# include <io.h>
# endif
2016-12-21 04:23:34 -08:00
# include "mem.h"
2015-01-23 16:58:16 -08:00
# include "fileio.h"
2016-06-04 10:47:02 -07:00
# define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */
# include "zstd.h"
2017-01-19 16:59:56 -08:00
# ifdef ZSTD_MULTITHREAD
# include "zstdmt_compress.h"
2016-12-05 09:02:40 -08:00
# endif
2017-02-08 07:54:23 -08:00
# if defined(ZSTD_GZCOMPRESS) || defined(ZSTD_GZDECOMPRESS)
2017-02-06 11:32:13 -08:00
# include <zlib.h>
2017-01-19 16:59:56 -08:00
# if !defined(z_const)
# define z_const
# endif
2016-11-30 06:05:54 -08:00
# endif
2017-03-13 18:11:07 -07:00
# if defined(ZSTD_LZMACOMPRESS) || defined(ZSTD_LZMADECOMPRESS)
# include <lzma.h>
# endif
2015-01-23 16:58:16 -08:00
2017-04-24 16:48:25 -07:00
# define LZ4_MAGICNUMBER 0x184D2204
# if defined(ZSTD_LZ4COMPRESS) || defined(ZSTD_LZ4DECOMPRESS)
# include <lz4frame.h>
2017-04-25 11:00:54 -07:00
# include <lz4.h>
2017-04-24 16:48:25 -07:00
# endif
2015-01-23 16:58:16 -08:00
2016-02-12 11:19:48 -08:00
/*-*************************************
2015-01-23 16:58:16 -08:00
* Constants
2015-10-22 08:55:40 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-07-02 16:10:53 -07:00
# define KB *(1<<10)
# define MB *(1<<20)
# define GB *(1U<<30)
2015-01-23 16:58:16 -08:00
# define _1BIT 0x01
# define _2BITS 0x03
# define _3BITS 0x07
# define _4BITS 0x0F
# define _6BITS 0x3F
# define _8BITS 0xFF
2015-11-25 05:42:45 -08:00
# define BLOCKSIZE (128 KB)
# define ROLLBUFFERSIZE (BLOCKSIZE*8*64)
2015-01-23 16:58:16 -08:00
2016-02-12 11:19:48 -08:00
# define FIO_FRAMEHEADERSIZE 5 /* as a define, because needed to allocated table on stack */
# define FSE_CHECKSUM_SEED 0
2015-01-23 16:58:16 -08:00
# define CACHELINE 64
2017-04-11 14:41:02 -07:00
# define DICTSIZE_MAX (32 MB) /* protection against large input (attack scenario) */
2016-02-12 11:19:48 -08:00
2016-04-22 04:59:05 -07:00
# define FNSPACE 30
2015-01-23 16:58:16 -08:00
2016-02-15 11:37:23 -08:00
/*-*************************************
2015-01-23 16:58:16 -08:00
* Macros
2015-10-22 08:55:40 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-01-23 16:58:16 -08:00
# define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
2017-01-27 13:30:18 -08:00
# define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } }
2017-03-23 11:13:52 -07:00
static int g_displayLevel = 2 ; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
2016-03-10 12:02:25 -08:00
void FIO_setNotificationLevel ( unsigned level ) { g_displayLevel = level ; }
2015-01-23 16:58:16 -08:00
2017-01-27 13:30:18 -08:00
# define DISPLAYUPDATE(l, ...) { if (g_displayLevel>=l) { \
2016-07-01 16:05:31 -07:00
if ( ( clock ( ) - g_time > refreshRate ) | | ( g_displayLevel > = 4 ) ) \
2015-01-23 16:58:16 -08:00
{ g_time = clock ( ) ; DISPLAY ( __VA_ARGS__ ) ; \
2017-03-23 11:13:52 -07:00
if ( g_displayLevel > = 4 ) fflush ( stderr ) ; } } }
2016-07-01 16:05:31 -07:00
static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100 ;
2015-01-23 16:58:16 -08:00
static clock_t g_time = 0 ;
2017-04-13 15:35:05 -07:00
# undef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
2016-07-02 16:10:53 -07:00
2017-04-27 00:29:04 -07:00
2017-02-14 00:45:33 -08:00
/* ************************************************************
* Avoid fseek ( ) ' s 2 GiB barrier with MSVC , MacOS , * BSD , MinGW
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-12 01:27:18 -08:00
# if defined(_MSC_VER) && _MSC_VER >= 1400
# define LONG_SEEK _fseeki64
2017-02-14 00:45:33 -08:00
# elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */
2017-02-14 00:52:52 -08:00
# define LONG_SEEK fseeko
2017-02-12 01:27:18 -08:00
# elif defined(__MINGW32__) && !defined(__STRICT_ANSI__) && !defined(__NO_MINGW_LFS) && defined(__MSVCRT__)
# define LONG_SEEK fseeko64
# elif defined(_WIN32) && !defined(__DJGPP__)
# include <windows.h>
static int LONG_SEEK ( FILE * file , __int64 offset , int origin ) {
LARGE_INTEGER off ;
DWORD method ;
off . QuadPart = offset ;
if ( origin = = SEEK_END )
method = FILE_END ;
else if ( origin = = SEEK_CUR )
method = FILE_CURRENT ;
else
method = FILE_BEGIN ;
if ( SetFilePointerEx ( ( HANDLE ) _get_osfhandle ( _fileno ( file ) ) , off , NULL , method ) )
2017-02-13 03:00:59 -08:00
return 0 ;
2017-02-12 01:27:18 -08:00
else
2017-02-13 03:00:59 -08:00
return - 1 ;
2017-02-12 01:27:18 -08:00
}
# else
# define LONG_SEEK fseek
# endif
2016-02-15 11:37:23 -08:00
/*-*************************************
2016-07-01 16:05:31 -07:00
* Local Parameters - Not thread safe
2015-10-22 08:55:40 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-14 00:23:32 -08:00
static FIO_compressionType_t g_compressionType = FIO_zstdCompression ;
void FIO_setCompressionType ( FIO_compressionType_t compressionType ) { g_compressionType = compressionType ; }
2015-01-23 16:58:16 -08:00
static U32 g_overwrite = 0 ;
void FIO_overwriteMode ( void ) { g_overwrite = 1 ; }
2016-05-23 07:56:56 -07:00
static U32 g_sparseFileSupport = 1 ; /* 0 : no sparse allowed; 1: auto (file yes, stdout no); 2: force sparse */
void FIO_setSparseWrite ( unsigned sparse ) { g_sparseFileSupport = sparse ; }
2016-05-30 17:29:45 -07:00
static U32 g_dictIDFlag = 1 ;
void FIO_setDictIDFlag ( unsigned dictIDFlag ) { g_dictIDFlag = dictIDFlag ; }
2016-06-20 07:31:24 -07:00
static U32 g_checksumFlag = 1 ;
2016-06-01 10:22:15 -07:00
void FIO_setChecksumFlag ( unsigned checksumFlag ) { g_checksumFlag = checksumFlag ; }
2016-06-09 13:59:51 -07:00
static U32 g_removeSrcFile = 0 ;
void FIO_setRemoveSrcFile ( unsigned flag ) { g_removeSrcFile = ( flag > 0 ) ; }
2016-10-14 13:13:13 -07:00
static U32 g_memLimit = 0 ;
void FIO_setMemLimit ( unsigned memLimit ) { g_memLimit = memLimit ; }
2017-01-19 16:59:56 -08:00
static U32 g_nbThreads = 1 ;
void FIO_setNbThreads ( unsigned nbThreads ) {
# ifndef ZSTD_MULTITHREAD
if ( nbThreads > 1 ) DISPLAYLEVEL ( 2 , " Note : multi-threading is disabled \n " ) ;
# endif
g_nbThreads = nbThreads ;
}
2017-01-24 17:02:26 -08:00
static U32 g_blockSize = 0 ;
void FIO_setBlockSize ( unsigned blockSize ) {
if ( blockSize & & g_nbThreads = = 1 )
DISPLAYLEVEL ( 2 , " Setting block size is useless in single-thread mode \n " ) ;
# ifdef ZSTD_MULTITHREAD
if ( blockSize - 1 < ZSTDMT_SECTION_SIZE_MIN - 1 ) /* intentional underflow */
DISPLAYLEVEL ( 2 , " Note : minimum block size is %u KB \n " , ( ZSTDMT_SECTION_SIZE_MIN > > 10 ) ) ;
# endif
g_blockSize = blockSize ;
}
2017-01-30 14:37:08 -08:00
# define FIO_OVERLAP_LOG_NOTSET 9999
static U32 g_overlapLog = FIO_OVERLAP_LOG_NOTSET ;
2017-01-30 11:17:26 -08:00
void FIO_setOverlapLog ( unsigned overlapLog ) {
if ( overlapLog & & g_nbThreads = = 1 )
DISPLAYLEVEL ( 2 , " Setting overlapLog is useless in single-thread mode \n " ) ;
g_overlapLog = overlapLog ;
}
2015-01-23 16:58:16 -08:00
2016-02-15 11:37:23 -08:00
/*-*************************************
2015-01-23 16:58:16 -08:00
* Exceptions
2015-10-22 08:55:40 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef DEBUG
# define DEBUG 0
# endif
2015-01-23 16:58:16 -08:00
# define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
# define EXM_THROW(error, ...) \
{ \
DEBUGOUTPUT ( " Error defined at %s, line %i : \n " , __FILE__ , __LINE__ ) ; \
DISPLAYLEVEL ( 1 , " Error %i : " , error ) ; \
DISPLAYLEVEL ( 1 , __VA_ARGS__ ) ; \
2016-11-11 17:26:54 -08:00
DISPLAYLEVEL ( 1 , " \n " ) ; \
2015-01-23 16:58:16 -08:00
exit ( error ) ; \
}
2016-02-15 11:37:23 -08:00
/*-*************************************
2015-01-23 16:58:16 -08:00
* Functions
2015-10-22 08:55:40 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-04-06 12:56:40 -07:00
/** FIO_remove() :
* @ result : Unlink ` fileName ` , even if it ' s read - only */
static int FIO_remove ( const char * path )
{
# if defined(_WIN32) || defined(WIN32)
/* windows doesn't allow remove read-only files, so try to make it
* writable first */
chmod ( path , _S_IWRITE ) ;
# endif
return remove ( path ) ;
}
2016-11-11 17:26:54 -08:00
/** FIO_openSrcFile() :
* condition : ` dstFileName ` must be non - NULL .
* @ result : FILE * to ` dstFileName ` , or NULL if it fails */
2016-02-12 06:56:46 -08:00
static FILE * FIO_openSrcFile ( const char * srcFileName )
2015-12-16 17:23:58 -08:00
{
2016-02-12 06:56:46 -08:00
FILE * f ;
2016-02-02 05:36:49 -08:00
if ( ! strcmp ( srcFileName , stdinmark ) ) {
2015-12-16 17:23:58 -08:00
DISPLAYLEVEL ( 4 , " Using stdin for input \n " ) ;
2016-02-12 06:56:46 -08:00
f = stdin ;
2015-12-16 17:23:58 -08:00
SET_BINARY_MODE ( stdin ) ;
2016-02-02 05:36:49 -08:00
} else {
2017-02-14 00:38:51 -08:00
if ( ! UTIL_isRegFile ( srcFileName ) ) {
2017-01-25 04:11:26 -08:00
DISPLAYLEVEL ( 1 , " zstd: %s is not a regular file -- ignored \n " , srcFileName ) ;
return NULL ;
}
2016-02-12 06:56:46 -08:00
f = fopen ( srcFileName , " rb " ) ;
2016-08-13 11:49:47 -07:00
if ( f = = NULL ) DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , srcFileName , strerror ( errno ) ) ;
2015-12-16 17:23:58 -08:00
}
2016-02-12 06:56:46 -08:00
return f ;
}
2016-09-15 06:38:44 -07:00
/** FIO_openDstFile() :
* condition : ` dstFileName ` must be non - NULL .
* @ result : FILE * to ` dstFileName ` , or NULL if it fails */
2016-02-12 06:56:46 -08:00
static FILE * FIO_openDstFile ( const char * dstFileName )
{
FILE * f ;
2015-12-16 17:23:58 -08:00
2016-02-02 05:36:49 -08:00
if ( ! strcmp ( dstFileName , stdoutmark ) ) {
2015-12-16 17:23:58 -08:00
DISPLAYLEVEL ( 4 , " Using stdout for output \n " ) ;
2016-02-12 06:56:46 -08:00
f = stdout ;
2015-12-16 17:23:58 -08:00
SET_BINARY_MODE ( stdout ) ;
2016-05-23 07:56:56 -07:00
if ( g_sparseFileSupport = = 1 ) {
g_sparseFileSupport = 0 ;
DISPLAYLEVEL ( 4 , " Sparse File Support is automatically disabled on stdout ; try --sparse \n " ) ;
}
2016-02-02 05:36:49 -08:00
} else {
2017-03-31 15:20:50 -07:00
if ( g_sparseFileSupport = = 1 ) {
g_sparseFileSupport = ZSTD_SPARSE_DEFAULT ;
2017-03-31 15:16:43 -07:00
}
2017-04-06 12:56:40 -07:00
if ( strcmp ( dstFileName , nulmark ) ) { /* Check if destination file already exists */
2016-02-12 06:56:46 -08:00
f = fopen ( dstFileName , " rb " ) ;
if ( f ! = 0 ) { /* dest file exists, prompt for overwrite authorization */
fclose ( f ) ;
2017-04-06 12:56:40 -07:00
if ( ! g_overwrite ) {
if ( g_displayLevel < = 1 ) {
/* No interaction possible */
DISPLAY ( " zstd: %s already exists; not overwritten \n " , dstFileName ) ;
2016-07-01 16:05:31 -07:00
return NULL ;
2015-12-29 02:57:15 -08:00
}
2017-04-06 12:56:40 -07:00
DISPLAY ( " zstd: %s already exists; do you wish to overwrite (y/N) ? " , dstFileName ) ;
{ int ch = getchar ( ) ;
if ( ( ch ! = ' Y ' ) & & ( ch ! = ' y ' ) ) {
DISPLAY ( " not overwritten \n " ) ;
return NULL ;
}
while ( ( ch ! = EOF ) & & ( ch ! = ' \n ' ) ) ch = getchar ( ) ; /* flush rest of input line */
}
}
/* need to unlink */
FIO_remove ( dstFileName ) ;
} }
2016-02-12 06:56:46 -08:00
f = fopen ( dstFileName , " wb " ) ;
2016-08-13 11:49:47 -07:00
if ( f = = NULL ) DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , dstFileName , strerror ( errno ) ) ;
2016-02-12 06:56:46 -08:00
}
2016-07-01 16:05:31 -07:00
2016-02-12 06:56:46 -08:00
return f ;
}
2017-04-11 14:41:02 -07:00
/*! FIO_createDictBuffer() :
* creates a buffer , pointed by ` * bufferPtr ` ,
* loads ` filename ` content into it , up to DICTSIZE_MAX bytes .
* @ return : loaded size
* if fileName = = NULL , returns 0 and a NULL pointer
*/
static size_t FIO_createDictBuffer ( void * * bufferPtr , const char * fileName )
2015-12-17 11:30:14 -08:00
{
FILE * fileHandle ;
U64 fileSize ;
* bufferPtr = NULL ;
2016-02-02 05:36:49 -08:00
if ( fileName = = NULL ) return 0 ;
2015-12-17 11:30:14 -08:00
DISPLAYLEVEL ( 4 , " Loading %s as dictionary \n " , fileName ) ;
fileHandle = fopen ( fileName , " rb " ) ;
2016-07-01 16:05:31 -07:00
if ( fileHandle = = 0 ) EXM_THROW ( 31 , " zstd: %s: %s " , fileName , strerror ( errno ) ) ;
2016-04-28 03:23:33 -07:00
fileSize = UTIL_getFileSize ( fileName ) ;
2017-04-11 14:41:02 -07:00
if ( fileSize > DICTSIZE_MAX ) EXM_THROW ( 32 , " Dictionary file %s is too large (> %u MB) " , fileName , DICTSIZE_MAX > > 20 ) ; /* avoid extreme cases */
2016-07-01 16:05:31 -07:00
* bufferPtr = malloc ( ( size_t ) fileSize ) ;
2016-07-02 02:14:30 -07:00
if ( * bufferPtr = = NULL ) EXM_THROW ( 34 , " zstd: %s " , strerror ( errno ) ) ;
2016-05-30 17:40:42 -07:00
{ size_t const readSize = fread ( * bufferPtr , 1 , ( size_t ) fileSize , fileHandle ) ;
if ( readSize ! = fileSize ) EXM_THROW ( 35 , " Error reading dictionary file %s " , fileName ) ; }
2015-12-17 11:30:14 -08:00
fclose ( fileHandle ) ;
return ( size_t ) fileSize ;
}
2016-04-22 04:59:05 -07:00
# ifndef ZSTD_NOCOMPRESS
2015-12-16 17:23:58 -08:00
2016-03-10 12:02:25 -08:00
/*-**********************************************************************
2015-12-16 17:23:58 -08:00
* Compression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
typedef struct {
2017-01-19 16:59:56 -08:00
FILE * srcFile ;
FILE * dstFile ;
2015-12-16 17:23:58 -08:00
void * srcBuffer ;
size_t srcBufferSize ;
void * dstBuffer ;
size_t dstBufferSize ;
2017-01-19 16:59:56 -08:00
# ifdef ZSTD_MULTITHREAD
ZSTDMT_CCtx * cctx ;
# else
2016-08-13 14:45:45 -07:00
ZSTD_CStream * cctx ;
2017-01-19 16:59:56 -08:00
# endif
2015-12-16 17:23:58 -08:00
} cRess_t ;
2017-01-19 16:59:56 -08:00
static cRess_t FIO_createCResources ( const char * dictFileName , int cLevel ,
2017-02-07 16:33:48 -08:00
U64 srcSize , int srcRegFile ,
ZSTD_compressionParameters * comprParams ) {
2015-12-16 17:23:58 -08:00
cRess_t ress ;
2016-07-13 08:38:39 -07:00
memset ( & ress , 0 , sizeof ( ress ) ) ;
2015-12-16 17:23:58 -08:00
2017-01-19 16:59:56 -08:00
# ifdef ZSTD_MULTITHREAD
ress . cctx = ZSTDMT_createCCtx ( g_nbThreads ) ;
2017-01-25 17:01:13 -08:00
if ( ress . cctx = = NULL ) EXM_THROW ( 30 , " zstd: allocation error : can't create ZSTD_CStream " ) ;
2017-01-30 14:37:08 -08:00
if ( ( cLevel = = ZSTD_maxCLevel ( ) ) & & ( g_overlapLog = = FIO_OVERLAP_LOG_NOTSET ) )
2017-01-30 13:35:45 -08:00
ZSTDMT_setMTCtxParameter ( ress . cctx , ZSTDMT_p_overlapSectionLog , 9 ) ; /* use complete window for overlap */
2017-01-30 14:37:08 -08:00
if ( g_overlapLog ! = FIO_OVERLAP_LOG_NOTSET )
2017-01-30 11:17:26 -08:00
ZSTDMT_setMTCtxParameter ( ress . cctx , ZSTDMT_p_overlapSectionLog , g_overlapLog ) ;
2017-01-19 16:59:56 -08:00
# else
2016-08-13 14:45:45 -07:00
ress . cctx = ZSTD_createCStream ( ) ;
if ( ress . cctx = = NULL ) EXM_THROW ( 30 , " zstd: allocation error : can't create ZSTD_CStream " ) ;
2017-01-25 17:01:13 -08:00
# endif
2016-08-13 14:45:45 -07:00
ress . srcBufferSize = ZSTD_CStreamInSize ( ) ;
2015-12-16 17:23:58 -08:00
ress . srcBuffer = malloc ( ress . srcBufferSize ) ;
2016-08-13 14:45:45 -07:00
ress . dstBufferSize = ZSTD_CStreamOutSize ( ) ;
2015-12-16 17:23:58 -08:00
ress . dstBuffer = malloc ( ress . dstBufferSize ) ;
2016-07-02 02:14:30 -07:00
if ( ! ress . srcBuffer | | ! ress . dstBuffer ) EXM_THROW ( 31 , " zstd: allocation error : not enough memory " ) ;
2015-12-16 17:23:58 -08:00
/* dictionary */
2016-09-15 06:38:44 -07:00
{ void * dictBuffer ;
2017-04-11 16:57:32 -07:00
size_t const dictBuffSize = FIO_createDictBuffer ( & dictBuffer , dictFileName ) ; /* works with dictFileName==NULL */
2016-09-15 06:38:44 -07:00
if ( dictFileName & & ( dictBuffer = = NULL ) ) EXM_THROW ( 32 , " zstd: allocation error : can't create dictBuffer " ) ;
2016-09-21 07:46:08 -07:00
{ ZSTD_parameters params = ZSTD_getParams ( cLevel , srcSize , dictBuffSize ) ;
2017-02-07 16:33:48 -08:00
params . fParams . contentSizeFlag = srcRegFile ;
2016-09-15 06:38:44 -07:00
params . fParams . checksumFlag = g_checksumFlag ;
params . fParams . noDictIDFlag = ! g_dictIDFlag ;
2016-12-13 04:24:59 -08:00
if ( comprParams - > windowLog ) params . cParams . windowLog = comprParams - > windowLog ;
if ( comprParams - > chainLog ) params . cParams . chainLog = comprParams - > chainLog ;
if ( comprParams - > hashLog ) params . cParams . hashLog = comprParams - > hashLog ;
if ( comprParams - > searchLog ) params . cParams . searchLog = comprParams - > searchLog ;
if ( comprParams - > searchLength ) params . cParams . searchLength = comprParams - > searchLength ;
if ( comprParams - > targetLength ) params . cParams . targetLength = comprParams - > targetLength ;
2017-04-11 16:57:32 -07:00
if ( comprParams - > strategy ) params . cParams . strategy = ( ZSTD_strategy ) ( comprParams - > strategy - 1 ) ; /* 0 means : do not change */
2017-01-19 16:59:56 -08:00
# ifdef ZSTD_MULTITHREAD
{ size_t const errorCode = ZSTDMT_initCStream_advanced ( ress . cctx , dictBuffer , dictBuffSize , params , srcSize ) ;
2017-01-24 17:02:26 -08:00
if ( ZSTD_isError ( errorCode ) ) EXM_THROW ( 33 , " Error initializing CStream : %s " , ZSTD_getErrorName ( errorCode ) ) ;
ZSTDMT_setMTCtxParameter ( ress . cctx , ZSTDMT_p_sectionSize , g_blockSize ) ;
2017-01-19 16:59:56 -08:00
# else
2016-09-21 07:46:08 -07:00
{ size_t const errorCode = ZSTD_initCStream_advanced ( ress . cctx , dictBuffer , dictBuffSize , params , srcSize ) ;
2016-09-15 06:38:44 -07:00
if ( ZSTD_isError ( errorCode ) ) EXM_THROW ( 33 , " Error initializing CStream : %s " , ZSTD_getErrorName ( errorCode ) ) ;
2017-01-24 17:02:26 -08:00
# endif
2016-09-15 06:38:44 -07:00
} }
free ( dictBuffer ) ;
}
2015-12-16 17:23:58 -08:00
return ress ;
}
static void FIO_freeCResources ( cRess_t ress )
{
free ( ress . srcBuffer ) ;
free ( ress . dstBuffer ) ;
2017-01-19 16:59:56 -08:00
# ifdef ZSTD_MULTITHREAD
ZSTDMT_freeCCtx ( ress . cctx ) ;
# else
2016-09-15 06:38:44 -07:00
ZSTD_freeCStream ( ress . cctx ) ; /* never fails */
2017-01-19 16:59:56 -08:00
# endif
2015-12-16 17:23:58 -08:00
}
2017-02-08 07:54:23 -08:00
# ifdef ZSTD_GZCOMPRESS
static unsigned long long FIO_compressGzFrame ( cRess_t * ress , const char * srcFileName , U64 const srcFileSize , int compressionLevel , U64 * readsize )
{
unsigned long long inFileSize = 0 , outFileSize = 0 ;
z_stream strm ;
2017-02-08 08:37:14 -08:00
int ret ;
2017-02-08 07:54:23 -08:00
2017-02-13 12:00:41 -08:00
if ( compressionLevel > Z_BEST_COMPRESSION ) compressionLevel = Z_BEST_COMPRESSION ;
2017-02-08 07:54:23 -08:00
strm . zalloc = Z_NULL ;
strm . zfree = Z_NULL ;
strm . opaque = Z_NULL ;
2017-02-08 08:37:14 -08:00
2017-02-14 00:23:32 -08:00
ret = deflateInit2 ( & strm , compressionLevel , Z_DEFLATED , 15 /* maxWindowLogSize */ + 16 /* gzip only */ , 8 , Z_DEFAULT_STRATEGY ) ; /* see http://www.zlib.net/manual.html */
if ( ret ! = Z_OK ) EXM_THROW ( 71 , " zstd: %s: deflateInit2 error %d \n " , srcFileName , ret ) ;
2017-02-08 07:54:23 -08:00
2017-02-08 08:37:14 -08:00
strm . next_in = 0 ;
2017-02-27 04:21:05 -08:00
strm . avail_in = 0 ;
2017-02-08 07:54:23 -08:00
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
while ( 1 ) {
if ( strm . avail_in = = 0 ) {
size_t const inSize = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , ress - > srcFile ) ;
if ( inSize = = 0 ) break ;
inFileSize + = inSize ;
strm . next_in = ( z_const unsigned char * ) ress - > srcBuffer ;
strm . avail_in = ( uInt ) inSize ;
}
ret = deflate ( & strm , Z_NO_FLUSH ) ;
2017-02-08 08:37:14 -08:00
if ( ret ! = Z_OK ) EXM_THROW ( 72 , " zstd: %s: deflate error %d \n " , srcFileName , ret ) ;
2017-02-08 07:54:23 -08:00
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
if ( decompBytes ) {
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes ) EXM_THROW ( 73 , " Write error : cannot write to output file " ) ;
outFileSize + = decompBytes ;
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
}
}
if ( ! srcFileSize ) DISPLAYUPDATE ( 2 , " \r Read : %u MB ==> %.2f%% " , ( U32 ) ( inFileSize > > 20 ) , ( double ) outFileSize / inFileSize * 100 )
else DISPLAYUPDATE ( 2 , " \r Read : %u / %u MB ==> %.2f%% " , ( U32 ) ( inFileSize > > 20 ) , ( U32 ) ( srcFileSize > > 20 ) , ( double ) outFileSize / inFileSize * 100 ) ;
}
while ( 1 ) {
2017-02-08 08:37:14 -08:00
ret = deflate ( & strm , Z_FINISH ) ;
2017-02-08 07:54:23 -08:00
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
if ( decompBytes ) {
2017-02-08 08:37:14 -08:00
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes ) EXM_THROW ( 75 , " Write error : cannot write to output file " ) ;
2017-02-08 07:54:23 -08:00
outFileSize + = decompBytes ;
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
}
}
if ( ret = = Z_STREAM_END ) break ;
2017-02-08 08:37:14 -08:00
if ( ret ! = Z_BUF_ERROR ) EXM_THROW ( 77 , " zstd: %s: deflate error %d \n " , srcFileName , ret ) ;
2017-02-08 07:54:23 -08:00
}
2017-02-08 08:37:14 -08:00
ret = deflateEnd ( & strm ) ;
if ( ret ! = Z_OK ) EXM_THROW ( 79 , " zstd: %s: deflateEnd error %d \n " , srcFileName , ret ) ;
2017-02-08 07:54:23 -08:00
* readsize = inFileSize ;
return outFileSize ;
}
# endif
2017-03-13 18:11:07 -07:00
# ifdef ZSTD_LZMACOMPRESS
static unsigned long long FIO_compressLzmaFrame ( cRess_t * ress , const char * srcFileName , U64 const srcFileSize , int compressionLevel , U64 * readsize , int plain_lzma )
{
unsigned long long inFileSize = 0 , outFileSize = 0 ;
lzma_stream strm = LZMA_STREAM_INIT ;
lzma_action action = LZMA_RUN ;
lzma_ret ret ;
if ( compressionLevel < 0 ) compressionLevel = 0 ;
if ( compressionLevel > 9 ) compressionLevel = 9 ;
if ( plain_lzma ) {
lzma_options_lzma opt_lzma ;
if ( lzma_lzma_preset ( & opt_lzma , compressionLevel ) ) EXM_THROW ( 71 , " zstd: %s: lzma_lzma_preset error " , srcFileName ) ;
ret = lzma_alone_encoder ( & strm , & opt_lzma ) ; /* LZMA */
if ( ret ! = LZMA_OK ) EXM_THROW ( 71 , " zstd: %s: lzma_alone_encoder error %d " , srcFileName , ret ) ;
} else {
ret = lzma_easy_encoder ( & strm , compressionLevel , LZMA_CHECK_CRC64 ) ; /* XZ */
if ( ret ! = LZMA_OK ) EXM_THROW ( 71 , " zstd: %s: lzma_easy_encoder error %d " , srcFileName , ret ) ;
}
strm . next_in = 0 ;
strm . avail_in = 0 ;
strm . next_out = ress - > dstBuffer ;
strm . avail_out = ress - > dstBufferSize ;
while ( 1 ) {
if ( strm . avail_in = = 0 ) {
size_t const inSize = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , ress - > srcFile ) ;
if ( inSize = = 0 ) action = LZMA_FINISH ;
inFileSize + = inSize ;
strm . next_in = ress - > srcBuffer ;
strm . avail_in = inSize ;
}
ret = lzma_code ( & strm , action ) ;
if ( ret ! = LZMA_OK & & ret ! = LZMA_STREAM_END ) EXM_THROW ( 72 , " zstd: %s: lzma_code encoding error %d " , srcFileName , ret ) ;
{ size_t const compBytes = ress - > dstBufferSize - strm . avail_out ;
if ( compBytes ) {
if ( fwrite ( ress - > dstBuffer , 1 , compBytes , ress - > dstFile ) ! = compBytes ) EXM_THROW ( 73 , " Write error : cannot write to output file " ) ;
outFileSize + = compBytes ;
strm . next_out = ress - > dstBuffer ;
strm . avail_out = ress - > dstBufferSize ;
}
}
if ( ! srcFileSize ) DISPLAYUPDATE ( 2 , " \r Read : %u MB ==> %.2f%% " , ( U32 ) ( inFileSize > > 20 ) , ( double ) outFileSize / inFileSize * 100 )
else DISPLAYUPDATE ( 2 , " \r Read : %u / %u MB ==> %.2f%% " , ( U32 ) ( inFileSize > > 20 ) , ( U32 ) ( srcFileSize > > 20 ) , ( double ) outFileSize / inFileSize * 100 ) ;
if ( ret = = LZMA_STREAM_END ) break ;
}
lzma_end ( & strm ) ;
* readsize = inFileSize ;
return outFileSize ;
}
# endif
2017-04-24 16:48:25 -07:00
# ifdef ZSTD_LZ4COMPRESS
static int FIO_LZ4_GetBlockSize_FromBlockId ( int id ) { return ( 1 < < ( 8 + ( 2 * id ) ) ) ; }
static unsigned long long FIO_compressLz4Frame ( cRess_t * ress , const char * srcFileName , U64 const srcFileSize , int compressionLevel , U64 * readsize )
{
unsigned long long inFileSize = 0 , outFileSize = 0 ;
LZ4F_preferences_t prefs ;
2017-04-25 11:00:54 -07:00
LZ4F_compressionContext_t ctx ;
2017-04-24 16:48:25 -07:00
LZ4F_errorCode_t const errorCode = LZ4F_createCompressionContext ( & ctx , LZ4F_VERSION ) ;
if ( LZ4F_isError ( errorCode ) ) EXM_THROW ( 31 , " zstd: failed to create lz4 compression context " ) ;
memset ( & prefs , 0 , sizeof ( prefs ) ) ;
2017-04-26 10:17:38 -07:00
# if LZ4_VERSION_NUMBER <= 10600
# define LZ4F_blockIndependent blockIndependent
# define LZ4F_max4MB max4MB
# endif
2017-04-24 16:48:25 -07:00
prefs . autoFlush = 1 ;
prefs . compressionLevel = compressionLevel ;
2017-04-26 10:17:38 -07:00
prefs . frameInfo . blockMode = LZ4F_blockIndependent ; /* stick to defaults for lz4 cli */
prefs . frameInfo . blockSizeID = LZ4F_max4MB ;
2017-04-25 11:00:54 -07:00
prefs . frameInfo . contentChecksumFlag = ( contentChecksum_t ) g_checksumFlag ;
# if LZ4_VERSION_NUMBER >= 10600
2017-04-24 16:48:25 -07:00
prefs . frameInfo . contentSize = srcFileSize ;
2017-04-25 11:00:54 -07:00
# endif
2017-04-24 16:48:25 -07:00
{
2017-04-26 10:17:38 -07:00
size_t blockSize = FIO_LZ4_GetBlockSize_FromBlockId ( LZ4F_max4MB ) ;
2017-04-24 16:48:25 -07:00
size_t readSize ;
size_t headerSize = LZ4F_compressBegin ( ctx , ress - > dstBuffer , ress - > dstBufferSize , & prefs ) ;
if ( LZ4F_isError ( headerSize ) ) EXM_THROW ( 33 , " File header generation failed : %s " , LZ4F_getErrorName ( headerSize ) ) ;
{ size_t const sizeCheck = fwrite ( ress - > dstBuffer , 1 , headerSize , ress - > dstFile ) ;
if ( sizeCheck ! = headerSize ) EXM_THROW ( 34 , " Write error : cannot write header " ) ; }
outFileSize + = headerSize ;
/* Read first block */
readSize = fread ( ress - > srcBuffer , ( size_t ) 1 , ( size_t ) blockSize , ress - > srcFile ) ;
inFileSize + = readSize ;
/* Main Loop */
while ( readSize > 0 ) {
size_t outSize ;
/* Compress Block */
outSize = LZ4F_compressUpdate ( ctx , ress - > dstBuffer , ress - > dstBufferSize , ress - > srcBuffer , readSize , NULL ) ;
if ( LZ4F_isError ( outSize ) ) EXM_THROW ( 35 , " zstd: %s: lz4 compression failed : %s " , srcFileName , LZ4F_getErrorName ( outSize ) ) ;
outFileSize + = outSize ;
if ( ! srcFileSize ) DISPLAYUPDATE ( 2 , " \r Read : %u MB ==> %.2f%% " , ( U32 ) ( inFileSize > > 20 ) , ( double ) outFileSize / inFileSize * 100 )
else DISPLAYUPDATE ( 2 , " \r Read : %u / %u MB ==> %.2f%% " , ( U32 ) ( inFileSize > > 20 ) , ( U32 ) ( srcFileSize > > 20 ) , ( double ) outFileSize / inFileSize * 100 ) ;
/* Write Block */
{ size_t const sizeCheck = fwrite ( ress - > dstBuffer , 1 , outSize , ress - > dstFile ) ;
if ( sizeCheck ! = outSize ) EXM_THROW ( 36 , " Write error : cannot write compressed block " ) ; }
/* Read next block */
readSize = fread ( ress - > srcBuffer , ( size_t ) 1 , ( size_t ) blockSize , ress - > srcFile ) ;
inFileSize + = readSize ;
}
if ( ferror ( ress - > srcFile ) ) EXM_THROW ( 37 , " Error reading %s " , srcFileName ) ;
/* End of Stream mark */
headerSize = LZ4F_compressEnd ( ctx , ress - > dstBuffer , ress - > dstBufferSize , NULL ) ;
if ( LZ4F_isError ( headerSize ) ) EXM_THROW ( 38 , " zstd: %s: lz4 end of file generation failed : %s " , srcFileName , LZ4F_getErrorName ( headerSize ) ) ;
{ size_t const sizeCheck = fwrite ( ress - > dstBuffer , 1 , headerSize , ress - > dstFile ) ;
if ( sizeCheck ! = headerSize ) EXM_THROW ( 39 , " Write error : cannot write end of stream " ) ; }
outFileSize + = headerSize ;
}
* readsize = inFileSize ;
LZ4F_freeCompressionContext ( ctx ) ;
return outFileSize ;
}
# endif
2017-03-13 18:11:07 -07:00
2016-02-12 06:56:46 -08:00
/*! FIO_compressFilename_internal() :
2016-03-10 12:02:25 -08:00
* same as FIO_compressFilename_extRess ( ) , with ` ress . desFile ` already opened .
2016-02-12 06:56:46 -08:00
* @ return : 0 : compression completed correctly ,
* 1 : missing or pb opening srcFileName
2015-12-16 17:23:58 -08:00
*/
2016-02-12 06:56:46 -08:00
static int FIO_compressFilename_internal ( cRess_t ress ,
2017-02-08 07:54:23 -08:00
const char * dstFileName , const char * srcFileName , int compressionLevel )
2015-12-16 17:23:58 -08:00
{
2016-05-07 13:43:40 -07:00
FILE * const srcFile = ress . srcFile ;
FILE * const dstFile = ress . dstFile ;
2016-03-26 12:52:14 -07:00
U64 readsize = 0 ;
2015-12-16 17:23:58 -08:00
U64 compressedfilesize = 0 ;
2016-04-28 03:23:33 -07:00
U64 const fileSize = UTIL_getFileSize ( srcFileName ) ;
2015-12-16 17:23:58 -08:00
2017-03-13 18:11:07 -07:00
switch ( g_compressionType ) {
case FIO_zstdCompression :
break ;
case FIO_gzipCompression :
2017-02-08 08:37:14 -08:00
# ifdef ZSTD_GZCOMPRESS
2017-03-13 18:11:07 -07:00
compressedfilesize = FIO_compressGzFrame ( & ress , srcFileName , fileSize , compressionLevel , & readsize ) ;
# else
( void ) compressionLevel ;
EXM_THROW ( 20 , " zstd: %s: file cannot be compressed as gzip (zstd compiled without ZSTD_GZCOMPRESS) -- ignored \n " , srcFileName ) ;
# endif
goto finish ;
case FIO_xzCompression :
case FIO_lzmaCompression :
# ifdef ZSTD_LZMACOMPRESS
compressedfilesize = FIO_compressLzmaFrame ( & ress , srcFileName , fileSize , compressionLevel , & readsize , g_compressionType = = FIO_lzmaCompression ) ;
2017-02-08 08:37:14 -08:00
# else
2017-03-13 18:11:07 -07:00
( void ) compressionLevel ;
EXM_THROW ( 20 , " zstd: %s: file cannot be compressed as xz/lzma (zstd compiled without ZSTD_LZMACOMPRESS) -- ignored \n " , srcFileName ) ;
2017-04-24 16:48:25 -07:00
# endif
case FIO_lz4Compression :
# ifdef ZSTD_LZ4COMPRESS
compressedfilesize = FIO_compressLz4Frame ( & ress , srcFileName , fileSize , compressionLevel , & readsize ) ;
# else
( void ) compressionLevel ;
EXM_THROW ( 20 , " zstd: %s: file cannot be compressed as lz4 (zstd compiled without ZSTD_LZ4COMPRESS) -- ignored \n " , srcFileName ) ;
2017-02-08 08:37:14 -08:00
# endif
2017-03-13 18:11:07 -07:00
goto finish ;
2017-02-08 07:54:23 -08:00
}
2015-12-16 17:23:58 -08:00
/* init */
2017-01-19 16:59:56 -08:00
# ifdef ZSTD_MULTITHREAD
{ size_t const resetError = ZSTDMT_resetCStream ( ress . cctx , fileSize ) ;
# else
2016-09-15 06:38:44 -07:00
{ size_t const resetError = ZSTD_resetCStream ( ress . cctx , fileSize ) ;
2017-01-19 16:59:56 -08:00
# endif
2016-09-15 06:38:44 -07:00
if ( ZSTD_isError ( resetError ) ) EXM_THROW ( 21 , " Error initializing compression : %s " , ZSTD_getErrorName ( resetError ) ) ;
}
2015-12-16 17:23:58 -08:00
/* Main compression loop */
2016-01-26 07:31:22 -08:00
while ( 1 ) {
2015-12-16 17:23:58 -08:00
/* Fill input Buffer */
2016-03-26 12:52:14 -07:00
size_t const inSize = fread ( ress . srcBuffer , ( size_t ) 1 , ress . srcBufferSize , srcFile ) ;
2015-12-16 17:23:58 -08:00
if ( inSize = = 0 ) break ;
2016-03-26 12:52:14 -07:00
readsize + = inSize ;
2015-12-16 17:23:58 -08:00
2016-08-16 16:39:22 -07:00
{ ZSTD_inBuffer inBuff = { ress . srcBuffer , inSize , 0 } ;
2017-04-11 16:57:32 -07:00
while ( inBuff . pos ! = inBuff . size ) {
ZSTD_outBuffer outBuff = { ress . dstBuffer , ress . dstBufferSize , 0 } ;
2017-01-19 16:59:56 -08:00
# ifdef ZSTD_MULTITHREAD
size_t const result = ZSTDMT_compressStream ( ress . cctx , & outBuff , & inBuff ) ;
# else
size_t const result = ZSTD_compressStream ( ress . cctx , & outBuff , & inBuff ) ;
# endif
if ( ZSTD_isError ( result ) ) EXM_THROW ( 23 , " Compression error : %s " , ZSTD_getErrorName ( result ) ) ;
2015-12-16 17:23:58 -08:00
2017-01-25 12:31:07 -08:00
/* Write compressed stream */
if ( outBuff . pos ) {
size_t const sizeCheck = fwrite ( ress . dstBuffer , 1 , outBuff . pos , dstFile ) ;
if ( sizeCheck ! = outBuff . pos ) EXM_THROW ( 25 , " Write error : cannot write compressed block into %s " , dstFileName ) ;
compressedfilesize + = outBuff . pos ;
} } }
2017-04-11 16:57:32 -07:00
if ( g_nbThreads > 1 ) {
if ( ! fileSize ) DISPLAYUPDATE ( 2 , " \r Read : %u MB " , ( U32 ) ( readsize > > 20 ) )
else DISPLAYUPDATE ( 2 , " \r Read : %u / %u MB " , ( U32 ) ( readsize > > 20 ) , ( U32 ) ( fileSize > > 20 ) ) ;
} else {
if ( ! fileSize ) DISPLAYUPDATE ( 2 , " \r Read : %u MB ==> %.2f%% " , ( U32 ) ( readsize > > 20 ) , ( double ) compressedfilesize / readsize * 100 )
else DISPLAYUPDATE ( 2 , " \r Read : %u / %u MB ==> %.2f%% " , ( U32 ) ( readsize > > 20 ) , ( U32 ) ( fileSize > > 20 ) , ( double ) compressedfilesize / readsize * 100 ) ;
}
2015-12-16 17:23:58 -08:00
}
/* End of Frame */
2017-01-19 16:59:56 -08:00
{ size_t result = 1 ;
while ( result ! = 0 ) { /* note : is there any possibility of endless loop ? */
ZSTD_outBuffer outBuff = { ress . dstBuffer , ress . dstBufferSize , 0 } ;
# ifdef ZSTD_MULTITHREAD
result = ZSTDMT_endStream ( ress . cctx , & outBuff ) ;
# else
result = ZSTD_endStream ( ress . cctx , & outBuff ) ;
# endif
if ( ZSTD_isError ( result ) ) EXM_THROW ( 26 , " Compression error during frame end : %s " , ZSTD_getErrorName ( result ) ) ;
{ size_t const sizeCheck = fwrite ( ress . dstBuffer , 1 , outBuff . pos , dstFile ) ;
if ( sizeCheck ! = outBuff . pos ) EXM_THROW ( 27 , " Write error : cannot write frame end into %s " , dstFileName ) ; }
compressedfilesize + = outBuff . pos ;
}
2015-12-16 17:23:58 -08:00
}
2017-02-08 07:54:23 -08:00
finish :
2015-12-16 17:23:58 -08:00
/* Status */
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
2016-08-13 11:26:21 -07:00
DISPLAYLEVEL ( 2 , " %-20s :%6.2f%% (%6llu => %6llu bytes, %s) \n " , srcFileName ,
2016-07-13 10:30:40 -07:00
( double ) compressedfilesize / ( readsize + ( ! readsize ) /* avoid div by zero */ ) * 100 ,
( unsigned long long ) readsize , ( unsigned long long ) compressedfilesize ,
dstFileName ) ;
2015-12-16 17:23:58 -08:00
return 0 ;
}
2016-07-01 16:05:31 -07:00
/*! FIO_compressFilename_srcFile() :
* note : ress . destFile already opened
2016-02-15 11:37:23 -08:00
* @ return : 0 : compression completed correctly ,
* 1 : missing or pb opening srcFileName
*/
static int FIO_compressFilename_srcFile ( cRess_t ress ,
2017-02-08 07:54:23 -08:00
const char * dstFileName , const char * srcFileName , int compressionLevel )
2016-02-15 11:37:23 -08:00
{
int result ;
/* File check */
2016-06-09 13:59:51 -07:00
if ( UTIL_isDirectory ( srcFileName ) ) {
DISPLAYLEVEL ( 1 , " zstd: %s is a directory -- ignored \n " , srcFileName ) ;
return 1 ;
}
2017-01-25 04:02:33 -08:00
2016-02-15 11:37:23 -08:00
ress . srcFile = FIO_openSrcFile ( srcFileName ) ;
if ( ! ress . srcFile ) return 1 ; /* srcFile could not be opened */
2017-02-08 07:54:23 -08:00
result = FIO_compressFilename_internal ( ress , dstFileName , srcFileName , compressionLevel ) ;
2016-02-15 11:37:23 -08:00
fclose ( ress . srcFile ) ;
2017-02-27 15:57:50 -08:00
if ( g_removeSrcFile /* --rm */ & & ! result & & strcmp ( srcFileName , stdinmark ) ) {
if ( remove ( srcFileName ) )
EXM_THROW ( 1 , " zstd: %s: %s " , srcFileName , strerror ( errno ) ) ;
}
2016-02-15 11:37:23 -08:00
return result ;
}
2016-06-09 13:59:51 -07:00
/*! FIO_compressFilename_dstFile() :
2016-02-12 06:56:46 -08:00
* @ return : 0 : compression completed correctly ,
2016-06-09 13:59:51 -07:00
* 1 : pb
2016-02-12 06:56:46 -08:00
*/
2016-06-09 13:59:51 -07:00
static int FIO_compressFilename_dstFile ( cRess_t ress ,
2017-02-08 07:54:23 -08:00
const char * dstFileName , const char * srcFileName , int compressionLevel )
2016-02-12 06:56:46 -08:00
{
int result ;
2016-11-02 06:08:07 -07:00
stat_t statbuf ;
int stat_result = 0 ;
2016-02-12 06:56:46 -08:00
ress . dstFile = FIO_openDstFile ( dstFileName ) ;
2016-09-15 06:38:44 -07:00
if ( ress . dstFile = = NULL ) return 1 ; /* could not open dstFileName */
2016-02-12 06:56:46 -08:00
2016-11-02 06:08:07 -07:00
if ( strcmp ( srcFileName , stdinmark ) & & UTIL_getFileStat ( srcFileName , & statbuf ) ) stat_result = 1 ;
2017-02-08 07:54:23 -08:00
result = FIO_compressFilename_srcFile ( ress , dstFileName , srcFileName , compressionLevel ) ;
2016-03-13 22:24:46 -07:00
2016-09-15 06:38:44 -07:00
if ( fclose ( ress . dstFile ) ) { DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , dstFileName , strerror ( errno ) ) ; result = 1 ; } /* error closing dstFile */
2016-07-13 10:30:40 -07:00
if ( result ! = 0 ) { if ( remove ( dstFileName ) ) EXM_THROW ( 1 , " zstd: %s: %s " , dstFileName , strerror ( errno ) ) ; } /* remove operation artefact */
2016-11-02 06:08:07 -07:00
else if ( strcmp ( dstFileName , stdoutmark ) & & stat_result ) UTIL_setFileStat ( dstFileName , & statbuf ) ;
2016-02-12 06:56:46 -08:00
return result ;
}
2015-12-17 05:09:55 -08:00
int FIO_compressFilename ( const char * dstFileName , const char * srcFileName ,
2016-12-13 04:24:59 -08:00
const char * dictFileName , int compressionLevel , ZSTD_compressionParameters * comprParams )
2015-01-23 16:58:16 -08:00
{
2016-05-30 17:29:45 -07:00
clock_t const start = clock ( ) ;
2016-09-21 07:46:08 -07:00
U64 const srcSize = UTIL_getFileSize ( srcFileName ) ;
2017-02-07 16:33:48 -08:00
int const regFile = UTIL_isRegFile ( srcFileName ) ;
2015-01-23 16:58:16 -08:00
2017-02-07 16:33:48 -08:00
cRess_t const ress = FIO_createCResources ( dictFileName , compressionLevel , srcSize , regFile , comprParams ) ;
2017-02-08 07:54:23 -08:00
int const result = FIO_compressFilename_dstFile ( ress , dstFileName , srcFileName , compressionLevel ) ;
2015-01-23 16:58:16 -08:00
2016-07-01 16:05:31 -07:00
double const seconds = ( double ) ( clock ( ) - start ) / CLOCKS_PER_SEC ;
DISPLAYLEVEL ( 4 , " Completed in %.2f sec \n " , seconds ) ;
FIO_freeCResources ( ress ) ;
return result ;
2015-01-23 16:58:16 -08:00
}
2015-12-17 05:09:55 -08:00
int FIO_compressMultipleFilenames ( const char * * inFileNamesTable , unsigned nbFiles ,
2015-12-16 17:23:58 -08:00
const char * suffix ,
2016-12-13 04:24:59 -08:00
const char * dictFileName , int compressionLevel ,
ZSTD_compressionParameters * comprParams )
2015-12-16 17:23:58 -08:00
{
int missed_files = 0 ;
size_t dfnSize = FNSPACE ;
2016-07-13 10:30:40 -07:00
char * dstFileName = ( char * ) malloc ( FNSPACE ) ;
2016-05-07 13:43:40 -07:00
size_t const suffixSize = suffix ? strlen ( suffix ) : 0 ;
2016-09-21 07:46:08 -07:00
U64 const srcSize = ( nbFiles ! = 1 ) ? 0 : UTIL_getFileSize ( inFileNamesTable [ 0 ] ) ;
2017-02-07 16:33:48 -08:00
int const regFile = ( nbFiles ! = 1 ) ? 0 : UTIL_isRegFile ( inFileNamesTable [ 0 ] ) ;
cRess_t ress = FIO_createCResources ( dictFileName , compressionLevel , srcSize , regFile , comprParams ) ;
2015-12-16 17:23:58 -08:00
/* init */
2016-07-13 10:30:40 -07:00
if ( dstFileName = = NULL ) EXM_THROW ( 27 , " FIO_compressMultipleFilenames : allocation error for dstFileName " ) ;
if ( suffix = = NULL ) EXM_THROW ( 28 , " FIO_compressMultipleFilenames : dst unknown " ) ; /* should never happen */
2015-12-16 17:23:58 -08:00
/* loop on each file */
2016-02-15 11:37:23 -08:00
if ( ! strcmp ( suffix , stdoutmark ) ) {
2016-05-07 13:43:40 -07:00
unsigned u ;
2016-02-15 11:37:23 -08:00
ress . dstFile = stdout ;
2016-05-19 01:29:49 -07:00
SET_BINARY_MODE ( stdout ) ;
2016-02-15 11:37:23 -08:00
for ( u = 0 ; u < nbFiles ; u + + )
2017-02-08 07:54:23 -08:00
missed_files + = FIO_compressFilename_srcFile ( ress , stdoutmark , inFileNamesTable [ u ] , compressionLevel ) ;
2016-11-03 03:38:01 -07:00
if ( fclose ( ress . dstFile ) ) EXM_THROW ( 29 , " Write error : cannot properly close stdout " ) ;
2016-02-15 11:37:23 -08:00
} else {
2016-05-07 13:43:40 -07:00
unsigned u ;
2016-02-12 06:56:46 -08:00
for ( u = 0 ; u < nbFiles ; u + + ) {
size_t ifnSize = strlen ( inFileNamesTable [ u ] ) ;
if ( dfnSize < = ifnSize + suffixSize + 1 ) { free ( dstFileName ) ; dfnSize = ifnSize + 20 ; dstFileName = ( char * ) malloc ( dfnSize ) ; }
strcpy ( dstFileName , inFileNamesTable [ u ] ) ;
strcat ( dstFileName , suffix ) ;
2017-02-08 07:54:23 -08:00
missed_files + = FIO_compressFilename_dstFile ( ress , dstFileName , inFileNamesTable [ u ] , compressionLevel ) ;
2016-02-15 11:37:23 -08:00
} }
2015-12-16 17:23:58 -08:00
/* Close & Free */
FIO_freeCResources ( ress ) ;
free ( dstFileName ) ;
return missed_files ;
}
2016-05-07 13:43:40 -07:00
# endif /* #ifndef ZSTD_NOCOMPRESS */
2016-04-22 04:59:05 -07:00
2015-12-16 17:23:58 -08:00
2016-04-22 09:22:30 -07:00
# ifndef ZSTD_NODECOMPRESS
2015-12-16 17:23:58 -08:00
/* **************************************************************************
* Decompression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-12-17 11:30:14 -08:00
typedef struct {
void * srcBuffer ;
2016-12-05 08:39:38 -08:00
size_t srcBufferLoaded ;
2015-12-17 11:30:14 -08:00
size_t srcBufferSize ;
void * dstBuffer ;
size_t dstBufferSize ;
2016-08-13 14:45:45 -07:00
ZSTD_DStream * dctx ;
2016-02-12 09:33:26 -08:00
FILE * dstFile ;
2015-12-17 11:30:14 -08:00
} dRess_t ;
static dRess_t FIO_createDResources ( const char * dictFileName )
{
dRess_t ress ;
2016-07-13 08:38:39 -07:00
memset ( & ress , 0 , sizeof ( ress ) ) ;
2015-12-17 11:30:14 -08:00
2016-07-13 08:38:39 -07:00
/* Allocation */
2016-08-13 14:45:45 -07:00
ress . dctx = ZSTD_createDStream ( ) ;
if ( ress . dctx = = NULL ) EXM_THROW ( 60 , " Can't create ZSTD_DStream " ) ;
2017-01-25 16:25:38 -08:00
ZSTD_setDStreamParameter ( ress . dctx , DStream_p_maxWindowSize , g_memLimit ) ;
2016-08-13 14:45:45 -07:00
ress . srcBufferSize = ZSTD_DStreamInSize ( ) ;
2015-12-17 11:30:14 -08:00
ress . srcBuffer = malloc ( ress . srcBufferSize ) ;
2016-08-13 14:45:45 -07:00
ress . dstBufferSize = ZSTD_DStreamOutSize ( ) ;
2015-12-17 11:30:14 -08:00
ress . dstBuffer = malloc ( ress . dstBufferSize ) ;
if ( ! ress . srcBuffer | | ! ress . dstBuffer ) EXM_THROW ( 61 , " Allocation error : not enough memory " ) ;
2015-12-16 17:23:58 -08:00
2015-12-17 11:30:14 -08:00
/* dictionary */
2016-09-14 08:26:59 -07:00
{ void * dictBuffer ;
2017-04-11 14:41:02 -07:00
size_t const dictBufferSize = FIO_createDictBuffer ( & dictBuffer , dictFileName ) ;
2016-09-14 08:26:59 -07:00
size_t const initError = ZSTD_initDStream_usingDict ( ress . dctx , dictBuffer , dictBufferSize ) ;
if ( ZSTD_isError ( initError ) ) EXM_THROW ( 61 , " ZSTD_initDStream_usingDict error : %s " , ZSTD_getErrorName ( initError ) ) ;
free ( dictBuffer ) ;
}
2015-12-17 11:30:14 -08:00
return ress ;
}
static void FIO_freeDResources ( dRess_t ress )
{
2016-08-13 14:45:45 -07:00
size_t const errorCode = ZSTD_freeDStream ( ress . dctx ) ;
if ( ZSTD_isError ( errorCode ) ) EXM_THROW ( 69 , " Error : can't free ZSTD_DStream context resource : %s " , ZSTD_getErrorName ( errorCode ) ) ;
2015-12-17 11:30:14 -08:00
free ( ress . srcBuffer ) ;
free ( ress . dstBuffer ) ;
}
2016-05-23 07:56:56 -07:00
/** FIO_fwriteSparse() :
* @ return : storedSkips , to be provided to next call to FIO_fwriteSparse ( ) of LZ4IO_fwriteSparseEnd ( ) */
static unsigned FIO_fwriteSparse ( FILE * file , const void * buffer , size_t bufferSize , unsigned storedSkips )
{
const size_t * const bufferT = ( const size_t * ) buffer ; /* Buffer is supposed malloc'ed, hence aligned on size_t */
size_t bufferSizeT = bufferSize / sizeof ( size_t ) ;
const size_t * const bufferTEnd = bufferT + bufferSizeT ;
const size_t * ptrT = bufferT ;
static const size_t segmentSizeT = ( 32 KB ) / sizeof ( size_t ) ; /* 0-test re-attempted every 32 KB */
if ( ! g_sparseFileSupport ) { /* normal write */
size_t const sizeCheck = fwrite ( buffer , 1 , bufferSize , file ) ;
if ( sizeCheck ! = bufferSize ) EXM_THROW ( 70 , " Write error : cannot write decoded block " ) ;
return 0 ;
}
/* avoid int overflow */
if ( storedSkips > 1 GB ) {
2017-02-12 01:27:18 -08:00
int const seekResult = LONG_SEEK ( file , 1 GB , SEEK_CUR ) ;
2016-05-23 07:56:56 -07:00
if ( seekResult ! = 0 ) EXM_THROW ( 71 , " 1 GB skip error (sparse file support) " ) ;
storedSkips - = 1 GB ;
}
while ( ptrT < bufferTEnd ) {
size_t seg0SizeT = segmentSizeT ;
size_t nb0T ;
/* count leading zeros */
if ( seg0SizeT > bufferSizeT ) seg0SizeT = bufferSizeT ;
bufferSizeT - = seg0SizeT ;
for ( nb0T = 0 ; ( nb0T < seg0SizeT ) & & ( ptrT [ nb0T ] = = 0 ) ; nb0T + + ) ;
storedSkips + = ( unsigned ) ( nb0T * sizeof ( size_t ) ) ;
if ( nb0T ! = seg0SizeT ) { /* not all 0s */
2017-02-12 01:27:18 -08:00
int const seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2016-05-23 07:56:56 -07:00
if ( seekResult ) EXM_THROW ( 72 , " Sparse skip error ; try --no-sparse " ) ;
storedSkips = 0 ;
seg0SizeT - = nb0T ;
ptrT + = nb0T ;
{ size_t const sizeCheck = fwrite ( ptrT , sizeof ( size_t ) , seg0SizeT , file ) ;
if ( sizeCheck ! = seg0SizeT ) EXM_THROW ( 73 , " Write error : cannot write decoded block " ) ;
} }
ptrT + = seg0SizeT ;
}
{ static size_t const maskT = sizeof ( size_t ) - 1 ;
if ( bufferSize & maskT ) { /* size not multiple of sizeof(size_t) : implies end of block */
const char * const restStart = ( const char * ) bufferTEnd ;
const char * restPtr = restStart ;
size_t restSize = bufferSize & maskT ;
const char * const restEnd = restStart + restSize ;
for ( ; ( restPtr < restEnd ) & & ( * restPtr = = 0 ) ; restPtr + + ) ;
storedSkips + = ( unsigned ) ( restPtr - restStart ) ;
if ( restPtr ! = restEnd ) {
2017-02-12 01:27:18 -08:00
int seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2016-05-23 07:56:56 -07:00
if ( seekResult ) EXM_THROW ( 74 , " Sparse skip error ; try --no-sparse " ) ;
storedSkips = 0 ;
{ size_t const sizeCheck = fwrite ( restPtr , 1 , restEnd - restPtr , file ) ;
if ( sizeCheck ! = ( size_t ) ( restEnd - restPtr ) ) EXM_THROW ( 75 , " Write error : cannot write decoded end of block " ) ;
} } } }
return storedSkips ;
}
static void FIO_fwriteSparseEnd ( FILE * file , unsigned storedSkips )
{
if ( storedSkips - - > 0 ) { /* implies g_sparseFileSupport>0 */
2017-02-12 01:27:18 -08:00
int const seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2017-03-13 18:11:07 -07:00
if ( seekResult ! = 0 ) EXM_THROW ( 69 , " Final skip error (sparse file) " ) ;
2016-05-23 07:56:56 -07:00
{ const char lastZeroByte [ 1 ] = { 0 } ;
size_t const sizeCheck = fwrite ( lastZeroByte , 1 , 1 , file ) ;
2017-03-13 18:11:07 -07:00
if ( sizeCheck ! = 1 ) EXM_THROW ( 69 , " Write error : cannot write last zero " ) ;
2016-05-23 07:56:56 -07:00
} }
}
2016-12-05 08:39:38 -08:00
/** FIO_passThrough() : just copy input into output, for compatibility with gzip -df mode
@ return : 0 ( no error ) */
2016-12-05 09:31:14 -08:00
static unsigned FIO_passThrough ( FILE * foutput , FILE * finput , void * buffer , size_t bufferSize , size_t alreadyLoaded )
2016-12-05 08:39:38 -08:00
{
size_t const blockSize = MIN ( 64 KB , bufferSize ) ;
size_t readFromInput = 1 ;
unsigned storedSkips = 0 ;
2016-12-05 09:31:14 -08:00
/* assumption : ress->srcBufferLoaded bytes already loaded and stored within buffer */
{ size_t const sizeCheck = fwrite ( buffer , 1 , alreadyLoaded , foutput ) ;
if ( sizeCheck ! = alreadyLoaded ) EXM_THROW ( 50 , " Pass-through write error " ) ; }
2016-12-05 08:39:38 -08:00
while ( readFromInput ) {
readFromInput = fread ( buffer , 1 , blockSize , finput ) ;
storedSkips = FIO_fwriteSparse ( foutput , buffer , readFromInput , storedSkips ) ;
}
FIO_fwriteSparseEnd ( foutput , storedSkips ) ;
return 0 ;
}
2016-03-15 04:56:03 -07:00
/** FIO_decompressFrame() :
@ return : size of decoded frame
*/
2016-12-05 08:39:38 -08:00
unsigned long long FIO_decompressFrame ( dRess_t * ress ,
FILE * finput ,
2016-11-07 14:41:21 -08:00
U64 alreadyDecoded )
2015-01-23 16:58:16 -08:00
{
2016-08-28 12:47:17 -07:00
U64 frameSize = 0 ;
2016-05-23 07:56:56 -07:00
U32 storedSkips = 0 ;
2015-01-23 16:58:16 -08:00
2016-12-05 08:39:38 -08:00
ZSTD_resetDStream ( ress - > dctx ) ;
2016-03-15 04:56:03 -07:00
2016-05-10 05:14:19 -07:00
/* Header loading (optional, saves one loop) */
2016-12-05 08:39:38 -08:00
{ size_t const toRead = 9 ;
if ( ress - > srcBufferLoaded < toRead )
ress - > srcBufferLoaded + = fread ( ( ( char * ) ress - > srcBuffer ) + ress - > srcBufferLoaded , 1 , toRead - ress - > srcBufferLoaded , finput ) ;
2016-03-15 04:56:03 -07:00
}
/* Main decompression Loop */
2016-02-02 05:36:49 -08:00
while ( 1 ) {
2016-12-05 08:39:38 -08:00
ZSTD_inBuffer inBuff = { ress - > srcBuffer , ress - > srcBufferLoaded , 0 } ;
ZSTD_outBuffer outBuff = { ress - > dstBuffer , ress - > dstBufferSize , 0 } ;
size_t const readSizeHint = ZSTD_decompressStream ( ress - > dctx , & outBuff , & inBuff ) ;
2016-09-07 05:54:23 -07:00
if ( ZSTD_isError ( readSizeHint ) ) EXM_THROW ( 36 , " Decoding error : %s " , ZSTD_getErrorName ( readSizeHint ) ) ;
2015-11-25 05:42:45 -08:00
/* Write block */
2017-01-19 16:59:56 -08:00
storedSkips = FIO_fwriteSparse ( ress - > dstFile , ress - > dstBuffer , outBuff . pos , storedSkips ) ;
2016-08-16 16:39:22 -07:00
frameSize + = outBuff . pos ;
2016-11-07 14:41:21 -08:00
DISPLAYUPDATE ( 2 , " \r Decoded : %u MB... " , ( U32 ) ( ( alreadyDecoded + frameSize ) > > 20 ) ) ;
2015-11-25 05:42:45 -08:00
2016-12-05 08:39:38 -08:00
if ( inBuff . pos > 0 ) {
memmove ( ress - > srcBuffer , ( char * ) ress - > srcBuffer + inBuff . pos , inBuff . size - inBuff . pos ) ;
ress - > srcBufferLoaded - = inBuff . pos ;
}
2016-09-07 05:54:23 -07:00
if ( readSizeHint = = 0 ) break ; /* end of frame */
2016-08-16 16:39:22 -07:00
if ( inBuff . size ! = inBuff . pos ) EXM_THROW ( 37 , " Decoding error : should consume entire input " ) ;
2015-01-23 16:58:16 -08:00
/* Fill input buffer */
2016-12-05 08:39:38 -08:00
{ size_t const toRead = MIN ( readSizeHint , ress - > srcBufferSize ) ; /* support large skippable frames */
if ( ress - > srcBufferLoaded < toRead )
ress - > srcBufferLoaded + = fread ( ( ( char * ) ress - > srcBuffer ) + ress - > srcBufferLoaded , 1 , toRead - ress - > srcBufferLoaded , finput ) ;
if ( ress - > srcBufferLoaded < toRead ) EXM_THROW ( 39 , " Read error : premature end " ) ;
2016-09-07 05:54:23 -07:00
} }
2015-01-23 16:58:16 -08:00
2016-12-05 08:39:38 -08:00
FIO_fwriteSparseEnd ( ress - > dstFile , storedSkips ) ;
2016-05-23 07:56:56 -07:00
2015-11-25 05:42:45 -08:00
return frameSize ;
2015-09-10 15:26:09 -07:00
}
2016-12-01 02:56:31 -08:00
# ifdef ZSTD_GZDECOMPRESS
2016-12-05 08:39:38 -08:00
static unsigned long long FIO_decompressGzFrame ( dRess_t * ress , FILE * srcFile , const char * srcFileName )
2016-12-02 04:50:29 -08:00
{
2016-12-02 12:40:57 -08:00
unsigned long long outFileSize = 0 ;
2016-12-02 06:01:31 -08:00
z_stream strm ;
2017-03-13 18:11:07 -07:00
int flush = Z_NO_FLUSH ;
2017-02-27 04:21:05 -08:00
int ret ;
2016-12-02 12:40:57 -08:00
2016-12-02 06:01:31 -08:00
strm . zalloc = Z_NULL ;
strm . zfree = Z_NULL ;
strm . opaque = Z_NULL ;
strm . next_in = 0 ;
2017-02-27 04:21:05 -08:00
strm . avail_in = 0 ;
2016-12-02 12:40:57 -08:00
if ( inflateInit2 ( & strm , 15 /* maxWindowLogSize */ + 16 /* gzip only */ ) ! = Z_OK ) return 0 ; /* see http://www.zlib.net/manual.html */
2017-02-03 08:43:06 -08:00
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
2017-02-02 17:12:50 -08:00
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
strm . avail_in = ( uInt ) ress - > srcBufferLoaded ;
2016-12-05 08:39:38 -08:00
strm . next_in = ( z_const unsigned char * ) ress - > srcBuffer ;
2016-12-01 02:56:31 -08:00
2016-12-02 06:01:31 -08:00
for ( ; ; ) {
2016-12-05 08:39:38 -08:00
if ( strm . avail_in = = 0 ) {
ress - > srcBufferLoaded = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , srcFile ) ;
2017-03-13 18:11:07 -07:00
if ( ress - > srcBufferLoaded = = 0 ) flush = Z_FINISH ;
2016-12-05 08:39:38 -08:00
strm . next_in = ( z_const unsigned char * ) ress - > srcBuffer ;
2017-02-02 17:12:50 -08:00
strm . avail_in = ( uInt ) ress - > srcBufferLoaded ;
2016-12-02 04:11:39 -08:00
}
2017-03-13 18:11:07 -07:00
ret = inflate ( & strm , flush ) ;
if ( ret = = Z_BUF_ERROR ) EXM_THROW ( 39 , " zstd: %s: premature end " , srcFileName ) ;
2016-12-05 08:39:38 -08:00
if ( ret ! = Z_OK & & ret ! = Z_STREAM_END ) { DISPLAY ( " zstd: %s: inflate error %d \n " , srcFileName , ret ) ; return 0 ; }
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
2016-12-02 12:40:57 -08:00
if ( decompBytes ) {
2016-12-05 08:39:38 -08:00
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes ) EXM_THROW ( 31 , " Write error : cannot write to output file " ) ;
2016-12-02 12:40:57 -08:00
outFileSize + = decompBytes ;
2017-02-03 08:43:06 -08:00
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
2017-02-02 17:12:50 -08:00
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
2016-12-05 08:39:38 -08:00
}
}
if ( ret = = Z_STREAM_END ) break ;
}
2016-12-01 02:56:31 -08:00
2016-12-05 08:39:38 -08:00
if ( strm . avail_in > 0 ) memmove ( ress - > srcBuffer , strm . next_in , strm . avail_in ) ;
ress - > srcBufferLoaded = strm . avail_in ;
2017-02-27 04:21:05 -08:00
ret = inflateEnd ( & strm ) ;
2017-03-13 18:11:07 -07:00
if ( ret ! = Z_OK ) EXM_THROW ( 32 , " zstd: %s: inflateEnd error %d " , srcFileName , ret ) ;
return outFileSize ;
}
# endif
# ifdef ZSTD_LZMADECOMPRESS
static unsigned long long FIO_decompressLzmaFrame ( dRess_t * ress , FILE * srcFile , const char * srcFileName , int plain_lzma )
{
unsigned long long outFileSize = 0 ;
lzma_stream strm = LZMA_STREAM_INIT ;
lzma_action action = LZMA_RUN ;
lzma_ret ret ;
strm . next_in = 0 ;
strm . avail_in = 0 ;
if ( plain_lzma ) {
ret = lzma_alone_decoder ( & strm , UINT64_MAX ) ; /* LZMA */
} else {
ret = lzma_stream_decoder ( & strm , UINT64_MAX , 0 ) ; /* XZ */
}
if ( ret ! = LZMA_OK ) EXM_THROW ( 71 , " zstd: %s: lzma_alone_decoder/lzma_stream_decoder error %d " , srcFileName , ret ) ;
strm . next_out = ress - > dstBuffer ;
strm . avail_out = ress - > dstBufferSize ;
strm . avail_in = ress - > srcBufferLoaded ;
strm . next_in = ress - > srcBuffer ;
for ( ; ; ) {
if ( strm . avail_in = = 0 ) {
ress - > srcBufferLoaded = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , srcFile ) ;
if ( ress - > srcBufferLoaded = = 0 ) action = LZMA_FINISH ;
strm . next_in = ress - > srcBuffer ;
strm . avail_in = ress - > srcBufferLoaded ;
}
ret = lzma_code ( & strm , action ) ;
if ( ret = = LZMA_BUF_ERROR ) EXM_THROW ( 39 , " zstd: %s: premature end " , srcFileName ) ;
if ( ret ! = LZMA_OK & & ret ! = LZMA_STREAM_END ) { DISPLAY ( " zstd: %s: lzma_code decoding error %d \n " , srcFileName , ret ) ; return 0 ; }
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
if ( decompBytes ) {
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes ) EXM_THROW ( 31 , " Write error : cannot write to output file " ) ;
outFileSize + = decompBytes ;
strm . next_out = ress - > dstBuffer ;
strm . avail_out = ress - > dstBufferSize ;
}
}
if ( ret = = LZMA_STREAM_END ) break ;
}
if ( strm . avail_in > 0 ) memmove ( ress - > srcBuffer , strm . next_in , strm . avail_in ) ;
ress - > srcBufferLoaded = strm . avail_in ;
lzma_end ( & strm ) ;
2016-12-02 06:01:31 -08:00
return outFileSize ;
2016-12-01 02:56:31 -08:00
}
# endif
2017-04-24 16:48:25 -07:00
# ifdef ZSTD_LZ4DECOMPRESS
static unsigned long long FIO_decompressLz4Frame ( dRess_t * ress , FILE * srcFile , const char * srcFileName )
{
unsigned long long filesize = 0 ;
LZ4F_errorCode_t nextToLoad ;
2017-04-25 11:00:54 -07:00
LZ4F_decompressionContext_t dCtx ;
2017-04-24 16:48:25 -07:00
LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext ( & dCtx , LZ4F_VERSION ) ;
if ( LZ4F_isError ( errorCode ) ) EXM_THROW ( 61 , " zstd: failed to create lz4 decompression context " ) ;
/* Init feed with magic number (already consumed from FILE* sFile) */
{ size_t inSize = 4 ;
size_t outSize = 0 ;
MEM_writeLE32 ( ress - > srcBuffer , LZ4_MAGICNUMBER ) ;
nextToLoad = LZ4F_decompress ( dCtx , ress - > dstBuffer , & outSize , ress - > srcBuffer , & inSize , NULL ) ;
if ( LZ4F_isError ( nextToLoad ) ) EXM_THROW ( 62 , " zstd: %s: lz4 header error : %s " , srcFileName , LZ4F_getErrorName ( nextToLoad ) ) ;
}
/* Main Loop */
for ( ; nextToLoad ; ) {
size_t readSize ;
size_t pos = 0 ;
size_t decodedBytes = ress - > dstBufferSize ;
/* Read input */
if ( nextToLoad > ress - > srcBufferSize ) nextToLoad = ress - > srcBufferSize ;
readSize = fread ( ress - > srcBuffer , 1 , nextToLoad , srcFile ) ;
if ( ! readSize ) break ; /* reached end of file or stream */
while ( ( pos < readSize ) | | ( decodedBytes = = ress - > dstBufferSize ) ) { /* still to read, or still to flush */
/* Decode Input (at least partially) */
size_t remaining = readSize - pos ;
decodedBytes = ress - > dstBufferSize ;
nextToLoad = LZ4F_decompress ( dCtx , ress - > dstBuffer , & decodedBytes , ( char * ) ( ress - > srcBuffer ) + pos , & remaining , NULL ) ;
if ( LZ4F_isError ( nextToLoad ) ) EXM_THROW ( 66 , " zstd: %s: decompression error : %s " , srcFileName , LZ4F_getErrorName ( nextToLoad ) ) ;
pos + = remaining ;
/* Write Block */
if ( decodedBytes ) {
if ( fwrite ( ress - > dstBuffer , 1 , decodedBytes , ress - > dstFile ) ! = decodedBytes ) EXM_THROW ( 63 , " Write error : cannot write to output file " ) ;
filesize + = decodedBytes ;
DISPLAYUPDATE ( 2 , " \r Decompressed : %u MB " , ( unsigned ) ( filesize > > 20 ) ) ;
}
if ( ! nextToLoad ) break ;
}
}
/* can be out because readSize == 0, which could be an fread() error */
if ( ferror ( srcFile ) ) EXM_THROW ( 67 , " zstd: %s: read error " , srcFileName ) ;
if ( nextToLoad ! = 0 ) EXM_THROW ( 68 , " zstd: %s: unfinished stream " , srcFileName ) ;
LZ4F_freeDecompressionContext ( dCtx ) ;
ress - > srcBufferLoaded = 0 ; /* LZ4F will go to the frame boundary */
return filesize ;
}
# endif
2016-12-01 02:56:31 -08:00
2016-02-12 09:33:26 -08:00
/** FIO_decompressSrcFile() :
Decompression ` srcFileName ` into ` ress . dstFile `
@ return : 0 : OK
1 : operation not started
*/
2016-12-02 15:18:57 -08:00
static int FIO_decompressSrcFile ( dRess_t ress , const char * dstFileName , const char * srcFileName )
2015-10-18 14:18:32 -07:00
{
2016-12-02 04:50:29 -08:00
FILE * srcFile ;
2016-07-26 07:44:09 -07:00
unsigned readSomething = 0 ;
2016-12-02 12:40:57 -08:00
unsigned long long filesize = 0 ;
2016-11-30 04:34:21 -08:00
2016-06-09 13:59:51 -07:00
if ( UTIL_isDirectory ( srcFileName ) ) {
DISPLAYLEVEL ( 1 , " zstd: %s is a directory -- ignored \n " , srcFileName ) ;
return 1 ;
}
2016-11-30 04:34:21 -08:00
2016-12-02 04:50:29 -08:00
srcFile = FIO_openSrcFile ( srcFileName ) ;
2017-02-27 00:27:30 -08:00
if ( srcFile = = NULL ) return 1 ;
2016-11-30 06:05:54 -08:00
2016-12-02 06:01:31 -08:00
/* for each frame */
for ( ; ; ) {
/* check magic number -> version */
2016-12-02 07:20:16 -08:00
size_t const toRead = 4 ;
const BYTE * buf = ( const BYTE * ) ress . srcBuffer ;
2016-12-05 08:39:38 -08:00
if ( ress . srcBufferLoaded < toRead )
ress . srcBufferLoaded + = fread ( ( char * ) ress . srcBuffer + ress . srcBufferLoaded , ( size_t ) 1 , toRead - ress . srcBufferLoaded , srcFile ) ;
if ( ress . srcBufferLoaded = = 0 ) {
2016-12-02 07:20:16 -08:00
if ( readSomething = = 0 ) { DISPLAY ( " zstd: %s: unexpected end of file \n " , srcFileName ) ; fclose ( srcFile ) ; return 1 ; } /* srcFileName is empty */
break ; /* no more input */
}
readSomething = 1 ; /* there is at least >= 4 bytes in srcFile */
2016-12-05 08:39:38 -08:00
if ( ress . srcBufferLoaded < toRead ) { DISPLAY ( " zstd: %s: unknown header \n " , srcFileName ) ; fclose ( srcFile ) ; return 1 ; } /* srcFileName is empty */
2017-03-13 18:11:07 -07:00
if ( buf [ 0 ] = = 31 & & buf [ 1 ] = = 139 ) { /* gz magic number */
2016-12-02 06:01:31 -08:00
# ifdef ZSTD_GZDECOMPRESS
2016-12-05 08:39:38 -08:00
unsigned long long const result = FIO_decompressGzFrame ( & ress , srcFile , srcFileName ) ;
2016-12-02 07:20:16 -08:00
if ( result = = 0 ) return 1 ;
filesize + = result ;
2016-11-30 06:05:54 -08:00
# else
2016-12-02 12:40:57 -08:00
DISPLAYLEVEL ( 1 , " zstd: %s: gzip file cannot be uncompressed (zstd compiled without ZSTD_GZDECOMPRESS) -- ignored \n " , srcFileName ) ;
2016-12-02 07:20:16 -08:00
return 1 ;
2017-03-13 18:11:07 -07:00
# endif
} else if ( ( buf [ 0 ] = = 0xFD & & buf [ 1 ] = = 0x37 ) /* xz magic number */
| | ( buf [ 0 ] = = 0x5D & & buf [ 1 ] = = 0x00 ) ) { /* lzma header (no magic number) */
# ifdef ZSTD_LZMADECOMPRESS
unsigned long long const result = FIO_decompressLzmaFrame ( & ress , srcFile , srcFileName , buf [ 0 ] ! = 0xFD ) ;
if ( result = = 0 ) return 1 ;
filesize + = result ;
# else
DISPLAYLEVEL ( 1 , " zstd: %s: xz/lzma file cannot be uncompressed (zstd compiled without ZSTD_LZMADECOMPRESS) -- ignored \n " , srcFileName ) ;
return 1 ;
2017-04-24 16:48:25 -07:00
# endif
} else if ( MEM_readLE32 ( buf ) = = LZ4_MAGICNUMBER ) {
# ifdef ZSTD_LZ4DECOMPRESS
unsigned long long const result = FIO_decompressLz4Frame ( & ress , srcFile , srcFileName ) ;
if ( result = = 0 ) return 1 ;
filesize + = result ;
# else
DISPLAYLEVEL ( 1 , " zstd: %s: lz4 file cannot be uncompressed (zstd compiled without ZSTD_LZ4DECOMPRESS) -- ignored \n " , srcFileName ) ;
return 1 ;
2016-11-30 06:05:54 -08:00
# endif
2016-12-02 07:20:16 -08:00
} else {
if ( ! ZSTD_isFrame ( ress . srcBuffer , toRead ) ) {
2016-12-02 15:18:57 -08:00
if ( ( g_overwrite ) & & ! strcmp ( dstFileName , stdoutmark ) ) { /* pass-through mode */
2016-12-05 09:31:14 -08:00
unsigned const result = FIO_passThrough ( ress . dstFile , srcFile , ress . srcBuffer , ress . srcBufferSize , ress . srcBufferLoaded ) ;
2016-12-02 07:20:16 -08:00
if ( fclose ( srcFile ) ) EXM_THROW ( 32 , " zstd: %s close error " , srcFileName ) ; /* error should never happen */
return result ;
} else {
DISPLAYLEVEL ( 1 , " zstd: %s: not in zstd format \n " , srcFileName ) ;
fclose ( srcFile ) ;
return 1 ;
} }
2016-12-05 08:39:38 -08:00
filesize + = FIO_decompressFrame ( & ress , srcFile , filesize ) ;
2016-12-02 06:01:31 -08:00
}
2015-10-18 14:18:32 -07:00
}
2015-12-17 11:30:14 -08:00
/* Final Status */
2015-10-18 14:18:32 -07:00
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
2016-08-28 12:47:17 -07:00
DISPLAYLEVEL ( 2 , " %-20s: %llu bytes \n " , srcFileName , filesize ) ;
2015-10-18 14:18:32 -07:00
2016-12-02 04:50:29 -08:00
/* Close file */
if ( fclose ( srcFile ) ) EXM_THROW ( 33 , " zstd: %s close error " , srcFileName ) ; /* error should never happen */
2017-02-28 00:42:37 -08:00
if ( g_removeSrcFile /* --rm */ & & strcmp ( srcFileName , stdinmark ) ) { if ( remove ( srcFileName ) ) EXM_THROW ( 34 , " zstd: %s: %s " , srcFileName , strerror ( errno ) ) ; } ;
2016-02-12 09:33:26 -08:00
return 0 ;
}
/** FIO_decompressFile_extRess() :
decompress ` srcFileName ` into ` dstFileName `
@ return : 0 : OK
1 : operation aborted ( src not available , dst already taken , etc . )
*/
2016-06-09 13:59:51 -07:00
static int FIO_decompressDstFile ( dRess_t ress ,
2016-12-02 12:40:57 -08:00
const char * dstFileName , const char * srcFileName )
2016-02-12 09:33:26 -08:00
{
2016-03-13 22:24:46 -07:00
int result ;
2016-11-02 06:08:07 -07:00
stat_t statbuf ;
int stat_result = 0 ;
2016-11-02 05:08:39 -07:00
2016-02-12 09:33:26 -08:00
ress . dstFile = FIO_openDstFile ( dstFileName ) ;
if ( ress . dstFile = = 0 ) return 1 ;
2015-12-17 11:30:14 -08:00
2016-11-02 06:08:07 -07:00
if ( strcmp ( srcFileName , stdinmark ) & & UTIL_getFileStat ( srcFileName , & statbuf ) ) stat_result = 1 ;
2016-12-02 15:18:57 -08:00
result = FIO_decompressSrcFile ( ress , dstFileName , srcFileName ) ;
2016-02-12 09:33:26 -08:00
2016-11-07 14:41:21 -08:00
if ( fclose ( ress . dstFile ) ) EXM_THROW ( 38 , " Write error : cannot properly close %s " , dstFileName ) ;
2016-11-02 05:08:39 -07:00
2016-09-06 22:00:08 -07:00
if ( ( result ! = 0 )
& & strcmp ( dstFileName , nulmark ) /* special case : don't remove() /dev/null (#316) */
& & remove ( dstFileName ) )
2016-09-06 22:01:33 -07:00
result = 1 ; /* don't do anything special if remove() fails */
2016-11-02 06:08:07 -07:00
else if ( strcmp ( dstFileName , stdoutmark ) & & stat_result ) UTIL_setFileStat ( dstFileName , & statbuf ) ;
2016-03-13 22:24:46 -07:00
return result ;
2015-10-18 14:18:32 -07:00
}
2015-12-17 11:30:14 -08:00
int FIO_decompressFilename ( const char * dstFileName , const char * srcFileName ,
const char * dictFileName )
{
int missingFiles = 0 ;
dRess_t ress = FIO_createDResources ( dictFileName ) ;
2016-06-09 13:59:51 -07:00
missingFiles + = FIO_decompressDstFile ( ress , dstFileName , srcFileName ) ;
2015-12-17 11:30:14 -08:00
FIO_freeDResources ( ress ) ;
return missingFiles ;
}
# define MAXSUFFIXSIZE 8
int FIO_decompressMultipleFilenames ( const char * * srcNamesTable , unsigned nbFiles ,
const char * suffix ,
const char * dictFileName )
{
int skippedFiles = 0 ;
int missingFiles = 0 ;
2016-05-09 20:37:43 -07:00
dRess_t ress = FIO_createDResources ( dictFileName ) ;
2015-12-17 11:30:14 -08:00
2016-07-13 10:30:40 -07:00
if ( suffix = = NULL ) EXM_THROW ( 70 , " zstd: decompression: unknown dst " ) ; /* should never happen */
2016-12-02 15:18:57 -08:00
if ( ! strcmp ( suffix , stdoutmark ) | | ! strcmp ( suffix , nulmark ) ) { /* special cases : -c or -t */
2016-05-07 13:43:40 -07:00
unsigned u ;
2016-02-15 10:33:16 -08:00
ress . dstFile = FIO_openDstFile ( suffix ) ;
if ( ress . dstFile = = 0 ) EXM_THROW ( 71 , " cannot open %s " , suffix ) ;
for ( u = 0 ; u < nbFiles ; u + + )
2016-12-02 15:18:57 -08:00
missingFiles + = FIO_decompressSrcFile ( ress , suffix , srcNamesTable [ u ] ) ;
2016-11-03 03:38:01 -07:00
if ( fclose ( ress . dstFile ) ) EXM_THROW ( 72 , " Write error : cannot properly close stdout " ) ;
2016-02-15 10:33:16 -08:00
} else {
2017-03-13 18:11:07 -07:00
size_t suffixSize ;
2016-05-09 20:37:43 -07:00
size_t dfnSize = FNSPACE ;
2016-05-07 13:43:40 -07:00
unsigned u ;
2016-05-09 20:37:43 -07:00
char * dstFileName = ( char * ) malloc ( FNSPACE ) ;
2016-07-13 10:30:40 -07:00
if ( dstFileName = = NULL ) EXM_THROW ( 73 , " not enough memory for dstFileName " ) ;
2016-02-12 09:33:26 -08:00
for ( u = 0 ; u < nbFiles ; u + + ) { /* create dstFileName */
2016-05-09 20:37:43 -07:00
const char * const srcFileName = srcNamesTable [ u ] ;
2017-03-13 18:11:07 -07:00
const char * const suffixPtr = strrchr ( srcFileName , ' . ' ) ;
2016-05-09 20:37:43 -07:00
size_t const sfnSize = strlen ( srcFileName ) ;
2017-03-13 18:11:07 -07:00
if ( ! suffixPtr ) {
DISPLAYLEVEL ( 1 , " zstd: %s: unknown suffix -- ignored \n " , srcFileName ) ;
skippedFiles + + ;
continue ;
}
suffixSize = strlen ( suffixPtr ) ;
2016-02-15 10:33:16 -08:00
if ( dfnSize + suffixSize < = sfnSize + 1 ) {
free ( dstFileName ) ;
dfnSize = sfnSize + 20 ;
dstFileName = ( char * ) malloc ( dfnSize ) ;
2016-07-13 10:30:40 -07:00
if ( dstFileName = = NULL ) EXM_THROW ( 74 , " not enough memory for dstFileName " ) ;
2016-02-15 10:33:16 -08:00
}
2017-04-24 16:48:25 -07:00
if ( sfnSize < = suffixSize | | ( strcmp ( suffixPtr , GZ_EXTENSION ) & & strcmp ( suffixPtr , XZ_EXTENSION ) & & strcmp ( suffixPtr , ZSTD_EXTENSION ) & & strcmp ( suffixPtr , LZMA_EXTENSION ) & & strcmp ( suffixPtr , LZ4_EXTENSION ) ) ) {
2017-03-13 18:11:07 -07:00
DISPLAYLEVEL ( 1 , " zstd: %s: unknown suffix (%s/%s/%s/%s expected) -- ignored \n " , srcFileName , GZ_EXTENSION , XZ_EXTENSION , ZSTD_EXTENSION , LZMA_EXTENSION ) ;
skippedFiles + + ;
continue ;
2016-11-30 04:34:21 -08:00
} else {
memcpy ( dstFileName , srcFileName , sfnSize - suffixSize ) ;
dstFileName [ sfnSize - suffixSize ] = ' \0 ' ;
2016-02-12 09:33:26 -08:00
}
2016-06-09 13:59:51 -07:00
missingFiles + = FIO_decompressDstFile ( ress , dstFileName , srcFileName ) ;
2016-05-09 20:37:43 -07:00
}
free ( dstFileName ) ;
}
2015-12-17 11:30:14 -08:00
FIO_freeDResources ( ress ) ;
return missingFiles + skippedFiles ;
}
2016-02-15 10:33:16 -08:00
2016-05-09 20:37:43 -07:00
# endif /* #ifndef ZSTD_NODECOMPRESS */