714dd74636
git-svn-id: svn://10.65.10.50/trunk@5350 c028cbd2-c16b-5b4b-a496-9718f37d4682
656 lines
18 KiB
C++
Executable File
656 lines
18 KiB
C++
Executable File
//
|
|
// PKENGNC.CPP
|
|
//
|
|
// Source file for ArchiveLib 2.0
|
|
//
|
|
// Copyright (c) Greenleaf Software, Inc. 1994-1996
|
|
// All Rights Reserved
|
|
//
|
|
// CONTENTS
|
|
//
|
|
// ALPkCompressor::operator new()
|
|
// ALPkCompressor::ALPkCompressor()
|
|
// newALPkCompressor()
|
|
// ALPkCompressor::~ALPkCompressor()
|
|
// ALPkCompressor::Compress()
|
|
// ALPkCompressor::Clone()
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// All of the source required to support the PKWare compatible compressor.
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// February 14, 1996 2.0A : New release
|
|
|
|
#include "arclib.h"
|
|
#if !defined( AL_IBM )
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#include "copyengn.h"
|
|
#include "pkengn.h"
|
|
#include "_openf.h"
|
|
#include "zutil.h"
|
|
#include "zlib.h"
|
|
|
|
//
|
|
// NAME
|
|
//
|
|
// ALPkCompressor::operator new()
|
|
//
|
|
// PLATFORMS/ENVIRONMENTS
|
|
//
|
|
// Console Windows PM
|
|
// C++
|
|
//
|
|
// SHORT DESCRIPTION
|
|
//
|
|
// Memory allocator used when ArchiveLib resides in a 16 bit DLL.
|
|
//
|
|
// C++ SYNOPSIS
|
|
//
|
|
// #include "arclib.h"
|
|
// #include "pkengn.h"
|
|
//
|
|
// void * ALPkCompressor::operator new( size_t size )
|
|
//
|
|
// C SYNOPSIS
|
|
//
|
|
// None.
|
|
//
|
|
// VB SYNOPSIS
|
|
//
|
|
// None.
|
|
//
|
|
// DELPHI SYNOPSIS
|
|
//
|
|
// None.
|
|
//
|
|
// ARGUMENTS
|
|
//
|
|
// size : The number of bytes that the compiler has decided will be
|
|
// necessary to construct a new ALPkCompressor object.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// When using a DLL, it is easy to get into a dangerous situation when
|
|
// creating objects whose ctor and dtor are both in the DLL. The problem
|
|
// arises because when you create an object using new, the memory for
|
|
// the object will be allocated from the EXE. However, when you destroy
|
|
// the object using delete, the memory is freed inside the DLL. Since
|
|
// the DLL doesn't really own that memory, bad things can happen.
|
|
//
|
|
// But, you say, won't the space just go back to the Windows heap regardless
|
|
// of who tries to free it? Maybe, but maybe not. If the DLL is using
|
|
// a subsegment allocation scheme, it might do some sort of local free
|
|
// before returning the space to the windows heap. That is the point where
|
|
// you could conceivably cook your heap.
|
|
//
|
|
// By providing our own version of operator new inside this class, we
|
|
// ensure that all memory allocation for the class will be done from
|
|
// inside the DLL, not the EXE calling the DLL.
|
|
//
|
|
// Incidentally, I suspect that this function never gets called. If an
|
|
// object of a derived archive class is being created, it should use
|
|
// its own new operator, rendering this one useless.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// A pointer to some memory that should have been pulled out of the
|
|
// heap for the DLL.
|
|
//
|
|
// EXAMPLE
|
|
//
|
|
// SEE ALSO
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// February 14, 1996 2.0A : New release
|
|
//
|
|
|
|
#if defined( AL_BUILDING_DLL )
|
|
|
|
void AL_DLL_FAR * AL_PROTO
|
|
ALPkCompressor::operator new( size_t size ) /* Tag protected function */
|
|
{
|
|
return ::new char[ size ];
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// NAME
|
|
//
|
|
// ALPkCompressor::ALPkCompressor()
|
|
//
|
|
// PLATFORMS/ENVIRONMENTS
|
|
//
|
|
// Console Windows PM
|
|
// C++ C VB Delphi
|
|
//
|
|
// SHORT DESCRIPTION
|
|
//
|
|
// Constructor for the PkWare deflate compressor engine.
|
|
//
|
|
// C++ SYNOPSIS
|
|
//
|
|
// #include "arclib.h"
|
|
// #include "pkengn.h"
|
|
//
|
|
// ALPkCompressor::ALPkCompressor( int level = 6,
|
|
// int window_bits = 13 /* or 15 */,
|
|
// int mem_level = 6 /* or 8 */ )
|
|
//
|
|
// C SYNOPSIS
|
|
//
|
|
// #include "arclib.h"
|
|
// #include "pkengn.h"
|
|
//
|
|
// hALCompressor newALPkCompressor( int level, int window_bits, int mem_level );
|
|
//
|
|
// VB SYNOPSIS
|
|
//
|
|
// Declare Function newALPkCompressor Lib "AL20LW"
|
|
// (ByVal level%, ByVal window_bits%, ByVal mem_level% ) As Long
|
|
//
|
|
// DELPHI SYNOPSIS
|
|
//
|
|
// function newALPkCompressor( level : Integer;
|
|
// window_bits : Integer;
|
|
// mem_level : Integer ) : hALCompressor;
|
|
//
|
|
// ARGUMENTS
|
|
//
|
|
// level : A number between 1 and 9. 1 gives the best speed, 9 gives
|
|
// the best compression.
|
|
//
|
|
// window_bits :
|
|
//
|
|
// mem_level : How much memory should be allocated for the internal
|
|
// compression state. memLevel=1 uses minimum memory but
|
|
// is slow and reduces compression ratio; memLevel=9 uses
|
|
// maximum memory for optimal speed. (quoted from zlib.h)
|
|
//
|
|
// Note that the C/VB/Delphi version of the ctor can use default parameter
|
|
// values by simply passing AL_DEFAULT for each of the different numeric
|
|
// parameters.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// This constructor creates a new ALPkCompressor. This compressor by
|
|
// itself is a low cost object, with just a couple of data members that
|
|
// help it remember what parameters to use when it comes time to
|
|
// compress. The compressor becomes a resource user when you call the
|
|
// Compress() member function.
|
|
//
|
|
// Create compressor objects when you are initializing a toolkit, or when
|
|
// compressing files by hand, or when using an ALCompressedObject.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// The constructor doesn't return anything to C++ programmers. C/VB/Delphi
|
|
// programmers get a handle that points to the newly created object.
|
|
//
|
|
// EXAMPLE
|
|
//
|
|
// SEE ALSO
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// February 14, 1996 2.0A : New release
|
|
//
|
|
|
|
AL_PROTO
|
|
ALPkCompressor::ALPkCompressor( int level /* = 6 */, /* Tag public function */
|
|
int window_bits /* = 13 or 15 */,
|
|
int mem_level /* = 8 or 6 */ )
|
|
: ALCompressor( AL_COMPRESSION_DEFLATE, "" )
|
|
{
|
|
miWindowBits = window_bits;
|
|
miMemLevel = mem_level;
|
|
switch ( level ) {
|
|
case 9 :
|
|
mszCompressionType = "Deflate Maximum";
|
|
option = MAXIMUM;
|
|
miLevel = level;
|
|
break;
|
|
case 8 :
|
|
case 7 :
|
|
case 6 :
|
|
case 5 :
|
|
case 4 :
|
|
case 3 :
|
|
case 2 :
|
|
option = NORMAL;
|
|
mszCompressionType = "Deflate Normal";
|
|
miLevel = level;
|
|
break;
|
|
case 1 :
|
|
option = FAST;
|
|
mszCompressionType = "Deflate Fast";
|
|
miLevel = 1;
|
|
break;
|
|
case 0 :
|
|
option = NORMAL;
|
|
mszCompressionType = "Stored";
|
|
miLevel = 0;
|
|
break;
|
|
default :
|
|
option = NORMAL;
|
|
mszCompressionType = "???";
|
|
miLevel = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if !defined( AL_NO_C )
|
|
|
|
extern "C" AL_LINKAGE hALCompressor AL_FUNCTION
|
|
newALPkCompressor( int level, /* Tag public function */
|
|
int window_bits,
|
|
int mem_level )
|
|
{
|
|
if ( level == AL_DEFAULT )
|
|
level = 6;
|
|
if ( window_bits == AL_DEFAULT )
|
|
window_bits = AL_PK_DEFAULT_WINDOW_BITS;
|
|
if ( mem_level == AL_DEFAULT )
|
|
mem_level = AL_PK_DEFAULT_MEM_LEVEL;
|
|
return (hALCompressor) new ALPkCompressor( level, window_bits, mem_level );
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// NAME
|
|
//
|
|
// ALPkCompressor::~ALPkCompressor()
|
|
//
|
|
// PLATFORMS/ENVIRONMENTS
|
|
//
|
|
// Console Windows PM
|
|
// C++
|
|
//
|
|
// SHORT DESCRIPTION
|
|
//
|
|
// The PKWare deflate Compressor destructor.
|
|
//
|
|
// C++ SYNOPSIS
|
|
//
|
|
// #include "arclib.h"
|
|
// #include "pkengn.h"
|
|
//
|
|
// ALPkCompressor::~ALPkCompressor()
|
|
//
|
|
// C SYNOPSIS
|
|
//
|
|
// None. C programmers need to call deleteALCompressor().
|
|
//
|
|
// VB SYNOPSIS
|
|
//
|
|
// None. VB programmers need to call deleteALCompressor().
|
|
//
|
|
// DELPHI SYNOPSIS
|
|
//
|
|
// None. Delphi programmers need to call deleteALCompressor().
|
|
//
|
|
// ARGUMENTS
|
|
//
|
|
// None.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// The destructor for objects of this class doesn't have to do
|
|
// anything. In debug mode, we at least check for the validity
|
|
// of the object.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// Nothing.
|
|
//
|
|
// EXAMPLE
|
|
//
|
|
// SEE ALSO
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// February 14, 1996 2.0A : New release
|
|
//
|
|
|
|
AL_PROTO
|
|
ALPkCompressor::~ALPkCompressor() /* Tag public function */
|
|
{
|
|
AL_ASSERT( GoodTag(), "~ALPkCompressor: Attempt to delete invalid object" );
|
|
}
|
|
|
|
//
|
|
// I've tried two different ways to feed data to the compressor.
|
|
// The "normal" way is to just give the engine a pointer to a buffer,
|
|
// then work on filling that buffer by calling my own Read routines.
|
|
// The hacked way ought to work better. When hacked, I use the buffer
|
|
// in the storage object, instead of creating a standalong buffer. This
|
|
// means the compressor has to be a friend of ALStorage, but that's
|
|
// manageable. Right now, Hacked seems to be okay, and it saves some space
|
|
// so that's what we're doing.
|
|
//
|
|
// Changing to unhacked is possible, but the buffer allocation should then
|
|
// be done dynamically, as this static buffer's going to have trouble
|
|
// when inside a DLL.
|
|
//
|
|
|
|
#define HACK_INPUT
|
|
#define HACK_OUTPUT
|
|
|
|
#if !defined( HACK_OUTPUT )
|
|
const int OUTBUF_LEN = 1024;
|
|
static char outbuf[ OUTBUF_LEN ];
|
|
#endif
|
|
|
|
#if !defined( HACK_INPUT )
|
|
const int INBUF_LEN = 1024;
|
|
char inbuf[ INBUF_LEN ];
|
|
#endif
|
|
|
|
//
|
|
// NAME
|
|
//
|
|
// ALPkCompressor::Compress()
|
|
//
|
|
// PLATFORMS/ENVIRONMENTS
|
|
//
|
|
// Console Windows PM
|
|
// C++
|
|
//
|
|
// SHORT DESCRIPTION
|
|
//
|
|
// Compress using the deflate algorithm.
|
|
//
|
|
// C++ SYNOPSIS
|
|
//
|
|
// #include "arclib.h"
|
|
// #include "pkengn.h"
|
|
//
|
|
// int ALPkCompressor::Compress( ALStorage& input,
|
|
// ALStorage& output );
|
|
//
|
|
// C SYNOPSIS
|
|
//
|
|
// None, see the base class function ALCompress().
|
|
//
|
|
// VB SYNOPSIS
|
|
//
|
|
// None, see the base class function ALCompress().
|
|
//
|
|
// DELPHI SYNOPSIS
|
|
//
|
|
// None, see the base class function ALCompress().
|
|
//
|
|
// ARGUMENTS
|
|
//
|
|
// input : A reference to the input storage object.
|
|
//
|
|
// output : A reference to the output storage object.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// This is the virtual function that is called to compress data.
|
|
// This section of code is really just a front end to the real engine,
|
|
// which is found mostly in deflate.cpp
|
|
//
|
|
// It's kind of hard to see what's going on here with the #ifdefs, but
|
|
// it really isn't too complicated. The deflate code wants a zstream
|
|
// structure to work on. We set up zstream to contain buffer pointers
|
|
// to both the input and output streams. We then sit in a loop calling
|
|
// deflate() repeatedly. The deflate() code compresses as much data
|
|
// as it can, and returns. After each call, I flush all the data I can,
|
|
// load as much new data as I can, then try it again. This repeats until
|
|
// deflate() finally indicates that it's done.
|
|
//
|
|
// After deflate is done, we have to check for errors on
|
|
// any of the other objects involved in the compression, and return the
|
|
// cumulative result.
|
|
//
|
|
// This function will almost always be called indirectly, by means of
|
|
// a virtual function call off the base class. That's why you won't
|
|
// see any C, VB, or Delphi functions here. Those languages will only
|
|
// be able to call the Compress() routine by way of the base class.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// AL_SUCCESS, or < AL_SUCCESS if something bad happens.
|
|
//
|
|
// EXAMPLE
|
|
//
|
|
// SEE ALSO
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// February 14, 1996 2.0A : New release
|
|
//
|
|
|
|
int AL_PROTO
|
|
ALPkCompressor::Compress( ALStorage AL_DLL_FAR &input, /* Tag public function */
|
|
ALStorage AL_DLL_FAR &output )
|
|
{
|
|
//
|
|
// Open the input and output files, and initialize CRC 32 checking.
|
|
//
|
|
ALOpenFiles files( input, output );
|
|
if ( input.mStatus < AL_SUCCESS )
|
|
return mStatus = input.mStatus;
|
|
if ( output.mStatus < AL_SUCCESS )
|
|
return mStatus = output.mStatus;
|
|
input.InitCrc32();
|
|
|
|
int result;
|
|
z_stream stream;
|
|
|
|
stream.zalloc = 0;
|
|
stream.zfree = 0;
|
|
result = deflateInit2( &stream,
|
|
miLevel,
|
|
DEFLATED,
|
|
-miWindowBits,
|
|
miMemLevel,
|
|
0 );
|
|
if ( result != 0 ) {
|
|
deflateEnd( &stream );
|
|
return mStatus.SetError( AL_CANT_CREATE_ENGINE,
|
|
"Error creating deflate engine. "
|
|
"ZLIB returned %d\n",
|
|
result );
|
|
}
|
|
#if defined( HACK_OUTPUT )
|
|
output.FlushBuffer();
|
|
stream.avail_out = output.muBufferSize;
|
|
stream.next_out = (Byte ZL_FAR *) output.mpcBuffer;
|
|
#else
|
|
stream.avail_out = OUTBUF_LEN;
|
|
stream.next_out = (Byte ZL_FAR *) outbuf;
|
|
#endif
|
|
stream.avail_in = 0;
|
|
#if !defined( HACK_INPUT )
|
|
stream.next_in = (Byte ZL_FAR *) inbuf;
|
|
#endif
|
|
for ( ; ; ) {
|
|
if ( stream.avail_in == 0 ) {
|
|
#if !defined( HACK_INPUT )
|
|
stream.avail_in = input.ReadBuffer( (unsigned char *) inbuf, INBUF_LEN );
|
|
stream.next_in = (unsigned char *) inbuf;
|
|
if ( stream.avail_in == 0 )
|
|
break;
|
|
#else
|
|
if ( input.muReadIndex >= input.muBufferValidData ) {
|
|
if ( input.LoadBuffer( input.mlFilePointer ) < 0 )
|
|
break;
|
|
}
|
|
stream.avail_in = input.muBufferValidData - input.muReadIndex;
|
|
stream.next_in = input.mpcBuffer + input.muReadIndex;
|
|
input.muReadIndex += input.muBufferValidData;
|
|
#endif
|
|
}
|
|
result = deflate( &stream, Z_NO_FLUSH );
|
|
#if defined( HACK_OUTPUT )
|
|
if ( stream.avail_out != output.muBufferSize ) {
|
|
output.muWriteIndex = output.muBufferSize - stream.avail_out;
|
|
output.FlushBuffer();
|
|
stream.avail_out = output.muBufferSize;
|
|
stream.next_out = (Byte ZL_FAR *) output.mpcBuffer;
|
|
}
|
|
#else
|
|
if ( stream.avail_out != OUTBUF_LEN ) {
|
|
output.WriteBuffer( (unsigned char*) outbuf, OUTBUF_LEN - stream.avail_out );
|
|
stream.avail_out = OUTBUF_LEN;
|
|
stream.next_out = (Byte ZL_FAR *) outbuf;
|
|
};
|
|
#endif
|
|
if ( output.mStatus < AL_SUCCESS || result != Z_OK) {
|
|
deflateEnd( &stream );
|
|
return mStatus = output.mStatus;
|
|
}
|
|
}
|
|
//
|
|
// Now its time to start flushing
|
|
//
|
|
for ( ; ; ) {
|
|
result = deflate( &stream, Z_FINISH );
|
|
#if defined( HACK_OUTPUT )
|
|
if ( stream.avail_out != output.muBufferSize ) {
|
|
output.muWriteIndex = output.muBufferSize - stream.avail_out;
|
|
output.FlushBuffer();
|
|
stream.avail_out = output.muBufferSize;
|
|
stream.next_out = (Byte ZL_FAR *) output.mpcBuffer;
|
|
#else
|
|
if ( stream.avail_out != OUTBUF_LEN ) {
|
|
output.WriteBuffer( (unsigned char *) outbuf, OUTBUF_LEN - stream.avail_out );
|
|
stream.avail_out = OUTBUF_LEN;
|
|
stream.next_out = (Byte ZL_FAR *) outbuf;
|
|
#endif
|
|
};
|
|
if ( result == Z_STREAM_END )
|
|
break;
|
|
}
|
|
deflateEnd( &stream );
|
|
|
|
//
|
|
// Finally, check on the error status codes, then return.
|
|
//
|
|
if ( input.mStatus < AL_SUCCESS )
|
|
return mStatus = input.mStatus;
|
|
if ( output.mStatus < AL_SUCCESS )
|
|
return mStatus = output.mStatus;
|
|
return mStatus;
|
|
}
|
|
|
|
//
|
|
// NAME
|
|
//
|
|
// ALPkCompressor::Clone()
|
|
//
|
|
// PLATFORMS/ENVIRONMENTS
|
|
//
|
|
// Console Windows PM
|
|
// C++
|
|
//
|
|
// SHORT DESCRIPTION
|
|
//
|
|
// Create a copy of an existing Compressor
|
|
//
|
|
// C++ SYNOPSIS
|
|
//
|
|
// #include "arclib.h"
|
|
// #include "pkengn.h"
|
|
//
|
|
// ALPkCompressor::Clone( int engine_type );
|
|
//
|
|
// C SYNOPSIS
|
|
//
|
|
// No C equivalent.
|
|
//
|
|
// VB SYNOPSIS
|
|
//
|
|
// No VB equivalent.
|
|
//
|
|
// DELPHI SYNOPSIS
|
|
//
|
|
// No Delphi equivalent.
|
|
//
|
|
// ARGUMENTS
|
|
//
|
|
// engine_type : This argument indicates what sort of engine the
|
|
// caller wants to create. A value of either
|
|
// AL_COMPRESSION_DEFAULT, AL_COMPRESSION_DEFLATE,
|
|
// AL_DEFLATE_COPY, or AL_COPY will cause this function to
|
|
// create a clone. Any other
|
|
// value (for example, AL_GREENLEAF), will return a 0,
|
|
// indicating that this object doesn't know how to
|
|
// perform that sort of compression.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// Although this is a public function, it isn't really of any use
|
|
// to end users. Clone() is a virtual function for the base class
|
|
// ALCompressor, and can be called to create a duplicate of an
|
|
// existing compression engine.
|
|
//
|
|
// Why is this useful? It is useful because it allows us to use
|
|
// what is the equivalent of a virtual constructor. We can pass a
|
|
// pointer to a PKWare engine to the archiving code, and it can then in
|
|
// turn stuff copies of that engine into an ALEntryList without
|
|
// having any idea what sort of compression engine it is actually creating.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// A copy of a newly created compression engine. When this routine is
|
|
// called, it will usually be called via a virtual function from a pointer
|
|
// to a base class object, which means the resulting pointer will be
|
|
// treated as an ALCompressor * by the code.
|
|
//
|
|
// If this routine doesn't know how to create an engine of the correct type,
|
|
// it returns a 0. When performing compression into an archive, the
|
|
// Clone() functions will usually be called with the AL_DEFAULT_COMPRESSION
|
|
// engine type, meaning they are happy to take a copy of whatever engine
|
|
// happens to show up first in the toolkit.
|
|
//
|
|
// EXAMPLE
|
|
//
|
|
// SEE ALSO
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// February 14, 1996 2.0A : New release
|
|
//
|
|
|
|
ALCompressor AL_DLL_FAR * AL_PROTO
|
|
ALPkCompressor::Clone( int engine_type ) const /* Tag public function */
|
|
{
|
|
_option pk_option;
|
|
ALPkCompressor *compressor;
|
|
switch ( engine_type ) {
|
|
case AL_COMPRESSION_COPY :
|
|
case AL_COMPRESSION_DEFLATE_COPY :
|
|
return new ALCopyCompressor();
|
|
case AL_COMPRESSION_DEFLATE + 3 :
|
|
pk_option = SUPER_FAST;
|
|
break;
|
|
case AL_COMPRESSION_DEFLATE + 2 :
|
|
pk_option = FAST;
|
|
break;
|
|
case AL_COMPRESSION_DEFLATE + 1 :
|
|
pk_option = MAXIMUM;
|
|
break;
|
|
case AL_COMPRESSION_DEFLATE + 0 : /* Normal */
|
|
case AL_COMPRESSION_DEFAULT :
|
|
pk_option = NORMAL;
|
|
break;
|
|
default :
|
|
return 0;
|
|
}
|
|
compressor = new ALPkCompressor( miLevel, miWindowBits, miMemLevel );
|
|
if ( compressor )
|
|
compressor->option = pk_option;
|
|
return compressor;
|
|
}
|
|
|