2016-08-30 17:04:33 +00: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-24 00:58:16 +00:00
2017-01-26 01:01:13 +00:00
2015-10-22 15:55:40 +00:00
/* *************************************
2015-01-24 00:58:16 +00:00
* Compiler Options
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-08-13 23:19:12 +00:00
# ifdef _MSC_VER /* Visual */
2016-12-21 12:47:11 +00:00
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
2016-08-13 23:19:12 +00:00
# pragma warning(disable : 4204) /* non-constant aggregate initializer */
# endif
2016-12-21 12:23:34 +00:00
# if defined(__MINGW32__) && !defined(_POSIX_SOURCE)
# define _POSIX_SOURCE 1 /* disable %llu warnings with MinGW on Windows */
# endif
2015-01-24 00:58:16 +00:00
2016-11-03 00:30:49 +00:00
2016-02-12 19:19:48 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Includes
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-12-21 14:08:44 +00:00
# include "platform.h" /* Large Files support, SET_BINARY_MODE */
# include "util.h" /* UTIL_getFileSize */
2015-11-09 16:42:17 +00: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 12:40:45 +00:00
2016-12-21 12:23:34 +00:00
# include "mem.h"
2015-01-24 00:58:16 +00:00
# include "fileio.h"
2016-06-04 17:47:02 +00:00
# define ZSTD_STATIC_LINKING_ONLY /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */
# include "zstd.h"
2017-01-20 00:59:56 +00:00
# ifdef ZSTD_MULTITHREAD
# include "zstdmt_compress.h"
2016-12-05 17:02:40 +00:00
# endif
2017-02-08 15:54:23 +00:00
# if defined(ZSTD_GZCOMPRESS) || defined(ZSTD_GZDECOMPRESS)
2017-02-06 19:32:13 +00:00
# include <zlib.h>
2017-01-20 00:59:56 +00:00
# if !defined(z_const)
# define z_const
# endif
2016-11-30 14:05:54 +00:00
# endif
2015-01-24 00:58:16 +00:00
2016-02-12 19:19:48 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Constants
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-07-02 23:10:53 +00:00
# define KB *(1<<10)
# define MB *(1<<20)
# define GB *(1U<<30)
2015-01-24 00:58:16 +00:00
# define _1BIT 0x01
# define _2BITS 0x03
# define _3BITS 0x07
# define _4BITS 0x0F
# define _6BITS 0x3F
# define _8BITS 0xFF
2015-11-25 13:42:45 +00:00
# define BLOCKSIZE (128 KB)
# define ROLLBUFFERSIZE (BLOCKSIZE*8*64)
2015-01-24 00:58:16 +00:00
2016-02-12 19:19:48 +00:00
# define FIO_FRAMEHEADERSIZE 5 /* as a define, because needed to allocated table on stack */
# define FSE_CHECKSUM_SEED 0
2015-01-24 00:58:16 +00:00
# define CACHELINE 64
2016-05-31 00:40:42 +00:00
# define MAX_DICT_SIZE (8 MB) /* protection against large input (attack scenario) */
2016-02-12 19:19:48 +00:00
2016-04-22 11:59:05 +00:00
# define FNSPACE 30
2016-11-30 12:34:21 +00:00
# define GZ_EXTENSION ".gz"
2016-04-22 11:59:05 +00:00
2015-01-24 00:58:16 +00:00
2016-02-15 19:37:23 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Macros
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-01-24 00:58:16 +00:00
# define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
2017-01-27 21:30:18 +00:00
# define DISPLAYLEVEL(l, ...) { if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } }
2015-01-24 00:58:16 +00:00
static U32 g_displayLevel = 2 ; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
2016-03-10 20:02:25 +00:00
void FIO_setNotificationLevel ( unsigned level ) { g_displayLevel = level ; }
2015-01-24 00:58:16 +00:00
2017-01-27 21:30:18 +00:00
# define DISPLAYUPDATE(l, ...) { if (g_displayLevel>=l) { \
2016-07-01 23:05:31 +00:00
if ( ( clock ( ) - g_time > refreshRate ) | | ( g_displayLevel > = 4 ) ) \
2015-01-24 00:58:16 +00:00
{ g_time = clock ( ) ; DISPLAY ( __VA_ARGS__ ) ; \
2017-01-27 21:30:18 +00:00
if ( g_displayLevel > = 4 ) fflush ( stdout ) ; } } }
2016-07-01 23:05:31 +00:00
static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100 ;
2015-01-24 00:58:16 +00:00
static clock_t g_time = 0 ;
2016-07-02 23:10:53 +00:00
# define MIN(a,b) ((a) < (b) ? (a) : (b))
2017-02-14 08:45:33 +00:00
/* ************************************************************
* Avoid fseek ( ) ' s 2 GiB barrier with MSVC , MacOS , * BSD , MinGW
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-12 09:27:18 +00:00
# if defined(_MSC_VER) && _MSC_VER >= 1400
# define LONG_SEEK _fseeki64
2017-02-14 08:45:33 +00:00
# elif !defined(__64BIT__) && (PLATFORM_POSIX_VERSION >= 200112L) /* No point defining Large file for 64 bit */
2017-02-14 08:52:52 +00:00
# define LONG_SEEK fseeko
2017-02-12 09:27:18 +00: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 11:00:59 +00:00
return 0 ;
2017-02-12 09:27:18 +00:00
else
2017-02-13 11:00:59 +00:00
return - 1 ;
2017-02-12 09:27:18 +00:00
}
# else
# define LONG_SEEK fseek
# endif
2016-02-15 19:37:23 +00:00
/*-*************************************
2016-07-01 23:05:31 +00:00
* Local Parameters - Not thread safe
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-14 08:23:32 +00:00
static FIO_compressionType_t g_compressionType = FIO_zstdCompression ;
void FIO_setCompressionType ( FIO_compressionType_t compressionType ) { g_compressionType = compressionType ; }
2015-01-24 00:58:16 +00:00
static U32 g_overwrite = 0 ;
void FIO_overwriteMode ( void ) { g_overwrite = 1 ; }
2016-05-23 14:56:56 +00: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-31 00:29:45 +00:00
static U32 g_dictIDFlag = 1 ;
void FIO_setDictIDFlag ( unsigned dictIDFlag ) { g_dictIDFlag = dictIDFlag ; }
2016-06-20 14:31:24 +00:00
static U32 g_checksumFlag = 1 ;
2016-06-01 17:22:15 +00:00
void FIO_setChecksumFlag ( unsigned checksumFlag ) { g_checksumFlag = checksumFlag ; }
2016-06-09 20:59:51 +00:00
static U32 g_removeSrcFile = 0 ;
void FIO_setRemoveSrcFile ( unsigned flag ) { g_removeSrcFile = ( flag > 0 ) ; }
2016-10-14 20:13:13 +00:00
static U32 g_memLimit = 0 ;
void FIO_setMemLimit ( unsigned memLimit ) { g_memLimit = memLimit ; }
2017-01-20 00:59:56 +00: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-25 01:02:26 +00: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 22:37:08 +00:00
# define FIO_OVERLAP_LOG_NOTSET 9999
static U32 g_overlapLog = FIO_OVERLAP_LOG_NOTSET ;
2017-01-30 19:17:26 +00: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-24 00:58:16 +00:00
2016-02-15 19:37:23 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Exceptions
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef DEBUG
# define DEBUG 0
# endif
2015-01-24 00:58:16 +00: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-12 01:26:54 +00:00
DISPLAYLEVEL ( 1 , " \n " ) ; \
2015-01-24 00:58:16 +00:00
exit ( error ) ; \
}
2016-02-15 19:37:23 +00:00
/*-*************************************
2015-01-24 00:58:16 +00:00
* Functions
2015-10-22 15:55:40 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-11-12 01:26:54 +00:00
/** FIO_openSrcFile() :
* condition : ` dstFileName ` must be non - NULL .
* @ result : FILE * to ` dstFileName ` , or NULL if it fails */
2016-02-12 14:56:46 +00:00
static FILE * FIO_openSrcFile ( const char * srcFileName )
2015-12-17 01:23:58 +00:00
{
2016-02-12 14:56:46 +00:00
FILE * f ;
2016-02-02 13:36:49 +00:00
if ( ! strcmp ( srcFileName , stdinmark ) ) {
2015-12-17 01:23:58 +00:00
DISPLAYLEVEL ( 4 , " Using stdin for input \n " ) ;
2016-02-12 14:56:46 +00:00
f = stdin ;
2015-12-17 01:23:58 +00:00
SET_BINARY_MODE ( stdin ) ;
2016-02-02 13:36:49 +00:00
} else {
2017-02-14 08:38:51 +00:00
if ( ! UTIL_isRegFile ( srcFileName ) ) {
2017-01-25 12:11:26 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s is not a regular file -- ignored \n " , srcFileName ) ;
return NULL ;
}
2016-02-12 14:56:46 +00:00
f = fopen ( srcFileName , " rb " ) ;
2016-08-13 18:49:47 +00:00
if ( f = = NULL ) DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , srcFileName , strerror ( errno ) ) ;
2015-12-17 01:23:58 +00:00
}
2016-02-12 14:56:46 +00:00
return f ;
}
2016-09-15 13:38:44 +00:00
/** FIO_openDstFile() :
* condition : ` dstFileName ` must be non - NULL .
* @ result : FILE * to ` dstFileName ` , or NULL if it fails */
2016-02-12 14:56:46 +00:00
static FILE * FIO_openDstFile ( const char * dstFileName )
{
FILE * f ;
2015-12-17 01:23:58 +00:00
2016-02-02 13:36:49 +00:00
if ( ! strcmp ( dstFileName , stdoutmark ) ) {
2015-12-17 01:23:58 +00:00
DISPLAYLEVEL ( 4 , " Using stdout for output \n " ) ;
2016-02-12 14:56:46 +00:00
f = stdout ;
2015-12-17 01:23:58 +00:00
SET_BINARY_MODE ( stdout ) ;
2016-05-23 14:56:56 +00:00
if ( g_sparseFileSupport = = 1 ) {
g_sparseFileSupport = 0 ;
DISPLAYLEVEL ( 4 , " Sparse File Support is automatically disabled on stdout ; try --sparse \n " ) ;
}
2016-02-02 13:36:49 +00:00
} else {
2016-05-31 00:29:45 +00:00
if ( ! g_overwrite & & strcmp ( dstFileName , nulmark ) ) { /* Check if destination file already exists */
2016-02-12 14:56:46 +00:00
f = fopen ( dstFileName , " rb " ) ;
if ( f ! = 0 ) { /* dest file exists, prompt for overwrite authorization */
fclose ( f ) ;
if ( g_displayLevel < = 1 ) {
2015-12-17 19:30:14 +00:00
/* No interaction possible */
2016-02-12 14:56:46 +00:00
DISPLAY ( " zstd: %s already exists; not overwritten \n " , dstFileName ) ;
2016-07-01 23:05:31 +00:00
return NULL ;
2015-12-17 19:30:14 +00:00
}
2016-02-12 14:56:46 +00:00
DISPLAY ( " zstd: %s already exists; do you wish to overwrite (y/N) ? " , dstFileName ) ;
2016-05-23 14:56:56 +00:00
{ int ch = getchar ( ) ;
2016-02-02 13:36:49 +00:00
if ( ( ch ! = ' Y ' ) & & ( ch ! = ' y ' ) ) {
2016-02-12 14:56:46 +00:00
DISPLAY ( " not overwritten \n " ) ;
2016-07-01 23:05:31 +00:00
return NULL ;
2015-12-29 10:57:15 +00:00
}
while ( ( ch ! = EOF ) & & ( ch ! = ' \n ' ) ) ch = getchar ( ) ; /* flush rest of input line */
2016-02-02 13:36:49 +00:00
} } }
2016-02-12 14:56:46 +00:00
f = fopen ( dstFileName , " wb " ) ;
2016-08-13 18:49:47 +00:00
if ( f = = NULL ) DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , dstFileName , strerror ( errno ) ) ;
2016-02-12 14:56:46 +00:00
}
2016-07-01 23:05:31 +00:00
2016-02-12 14:56:46 +00:00
return f ;
}
2016-03-10 20:02:25 +00:00
/*! FIO_loadFile() :
2016-03-15 11:56:03 +00:00
* creates a buffer , pointed by ` * bufferPtr ` ,
2016-03-10 20:02:25 +00:00
* loads ` filename ` content into it ,
2016-05-31 00:40:42 +00:00
* up to MAX_DICT_SIZE bytes .
* @ return : loaded size
2015-12-17 19:30:14 +00:00
*/
static size_t FIO_loadFile ( void * * bufferPtr , const char * fileName )
{
FILE * fileHandle ;
U64 fileSize ;
* bufferPtr = NULL ;
2016-02-02 13:36:49 +00:00
if ( fileName = = NULL ) return 0 ;
2015-12-17 19:30:14 +00:00
DISPLAYLEVEL ( 4 , " Loading %s as dictionary \n " , fileName ) ;
fileHandle = fopen ( fileName , " rb " ) ;
2016-07-01 23:05:31 +00:00
if ( fileHandle = = 0 ) EXM_THROW ( 31 , " zstd: %s: %s " , fileName , strerror ( errno ) ) ;
2016-04-28 10:23:33 +00:00
fileSize = UTIL_getFileSize ( fileName ) ;
2016-02-02 13:36:49 +00:00
if ( fileSize > MAX_DICT_SIZE ) {
2015-12-17 19:30:14 +00:00
int seekResult ;
if ( fileSize > 1 GB ) EXM_THROW ( 32 , " Dictionary file %s is too large " , fileName ) ; /* avoid extreme cases */
2016-08-18 07:00:25 +00:00
DISPLAYLEVEL ( 2 , " Dictionary %s is too large : using last %u bytes only \n " , fileName , ( U32 ) MAX_DICT_SIZE ) ;
2015-12-17 19:30:14 +00:00
seekResult = fseek ( fileHandle , ( long int ) ( fileSize - MAX_DICT_SIZE ) , SEEK_SET ) ; /* use end of file */
2016-07-01 23:05:31 +00:00
if ( seekResult ! = 0 ) EXM_THROW ( 33 , " zstd: %s: %s " , fileName , strerror ( errno ) ) ;
2015-12-17 19:30:14 +00:00
fileSize = MAX_DICT_SIZE ;
}
2016-07-01 23:05:31 +00:00
* bufferPtr = malloc ( ( size_t ) fileSize ) ;
2016-07-02 09:14:30 +00:00
if ( * bufferPtr = = NULL ) EXM_THROW ( 34 , " zstd: %s " , strerror ( errno ) ) ;
2016-05-31 00:40:42 +00: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 19:30:14 +00:00
fclose ( fileHandle ) ;
return ( size_t ) fileSize ;
}
2016-04-22 11:59:05 +00:00
# ifndef ZSTD_NOCOMPRESS
2015-12-17 01:23:58 +00:00
2016-03-10 20:02:25 +00:00
/*-**********************************************************************
2015-12-17 01:23:58 +00:00
* Compression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
typedef struct {
2017-01-20 00:59:56 +00:00
FILE * srcFile ;
FILE * dstFile ;
2015-12-17 01:23:58 +00:00
void * srcBuffer ;
size_t srcBufferSize ;
void * dstBuffer ;
size_t dstBufferSize ;
2017-01-20 00:59:56 +00:00
# ifdef ZSTD_MULTITHREAD
ZSTDMT_CCtx * cctx ;
# else
2016-08-13 21:45:45 +00:00
ZSTD_CStream * cctx ;
2017-01-20 00:59:56 +00:00
# endif
2015-12-17 01:23:58 +00:00
} cRess_t ;
2017-01-20 00:59:56 +00:00
static cRess_t FIO_createCResources ( const char * dictFileName , int cLevel ,
2017-02-08 00:33:48 +00:00
U64 srcSize , int srcRegFile ,
ZSTD_compressionParameters * comprParams ) {
2015-12-17 01:23:58 +00:00
cRess_t ress ;
2016-07-13 15:38:39 +00:00
memset ( & ress , 0 , sizeof ( ress ) ) ;
2015-12-17 01:23:58 +00:00
2017-01-20 00:59:56 +00:00
# ifdef ZSTD_MULTITHREAD
ress . cctx = ZSTDMT_createCCtx ( g_nbThreads ) ;
2017-01-26 01:01:13 +00:00
if ( ress . cctx = = NULL ) EXM_THROW ( 30 , " zstd: allocation error : can't create ZSTD_CStream " ) ;
2017-01-30 22:37:08 +00:00
if ( ( cLevel = = ZSTD_maxCLevel ( ) ) & & ( g_overlapLog = = FIO_OVERLAP_LOG_NOTSET ) )
2017-01-30 21:35:45 +00:00
ZSTDMT_setMTCtxParameter ( ress . cctx , ZSTDMT_p_overlapSectionLog , 9 ) ; /* use complete window for overlap */
2017-01-30 22:37:08 +00:00
if ( g_overlapLog ! = FIO_OVERLAP_LOG_NOTSET )
2017-01-30 19:17:26 +00:00
ZSTDMT_setMTCtxParameter ( ress . cctx , ZSTDMT_p_overlapSectionLog , g_overlapLog ) ;
2017-01-20 00:59:56 +00:00
# else
2016-08-13 21:45:45 +00:00
ress . cctx = ZSTD_createCStream ( ) ;
if ( ress . cctx = = NULL ) EXM_THROW ( 30 , " zstd: allocation error : can't create ZSTD_CStream " ) ;
2017-01-26 01:01:13 +00:00
# endif
2016-08-13 21:45:45 +00:00
ress . srcBufferSize = ZSTD_CStreamInSize ( ) ;
2015-12-17 01:23:58 +00:00
ress . srcBuffer = malloc ( ress . srcBufferSize ) ;
2016-08-13 21:45:45 +00:00
ress . dstBufferSize = ZSTD_CStreamOutSize ( ) ;
2015-12-17 01:23:58 +00:00
ress . dstBuffer = malloc ( ress . dstBufferSize ) ;
2016-07-02 09:14:30 +00:00
if ( ! ress . srcBuffer | | ! ress . dstBuffer ) EXM_THROW ( 31 , " zstd: allocation error : not enough memory " ) ;
2015-12-17 01:23:58 +00:00
/* dictionary */
2016-09-15 13:38:44 +00:00
{ void * dictBuffer ;
size_t const dictBuffSize = FIO_loadFile ( & dictBuffer , dictFileName ) ;
if ( dictFileName & & ( dictBuffer = = NULL ) ) EXM_THROW ( 32 , " zstd: allocation error : can't create dictBuffer " ) ;
2016-09-21 14:46:08 +00:00
{ ZSTD_parameters params = ZSTD_getParams ( cLevel , srcSize , dictBuffSize ) ;
2017-02-08 00:33:48 +00:00
params . fParams . contentSizeFlag = srcRegFile ;
2016-09-15 13:38:44 +00:00
params . fParams . checksumFlag = g_checksumFlag ;
params . fParams . noDictIDFlag = ! g_dictIDFlag ;
2016-12-13 12:24:59 +00: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 ;
2016-12-13 19:04:32 +00:00
if ( comprParams - > strategy ) params . cParams . strategy = ( ZSTD_strategy ) ( comprParams - > strategy - 1 ) ;
2017-01-20 00:59:56 +00:00
# ifdef ZSTD_MULTITHREAD
{ size_t const errorCode = ZSTDMT_initCStream_advanced ( ress . cctx , dictBuffer , dictBuffSize , params , srcSize ) ;
2017-01-25 01:02:26 +00: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-20 00:59:56 +00:00
# else
2016-09-21 14:46:08 +00:00
{ size_t const errorCode = ZSTD_initCStream_advanced ( ress . cctx , dictBuffer , dictBuffSize , params , srcSize ) ;
2016-09-15 13:38:44 +00:00
if ( ZSTD_isError ( errorCode ) ) EXM_THROW ( 33 , " Error initializing CStream : %s " , ZSTD_getErrorName ( errorCode ) ) ;
2017-01-25 01:02:26 +00:00
# endif
2016-09-15 13:38:44 +00:00
} }
free ( dictBuffer ) ;
}
2015-12-17 01:23:58 +00:00
return ress ;
}
static void FIO_freeCResources ( cRess_t ress )
{
free ( ress . srcBuffer ) ;
free ( ress . dstBuffer ) ;
2017-01-20 00:59:56 +00:00
# ifdef ZSTD_MULTITHREAD
ZSTDMT_freeCCtx ( ress . cctx ) ;
# else
2016-09-15 13:38:44 +00:00
ZSTD_freeCStream ( ress . cctx ) ; /* never fails */
2017-01-20 00:59:56 +00:00
# endif
2015-12-17 01:23:58 +00:00
}
2017-02-08 15:54:23 +00: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 16:37:14 +00:00
int ret ;
2017-02-08 15:54:23 +00:00
2017-02-13 20:00:41 +00:00
if ( compressionLevel > Z_BEST_COMPRESSION ) compressionLevel = Z_BEST_COMPRESSION ;
2017-02-08 15:54:23 +00:00
strm . zalloc = Z_NULL ;
strm . zfree = Z_NULL ;
strm . opaque = Z_NULL ;
2017-02-08 16:37:14 +00:00
2017-02-14 08:23:32 +00: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 15:54:23 +00:00
2017-02-08 16:37:14 +00:00
strm . next_in = 0 ;
strm . avail_in = Z_NULL ;
2017-02-08 15:54:23 +00: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 16:37:14 +00:00
if ( ret ! = Z_OK ) EXM_THROW ( 72 , " zstd: %s: deflate error %d \n " , srcFileName , ret ) ;
2017-02-08 15:54:23 +00: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 16:37:14 +00:00
ret = deflate ( & strm , Z_FINISH ) ;
2017-02-08 15:54:23 +00:00
{ size_t const decompBytes = ress - > dstBufferSize - strm . avail_out ;
if ( decompBytes ) {
2017-02-08 16:37:14 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes ) EXM_THROW ( 75 , " Write error : cannot write to output file " ) ;
2017-02-08 15:54:23 +00:00
outFileSize + = decompBytes ;
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
}
}
if ( ret = = Z_STREAM_END ) break ;
2017-02-08 16:37:14 +00:00
if ( ret ! = Z_BUF_ERROR ) EXM_THROW ( 77 , " zstd: %s: deflate error %d \n " , srcFileName , ret ) ;
2017-02-08 15:54:23 +00:00
}
2017-02-08 16:37:14 +00:00
ret = deflateEnd ( & strm ) ;
if ( ret ! = Z_OK ) EXM_THROW ( 79 , " zstd: %s: deflateEnd error %d \n " , srcFileName , ret ) ;
2017-02-08 15:54:23 +00:00
* readsize = inFileSize ;
return outFileSize ;
}
# endif
2016-02-12 14:56:46 +00:00
/*! FIO_compressFilename_internal() :
2016-03-10 20:02:25 +00:00
* same as FIO_compressFilename_extRess ( ) , with ` ress . desFile ` already opened .
2016-02-12 14:56:46 +00:00
* @ return : 0 : compression completed correctly ,
* 1 : missing or pb opening srcFileName
2015-12-17 01:23:58 +00:00
*/
2016-02-12 14:56:46 +00:00
static int FIO_compressFilename_internal ( cRess_t ress ,
2017-02-08 15:54:23 +00:00
const char * dstFileName , const char * srcFileName , int compressionLevel )
2015-12-17 01:23:58 +00:00
{
2016-05-07 20:43:40 +00:00
FILE * const srcFile = ress . srcFile ;
FILE * const dstFile = ress . dstFile ;
2016-03-26 19:52:14 +00:00
U64 readsize = 0 ;
2015-12-17 01:23:58 +00:00
U64 compressedfilesize = 0 ;
2016-04-28 10:23:33 +00:00
U64 const fileSize = UTIL_getFileSize ( srcFileName ) ;
2015-12-17 01:23:58 +00:00
2017-02-14 08:23:32 +00:00
if ( g_compressionType ) {
2017-02-08 16:37:14 +00:00
# ifdef ZSTD_GZCOMPRESS
2017-02-08 15:54:23 +00:00
compressedfilesize = FIO_compressGzFrame ( & ress , srcFileName , fileSize , compressionLevel , & readsize ) ;
2017-02-08 16:37:14 +00:00
# else
2017-02-08 17:08:09 +00:00
( void ) compressionLevel ;
2017-02-08 16:37:14 +00:00
EXM_THROW ( 20 , " zstd: %s: file cannot be compressed as gzip (zstd compiled without ZSTD_GZCOMPRESS) -- ignored \n " , srcFileName ) ;
# endif
2017-02-08 17:08:09 +00:00
goto finish ;
2017-02-08 15:54:23 +00:00
}
2015-12-17 01:23:58 +00:00
/* init */
2017-01-20 00:59:56 +00:00
# ifdef ZSTD_MULTITHREAD
{ size_t const resetError = ZSTDMT_resetCStream ( ress . cctx , fileSize ) ;
# else
2016-09-15 13:38:44 +00:00
{ size_t const resetError = ZSTD_resetCStream ( ress . cctx , fileSize ) ;
2017-01-20 00:59:56 +00:00
# endif
2016-09-15 13:38:44 +00:00
if ( ZSTD_isError ( resetError ) ) EXM_THROW ( 21 , " Error initializing compression : %s " , ZSTD_getErrorName ( resetError ) ) ;
}
2015-12-17 01:23:58 +00:00
/* Main compression loop */
2016-01-26 15:31:22 +00:00
while ( 1 ) {
2015-12-17 01:23:58 +00:00
/* Fill input Buffer */
2016-03-26 19:52:14 +00:00
size_t const inSize = fread ( ress . srcBuffer , ( size_t ) 1 , ress . srcBufferSize , srcFile ) ;
2015-12-17 01:23:58 +00:00
if ( inSize = = 0 ) break ;
2016-03-26 19:52:14 +00:00
readsize + = inSize ;
2015-12-17 01:23:58 +00:00
2016-08-16 23:39:22 +00:00
{ ZSTD_inBuffer inBuff = { ress . srcBuffer , inSize , 0 } ;
2017-01-20 00:59:56 +00:00
while ( inBuff . pos ! = inBuff . size ) { /* note : is there any possibility of endless loop ? for example, if outBuff is not large enough ? */
2017-01-25 20:31:07 +00:00
ZSTD_outBuffer outBuff = { ress . dstBuffer , ress . dstBufferSize , 0 } ;
2017-01-20 00:59:56 +00: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-17 01:23:58 +00:00
2017-01-25 20:31:07 +00: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-01-27 21:30:18 +00:00
# ifdef ZSTD_MULTITHREAD
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 ) ;
# endif
2015-12-17 01:23:58 +00:00
}
/* End of Frame */
2017-01-20 00:59:56 +00: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-17 01:23:58 +00:00
}
2017-02-08 15:54:23 +00:00
finish :
2015-12-17 01:23:58 +00:00
/* Status */
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
2016-08-13 18:26:21 +00:00
DISPLAYLEVEL ( 2 , " %-20s :%6.2f%% (%6llu => %6llu bytes, %s) \n " , srcFileName ,
2016-07-13 17:30:40 +00:00
( double ) compressedfilesize / ( readsize + ( ! readsize ) /* avoid div by zero */ ) * 100 ,
( unsigned long long ) readsize , ( unsigned long long ) compressedfilesize ,
dstFileName ) ;
2015-12-17 01:23:58 +00:00
return 0 ;
}
2016-07-01 23:05:31 +00:00
/*! FIO_compressFilename_srcFile() :
* note : ress . destFile already opened
2016-02-15 19:37:23 +00:00
* @ return : 0 : compression completed correctly ,
* 1 : missing or pb opening srcFileName
*/
static int FIO_compressFilename_srcFile ( cRess_t ress ,
2017-02-08 15:54:23 +00:00
const char * dstFileName , const char * srcFileName , int compressionLevel )
2016-02-15 19:37:23 +00:00
{
int result ;
/* File check */
2016-06-09 20:59:51 +00:00
if ( UTIL_isDirectory ( srcFileName ) ) {
DISPLAYLEVEL ( 1 , " zstd: %s is a directory -- ignored \n " , srcFileName ) ;
return 1 ;
}
2017-01-25 12:02:33 +00:00
2016-02-15 19:37:23 +00:00
ress . srcFile = FIO_openSrcFile ( srcFileName ) ;
if ( ! ress . srcFile ) return 1 ; /* srcFile could not be opened */
2017-02-08 15:54:23 +00:00
result = FIO_compressFilename_internal ( ress , dstFileName , srcFileName , compressionLevel ) ;
2016-02-15 19:37:23 +00:00
fclose ( ress . srcFile ) ;
2016-09-15 13:38:44 +00:00
if ( g_removeSrcFile & & ! result ) { if ( remove ( srcFileName ) ) EXM_THROW ( 1 , " zstd: %s: %s " , srcFileName , strerror ( errno ) ) ; } /* remove source file : --rm */
2016-02-15 19:37:23 +00:00
return result ;
}
2016-06-09 20:59:51 +00:00
/*! FIO_compressFilename_dstFile() :
2016-02-12 14:56:46 +00:00
* @ return : 0 : compression completed correctly ,
2016-06-09 20:59:51 +00:00
* 1 : pb
2016-02-12 14:56:46 +00:00
*/
2016-06-09 20:59:51 +00:00
static int FIO_compressFilename_dstFile ( cRess_t ress ,
2017-02-08 15:54:23 +00:00
const char * dstFileName , const char * srcFileName , int compressionLevel )
2016-02-12 14:56:46 +00:00
{
int result ;
2016-11-02 13:08:07 +00:00
stat_t statbuf ;
int stat_result = 0 ;
2016-02-12 14:56:46 +00:00
ress . dstFile = FIO_openDstFile ( dstFileName ) ;
2016-09-15 13:38:44 +00:00
if ( ress . dstFile = = NULL ) return 1 ; /* could not open dstFileName */
2016-02-12 14:56:46 +00:00
2016-11-02 13:08:07 +00:00
if ( strcmp ( srcFileName , stdinmark ) & & UTIL_getFileStat ( srcFileName , & statbuf ) ) stat_result = 1 ;
2017-02-08 15:54:23 +00:00
result = FIO_compressFilename_srcFile ( ress , dstFileName , srcFileName , compressionLevel ) ;
2016-03-14 05:24:46 +00:00
2016-09-15 13:38:44 +00:00
if ( fclose ( ress . dstFile ) ) { DISPLAYLEVEL ( 1 , " zstd: %s: %s \n " , dstFileName , strerror ( errno ) ) ; result = 1 ; } /* error closing dstFile */
2016-07-13 17:30:40 +00:00
if ( result ! = 0 ) { if ( remove ( dstFileName ) ) EXM_THROW ( 1 , " zstd: %s: %s " , dstFileName , strerror ( errno ) ) ; } /* remove operation artefact */
2016-11-02 13:08:07 +00:00
else if ( strcmp ( dstFileName , stdoutmark ) & & stat_result ) UTIL_setFileStat ( dstFileName , & statbuf ) ;
2016-02-12 14:56:46 +00:00
return result ;
}
2015-12-17 13:09:55 +00:00
int FIO_compressFilename ( const char * dstFileName , const char * srcFileName ,
2016-12-13 12:24:59 +00:00
const char * dictFileName , int compressionLevel , ZSTD_compressionParameters * comprParams )
2015-01-24 00:58:16 +00:00
{
2016-05-31 00:29:45 +00:00
clock_t const start = clock ( ) ;
2016-09-21 14:46:08 +00:00
U64 const srcSize = UTIL_getFileSize ( srcFileName ) ;
2017-02-08 00:33:48 +00:00
int const regFile = UTIL_isRegFile ( srcFileName ) ;
2015-01-24 00:58:16 +00:00
2017-02-08 00:33:48 +00:00
cRess_t const ress = FIO_createCResources ( dictFileName , compressionLevel , srcSize , regFile , comprParams ) ;
2017-02-08 15:54:23 +00:00
int const result = FIO_compressFilename_dstFile ( ress , dstFileName , srcFileName , compressionLevel ) ;
2015-01-24 00:58:16 +00:00
2016-07-01 23:05:31 +00: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-24 00:58:16 +00:00
}
2015-12-17 13:09:55 +00:00
int FIO_compressMultipleFilenames ( const char * * inFileNamesTable , unsigned nbFiles ,
2015-12-17 01:23:58 +00:00
const char * suffix ,
2016-12-13 12:24:59 +00:00
const char * dictFileName , int compressionLevel ,
ZSTD_compressionParameters * comprParams )
2015-12-17 01:23:58 +00:00
{
int missed_files = 0 ;
size_t dfnSize = FNSPACE ;
2016-07-13 17:30:40 +00:00
char * dstFileName = ( char * ) malloc ( FNSPACE ) ;
2016-05-07 20:43:40 +00:00
size_t const suffixSize = suffix ? strlen ( suffix ) : 0 ;
2016-09-21 14:46:08 +00:00
U64 const srcSize = ( nbFiles ! = 1 ) ? 0 : UTIL_getFileSize ( inFileNamesTable [ 0 ] ) ;
2017-02-08 00:33:48 +00:00
int const regFile = ( nbFiles ! = 1 ) ? 0 : UTIL_isRegFile ( inFileNamesTable [ 0 ] ) ;
cRess_t ress = FIO_createCResources ( dictFileName , compressionLevel , srcSize , regFile , comprParams ) ;
2015-12-17 01:23:58 +00:00
/* init */
2016-07-13 17:30:40 +00: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-17 01:23:58 +00:00
/* loop on each file */
2016-02-15 19:37:23 +00:00
if ( ! strcmp ( suffix , stdoutmark ) ) {
2016-05-07 20:43:40 +00:00
unsigned u ;
2016-02-15 19:37:23 +00:00
ress . dstFile = stdout ;
2016-05-19 08:29:49 +00:00
SET_BINARY_MODE ( stdout ) ;
2016-02-15 19:37:23 +00:00
for ( u = 0 ; u < nbFiles ; u + + )
2017-02-08 15:54:23 +00:00
missed_files + = FIO_compressFilename_srcFile ( ress , stdoutmark , inFileNamesTable [ u ] , compressionLevel ) ;
2016-11-03 10:38:01 +00:00
if ( fclose ( ress . dstFile ) ) EXM_THROW ( 29 , " Write error : cannot properly close stdout " ) ;
2016-02-15 19:37:23 +00:00
} else {
2016-05-07 20:43:40 +00:00
unsigned u ;
2016-02-12 14:56:46 +00: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 15:54:23 +00:00
missed_files + = FIO_compressFilename_dstFile ( ress , dstFileName , inFileNamesTable [ u ] , compressionLevel ) ;
2016-02-15 19:37:23 +00:00
} }
2015-12-17 01:23:58 +00:00
/* Close & Free */
FIO_freeCResources ( ress ) ;
free ( dstFileName ) ;
return missed_files ;
}
2016-05-07 20:43:40 +00:00
# endif /* #ifndef ZSTD_NOCOMPRESS */
2016-04-22 11:59:05 +00:00
2015-12-17 01:23:58 +00:00
2016-04-22 16:22:30 +00:00
# ifndef ZSTD_NODECOMPRESS
2015-12-17 01:23:58 +00:00
/* **************************************************************************
* Decompression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-12-17 19:30:14 +00:00
typedef struct {
void * srcBuffer ;
2016-12-05 16:39:38 +00:00
size_t srcBufferLoaded ;
2015-12-17 19:30:14 +00:00
size_t srcBufferSize ;
void * dstBuffer ;
size_t dstBufferSize ;
2016-08-13 21:45:45 +00:00
ZSTD_DStream * dctx ;
2016-02-12 17:33:26 +00:00
FILE * dstFile ;
2015-12-17 19:30:14 +00:00
} dRess_t ;
static dRess_t FIO_createDResources ( const char * dictFileName )
{
dRess_t ress ;
2016-07-13 15:38:39 +00:00
memset ( & ress , 0 , sizeof ( ress ) ) ;
2015-12-17 19:30:14 +00:00
2016-07-13 15:38:39 +00:00
/* Allocation */
2016-08-13 21:45:45 +00:00
ress . dctx = ZSTD_createDStream ( ) ;
if ( ress . dctx = = NULL ) EXM_THROW ( 60 , " Can't create ZSTD_DStream " ) ;
2017-01-26 00:25:38 +00:00
ZSTD_setDStreamParameter ( ress . dctx , DStream_p_maxWindowSize , g_memLimit ) ;
2016-08-13 21:45:45 +00:00
ress . srcBufferSize = ZSTD_DStreamInSize ( ) ;
2015-12-17 19:30:14 +00:00
ress . srcBuffer = malloc ( ress . srcBufferSize ) ;
2016-08-13 21:45:45 +00:00
ress . dstBufferSize = ZSTD_DStreamOutSize ( ) ;
2015-12-17 19:30:14 +00:00
ress . dstBuffer = malloc ( ress . dstBufferSize ) ;
if ( ! ress . srcBuffer | | ! ress . dstBuffer ) EXM_THROW ( 61 , " Allocation error : not enough memory " ) ;
2015-12-17 01:23:58 +00:00
2015-12-17 19:30:14 +00:00
/* dictionary */
2016-09-14 15:26:59 +00:00
{ void * dictBuffer ;
size_t const dictBufferSize = FIO_loadFile ( & dictBuffer , dictFileName ) ;
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 19:30:14 +00:00
return ress ;
}
static void FIO_freeDResources ( dRess_t ress )
{
2016-08-13 21:45:45 +00: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 19:30:14 +00:00
free ( ress . srcBuffer ) ;
free ( ress . dstBuffer ) ;
}
2016-05-23 14:56:56 +00: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 09:27:18 +00:00
int const seekResult = LONG_SEEK ( file , 1 GB , SEEK_CUR ) ;
2016-05-23 14:56:56 +00: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 09:27:18 +00:00
int const seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2016-05-23 14:56:56 +00: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 09:27:18 +00:00
int seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2016-05-23 14:56:56 +00: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 09:27:18 +00:00
int const seekResult = LONG_SEEK ( file , storedSkips , SEEK_CUR ) ;
2016-05-23 14:56:56 +00:00
if ( seekResult ! = 0 ) EXM_THROW ( 69 , " Final skip error (sparse file) \n " ) ;
{ const char lastZeroByte [ 1 ] = { 0 } ;
size_t const sizeCheck = fwrite ( lastZeroByte , 1 , 1 , file ) ;
if ( sizeCheck ! = 1 ) EXM_THROW ( 69 , " Write error : cannot write last zero \n " ) ;
} }
}
2016-12-05 16:39:38 +00:00
/** FIO_passThrough() : just copy input into output, for compatibility with gzip -df mode
@ return : 0 ( no error ) */
2016-12-05 17:31:14 +00:00
static unsigned FIO_passThrough ( FILE * foutput , FILE * finput , void * buffer , size_t bufferSize , size_t alreadyLoaded )
2016-12-05 16:39:38 +00:00
{
size_t const blockSize = MIN ( 64 KB , bufferSize ) ;
size_t readFromInput = 1 ;
unsigned storedSkips = 0 ;
2016-12-05 17:31:14 +00: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 16:39:38 +00: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 11:56:03 +00:00
/** FIO_decompressFrame() :
@ return : size of decoded frame
*/
2016-12-05 16:39:38 +00:00
unsigned long long FIO_decompressFrame ( dRess_t * ress ,
FILE * finput ,
2016-11-07 22:41:21 +00:00
U64 alreadyDecoded )
2015-01-24 00:58:16 +00:00
{
2016-08-28 19:47:17 +00:00
U64 frameSize = 0 ;
2016-05-23 14:56:56 +00:00
U32 storedSkips = 0 ;
2015-01-24 00:58:16 +00:00
2016-12-05 16:39:38 +00:00
ZSTD_resetDStream ( ress - > dctx ) ;
2016-03-15 11:56:03 +00:00
2016-05-10 12:14:19 +00:00
/* Header loading (optional, saves one loop) */
2016-12-05 16:39:38 +00: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 11:56:03 +00:00
}
/* Main decompression Loop */
2016-02-02 13:36:49 +00:00
while ( 1 ) {
2016-12-05 16:39:38 +00: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 12:54:23 +00:00
if ( ZSTD_isError ( readSizeHint ) ) EXM_THROW ( 36 , " Decoding error : %s " , ZSTD_getErrorName ( readSizeHint ) ) ;
2015-11-25 13:42:45 +00:00
/* Write block */
2017-01-20 00:59:56 +00:00
storedSkips = FIO_fwriteSparse ( ress - > dstFile , ress - > dstBuffer , outBuff . pos , storedSkips ) ;
2016-08-16 23:39:22 +00:00
frameSize + = outBuff . pos ;
2016-11-07 22:41:21 +00:00
DISPLAYUPDATE ( 2 , " \r Decoded : %u MB... " , ( U32 ) ( ( alreadyDecoded + frameSize ) > > 20 ) ) ;
2015-11-25 13:42:45 +00:00
2016-12-05 16:39:38 +00:00
if ( inBuff . pos > 0 ) {
memmove ( ress - > srcBuffer , ( char * ) ress - > srcBuffer + inBuff . pos , inBuff . size - inBuff . pos ) ;
ress - > srcBufferLoaded - = inBuff . pos ;
}
2016-09-07 12:54:23 +00:00
if ( readSizeHint = = 0 ) break ; /* end of frame */
2016-08-16 23:39:22 +00:00
if ( inBuff . size ! = inBuff . pos ) EXM_THROW ( 37 , " Decoding error : should consume entire input " ) ;
2015-01-24 00:58:16 +00:00
/* Fill input buffer */
2016-12-05 16:39:38 +00: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 12:54:23 +00:00
} }
2015-01-24 00:58:16 +00:00
2016-12-05 16:39:38 +00:00
FIO_fwriteSparseEnd ( ress - > dstFile , storedSkips ) ;
2016-05-23 14:56:56 +00:00
2015-11-25 13:42:45 +00:00
return frameSize ;
2015-09-10 22:26:09 +00:00
}
2016-12-01 10:56:31 +00:00
# ifdef ZSTD_GZDECOMPRESS
2016-12-05 16:39:38 +00:00
static unsigned long long FIO_decompressGzFrame ( dRess_t * ress , FILE * srcFile , const char * srcFileName )
2016-12-02 12:50:29 +00:00
{
2016-12-02 20:40:57 +00:00
unsigned long long outFileSize = 0 ;
2016-12-02 14:01:31 +00:00
z_stream strm ;
2016-12-02 20:40:57 +00:00
2016-12-02 14:01:31 +00:00
strm . zalloc = Z_NULL ;
strm . zfree = Z_NULL ;
strm . opaque = Z_NULL ;
strm . next_in = 0 ;
strm . avail_in = Z_NULL ;
2016-12-02 20:40:57 +00:00
if ( inflateInit2 ( & strm , 15 /* maxWindowLogSize */ + 16 /* gzip only */ ) ! = Z_OK ) return 0 ; /* see http://www.zlib.net/manual.html */
2017-02-03 16:43:06 +00:00
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
2017-02-03 01:12:50 +00:00
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
strm . avail_in = ( uInt ) ress - > srcBufferLoaded ;
2016-12-05 16:39:38 +00:00
strm . next_in = ( z_const unsigned char * ) ress - > srcBuffer ;
2016-12-01 10:56:31 +00:00
2016-12-02 14:01:31 +00:00
for ( ; ; ) {
2016-12-05 16:39:38 +00:00
int ret ;
if ( strm . avail_in = = 0 ) {
ress - > srcBufferLoaded = fread ( ress - > srcBuffer , 1 , ress - > srcBufferSize , srcFile ) ;
if ( ress - > srcBufferLoaded = = 0 ) break ;
strm . next_in = ( z_const unsigned char * ) ress - > srcBuffer ;
2017-02-03 01:12:50 +00:00
strm . avail_in = ( uInt ) ress - > srcBufferLoaded ;
2016-12-02 12:11:39 +00:00
}
2016-12-05 16:39:38 +00:00
ret = inflate ( & strm , Z_NO_FLUSH ) ;
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 20:40:57 +00:00
if ( decompBytes ) {
2016-12-05 16:39:38 +00:00
if ( fwrite ( ress - > dstBuffer , 1 , decompBytes , ress - > dstFile ) ! = decompBytes ) EXM_THROW ( 31 , " Write error : cannot write to output file " ) ;
2016-12-02 20:40:57 +00:00
outFileSize + = decompBytes ;
2017-02-03 16:43:06 +00:00
strm . next_out = ( Bytef * ) ress - > dstBuffer ;
2017-02-03 01:12:50 +00:00
strm . avail_out = ( uInt ) ress - > dstBufferSize ;
2016-12-05 16:39:38 +00:00
}
}
if ( ret = = Z_STREAM_END ) break ;
}
2016-12-01 10:56:31 +00:00
2016-12-05 16:39:38 +00:00
if ( strm . avail_in > 0 ) memmove ( ress - > srcBuffer , strm . next_in , strm . avail_in ) ;
ress - > srcBufferLoaded = strm . avail_in ;
2016-12-02 14:01:31 +00:00
inflateEnd ( & strm ) ;
return outFileSize ;
2016-12-01 10:56:31 +00:00
}
# endif
2016-02-12 17:33:26 +00:00
/** FIO_decompressSrcFile() :
Decompression ` srcFileName ` into ` ress . dstFile `
@ return : 0 : OK
1 : operation not started
*/
2016-12-02 23:18:57 +00:00
static int FIO_decompressSrcFile ( dRess_t ress , const char * dstFileName , const char * srcFileName )
2015-10-18 21:18:32 +00:00
{
2016-12-02 12:50:29 +00:00
FILE * srcFile ;
2016-07-26 14:44:09 +00:00
unsigned readSomething = 0 ;
2016-12-02 20:40:57 +00:00
unsigned long long filesize = 0 ;
2016-11-30 12:34:21 +00:00
2016-06-09 20:59:51 +00:00
if ( UTIL_isDirectory ( srcFileName ) ) {
DISPLAYLEVEL ( 1 , " zstd: %s is a directory -- ignored \n " , srcFileName ) ;
return 1 ;
}
2016-11-30 12:34:21 +00:00
2016-12-02 12:50:29 +00:00
srcFile = FIO_openSrcFile ( srcFileName ) ;
if ( srcFile = = 0 ) return 1 ;
2016-11-30 14:05:54 +00:00
2016-12-02 14:01:31 +00:00
/* for each frame */
for ( ; ; ) {
/* check magic number -> version */
2016-12-02 15:20:16 +00:00
size_t const toRead = 4 ;
const BYTE * buf = ( const BYTE * ) ress . srcBuffer ;
2016-12-05 16:39:38 +00: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 15:20:16 +00: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 16:39:38 +00:00
if ( ress . srcBufferLoaded < toRead ) { DISPLAY ( " zstd: %s: unknown header \n " , srcFileName ) ; fclose ( srcFile ) ; return 1 ; } /* srcFileName is empty */
2016-12-02 15:20:16 +00:00
if ( buf [ 0 ] = = 31 & & buf [ 1 ] = = 139 ) { /* gz header */
2016-12-02 14:01:31 +00:00
# ifdef ZSTD_GZDECOMPRESS
2016-12-05 16:39:38 +00:00
unsigned long long const result = FIO_decompressGzFrame ( & ress , srcFile , srcFileName ) ;
2016-12-02 15:20:16 +00:00
if ( result = = 0 ) return 1 ;
filesize + = result ;
2016-11-30 14:05:54 +00:00
# else
2016-12-02 20:40:57 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: gzip file cannot be uncompressed (zstd compiled without ZSTD_GZDECOMPRESS) -- ignored \n " , srcFileName ) ;
2016-12-02 15:20:16 +00:00
return 1 ;
2016-11-30 14:05:54 +00:00
# endif
2016-12-02 15:20:16 +00:00
} else {
if ( ! ZSTD_isFrame ( ress . srcBuffer , toRead ) ) {
2016-12-02 23:18:57 +00:00
if ( ( g_overwrite ) & & ! strcmp ( dstFileName , stdoutmark ) ) { /* pass-through mode */
2016-12-05 17:31:14 +00:00
unsigned const result = FIO_passThrough ( ress . dstFile , srcFile , ress . srcBuffer , ress . srcBufferSize , ress . srcBufferLoaded ) ;
2016-12-02 15:20:16 +00: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 16:39:38 +00:00
filesize + = FIO_decompressFrame ( & ress , srcFile , filesize ) ;
2016-12-02 14:01:31 +00:00
}
2015-10-18 21:18:32 +00:00
}
2015-12-17 19:30:14 +00:00
/* Final Status */
2015-10-18 21:18:32 +00:00
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
2016-08-28 19:47:17 +00:00
DISPLAYLEVEL ( 2 , " %-20s: %llu bytes \n " , srcFileName , filesize ) ;
2015-10-18 21:18:32 +00:00
2016-12-02 12:50:29 +00:00
/* Close file */
if ( fclose ( srcFile ) ) EXM_THROW ( 33 , " zstd: %s close error " , srcFileName ) ; /* error should never happen */
if ( g_removeSrcFile ) { if ( remove ( srcFileName ) ) EXM_THROW ( 34 , " zstd: %s: %s " , srcFileName , strerror ( errno ) ) ; } ;
2016-02-12 17:33:26 +00: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 20:59:51 +00:00
static int FIO_decompressDstFile ( dRess_t ress ,
2016-12-02 20:40:57 +00:00
const char * dstFileName , const char * srcFileName )
2016-02-12 17:33:26 +00:00
{
2016-03-14 05:24:46 +00:00
int result ;
2016-11-02 13:08:07 +00:00
stat_t statbuf ;
int stat_result = 0 ;
2016-11-02 12:08:39 +00:00
2016-02-12 17:33:26 +00:00
ress . dstFile = FIO_openDstFile ( dstFileName ) ;
if ( ress . dstFile = = 0 ) return 1 ;
2015-12-17 19:30:14 +00:00
2016-11-02 13:08:07 +00:00
if ( strcmp ( srcFileName , stdinmark ) & & UTIL_getFileStat ( srcFileName , & statbuf ) ) stat_result = 1 ;
2016-12-02 23:18:57 +00:00
result = FIO_decompressSrcFile ( ress , dstFileName , srcFileName ) ;
2016-02-12 17:33:26 +00:00
2016-11-07 22:41:21 +00:00
if ( fclose ( ress . dstFile ) ) EXM_THROW ( 38 , " Write error : cannot properly close %s " , dstFileName ) ;
2016-11-02 12:08:39 +00:00
2016-09-07 05:00:08 +00:00
if ( ( result ! = 0 )
& & strcmp ( dstFileName , nulmark ) /* special case : don't remove() /dev/null (#316) */
& & remove ( dstFileName ) )
2016-09-07 05:01:33 +00:00
result = 1 ; /* don't do anything special if remove() fails */
2016-11-02 13:08:07 +00:00
else if ( strcmp ( dstFileName , stdoutmark ) & & stat_result ) UTIL_setFileStat ( dstFileName , & statbuf ) ;
2016-03-14 05:24:46 +00:00
return result ;
2015-10-18 21:18:32 +00:00
}
2015-12-17 19:30:14 +00: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 20:59:51 +00:00
missingFiles + = FIO_decompressDstFile ( ress , dstFileName , srcFileName ) ;
2015-12-17 19:30:14 +00: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-10 03:37:43 +00:00
dRess_t ress = FIO_createDResources ( dictFileName ) ;
2015-12-17 19:30:14 +00:00
2016-07-13 17:30:40 +00:00
if ( suffix = = NULL ) EXM_THROW ( 70 , " zstd: decompression: unknown dst " ) ; /* should never happen */
2016-12-02 23:18:57 +00:00
if ( ! strcmp ( suffix , stdoutmark ) | | ! strcmp ( suffix , nulmark ) ) { /* special cases : -c or -t */
2016-05-07 20:43:40 +00:00
unsigned u ;
2016-02-15 18:33:16 +00: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 23:18:57 +00:00
missingFiles + = FIO_decompressSrcFile ( ress , suffix , srcNamesTable [ u ] ) ;
2016-11-03 10:38:01 +00:00
if ( fclose ( ress . dstFile ) ) EXM_THROW ( 72 , " Write error : cannot properly close stdout " ) ;
2016-02-15 18:33:16 +00:00
} else {
2016-07-13 17:30:40 +00:00
size_t const suffixSize = strlen ( suffix ) ;
2016-12-02 12:11:39 +00:00
size_t const gzipSuffixSize = strlen ( GZ_EXTENSION ) ;
2016-05-10 03:37:43 +00:00
size_t dfnSize = FNSPACE ;
2016-05-07 20:43:40 +00:00
unsigned u ;
2016-05-10 03:37:43 +00:00
char * dstFileName = ( char * ) malloc ( FNSPACE ) ;
2016-07-13 17:30:40 +00:00
if ( dstFileName = = NULL ) EXM_THROW ( 73 , " not enough memory for dstFileName " ) ;
2016-02-12 17:33:26 +00:00
for ( u = 0 ; u < nbFiles ; u + + ) { /* create dstFileName */
2016-05-10 03:37:43 +00:00
const char * const srcFileName = srcNamesTable [ u ] ;
size_t const sfnSize = strlen ( srcFileName ) ;
const char * const suffixPtr = srcFileName + sfnSize - suffixSize ;
2016-12-02 12:11:39 +00:00
const char * const gzipSuffixPtr = srcFileName + sfnSize - gzipSuffixSize ;
2016-02-15 18:33:16 +00:00
if ( dfnSize + suffixSize < = sfnSize + 1 ) {
free ( dstFileName ) ;
dfnSize = sfnSize + 20 ;
dstFileName = ( char * ) malloc ( dfnSize ) ;
2016-07-13 17:30:40 +00:00
if ( dstFileName = = NULL ) EXM_THROW ( 74 , " not enough memory for dstFileName " ) ;
2016-02-15 18:33:16 +00:00
}
if ( sfnSize < = suffixSize | | strcmp ( suffixPtr , suffix ) ! = 0 ) {
2016-12-02 12:11:39 +00:00
if ( sfnSize < = gzipSuffixSize | | strcmp ( gzipSuffixPtr , GZ_EXTENSION ) ! = 0 ) {
2016-12-05 12:47:00 +00:00
DISPLAYLEVEL ( 1 , " zstd: %s: unknown suffix (%s/%s expected) -- ignored \n " , srcFileName , suffix , GZ_EXTENSION ) ;
2016-11-30 12:34:21 +00:00
skippedFiles + + ;
continue ;
} else {
2016-12-02 12:11:39 +00:00
memcpy ( dstFileName , srcFileName , sfnSize - gzipSuffixSize ) ;
dstFileName [ sfnSize - gzipSuffixSize ] = ' \0 ' ;
2016-11-30 12:34:21 +00:00
}
} else {
memcpy ( dstFileName , srcFileName , sfnSize - suffixSize ) ;
dstFileName [ sfnSize - suffixSize ] = ' \0 ' ;
2016-02-12 17:33:26 +00:00
}
2016-06-09 20:59:51 +00:00
missingFiles + = FIO_decompressDstFile ( ress , dstFileName , srcFileName ) ;
2016-05-10 03:37:43 +00:00
}
free ( dstFileName ) ;
}
2015-12-17 19:30:14 +00:00
FIO_freeDResources ( ress ) ;
return missingFiles + skippedFiles ;
}
2016-02-15 18:33:16 +00:00
2016-05-10 03:37:43 +00:00
# endif /* #ifndef ZSTD_NODECOMPRESS */