2014-02-04 14:11:10 +00:00
/*
LZ4io . c - LZ4 File / Stream Interface
2015-03-07 12:23:00 +00:00
Copyright ( C ) Yann Collet 2011 - 2015
2015-03-13 01:24:08 +00:00
2014-02-04 14:11:10 +00:00
GPL v2 License
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
You can contact the author at :
2015-03-13 01:24:08 +00:00
- LZ4 source repository : https : //github.com/Cyan4973/lz4
2014-02-04 14:11:10 +00:00
- LZ4 public forum : https : //groups.google.com/forum/#!forum/lz4c
*/
/*
Note : this is stand - alone program .
It is not part of LZ4 compression library , it is a user code of the LZ4 library .
- The license of LZ4 library is BSD .
- The license of xxHash library is BSD .
- The license of this source file is GPLv2 .
*/
2014-12-16 21:03:16 +00:00
/**************************************
* Compiler Options
2015-03-13 19:36:59 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-04 14:11:10 +00:00
# ifdef _MSC_VER /* Visual Studio */
# define _CRT_SECURE_NO_WARNINGS
2014-12-16 21:03:16 +00:00
# define _CRT_SECURE_NO_DEPRECATE /* VS2005 */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
2014-02-04 14:11:10 +00:00
# endif
2014-12-16 21:03:16 +00:00
# define _LARGE_FILES /* Large file support on 32-bits AIX */
# define _FILE_OFFSET_BITS 64 /* Large file support on 32-bits unix */
2014-02-04 14:11:10 +00:00
2015-03-13 19:36:59 +00:00
/*****************************
2014-12-16 21:03:16 +00:00
* Includes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-03-10 15:57:42 +00:00
# include <stdio.h> /* fprintf, fopen, fread, stdin, stdout */
2014-12-16 21:03:16 +00:00
# include <stdlib.h> /* malloc, free */
# include <string.h> /* strcmp, strlen */
# include <time.h> /* clock */
2014-02-04 14:11:10 +00:00
# include "lz4io.h"
2014-12-16 21:03:16 +00:00
# include "lz4.h" /* still required for legacy format */
# include "lz4hc.h" /* still required for legacy format */
2014-11-30 16:59:31 +00:00
# include "lz4frame.h"
2014-02-04 14:11:10 +00:00
2015-03-13 21:15:08 +00:00
/******************************
2014-12-16 21:03:16 +00:00
* OS - specific Includes
2015-03-13 21:15:08 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-04 14:11:10 +00:00
# if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
2014-12-16 21:03:16 +00:00
# include <fcntl.h> /* _O_BINARY */
2015-03-13 21:15:08 +00:00
# include <io.h> /* _setmode, _fileno, _get_osfhandle */
2015-03-10 15:57:42 +00:00
# define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY)
2015-03-13 21:15:08 +00:00
# include <Windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */
# define SET_SPARSE_FILE_MODE(file) { DWORD dw; DeviceIoControl((HANDLE) _get_osfhandle(_fileno(file)), FSCTL_SET_SPARSE, 0, 0, 0, 0, &dw, 0); }
2015-02-14 03:48:11 +00:00
# if defined(_MSC_VER) && (_MSC_VER >= 1400) /* Avoid MSVC fseek()'s 2GiB barrier */
# define fseek _fseeki64
# endif
2014-02-04 14:11:10 +00:00
# else
# define SET_BINARY_MODE(file)
2015-03-13 21:15:08 +00:00
# define SET_SPARSE_FILE_MODE(file)
2014-02-04 14:11:10 +00:00
# endif
2015-03-13 21:15:08 +00:00
/*****************************
2014-12-16 21:03:16 +00:00
* Constants
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-11-30 16:59:31 +00:00
# define KB *(1 <<10)
# define MB *(1 <<20)
2014-02-04 14:11:10 +00:00
# define GB *(1U<<30)
# define _1BIT 0x01
# define _2BITS 0x03
# define _3BITS 0x07
# define _4BITS 0x0F
# define _8BITS 0xFF
# define MAGICNUMBER_SIZE 4
# define LZ4S_MAGICNUMBER 0x184D2204
# define LZ4S_SKIPPABLE0 0x184D2A50
# define LZ4S_SKIPPABLEMASK 0xFFFFFFF0
# define LEGACY_MAGICNUMBER 0x184C2102
# define CACHELINE 64
# define LEGACY_BLOCKSIZE (8 MB)
2014-06-17 20:41:59 +00:00
# define MIN_STREAM_BUFSIZE (192 KB)
2014-02-04 14:11:10 +00:00
# define LZ4S_BLOCKSIZEID_DEFAULT 7
# define LZ4S_CHECKSUM_SEED 0
# define LZ4S_EOS 0
# define LZ4S_MAXHEADERSIZE (MAGICNUMBER_SIZE+2+8+4+1)
2014-12-16 21:03:16 +00:00
/**************************************
* Macros
2015-03-13 19:36:59 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-04 14:11:10 +00:00
# define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
2015-03-11 18:42:37 +00:00
# define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }
static int g_displayLevel = 0 ; /* 0 : no display ; 1: errors ; 2 : + result + interaction + warnings ; 3 : + progression; 4 : + information */
# define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \
if ( ( LZ4IO_GetMilliSpan ( g_time ) > refreshRate ) | | ( g_displayLevel > = 4 ) ) \
2014-11-30 16:59:31 +00:00
{ g_time = clock ( ) ; DISPLAY ( __VA_ARGS__ ) ; \
2015-03-11 18:42:37 +00:00
if ( g_displayLevel > = 4 ) fflush ( stdout ) ; } }
2014-11-30 16:59:31 +00:00
static const unsigned refreshRate = 150 ;
static clock_t g_time = 0 ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/**************************************
* Local Parameters
2015-03-13 19:36:59 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-03-11 18:42:37 +00:00
static int g_overwrite = 1 ;
static int g_blockSizeId = LZ4S_BLOCKSIZEID_DEFAULT ;
static int g_blockChecksum = 0 ;
static int g_streamChecksum = 1 ;
static int g_blockIndependence = 1 ;
static int g_sparseFileSupport = 0 ;
2014-02-04 14:11:10 +00:00
static const int minBlockSizeID = 4 ;
static const int maxBlockSizeID = 7 ;
2014-12-06 16:10:54 +00:00
2014-12-16 21:03:16 +00:00
/**************************************
* Exceptions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-04 14:11:10 +00:00
# define DEBUG 0
# 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__ ) ; \
DISPLAYLEVEL ( 1 , " \n " ) ; \
exit ( error ) ; \
}
2014-12-16 21:03:16 +00:00
/**************************************
* Version modifiers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-04 14:11:10 +00:00
# define EXTENDED_ARGUMENTS
# define EXTENDED_HELP
# define EXTENDED_FORMAT
# define DEFAULT_DECOMPRESSOR decodeLZ4S
/* ************************************************** */
/* ****************** Parameters ******************** */
/* ************************************************** */
/* Default setting : overwrite = 1; return : overwrite mode (0/1) */
int LZ4IO_setOverwrite ( int yes )
{
2015-03-11 18:42:37 +00:00
g_overwrite = ( yes ! = 0 ) ;
return g_overwrite ;
2014-02-04 14:11:10 +00:00
}
/* blockSizeID : valid values : 4-5-6-7 */
int LZ4IO_setBlockSizeID ( int bsid )
{
static const int blockSizeTable [ ] = { 64 KB , 256 KB , 1 MB , 4 MB } ;
if ( ( bsid < minBlockSizeID ) | | ( bsid > maxBlockSizeID ) ) return - 1 ;
2015-03-11 18:42:37 +00:00
g_blockSizeId = bsid ;
return blockSizeTable [ g_blockSizeId - minBlockSizeID ] ;
2014-02-04 14:11:10 +00:00
}
2014-11-30 16:59:31 +00:00
int LZ4IO_setBlockMode ( LZ4IO_blockMode_t blockMode )
2014-02-04 14:11:10 +00:00
{
2015-03-11 18:42:37 +00:00
g_blockIndependence = ( blockMode = = LZ4IO_blockIndependent ) ;
return g_blockIndependence ;
2014-02-04 14:11:10 +00:00
}
/* Default setting : no checksum */
int LZ4IO_setBlockChecksumMode ( int xxhash )
{
2015-03-11 18:42:37 +00:00
g_blockChecksum = ( xxhash ! = 0 ) ;
return g_blockChecksum ;
2014-02-04 14:11:10 +00:00
}
/* Default setting : checksum enabled */
int LZ4IO_setStreamChecksumMode ( int xxhash )
{
2015-03-11 18:42:37 +00:00
g_streamChecksum = ( xxhash ! = 0 ) ;
return g_streamChecksum ;
2014-02-04 14:11:10 +00:00
}
/* Default setting : 0 (no notification) */
int LZ4IO_setNotificationLevel ( int level )
{
2015-03-11 18:42:37 +00:00
g_displayLevel = level ;
return g_displayLevel ;
}
/* Default setting : 0 (disabled) */
int LZ4IO_setSparseFile ( int enable )
{
g_sparseFileSupport = enable ;
return g_sparseFileSupport ;
2014-02-04 14:11:10 +00:00
}
2014-11-30 16:59:31 +00:00
static unsigned LZ4IO_GetMilliSpan ( clock_t nPrevious )
{
clock_t nCurrent = clock ( ) ;
2014-12-06 16:10:54 +00:00
unsigned nSpan = ( unsigned ) ( ( ( nCurrent - nPrevious ) * 1000 ) / CLOCKS_PER_SEC ) ;
2014-11-30 16:59:31 +00:00
return nSpan ;
}
2014-02-04 14:11:10 +00:00
2015-03-13 19:36:59 +00:00
/* ************************************************************************ **
* * * * * * * * * * * * * * * * * * * * * * * * LZ4 File / Pipe compression * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-04 14:11:10 +00:00
static int LZ4S_GetBlockSize_FromBlockId ( int id ) { return ( 1 < < ( 8 + ( 2 * id ) ) ) ; }
static int LZ4S_isSkippableMagicNumber ( unsigned int magic ) { return ( magic & LZ4S_SKIPPABLEMASK ) = = LZ4S_SKIPPABLE0 ; }
2015-03-07 12:23:00 +00:00
static int get_fileHandle ( const char * input_filename , const char * output_filename , FILE * * pfinput , FILE * * pfoutput )
2014-02-04 14:11:10 +00:00
{
if ( ! strcmp ( input_filename , stdinmark ) )
{
DISPLAYLEVEL ( 4 , " Using stdin for input \n " ) ;
* pfinput = stdin ;
SET_BINARY_MODE ( stdin ) ;
}
else
{
* pfinput = fopen ( input_filename , " rb " ) ;
}
if ( ! strcmp ( output_filename , stdoutmark ) )
{
DISPLAYLEVEL ( 4 , " Using stdout for output \n " ) ;
* pfoutput = stdout ;
SET_BINARY_MODE ( stdout ) ;
}
else
{
2014-12-16 21:03:16 +00:00
/* Check if destination file already exists */
2014-02-04 14:11:10 +00:00
* pfoutput = 0 ;
if ( output_filename ! = nulmark ) * pfoutput = fopen ( output_filename , " rb " ) ;
if ( * pfoutput ! = 0 )
{
fclose ( * pfoutput ) ;
2015-03-11 18:42:37 +00:00
if ( ! g_overwrite )
2014-02-04 14:11:10 +00:00
{
char ch ;
DISPLAYLEVEL ( 2 , " Warning : %s already exists \n " , output_filename ) ;
DISPLAYLEVEL ( 2 , " Overwrite ? (Y/N) : " ) ;
2015-03-11 18:42:37 +00:00
if ( g_displayLevel < = 1 ) EXM_THROW ( 11 , " Operation aborted : %s already exists " , output_filename ) ; /* No interaction possible */
2014-02-04 14:11:10 +00:00
ch = ( char ) getchar ( ) ;
if ( ( ch ! = ' Y ' ) & & ( ch ! = ' y ' ) ) EXM_THROW ( 11 , " Operation aborted : %s already exists " , output_filename ) ;
}
}
* pfoutput = fopen ( output_filename , " wb " ) ;
}
if ( * pfinput = = 0 ) EXM_THROW ( 12 , " Pb opening %s " , input_filename ) ;
if ( * pfoutput = = 0 ) EXM_THROW ( 13 , " Pb opening %s " , output_filename ) ;
return 0 ;
}
2014-11-30 16:59:31 +00:00
/***************************************
2015-03-13 19:36:59 +00:00
* Legacy Compression
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-11-30 16:59:31 +00:00
/* unoptimized version; solves endianess & alignment issues */
static void LZ4IO_writeLE32 ( void * p , unsigned value32 )
{
2015-03-10 15:57:42 +00:00
unsigned char * dstPtr = ( unsigned char * ) p ;
2014-11-30 16:59:31 +00:00
dstPtr [ 0 ] = ( unsigned char ) value32 ;
dstPtr [ 1 ] = ( unsigned char ) ( value32 > > 8 ) ;
dstPtr [ 2 ] = ( unsigned char ) ( value32 > > 16 ) ;
dstPtr [ 3 ] = ( unsigned char ) ( value32 > > 24 ) ;
}
/* LZ4IO_compressFilename_Legacy :
* This function is intentionally " hidden " ( not published in . h )
* It generates compressed streams using the old ' legacy ' format */
2015-03-07 12:23:00 +00:00
int LZ4IO_compressFilename_Legacy ( const char * input_filename , const char * output_filename , int compressionlevel )
2014-02-04 14:11:10 +00:00
{
int ( * compressionFunction ) ( const char * , char * , int ) ;
unsigned long long filesize = 0 ;
unsigned long long compressedfilesize = MAGICNUMBER_SIZE ;
char * in_buff ;
char * out_buff ;
FILE * finput ;
FILE * foutput ;
clock_t start , end ;
size_t sizeCheck ;
2014-12-16 21:03:16 +00:00
/* Init */
2014-02-04 14:11:10 +00:00
start = clock ( ) ;
2014-11-30 16:59:31 +00:00
if ( compressionlevel < 3 ) compressionFunction = LZ4_compress ; else compressionFunction = LZ4_compressHC ;
2014-02-04 14:11:10 +00:00
get_fileHandle ( input_filename , output_filename , & finput , & foutput ) ;
2015-03-11 18:42:37 +00:00
if ( ( g_displayLevel = = 2 ) & & ( compressionlevel = = 1 ) ) g_displayLevel = 3 ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Allocate Memory */
2014-02-04 14:11:10 +00:00
in_buff = ( char * ) malloc ( LEGACY_BLOCKSIZE ) ;
out_buff = ( char * ) malloc ( LZ4_compressBound ( LEGACY_BLOCKSIZE ) ) ;
if ( ! in_buff | | ! out_buff ) EXM_THROW ( 21 , " Allocation error : not enough memory " ) ;
2014-12-16 21:03:16 +00:00
/* Write Archive Header */
2014-11-30 16:59:31 +00:00
LZ4IO_writeLE32 ( out_buff , LEGACY_MAGICNUMBER ) ;
2014-02-04 14:11:10 +00:00
sizeCheck = fwrite ( out_buff , 1 , MAGICNUMBER_SIZE , foutput ) ;
if ( sizeCheck ! = MAGICNUMBER_SIZE ) EXM_THROW ( 22 , " Write error : cannot write header " ) ;
2014-12-16 21:03:16 +00:00
/* Main Loop */
2014-02-04 14:11:10 +00:00
while ( 1 )
{
unsigned int outSize ;
2014-12-16 21:03:16 +00:00
/* Read Block */
2014-02-04 14:11:10 +00:00
int inSize = ( int ) fread ( in_buff , ( size_t ) 1 , ( size_t ) LEGACY_BLOCKSIZE , finput ) ;
if ( inSize < = 0 ) break ;
filesize + = inSize ;
2014-12-16 21:03:16 +00:00
/* Compress Block */
2014-02-04 14:11:10 +00:00
outSize = compressionFunction ( in_buff , out_buff + 4 , inSize ) ;
compressedfilesize + = outSize + 4 ;
2014-11-30 16:59:31 +00:00
DISPLAYUPDATE ( 3 , " \r Read : %i MB ==> %.2f%% " , ( int ) ( filesize > > 20 ) , ( double ) compressedfilesize / filesize * 100 ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Write Block */
2014-11-30 16:59:31 +00:00
LZ4IO_writeLE32 ( out_buff , outSize ) ;
2014-02-04 14:11:10 +00:00
sizeCheck = fwrite ( out_buff , 1 , outSize + 4 , foutput ) ;
if ( sizeCheck ! = ( size_t ) ( outSize + 4 ) ) EXM_THROW ( 23 , " Write error : cannot write compressed block " ) ;
}
2014-12-16 21:03:16 +00:00
/* Status */
2014-02-04 14:11:10 +00:00
end = clock ( ) ;
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
DISPLAYLEVEL ( 2 , " Compressed %llu bytes into %llu bytes ==> %.2f%% \n " ,
( unsigned long long ) filesize , ( unsigned long long ) compressedfilesize , ( double ) compressedfilesize / filesize * 100 ) ;
{
double seconds = ( double ) ( end - start ) / CLOCKS_PER_SEC ;
DISPLAYLEVEL ( 4 , " Done in %.2f s ==> %.2f MB/s \n " , seconds , ( double ) filesize / seconds / 1024 / 1024 ) ;
}
2014-12-16 21:03:16 +00:00
/* Close & Free */
2014-02-04 14:11:10 +00:00
free ( in_buff ) ;
free ( out_buff ) ;
fclose ( finput ) ;
fclose ( foutput ) ;
return 0 ;
}
2015-03-13 19:36:59 +00:00
/*********************************************
* Compression using Frame format
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-02-04 14:11:10 +00:00
2015-03-07 12:23:00 +00:00
int LZ4IO_compressFilename ( const char * input_filename , const char * output_filename , int compressionLevel )
2014-02-04 14:11:10 +00:00
{
unsigned long long filesize = 0 ;
unsigned long long compressedfilesize = 0 ;
char * in_buff ;
char * out_buff ;
FILE * finput ;
FILE * foutput ;
clock_t start , end ;
int blockSize ;
2014-11-30 16:59:31 +00:00
size_t sizeCheck , headerSize , readSize , outBuffSize ;
LZ4F_compressionContext_t ctx ;
LZ4F_errorCode_t errorCode ;
2015-03-10 15:57:42 +00:00
LZ4F_preferences_t prefs ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Init */
2014-02-04 14:11:10 +00:00
start = clock ( ) ;
2015-03-10 15:57:42 +00:00
memset ( & prefs , 0 , sizeof ( prefs ) ) ;
2015-03-11 18:42:37 +00:00
if ( ( g_displayLevel = = 2 ) & & ( compressionLevel > = 3 ) ) g_displayLevel = 3 ;
2014-11-30 16:59:31 +00:00
errorCode = LZ4F_createCompressionContext ( & ctx , LZ4F_VERSION ) ;
if ( LZ4F_isError ( errorCode ) ) EXM_THROW ( 30 , " Allocation error : can't create LZ4F context : %s " , LZ4F_getErrorName ( errorCode ) ) ;
2014-02-04 14:11:10 +00:00
get_fileHandle ( input_filename , output_filename , & finput , & foutput ) ;
2015-03-11 18:42:37 +00:00
blockSize = LZ4S_GetBlockSize_FromBlockId ( g_blockSizeId ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Set compression parameters */
2014-11-30 16:59:31 +00:00
prefs . autoFlush = 1 ;
prefs . compressionLevel = compressionLevel ;
2015-03-11 18:42:37 +00:00
prefs . frameInfo . blockMode = ( blockMode_t ) g_blockIndependence ;
prefs . frameInfo . blockSizeID = ( blockSizeID_t ) g_blockSizeId ;
prefs . frameInfo . contentChecksumFlag = ( contentChecksum_t ) g_streamChecksum ;
2014-11-30 16:59:31 +00:00
2014-12-16 21:03:16 +00:00
/* Allocate Memory */
2014-02-04 14:11:10 +00:00
in_buff = ( char * ) malloc ( blockSize ) ;
2014-11-30 16:59:31 +00:00
outBuffSize = LZ4F_compressBound ( blockSize , & prefs ) ;
out_buff = ( char * ) malloc ( outBuffSize ) ;
if ( ! in_buff | | ! out_buff ) EXM_THROW ( 31 , " Allocation error : not enough memory " ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Write Archive Header */
2014-11-30 16:59:31 +00:00
headerSize = LZ4F_compressBegin ( ctx , out_buff , outBuffSize , & prefs ) ;
if ( LZ4F_isError ( headerSize ) ) EXM_THROW ( 32 , " File header generation failed : %s " , LZ4F_getErrorName ( headerSize ) ) ;
sizeCheck = fwrite ( out_buff , 1 , headerSize , foutput ) ;
if ( sizeCheck ! = headerSize ) EXM_THROW ( 33 , " Write error : cannot write header " ) ;
compressedfilesize + = headerSize ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* read first block */
2014-02-04 14:11:10 +00:00
readSize = fread ( in_buff , ( size_t ) 1 , ( size_t ) blockSize , finput ) ;
2014-11-30 16:59:31 +00:00
filesize + = readSize ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Main Loop */
2014-02-04 14:11:10 +00:00
while ( readSize > 0 )
{
2014-11-30 16:59:31 +00:00
size_t outSize ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Compress Block */
2014-11-30 16:59:31 +00:00
outSize = LZ4F_compressUpdate ( ctx , out_buff , outBuffSize , in_buff , readSize , NULL ) ;
if ( LZ4F_isError ( outSize ) ) EXM_THROW ( 34 , " Compression failed : %s " , LZ4F_getErrorName ( outSize ) ) ;
compressedfilesize + = outSize ;
DISPLAYUPDATE ( 3 , " \r Read : %i MB ==> %.2f%% " , ( int ) ( filesize > > 20 ) , ( double ) compressedfilesize / filesize * 100 ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Write Block */
2014-11-30 16:59:31 +00:00
sizeCheck = fwrite ( out_buff , 1 , outSize , foutput ) ;
if ( sizeCheck ! = outSize ) EXM_THROW ( 35 , " Write error : cannot write compressed block " ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Read next block */
2014-02-04 14:11:10 +00:00
readSize = fread ( in_buff , ( size_t ) 1 , ( size_t ) blockSize , finput ) ;
2014-11-30 16:59:31 +00:00
filesize + = readSize ;
2014-02-04 14:11:10 +00:00
}
2014-12-16 21:03:16 +00:00
/* End of Stream mark */
2014-11-30 16:59:31 +00:00
headerSize = LZ4F_compressEnd ( ctx , out_buff , outBuffSize , NULL ) ;
if ( LZ4F_isError ( headerSize ) ) EXM_THROW ( 36 , " End of file generation failed : %s " , LZ4F_getErrorName ( headerSize ) ) ;
sizeCheck = fwrite ( out_buff , 1 , headerSize , foutput ) ;
if ( sizeCheck ! = headerSize ) EXM_THROW ( 37 , " Write error : cannot write end of stream " ) ;
compressedfilesize + = headerSize ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Close & Free */
2014-02-04 14:11:10 +00:00
free ( in_buff ) ;
free ( out_buff ) ;
fclose ( finput ) ;
fclose ( foutput ) ;
2014-11-30 16:59:31 +00:00
errorCode = LZ4F_freeCompressionContext ( ctx ) ;
if ( LZ4F_isError ( errorCode ) ) EXM_THROW ( 38 , " Error : can't free LZ4F context resource : %s " , LZ4F_getErrorName ( errorCode ) ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Final Status */
2014-02-04 14:11:10 +00:00
end = clock ( ) ;
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
DISPLAYLEVEL ( 2 , " Compressed %llu bytes into %llu bytes ==> %.2f%% \n " ,
( unsigned long long ) filesize , ( unsigned long long ) compressedfilesize , ( double ) compressedfilesize / filesize * 100 ) ;
{
double seconds = ( double ) ( end - start ) / CLOCKS_PER_SEC ;
DISPLAYLEVEL ( 4 , " Done in %.2f s ==> %.2f MB/s \n " , seconds , ( double ) filesize / seconds / 1024 / 1024 ) ;
}
return 0 ;
}
2015-03-07 12:23:00 +00:00
int LZ4IO_compressMultipleFilenames ( const char * * inFileNamesTable , int ifntSize , const char * suffix , int compressionlevel )
{
int i ;
char * outFileName = NULL ;
size_t ofnSize = 0 ;
const size_t suffixSize = strlen ( suffix ) ;
for ( i = 0 ; i < ifntSize ; i + + )
{
size_t ifnSize = strlen ( inFileNamesTable [ i ] ) ;
2015-03-10 15:57:42 +00:00
if ( ofnSize < = ifnSize + suffixSize + 1 ) { free ( outFileName ) ; ofnSize = ifnSize + 20 ; outFileName = ( char * ) malloc ( ofnSize ) ; }
2015-03-07 12:23:00 +00:00
strcpy ( outFileName , inFileNamesTable [ i ] ) ;
strcat ( outFileName , suffix ) ;
LZ4IO_compressFilename ( inFileNamesTable [ i ] , outFileName , compressionlevel ) ;
}
free ( outFileName ) ;
return 0 ;
}
2014-02-04 14:11:10 +00:00
/* ********************************************************************* */
2015-03-07 12:23:00 +00:00
/* ********************** LZ4 file-stream Decompression **************** */
2014-02-04 14:11:10 +00:00
/* ********************************************************************* */
2014-11-30 16:59:31 +00:00
static unsigned LZ4IO_readLE32 ( const void * s )
{
2015-03-10 15:57:42 +00:00
const unsigned char * srcPtr = ( const unsigned char * ) s ;
2014-11-30 16:59:31 +00:00
unsigned value32 = srcPtr [ 0 ] ;
value32 + = ( srcPtr [ 1 ] < < 8 ) ;
value32 + = ( srcPtr [ 2 ] < < 16 ) ;
value32 + = ( srcPtr [ 3 ] < < 24 ) ;
return value32 ;
}
2014-02-04 14:11:10 +00:00
static unsigned long long decodeLegacyStream ( FILE * finput , FILE * foutput )
{
unsigned long long filesize = 0 ;
char * in_buff ;
char * out_buff ;
2014-12-16 21:03:16 +00:00
/* Allocate Memory */
2014-02-04 14:11:10 +00:00
in_buff = ( char * ) malloc ( LZ4_compressBound ( LEGACY_BLOCKSIZE ) ) ;
out_buff = ( char * ) malloc ( LEGACY_BLOCKSIZE ) ;
if ( ! in_buff | | ! out_buff ) EXM_THROW ( 51 , " Allocation error : not enough memory " ) ;
2014-12-16 21:03:16 +00:00
/* Main Loop */
2014-02-04 14:11:10 +00:00
while ( 1 )
{
int decodeSize ;
size_t sizeCheck ;
2014-12-06 16:10:54 +00:00
unsigned int blockSize ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Block Size */
2014-11-30 16:59:31 +00:00
sizeCheck = fread ( in_buff , 1 , 4 , finput ) ;
2014-12-16 21:03:16 +00:00
if ( sizeCheck = = 0 ) break ; /* Nothing to read : file read is completed */
blockSize = LZ4IO_readLE32 ( in_buff ) ; /* Convert to Little Endian */
2014-02-04 14:11:10 +00:00
if ( blockSize > LZ4_COMPRESSBOUND ( LEGACY_BLOCKSIZE ) )
2014-12-16 21:03:16 +00:00
{ /* Cannot read next block : maybe new stream ? */
2014-02-04 14:11:10 +00:00
fseek ( finput , - 4 , SEEK_CUR ) ;
break ;
}
2014-12-16 21:03:16 +00:00
/* Read Block */
2014-02-04 14:11:10 +00:00
sizeCheck = fread ( in_buff , 1 , blockSize , finput ) ;
2014-12-16 21:03:16 +00:00
/* Decode Block */
2014-02-04 14:11:10 +00:00
decodeSize = LZ4_decompress_safe ( in_buff , out_buff , blockSize , LEGACY_BLOCKSIZE ) ;
if ( decodeSize < 0 ) EXM_THROW ( 52 , " Decoding Failed ! Corrupted input detected ! " ) ;
filesize + = decodeSize ;
2014-12-16 21:03:16 +00:00
/* Write Block */
2014-02-04 14:11:10 +00:00
sizeCheck = fwrite ( out_buff , 1 , decodeSize , foutput ) ;
if ( sizeCheck ! = ( size_t ) decodeSize ) EXM_THROW ( 53 , " Write error : cannot write decoded block into output \n " ) ;
}
2014-12-16 21:03:16 +00:00
/* Free */
2014-02-04 14:11:10 +00:00
free ( in_buff ) ;
free ( out_buff ) ;
return filesize ;
}
static unsigned long long decodeLZ4S ( FILE * finput , FILE * foutput )
{
unsigned long long filesize = 0 ;
2015-03-11 18:42:37 +00:00
void * inBuff ;
void * outBuff ;
2014-11-30 16:59:31 +00:00
# define HEADERMAX 20
char headerBuff [ HEADERMAX ] ;
size_t sizeCheck , nextToRead , outBuffSize , inBuffSize ;
LZ4F_decompressionContext_t ctx ;
LZ4F_errorCode_t errorCode ;
LZ4F_frameInfo_t frameInfo ;
2015-03-13 01:24:08 +00:00
unsigned storedSkips = 0 ;
2014-06-17 20:41:59 +00:00
2014-12-16 21:03:16 +00:00
/* init */
2014-11-30 16:59:31 +00:00
errorCode = LZ4F_createDecompressionContext ( & ctx , LZ4F_VERSION ) ;
if ( LZ4F_isError ( errorCode ) ) EXM_THROW ( 60 , " Allocation error : can't create context : %s " , LZ4F_getErrorName ( errorCode ) ) ;
LZ4IO_writeLE32 ( headerBuff , LZ4S_MAGICNUMBER ) ; /* regenerated here, as it was already read from finput */
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Decode stream descriptor */
2014-11-30 16:59:31 +00:00
outBuffSize = 0 ; inBuffSize = 0 ; sizeCheck = MAGICNUMBER_SIZE ;
nextToRead = LZ4F_decompress ( ctx , NULL , & outBuffSize , headerBuff , & sizeCheck , NULL ) ;
if ( LZ4F_isError ( nextToRead ) ) EXM_THROW ( 61 , " Decompression error : %s " , LZ4F_getErrorName ( nextToRead ) ) ;
if ( nextToRead > HEADERMAX ) EXM_THROW ( 62 , " Header too large (%i>%i) " , ( int ) nextToRead , HEADERMAX ) ;
sizeCheck = fread ( headerBuff , 1 , nextToRead , finput ) ;
if ( sizeCheck ! = nextToRead ) EXM_THROW ( 63 , " Read error " ) ;
nextToRead = LZ4F_decompress ( ctx , NULL , & outBuffSize , headerBuff , & sizeCheck , NULL ) ;
errorCode = LZ4F_getFrameInfo ( ctx , & frameInfo , NULL , & inBuffSize ) ;
if ( LZ4F_isError ( errorCode ) ) EXM_THROW ( 64 , " can't decode frame header : %s " , LZ4F_getErrorName ( errorCode ) ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Allocate Memory */
2014-11-30 16:59:31 +00:00
outBuffSize = LZ4IO_setBlockSizeID ( frameInfo . blockSizeID ) ;
inBuffSize = outBuffSize + 4 ;
2015-03-11 18:42:37 +00:00
inBuff = malloc ( inBuffSize ) ;
outBuff = malloc ( outBuffSize ) ;
2014-11-30 16:59:31 +00:00
if ( ! inBuff | | ! outBuff ) EXM_THROW ( 65 , " Allocation error : not enough memory " ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Main Loop */
2014-11-30 16:59:31 +00:00
while ( nextToRead ! = 0 )
2014-02-04 14:11:10 +00:00
{
2014-11-30 16:59:31 +00:00
size_t decodedBytes = outBuffSize ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Read Block */
2014-11-30 16:59:31 +00:00
sizeCheck = fread ( inBuff , 1 , nextToRead , finput ) ;
if ( sizeCheck ! = nextToRead ) EXM_THROW ( 66 , " Read error " ) ;
2014-06-17 20:41:59 +00:00
2014-12-16 21:03:16 +00:00
/* Decode Block */
2014-11-30 16:59:31 +00:00
errorCode = LZ4F_decompress ( ctx , outBuff , & decodedBytes , inBuff , & sizeCheck , NULL ) ;
if ( LZ4F_isError ( errorCode ) ) EXM_THROW ( 67 , " Decompression error : %s " , LZ4F_getErrorName ( errorCode ) ) ;
if ( sizeCheck ! = nextToRead ) EXM_THROW ( 67 , " Synchronization error " ) ;
nextToRead = errorCode ;
filesize + = decodedBytes ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Write Block */
2015-03-11 18:42:37 +00:00
if ( g_sparseFileSupport )
{
2015-03-13 19:36:59 +00:00
char * const oBuffStart = ( char * ) outBuff ;
char * oBuffPos = oBuffStart ;
char * const oBuffEnd = oBuffStart + decodedBytes ;
static const size_t zeroBlockSize = 32 KB ;
while ( oBuffPos < oBuffEnd )
2015-03-13 01:24:08 +00:00
{
2015-03-13 21:15:08 +00:00
const size_t * sPtr = ( const size_t * ) oBuffPos ;
2015-03-13 19:36:59 +00:00
size_t seg0Size = zeroBlockSize ;
size_t nbSizeT ;
size_t checked ;
size_t skippedLength ;
int seekResult ;
if ( seg0Size > decodedBytes ) seg0Size = decodedBytes ;
decodedBytes - = seg0Size ;
nbSizeT = seg0Size / sizeof ( size_t ) ;
for ( checked = 0 ; ( checked < nbSizeT ) & & ( sPtr [ checked ] = = 0 ) ; checked + + ) ;
skippedLength = checked * sizeof ( size_t ) ;
storedSkips + = ( unsigned ) skippedLength ;
if ( storedSkips > 1 GB )
{
seekResult = fseek ( foutput , 1 GB , SEEK_CUR ) ;
if ( seekResult ! = 0 ) EXM_THROW ( 68 , " 1 GB skip error (sparse file) \n " ) ;
storedSkips - = 1 GB ;
}
if ( skippedLength ! = seg0Size )
{
seekResult = fseek ( foutput , storedSkips , SEEK_CUR ) ;
if ( seekResult ! = 0 ) EXM_THROW ( 68 , " Skip error (sparse file) \n " ) ;
storedSkips = 0 ;
seg0Size - = skippedLength ;
oBuffPos + = skippedLength ;
sizeCheck = fwrite ( oBuffPos , 1 , seg0Size , foutput ) ;
if ( sizeCheck ! = seg0Size ) EXM_THROW ( 68 , " Write error : cannot write decoded block \n " ) ;
}
oBuffPos + = seg0Size ;
2015-03-13 01:24:08 +00:00
}
2015-03-11 18:42:37 +00:00
}
2015-03-13 01:24:08 +00:00
else
{
sizeCheck = fwrite ( outBuff , 1 , decodedBytes , foutput ) ;
if ( sizeCheck ! = decodedBytes ) EXM_THROW ( 68 , " Write error : cannot write decoded block \n " ) ;
}
}
if ( ( g_sparseFileSupport ) & & ( storedSkips > 0 ) )
{
int seekResult ;
storedSkips - - ;
seekResult = fseek ( foutput , storedSkips , SEEK_CUR ) ;
2015-03-13 19:36:59 +00:00
if ( seekResult ! = 0 ) EXM_THROW ( 69 , " Final skip error (sparse file) \n " ) ;
2015-03-13 01:24:08 +00:00
memset ( outBuff , 0 , 1 ) ;
sizeCheck = fwrite ( outBuff , 1 , 1 , foutput ) ;
2015-03-13 19:36:59 +00:00
if ( sizeCheck ! = 1 ) EXM_THROW ( 69 , " Write error : cannot write last zero \n " ) ;
2014-02-04 14:11:10 +00:00
}
2014-12-16 21:03:16 +00:00
/* Free */
2014-11-30 16:59:31 +00:00
free ( inBuff ) ;
free ( outBuff ) ;
errorCode = LZ4F_freeDecompressionContext ( ctx ) ;
if ( LZ4F_isError ( errorCode ) ) EXM_THROW ( 69 , " Error : can't free LZ4F context resource : %s " , LZ4F_getErrorName ( errorCode ) ) ;
2014-02-04 14:11:10 +00:00
return filesize ;
}
2014-11-04 11:11:14 +00:00
# define ENDOFSTREAM ((unsigned long long)-1)
2014-02-04 14:11:10 +00:00
static unsigned long long selectDecoder ( FILE * finput , FILE * foutput )
{
2014-11-30 16:59:31 +00:00
unsigned char U32store [ MAGICNUMBER_SIZE ] ;
unsigned magicNumber , size ;
2014-02-04 14:11:10 +00:00
int errorNb ;
size_t nbReadBytes ;
2014-12-16 21:03:16 +00:00
/* Check Archive Header */
2014-11-30 16:59:31 +00:00
nbReadBytes = fread ( U32store , 1 , MAGICNUMBER_SIZE , finput ) ;
2014-12-16 21:03:16 +00:00
if ( nbReadBytes = = 0 ) return ENDOFSTREAM ; /* EOF */
2014-11-30 16:59:31 +00:00
if ( nbReadBytes ! = MAGICNUMBER_SIZE ) EXM_THROW ( 40 , " Unrecognized header : Magic Number unreadable " ) ;
2014-12-16 21:03:16 +00:00
magicNumber = LZ4IO_readLE32 ( U32store ) ; /* Little Endian format */
if ( LZ4S_isSkippableMagicNumber ( magicNumber ) ) magicNumber = LZ4S_SKIPPABLE0 ; /* fold skippable magic numbers */
2014-02-04 14:11:10 +00:00
switch ( magicNumber )
{
case LZ4S_MAGICNUMBER :
return DEFAULT_DECOMPRESSOR ( finput , foutput ) ;
case LEGACY_MAGICNUMBER :
DISPLAYLEVEL ( 4 , " Detected : Legacy format \n " ) ;
return decodeLegacyStream ( finput , foutput ) ;
case LZ4S_SKIPPABLE0 :
DISPLAYLEVEL ( 4 , " Skipping detected skippable area \n " ) ;
2014-11-30 16:59:31 +00:00
nbReadBytes = fread ( U32store , 1 , 4 , finput ) ;
2014-02-04 14:11:10 +00:00
if ( nbReadBytes ! = 4 ) EXM_THROW ( 42 , " Stream error : skippable size unreadable " ) ;
2014-12-16 21:03:16 +00:00
size = LZ4IO_readLE32 ( U32store ) ; /* Little Endian format */
2014-02-04 14:11:10 +00:00
errorNb = fseek ( finput , size , SEEK_CUR ) ;
if ( errorNb ! = 0 ) EXM_THROW ( 43 , " Stream error : cannot skip skippable area " ) ;
return selectDecoder ( finput , foutput ) ;
EXTENDED_FORMAT ;
default :
2014-12-16 21:03:16 +00:00
if ( ftell ( finput ) = = MAGICNUMBER_SIZE ) EXM_THROW ( 44 , " Unrecognized header : file cannot be decoded " ) ; /* Wrong magic number at the beginning of 1st stream */
2014-02-04 14:11:10 +00:00
DISPLAYLEVEL ( 2 , " Stream followed by unrecognized data \n " ) ;
2014-11-04 11:11:14 +00:00
return ENDOFSTREAM ;
2014-02-04 14:11:10 +00:00
}
}
2015-03-07 12:23:00 +00:00
int LZ4IO_decompressFilename ( const char * input_filename , const char * output_filename )
2014-02-04 14:11:10 +00:00
{
unsigned long long filesize = 0 , decodedSize = 0 ;
FILE * finput ;
FILE * foutput ;
clock_t start , end ;
2014-12-16 21:03:16 +00:00
/* Init */
2014-02-04 14:11:10 +00:00
start = clock ( ) ;
get_fileHandle ( input_filename , output_filename , & finput , & foutput ) ;
2015-03-13 21:15:08 +00:00
/* sparse file */
if ( g_sparseFileSupport & & foutput )
{
SET_SPARSE_FILE_MODE ( foutput ) ;
}
2014-12-16 21:03:16 +00:00
/* Loop over multiple streams */
2014-02-04 14:11:10 +00:00
do
{
decodedSize = selectDecoder ( finput , foutput ) ;
2014-11-04 11:11:14 +00:00
if ( decodedSize ! = ENDOFSTREAM )
filesize + = decodedSize ;
} while ( decodedSize ! = ENDOFSTREAM ) ;
2014-02-04 14:11:10 +00:00
2014-12-16 21:03:16 +00:00
/* Final Status */
2014-02-04 14:11:10 +00:00
end = clock ( ) ;
DISPLAYLEVEL ( 2 , " \r %79s \r " , " " ) ;
DISPLAYLEVEL ( 2 , " Successfully decoded %llu bytes \n " , filesize ) ;
{
double seconds = ( double ) ( end - start ) / CLOCKS_PER_SEC ;
DISPLAYLEVEL ( 4 , " Done in %.2f s ==> %.2f MB/s \n " , seconds , ( double ) filesize / seconds / 1024 / 1024 ) ;
}
2014-12-16 21:03:16 +00:00
/* Close */
2014-02-04 14:11:10 +00:00
fclose ( finput ) ;
fclose ( foutput ) ;
2014-12-16 21:03:16 +00:00
/* Error status = OK */
2014-02-04 14:11:10 +00:00
return 0 ;
}