2025-02-20 21:31:06 +01:00
|
|
|
/* File to file example - Test program for the library lzlib
|
2025-02-20 21:35:19 +01:00
|
|
|
Copyright (C) 2010-2025 Antonio Diaz Diaz.
|
2025-02-20 21:31:06 +01:00
|
|
|
|
|
|
|
This program is free software: you have unlimited permission
|
|
|
|
to copy, distribute, and modify it.
|
|
|
|
|
|
|
|
Try 'ffexample -h' for usage information.
|
|
|
|
|
|
|
|
This program is an example of how file-to-file
|
|
|
|
compression/decompression can be implemented using lzlib.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define _FILE_OFFSET_BITS 64
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2025-02-20 21:32:02 +01:00
|
|
|
#if defined __MSVCRT__ || defined __OS2__ || defined __DJGPP__
|
2025-02-20 21:31:06 +01:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "lzlib.h"
|
|
|
|
|
|
|
|
#ifndef min
|
|
|
|
#define min(x,y) ((x) <= (y) ? (x) : (y))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static void show_help( void )
|
|
|
|
{
|
|
|
|
printf( "ffexample is an example program showing how file-to-file (de)compression can\n"
|
|
|
|
"be implemented using lzlib. The content of infile is compressed,\n"
|
|
|
|
"decompressed, or both, and then written to outfile.\n"
|
|
|
|
"\nUsage: ffexample operation [infile [outfile]]\n" );
|
|
|
|
printf( "\nOperation:\n"
|
|
|
|
" -h display this help and exit\n"
|
|
|
|
" -c compress infile to outfile\n"
|
|
|
|
" -d decompress infile to outfile\n"
|
|
|
|
" -b both (compress then decompress) infile to outfile\n"
|
|
|
|
" -m compress (multimember) infile to outfile\n"
|
|
|
|
" -l compress (1 member per line) infile to outfile\n"
|
|
|
|
" -r decompress with resync if data error or leading garbage\n"
|
|
|
|
"\nIf infile or outfile are omitted, or are specified as '-', standard input or\n"
|
|
|
|
"standard output are used in their place respectively.\n"
|
|
|
|
"\nReport bugs to lzip-bug@nongnu.org\n"
|
|
|
|
"Lzlib home page: http://www.nongnu.org/lzip/lzlib.html\n" );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-20 21:34:58 +01:00
|
|
|
int ffcompress( LZ_Encoder * const encoder,
|
2025-02-20 21:31:06 +01:00
|
|
|
FILE * const infile, FILE * const outfile )
|
|
|
|
{
|
|
|
|
enum { buffer_size = 16384 };
|
|
|
|
uint8_t buffer[buffer_size];
|
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
int len, ret;
|
|
|
|
int size = min( buffer_size, LZ_compress_write_size( encoder ) );
|
|
|
|
if( size > 0 )
|
|
|
|
{
|
|
|
|
len = fread( buffer, 1, size, infile );
|
|
|
|
ret = LZ_compress_write( encoder, buffer, len );
|
|
|
|
if( ret < 0 || ferror( infile ) ) break;
|
|
|
|
if( feof( infile ) ) LZ_compress_finish( encoder );
|
|
|
|
}
|
|
|
|
ret = LZ_compress_read( encoder, buffer, buffer_size );
|
|
|
|
if( ret < 0 ) break;
|
|
|
|
len = fwrite( buffer, 1, ret, outfile );
|
|
|
|
if( len < ret ) break;
|
|
|
|
if( LZ_compress_finished( encoder ) == 1 ) return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-20 21:34:58 +01:00
|
|
|
int ffdecompress( LZ_Decoder * const decoder,
|
2025-02-20 21:31:06 +01:00
|
|
|
FILE * const infile, FILE * const outfile )
|
|
|
|
{
|
|
|
|
enum { buffer_size = 16384 };
|
|
|
|
uint8_t buffer[buffer_size];
|
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
int len, ret;
|
|
|
|
int size = min( buffer_size, LZ_decompress_write_size( decoder ) );
|
|
|
|
if( size > 0 )
|
|
|
|
{
|
|
|
|
len = fread( buffer, 1, size, infile );
|
|
|
|
ret = LZ_decompress_write( decoder, buffer, len );
|
|
|
|
if( ret < 0 || ferror( infile ) ) break;
|
|
|
|
if( feof( infile ) ) LZ_decompress_finish( decoder );
|
|
|
|
}
|
|
|
|
ret = LZ_decompress_read( decoder, buffer, buffer_size );
|
|
|
|
if( ret < 0 ) break;
|
|
|
|
len = fwrite( buffer, 1, ret, outfile );
|
|
|
|
if( len < ret ) break;
|
|
|
|
if( LZ_decompress_finished( decoder ) == 1 ) return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-20 21:34:58 +01:00
|
|
|
int ffboth( LZ_Encoder * const encoder, LZ_Decoder * const decoder,
|
2025-02-20 21:31:06 +01:00
|
|
|
FILE * const infile, FILE * const outfile )
|
|
|
|
{
|
|
|
|
enum { buffer_size = 16384 };
|
|
|
|
uint8_t buffer[buffer_size];
|
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
int len, ret;
|
|
|
|
int size = min( buffer_size, LZ_compress_write_size( encoder ) );
|
|
|
|
if( size > 0 )
|
|
|
|
{
|
|
|
|
len = fread( buffer, 1, size, infile );
|
|
|
|
ret = LZ_compress_write( encoder, buffer, len );
|
|
|
|
if( ret < 0 || ferror( infile ) ) break;
|
|
|
|
if( feof( infile ) ) LZ_compress_finish( encoder );
|
|
|
|
}
|
|
|
|
size = min( buffer_size, LZ_decompress_write_size( decoder ) );
|
|
|
|
if( size > 0 )
|
|
|
|
{
|
|
|
|
ret = LZ_compress_read( encoder, buffer, size );
|
|
|
|
if( ret < 0 ) break;
|
|
|
|
ret = LZ_decompress_write( decoder, buffer, ret );
|
|
|
|
if( ret < 0 ) break;
|
|
|
|
if( LZ_compress_finished( encoder ) == 1 )
|
|
|
|
LZ_decompress_finish( decoder );
|
|
|
|
}
|
|
|
|
ret = LZ_decompress_read( decoder, buffer, buffer_size );
|
|
|
|
if( ret < 0 ) break;
|
|
|
|
len = fwrite( buffer, 1, ret, outfile );
|
|
|
|
if( len < ret ) break;
|
|
|
|
if( LZ_decompress_finished( decoder ) == 1 ) return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ffmmcompress( FILE * const infile, FILE * const outfile )
|
|
|
|
{
|
|
|
|
enum { buffer_size = 16384, member_size = 4096 };
|
|
|
|
uint8_t buffer[buffer_size];
|
|
|
|
bool done = false;
|
2025-02-20 21:34:58 +01:00
|
|
|
LZ_Encoder * const encoder = LZ_compress_open( 65535, 16, member_size );
|
2025-02-20 21:31:06 +01:00
|
|
|
if( !encoder || LZ_compress_errno( encoder ) != LZ_ok )
|
|
|
|
{ fputs( "ffexample: Not enough memory.\n", stderr );
|
|
|
|
LZ_compress_close( encoder ); return 1; }
|
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
int len, ret;
|
|
|
|
int size = min( buffer_size, LZ_compress_write_size( encoder ) );
|
|
|
|
if( size > 0 )
|
|
|
|
{
|
|
|
|
len = fread( buffer, 1, size, infile );
|
|
|
|
ret = LZ_compress_write( encoder, buffer, len );
|
|
|
|
if( ret < 0 || ferror( infile ) ) break;
|
|
|
|
if( feof( infile ) ) LZ_compress_finish( encoder );
|
|
|
|
}
|
|
|
|
ret = LZ_compress_read( encoder, buffer, buffer_size );
|
|
|
|
if( ret < 0 ) break;
|
|
|
|
len = fwrite( buffer, 1, ret, outfile );
|
|
|
|
if( len < ret ) break;
|
|
|
|
if( LZ_compress_member_finished( encoder ) == 1 )
|
|
|
|
{
|
|
|
|
if( LZ_compress_finished( encoder ) == 1 ) { done = true; break; }
|
|
|
|
if( LZ_compress_restart_member( encoder, member_size ) < 0 ) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( LZ_compress_close( encoder ) < 0 ) done = false;
|
|
|
|
return done;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-20 21:32:02 +01:00
|
|
|
/* Compress 'infile' to 'outfile' as a multimember stream with one member
|
2025-02-20 21:31:06 +01:00
|
|
|
for each line of text terminated by a newline character or by EOF.
|
2025-02-20 21:32:02 +01:00
|
|
|
Return 0 if success, 1 if error.
|
2025-02-20 21:31:06 +01:00
|
|
|
*/
|
2025-02-20 21:34:58 +01:00
|
|
|
int fflfcompress( LZ_Encoder * const encoder,
|
2025-02-20 21:31:06 +01:00
|
|
|
FILE * const infile, FILE * const outfile )
|
|
|
|
{
|
|
|
|
enum { buffer_size = 16384 };
|
|
|
|
uint8_t buffer[buffer_size];
|
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
int len, ret;
|
|
|
|
int size = min( buffer_size, LZ_compress_write_size( encoder ) );
|
|
|
|
if( size > 0 )
|
|
|
|
{
|
|
|
|
for( len = 0; len < size; )
|
|
|
|
{
|
|
|
|
int ch = getc( infile );
|
|
|
|
if( ch == EOF || ( buffer[len++] = ch ) == '\n' ) break;
|
|
|
|
}
|
|
|
|
/* avoid writing an empty member to outfile */
|
|
|
|
if( len == 0 && LZ_compress_data_position( encoder ) == 0 ) return 0;
|
|
|
|
ret = LZ_compress_write( encoder, buffer, len );
|
|
|
|
if( ret < 0 || ferror( infile ) ) break;
|
|
|
|
if( feof( infile ) || buffer[len-1] == '\n' )
|
|
|
|
LZ_compress_finish( encoder );
|
|
|
|
}
|
|
|
|
ret = LZ_compress_read( encoder, buffer, buffer_size );
|
|
|
|
if( ret < 0 ) break;
|
|
|
|
len = fwrite( buffer, 1, ret, outfile );
|
|
|
|
if( len < ret ) break;
|
|
|
|
if( LZ_compress_member_finished( encoder ) == 1 )
|
|
|
|
{
|
|
|
|
if( feof( infile ) && LZ_compress_finished( encoder ) == 1 ) return 0;
|
|
|
|
if( LZ_compress_restart_member( encoder, INT64_MAX ) < 0 ) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-20 21:32:02 +01:00
|
|
|
/* Decompress 'infile' to 'outfile' with automatic resynchronization to
|
2025-02-20 21:31:06 +01:00
|
|
|
next member in case of data error, including the automatic removal of
|
|
|
|
leading garbage.
|
|
|
|
*/
|
2025-02-20 21:34:58 +01:00
|
|
|
int ffrsdecompress( LZ_Decoder * const decoder,
|
2025-02-20 21:31:06 +01:00
|
|
|
FILE * const infile, FILE * const outfile )
|
|
|
|
{
|
|
|
|
enum { buffer_size = 16384 };
|
|
|
|
uint8_t buffer[buffer_size];
|
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
int len, ret;
|
|
|
|
int size = min( buffer_size, LZ_decompress_write_size( decoder ) );
|
|
|
|
if( size > 0 )
|
|
|
|
{
|
|
|
|
len = fread( buffer, 1, size, infile );
|
|
|
|
ret = LZ_decompress_write( decoder, buffer, len );
|
|
|
|
if( ret < 0 || ferror( infile ) ) break;
|
|
|
|
if( feof( infile ) ) LZ_decompress_finish( decoder );
|
|
|
|
}
|
|
|
|
ret = LZ_decompress_read( decoder, buffer, buffer_size );
|
|
|
|
if( ret < 0 )
|
|
|
|
{
|
|
|
|
if( LZ_decompress_errno( decoder ) == LZ_header_error ||
|
|
|
|
LZ_decompress_errno( decoder ) == LZ_data_error )
|
|
|
|
{ LZ_decompress_sync_to_member( decoder ); continue; }
|
2025-02-20 21:33:45 +01:00
|
|
|
break;
|
2025-02-20 21:31:06 +01:00
|
|
|
}
|
|
|
|
len = fwrite( buffer, 1, ret, outfile );
|
|
|
|
if( len < ret ) break;
|
|
|
|
if( LZ_decompress_finished( decoder ) == 1 ) return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main( const int argc, const char * const argv[] )
|
|
|
|
{
|
2025-02-20 21:32:02 +01:00
|
|
|
#if defined __MSVCRT__ || defined __OS2__ || defined __DJGPP__
|
2025-02-20 21:31:06 +01:00
|
|
|
setmode( STDIN_FILENO, O_BINARY );
|
|
|
|
setmode( STDOUT_FILENO, O_BINARY );
|
|
|
|
#endif
|
|
|
|
|
2025-02-20 21:34:58 +01:00
|
|
|
LZ_Encoder * const encoder = LZ_compress_open( 65535, 16, INT64_MAX );
|
|
|
|
LZ_Decoder * const decoder = LZ_decompress_open();
|
|
|
|
FILE * const infile = (argc >= 3 && strcmp( argv[2], "-" ) != 0) ?
|
2025-02-20 21:31:06 +01:00
|
|
|
fopen( argv[2], "rb" ) : stdin;
|
2025-02-20 21:34:58 +01:00
|
|
|
FILE * const outfile = (argc >= 4 && strcmp( argv[3], "-" ) != 0) ?
|
2025-02-20 21:31:06 +01:00
|
|
|
fopen( argv[3], "wb" ) : stdout;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
if( argc < 2 || argc > 4 || strlen( argv[1] ) != 2 || argv[1][0] != '-' )
|
|
|
|
{ show_help(); return 1; }
|
|
|
|
if( !encoder || LZ_compress_errno( encoder ) != LZ_ok ||
|
|
|
|
!decoder || LZ_decompress_errno( decoder ) != LZ_ok )
|
|
|
|
{ fputs( "ffexample: Not enough memory.\n", stderr );
|
|
|
|
LZ_compress_close( encoder ); LZ_decompress_close( decoder ); return 1; }
|
|
|
|
if( !infile )
|
2025-02-20 21:33:45 +01:00
|
|
|
{ fprintf( stderr, "ffexample: %s: Can't open input file: %s\n",
|
2025-02-20 21:31:06 +01:00
|
|
|
argv[2], strerror( errno ) ); return 1; }
|
|
|
|
if( !outfile )
|
2025-02-20 21:33:45 +01:00
|
|
|
{ fprintf( stderr, "ffexample: %s: Can't open output file: %s\n",
|
2025-02-20 21:31:06 +01:00
|
|
|
argv[3], strerror( errno ) ); return 1; }
|
|
|
|
|
|
|
|
switch( argv[1][1] )
|
|
|
|
{
|
|
|
|
case 'c': retval = ffcompress( encoder, infile, outfile ); break;
|
|
|
|
case 'd': retval = ffdecompress( decoder, infile, outfile ); break;
|
|
|
|
case 'b': retval = ffboth( encoder, decoder, infile, outfile ); break;
|
|
|
|
case 'm': retval = ffmmcompress( infile, outfile ); break;
|
|
|
|
case 'l': retval = fflfcompress( encoder, infile, outfile ); break;
|
|
|
|
case 'r': retval = ffrsdecompress( decoder, infile, outfile ); break;
|
2025-02-20 21:33:45 +01:00
|
|
|
default: show_help(); return argv[1][1] != 'h';
|
2025-02-20 21:31:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if( LZ_decompress_close( decoder ) < 0 || LZ_compress_close( encoder ) < 0 ||
|
|
|
|
fclose( outfile ) != 0 || fclose( infile ) != 0 ) retval = 1;
|
|
|
|
return retval;
|
|
|
|
}
|