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;
 | 
						|
}
 | 
						|
 |