diff options
Diffstat (limited to 'ffexample.c')
-rw-r--r-- | ffexample.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/ffexample.c b/ffexample.c new file mode 100644 index 0000000..826abcd --- /dev/null +++ b/ffexample.c @@ -0,0 +1,300 @@ +/* File to file example - Test program for the library lzlib + Copyright (C) 2010-2024 Antonio Diaz Diaz. + + 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> +#if defined __MSVCRT__ || defined __OS2__ || defined __DJGPP__ +#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" ); + } + + +int ffcompress( struct LZ_Encoder * const encoder, + 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; + } + + +int ffdecompress( struct LZ_Decoder * const decoder, + 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; + } + + +int ffboth( struct LZ_Encoder * const encoder, + struct LZ_Decoder * const decoder, + 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; + struct LZ_Encoder * const encoder = + LZ_compress_open( 65535, 16, member_size ); + 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; + } + + +/* Compress 'infile' to 'outfile' as a multimember stream with one member + for each line of text terminated by a newline character or by EOF. + Return 0 if success, 1 if error. +*/ +int fflfcompress( struct LZ_Encoder * const encoder, + 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; + } + + +/* Decompress 'infile' to 'outfile' with automatic resynchronization to + next member in case of data error, including the automatic removal of + leading garbage. +*/ +int ffrsdecompress( struct LZ_Decoder * const decoder, + 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; } + break; + } + 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[] ) + { +#if defined __MSVCRT__ || defined __OS2__ || defined __DJGPP__ + setmode( STDIN_FILENO, O_BINARY ); + setmode( STDOUT_FILENO, O_BINARY ); +#endif + + struct LZ_Encoder * const encoder = LZ_compress_open( 65535, 16, INT64_MAX ); + struct LZ_Decoder * const decoder = LZ_decompress_open(); + FILE * const infile = ( argc >= 3 && strcmp( argv[2], "-" ) != 0 ) ? + fopen( argv[2], "rb" ) : stdin; + FILE * const outfile = ( argc >= 4 && strcmp( argv[3], "-" ) != 0 ) ? + 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 ) + { fprintf( stderr, "ffexample: %s: Can't open input file: %s\n", + argv[2], strerror( errno ) ); return 1; } + if( !outfile ) + { fprintf( stderr, "ffexample: %s: Can't open output file: %s\n", + 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; + default: show_help(); return argv[1][1] != 'h'; + } + + if( LZ_decompress_close( decoder ) < 0 || LZ_compress_close( encoder ) < 0 || + fclose( outfile ) != 0 || fclose( infile ) != 0 ) retval = 1; + return retval; + } |