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