294 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			294 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| //
 | |
| // EX23CON.CPP
 | |
| //
 | |
| //  C++/DOS Example program for ArchiveLib 2.0
 | |
| //
 | |
| //  Copyright (c) Greenleaf Software, Inc. 1994 - 1996
 | |
| //  All Rights Reserved
 | |
| //
 | |
| // MEMBERS/FUNCTIONS DEMONSTRATED
 | |
| //
 | |
| //  ALEngine::Compress()
 | |
| //  ALEngine::Decompress()
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  This program is used to benchmark the performance of our various
 | |
| //  compression engines.  It is called with a single command line argument,
 | |
| //  which is a wildcard specification for a group of files.  The program
 | |
| //  expands the wild card specification and individually compresses and
 | |
| //  decompresses each of the files.  The temporary files created by this
 | |
| //  process are deleted.
 | |
| //
 | |
| //  After the whole batch of files is done, a summary of the compression
 | |
| //  time and statistics is displayed.
 | |
| //
 | |
| //  If the optional -c argument is appended to the command line, the
 | |
| //  program runs in "compress-only" mode.  In this case, the decompression
 | |
| //  state is skipped.  You can use this to determine the ratio between
 | |
| //  compression and decompresion times.
 | |
| //
 | |
| //  A program very similar to this is used to compare the speed of the
 | |
| //  PKWare data compression library to our library.  It is called
 | |
| //  PKWARE.CPP, and it is distributed with our example program.s
 | |
| //
 | |
| //  This example program does one funky thing to try to give us real
 | |
| //  fast performance.  Instead of using the default buffer size of 4096
 | |
| //  bytes, I jack it up to a hefty 28672 bytes.  This gives us a few
 | |
| //  percentage points.  Just change the definition of BIG_BUFFER to
 | |
| //  benchmark at the default size.
 | |
| //
 | |
| //  Note that the default version of this program doesn't use a monitor.
 | |
| //  To test the effects of a monitor on program performance, just define
 | |
| //
 | |
| //  Note that this is a non-destructive test!  None of the input files are
 | |
| //  modified at any time!
 | |
| //
 | |
| //  MONITOR.
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //  February 1, 1996  2.0A : Second release.
 | |
| //
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <iostream.h>
 | |
| #include <conio.h>
 | |
| 
 | |
| #include "al.h"
 | |
| #if !defined( AL_OS2 )
 | |
| #include <dos.h>
 | |
| #endif
 | |
| 
 | |
| //
 | |
| // This program runs under standard MS-DOS and extended DOS.  Under
 | |
| // extended DOS, we use the Windows API to get the time of day.  To
 | |
| // make the source code less messy, the details of the time of day
 | |
| // are concealed in this class.
 | |
| //
 | |
| 
 | |
| class TIME {
 | |
|     public :
 | |
|         long milliseconds;
 | |
|         TIME();
 | |
|         TIME( long t ){ milliseconds = t; }
 | |
|         TIME operator-(TIME &);
 | |
| };
 | |
| 
 | |
| //
 | |
| // The time constructor does the job of initializing the time of day.
 | |
| // It has to be done differently under Extended DOS as opposed to
 | |
| // standard real mode DOS.
 | |
| //
 | |
| 
 | |
| #if defined( AL_WINDOWS )
 | |
| 
 | |
| inline TIME::TIME( void )
 | |
| {
 | |
|     milliseconds = GetTickCount();
 | |
| }
 | |
| 
 | |
| #elif defined( AL_OS2 )
 | |
| 
 | |
| inline TIME::TIME(void )
 | |
| {
 | |
|     DATETIME t;
 | |
|     DosGetDateTime( &t );
 | |
|     milliseconds = t.hundredths * 10L;
 | |
|     milliseconds += t.seconds * 1000L;
 | |
|     milliseconds += t.minutes * 1000L * 60L;
 | |
|     milliseconds += t.hours * 1000L * 60L * 60L;
 | |
| }
 | |
| 
 | |
| #else
 | |
| 
 | |
| inline TIME::TIME( void )
 | |
| {
 | |
| #if defined( AL_SYMANTEC )
 | |
|     struct dos_time_t t;
 | |
| #else
 | |
|     struct dostime_t t;
 | |
| #endif
 | |
|     _dos_gettime( &t );
 | |
|     milliseconds = t.hsecond * 10L;
 | |
|     milliseconds += t.second * 1000L;
 | |
|     milliseconds += t.minute * 1000L * 60L;
 | |
|     milliseconds += t.hour * 1000L * 60L * 60L;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| //
 | |
| // To determine how long an operation took, I need to calculate the
 | |
| // difference of two times.  This is strictly a convenience.
 | |
| //
 | |
| TIME TIME::operator-( TIME &rhs )
 | |
| {
 | |
|     return TIME( milliseconds - rhs.milliseconds );
 | |
| }
 | |
| 
 | |
| //
 | |
| // A standard function for calculating the compression ratio of a file,
 | |
| // give the input and output sizes.
 | |
| //
 | |
| 
 | |
| inline int ratio( long plain, long compressed )
 | |
| {
 | |
|     if ( plain == 0 )
 | |
|         return 0;
 | |
|     compressed *= 100;
 | |
|     return (int) ( 100 - ( compressed / plain ) );
 | |
| }
 | |
| 
 | |
| //
 | |
| // There are many places in the code where I want to send the time
 | |
| // to an output stream.  This function takes care of that.
 | |
| //
 | |
| 
 | |
| ostream& operator<<(ostream& s, TIME t )
 | |
| {
 | |
|     long m = t.milliseconds;
 | |
|     int hours;
 | |
|     int minutes;
 | |
|     int seconds;
 | |
|     int hsecs;
 | |
| 
 | |
|     hours = (int) ( m / ( 1000L * 60L * 60L ) );
 | |
|     m -= hours * ( 1000L * 60L * 60L );
 | |
|     minutes = (int) ( m / ( 1000L * 60L ) );
 | |
|     m -= minutes * (1000L * 60L );
 | |
|     seconds = (int) ( m / ( 1000L ) );
 | |
|     m -= seconds * 1000L;
 | |
|     hsecs = (int) ( m / 10L );
 | |
|     (void) s.width( 2 );
 | |
|     char temp = s.fill( '0' );
 | |
|     s << (int) hours << ':';
 | |
|     (void) s.width( 2 );
 | |
|     s << (int) minutes << ':';
 | |
|     (void) s.width( 2 );
 | |
|     s << (int) seconds << '.';
 | |
|     (void) s.width( 2 );
 | |
|     s << (int) hsecs;
 | |
|     s.fill( temp );
 | |
|     return s;
 | |
| }
 | |
| 
 | |
| 
 | |
| //
 | |
| // main() is kind of long, but it should be pretty straightforward.
 | |
| // Most of the body of the code is grunt code to either create
 | |
| // nice looking output or to collect statistics.
 | |
| //
 | |
| 
 | |
| #if !defined( BIG_BUFFER )
 | |
| #define BIG_BUFFER 28672
 | |
| #endif
 | |
| 
 | |
| int main( int argc, char *argv[] )
 | |
| {
 | |
|     long total_input = 0;
 | |
|     long total_compressed = 0;
 | |
|     int compress_only_flag = 0;
 | |
|     int bad = 0;
 | |
| 
 | |
|     cout << "Archive Library 2.0\nEX23CON.CPP\n\n";
 | |
|     cout << "This program runs under standard MS-DOS and extended DOS.  Under\n";
 | |
|     cout << "extended DOS, we use the Windows API to get the time of day.  To\n";
 | |
|     cout << "make the source code less messy, the details of the time of day\n";
 | |
|     cout << "are concealed in this class.\n";
 | |
|     getch();
 | |
| 
 | |
|     if ( argc < 2 ) {
 | |
|         cout << "Usage: EX23CON wild-spec [-c]\n"
 | |
|              << "\n"
 | |
|              << "This program is used to run benchmarks on ArchiveLib's\n"
 | |
|              << "compression size and speed.  It compresses a group of\n"
 | |
|              << "files as specified in the wild-spec, and gives stats on\n"
 | |
|              << "total compression time and ratio.  To do a real test,\n"
 | |
|              << "you probably ought to also turn off SMARTDRV or any other\n"
 | |
|              << "disk caching program.\n"
 | |
|              << "\n"
 | |
|              << "The optional -c argument lets you specify that you only\n"
 | |
|              << "want to compress files, so the decompression pass is\n"
 | |
|              << "skipped.\n"
 | |
|              << "\n"
 | |
|              << "Note that this is a non-destructive test!  None of the\n"
 | |
|              << "input files are modified at any time!\n"
 | |
|              << "\n";
 | |
|         exit( 1 );
 | |
|     }
 | |
|     cout.rdbuf()->setbuf( (char *) 0, 0 ); // Some compilers buffer cout
 | |
|     if ( argc > 2 && strcmp( argv[ 2 ], "-c" ) == 0 ) {
 | |
|         cout << "\nSkipping decompression!\n\n";
 | |
|         compress_only_flag = 1;
 | |
|     }
 | |
|     ALWildCardExpander expander( argv[ 1 ] );
 | |
| #if defined( ZIP )
 | |
|     ALPkCompressor compressor( 6, 14, 7 );
 | |
|     ALPkDecompressor decompressor;
 | |
| #else
 | |
|     ALGlCompressor compressor( AL_GREENLEAF_LEVEL_4 );
 | |
|     ALGlDecompressor decompressor( AL_GREENLEAF_LEVEL_4 );
 | |
| #endif
 | |
|     char *name;
 | |
|     TIME global_start;
 | |
|     ALSpinner monitor( AL_MONITOR_OBJECTS, cout );
 | |
| //
 | |
| // This is the big loop where we compress all the files.
 | |
| //
 | |
|     while ( ( name = expander.GetNextFile() ) != 0 ) {
 | |
|         TIME local_start;
 | |
|         ALFile input( name, BIG_BUFFER );
 | |
|         ALFile compressed( "", BIG_BUFFER );
 | |
| //
 | |
| // Print out the name of the file, sans drive and path
 | |
| //
 | |
|         ALName filename( name );
 | |
|         filename.StripPath();
 | |
|         (void) cout.width( 13 );
 | |
|         cout << filename;
 | |
| #if defined( MONITOR )
 | |
|         compressed.mpMonitor = &monitor;
 | |
|         monitor.mlObjectStart = 0;
 | |
| #endif
 | |
|         compressor.Compress( input, compressed );
 | |
|         cout << " ";
 | |
|         (void) cout.width( 9 );
 | |
|         cout << input.GetSize() << " ";
 | |
|         (void) cout.width( 9 );
 | |
|         cout << compressed.GetSize();
 | |
|         ALFile output( "", BIG_BUFFER );
 | |
|         if ( !compress_only_flag )
 | |
|             decompressor.Decompress( compressed, output );
 | |
|         total_input += input.GetSize();
 | |
|         total_compressed += compressed.GetSize();
 | |
|         (void) cout.width( 4 );
 | |
|         cout << " ";
 | |
|         (void) cout.width( 4 );
 | |
|         cout << ratio( input.GetSize(), compressed.GetSize() ) << "%";
 | |
|         TIME local_stop;
 | |
|         cout << "  " << ( local_stop - local_start );
 | |
|         if ( !compress_only_flag ) {
 | |
|             int test = output.Compare( input );
 | |
|             if (test < 0 )
 | |
|                 bad++;
 | |
|             cout  << " compare: " << test;
 | |
|         }
 | |
|         cout << endl;
 | |
|         if ( !compress_only_flag )
 | |
|             output.Delete();
 | |
|         compressed.Delete();
 | |
|     }
 | |
|     TIME global_stop;
 | |
|     cout << "Total input:      " << total_input << " bytes.\n";
 | |
|     cout << "Total compressed: " << total_compressed << " bytes.\n";
 | |
|     cout << "Ratio           : " << ratio( total_input, total_compressed ) << "%\n";
 | |
|     cout << "Total time:       ";
 | |
|     cout << "Total failures:   " << bad << endl;
 | |
|     cout << ( global_stop - global_start );;
 | |
|     cout << "\n";
 | |
|     return 0;
 | |
| }
 | |
| 
 |