home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / l / lds_10.zip / COMP / COMP-2.C < prev    next >
C/C++ Source or Header  |  1990-06-02  |  7KB  |  219 lines

  1. /*
  2.  * Listing 10 -- comp-2.c
  3.  *
  4.  * This module is the driver program for a variable order
  5.  * finite context compression program.  The maximum order is
  6.  * determined by command line option.  This particular version
  7.  * also monitors compression ratios, and flushes the model whenever
  8.  * the local (last 256 symbols) compression ratio hits 90% or higher.
  9.  *
  10.  * To build this program:
  11.  *
  12.  * Turbo C:     tcc -w -mc comp-2.c model-2.c bitio.c coder.c
  13.  * QuickC:      qcl /AC /W3 comp-2.c model-2.c bitio.c coder.c
  14.  * Zortech:     ztc -mc comp-2.c model-2.c bitio.c coder.c
  15.  * *NIX:        cc -o comp-2 comp-2.c model-2.c bitio.c coder.c
  16.  *
  17.  * Command line options:
  18.  *
  19.  *  -f text_file_name  [defaults to test.inp]
  20.  *  -c compressed_file_name [defaults to test.cmp]
  21.  *  -o order [defaults to 3 for model-2]
  22.  */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include "coder.h"
  27. #include "model.h"
  28. #include "bitio.h"
  29.  
  30. /*
  31.  * The file pointers are used throughout this module.
  32.  */
  33. FILE *text_file;
  34. FILE *compressed_file;
  35.  
  36. /*
  37.  * Declarations for local procedures.
  38.  */
  39. void initialize_options( int argc, char **argv );
  40. int check_compression( void );
  41. void print_compression( void );
  42.  
  43. /*
  44.  * The main procedure is similar to the main found in COMP-1.C.
  45.  * It has to initialize the coder, the bit oriented I/O, the
  46.  * standard I/O, and the model.  It then sits in a loop reading
  47.  * input symbols and encoding them.  One difference is that every
  48.  * 256 symbols a compression check is performed.  If the compression
  49.  * ratio exceeds 90%, a flush character is encoded.  This flushes
  50.  * the encoding model, and will cause the decoder to flush its model
  51.  * when the file is being expanded.  The second difference is that
  52.  * each symbol is repeatedly encoded until a succesfull encoding
  53.  * occurs.  When trying to encode a character in a particular order,
  54.  * the model may have to transmit an ESCAPE character.  If this
  55.  * is the case, the character has to be retransmitted using a lower
  56.  * order.  This process repeats until a succesful match is found of
  57.  * the symbol in a particular context.  Usually this means going down
  58.  * no further than the order -1 model.  However, the FLUSH and DONE
  59.  * symbols do drop back to the order -2 model.  Note also that by
  60.  * all rights, add_character_to_model() and update_model() logically
  61.  * should be combined into a single routine.
  62.  */
  63. void main( int argc, char **argv )
  64. {
  65.     SYMBOL s;
  66.     int c;
  67.     int escaped;
  68.     int flush = 0;
  69.     long int text_count = 0;
  70.  
  71.     initialize_options( --argc, ++argv );
  72.     initialize_model();
  73.     initialize_output_bitstream();
  74.     initialize_arithmetic_encoder();
  75.     for ( ; ; )
  76.     {
  77.     if ( ( ++text_count & 0x0ff ) == 0 )
  78.             flush = check_compression();
  79.         if ( !flush )
  80.             c = getc( text_file );
  81.         else
  82.             c = FLUSH;
  83.         if ( c == EOF )
  84.             c = DONE;
  85.         do {
  86.             escaped = convert_int_to_symbol( c, &s );
  87.             encode_symbol( compressed_file, &s );
  88.         } while ( escaped );
  89.         if ( c == DONE )
  90.         break;
  91.         if ( c == FLUSH )
  92.     {
  93.         flush_model();
  94.             flush = 0;
  95.     }
  96.         update_model( c );
  97.         add_character_to_model( c );
  98.     }
  99.     flush_arithmetic_encoder( compressed_file );
  100.     flush_output_bitstream( compressed_file );
  101.     print_compression();
  102.     fputc( '\n', stderr );
  103.     exit( 0 );
  104. }
  105.  
  106. /*
  107.  * This routine checks for command line options, and opens the
  108.  * input and output files.  The only other command line option
  109.  * besides the input and output file names is the order of the model,
  110.  * which defaults to 3.
  111.  */
  112. void initialize_options( int argc, char **argv )
  113. {
  114.     char text_file_name[ 81 ];
  115.     char compressed_file_name[ 81 ];
  116.  
  117.     strcpy( compressed_file_name, "test.cmp" );
  118.     strcpy( text_file_name, "test.inp" );
  119.     while ( argc-- > 0 )
  120.     {
  121.         if ( strcmp( *argv, "-f" ) == 0 )
  122.     {
  123.         argc--;
  124.         strcpy( text_file_name, *++argv );
  125.     }
  126.         else if ( strcmp( *argv, "-c" ) == 0 )
  127.     {
  128.         argc--;
  129.         strcpy( compressed_file_name, *++argv );
  130.     }
  131.         else if ( strcmp( *argv, "-o" ) == 0 )
  132.     {
  133.         argc--;
  134.             max_order = atoi( *++argv );
  135.     }
  136.     else
  137.     {
  138.             fprintf( stderr, "\nUsage: COMP-2 [-o order] " );
  139.             fprintf( stderr, "[-f text file] [-c compressed file]\n" );
  140.             exit( -1 );
  141.     }
  142.     argc--;
  143.     argv++;
  144.     }
  145.     text_file = fopen( text_file_name, "rb" );
  146.     compressed_file = fopen( "test.cmp", "wb" );
  147.     if ( text_file == NULL || compressed_file == NULL )
  148.     {
  149.         printf( "Had trouble opening one of the files!\n" );
  150.         exit( -1 );
  151.     }
  152.     setvbuf( text_file, NULL, _IOFBF, 4096 );
  153.     setbuf( stdout, NULL );
  154.     printf( "Compressing %s to %s, order %d.\n",
  155.             text_file_name,
  156.             compressed_file_name,
  157.             max_order );
  158. }
  159.  
  160. /*
  161.  * This routine is called to print the current compression ratio.
  162.  * It prints out the number of input bytes, the number of output bytes,
  163.  * and the bits per byte compression ratio.   This is done both as a
  164.  * pacifier and as a seat-of-the-pants diagnostice.  A better version
  165.  * of this routine would also print the local compression ratio.
  166.  */
  167. void print_compression()
  168. {
  169.     long total_input_bytes;
  170.     long total_output_bytes;
  171.  
  172.     total_input_bytes  =  ftell( text_file );
  173.     total_output_bytes = bit_ftell_output( compressed_file );
  174.     if ( total_output_bytes == 0 )
  175.         total_output_bytes = 1;
  176.  
  177.     fprintf( stderr,"%ld/%ld, %2.3f\r",
  178.          total_input_bytes,
  179.          total_output_bytes,
  180.              8.0 * total_output_bytes / total_input_bytes );
  181. }
  182.  
  183. /*
  184.  * This routine is called once every 256 input symbols.  Its job is to
  185.  * check to see if the compression ratio hits or exceeds 90%.  If the
  186.  * output size is 90% of the input size, it means not much compression
  187.  * is taking place, so we probably ought to flush the statistics in the
  188.  * model to allow for more current statistics to have greater impactic.
  189.  * This heuristic approach does seem to have some effect.
  190.  */
  191. int check_compression()
  192. {
  193.     static long local_input_marker = 0L;
  194.     static long local_output_marker = 0L;
  195.     long total_input_bytes;
  196.     long total_output_bytes;
  197.     int local_ratio;
  198.  
  199.     print_compression();
  200.     total_input_bytes  =  ftell( text_file ) - local_input_marker;
  201.     total_output_bytes = bit_ftell_output( compressed_file );
  202.     total_output_bytes -= local_output_marker;
  203.     if ( total_output_bytes == 0 )
  204.         total_output_bytes = 1;
  205.     local_ratio = (int)( ( total_output_bytes * 100 ) / total_input_bytes );
  206.  
  207.     local_input_marker = ftell( text_file );
  208.     local_output_marker = bit_ftell_output( compressed_file );
  209.  
  210.     if ( local_ratio > 90 && flushing_enabled )
  211.     {
  212.         fprintf( stderr, "Flushing... \r" );
  213.         return( 1 );
  214.     }
  215.     return( 0 );
  216. }
  217.  
  218.  
  219.