362 lines
11 KiB
C++
Executable File
362 lines
11 KiB
C++
Executable File
//
|
|
// GRENENGN.CPP
|
|
//
|
|
// Source file for ArchiveLib 1.0
|
|
//
|
|
// Copyright (c) Greenleaf Software, Inc. 1994
|
|
// All Rights Reserved
|
|
//
|
|
// CONTENTS
|
|
//
|
|
// ALGreenleafEngine::operator new()
|
|
// ALGreenleafEngine::ALGreenleafEngine()
|
|
// ALGreenleafEngine::~ALGreenleafEngine()
|
|
// ALGreenleafEngine::Compress()
|
|
// ALGreenleafEngine::Decompress()
|
|
// ALGreenleafEngine::WriteEngineData()
|
|
// ALGreenleafEngine::ReadEngineData()
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// This file contains the front end to the Greenleaf compression engine.
|
|
// This contains everything but the actual low level compression
|
|
// and expansion code, which can be found in _RE.CPP and _RC.CPP. Those
|
|
// two source files are shrouded though, so you won't get a tremendous
|
|
// amount of detail!
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// May 26, 1994 1.0A : First release
|
|
//
|
|
//
|
|
|
|
#include "arclib.h"
|
|
#pragma hdrstop
|
|
|
|
#include "grenengn.h"
|
|
#include "_openf.h"
|
|
#include "_r.h"
|
|
|
|
|
|
//
|
|
// void * ALGreenleafEngine::operator new( size_t size )
|
|
//
|
|
// ARGUMENTS:
|
|
//
|
|
// size : The number of bytes needed to create a new object.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// A pointer to the newly allocated storage area, or 0 if no storage
|
|
// was available.
|
|
//
|
|
// 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.
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// May 26, 1994 1.0A : First release
|
|
//
|
|
|
|
#if defined( AL_BUILDING_DLL )
|
|
void AL_DLL_FAR * AL_PROTO ALGreenleafEngine::operator new( size_t size )
|
|
{
|
|
return ::new char[ size ];
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// ALGreenleafEngine::
|
|
// ALGreenleafEngine( short int compression_level = AL_GREENLEAF_LEVEL_2,
|
|
// short int fail_uncompressible = 0 )
|
|
//
|
|
// ARGUMENTS:
|
|
//
|
|
// compression_level : This is one of the enumerated types found in ALDEFS.H,
|
|
// namely AL_GREENLEAF_LEVEL_0 through
|
|
// AL_GREENLEAF_LEVEL_4. Level 4 gives the most
|
|
// compression, but takes up the most memory as well.
|
|
//
|
|
// fail_uncompressible : This flag is used to indicate the disposition
|
|
// of an uncompressible file. If this flag is set,
|
|
// the compression of an incompressible file will
|
|
// be interrupted, and the file will be recompressed
|
|
// using a straight copy. Note that this requires
|
|
// a Seek() operation! Note also that this feature
|
|
// is NOT YET IMPLEMENTED!!!
|
|
//
|
|
// RETURNS
|
|
//
|
|
// Nothing, a constructor.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// The constructor for the Greenleaf engine has a pretty simple life. All
|
|
// it has to do is call the base class constructor, then define a couple of
|
|
// data members. This is a lightweight object until the compression
|
|
// or expansion routines are invoked, at which time the memory requirements
|
|
// go through the roof.
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// May 26, 1994 1.0A : First release
|
|
//
|
|
|
|
AL_PROTO ALGreenleafEngine::
|
|
ALGreenleafEngine( short int compression_level /* = AL_GREENLEAF_LEVEL_2 */,
|
|
short int fail_uncompressible /* = 0 */ )
|
|
: ALCompressionEngine( AL_COMPRESSION_GREENLEAF, "Greenleaf" )
|
|
{
|
|
miCompressionLevel = compression_level;
|
|
miFailUncompressible = fail_uncompressible;
|
|
}
|
|
|
|
//
|
|
// ALGreenleafEngine::~ALGreenleafEngine()
|
|
//
|
|
// ARGUMENTS:
|
|
//
|
|
// None.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// Nothing.
|
|
//
|
|
// 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.
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// May 26, 1994 1.0A : First release
|
|
//
|
|
|
|
AL_PROTO ALGreenleafEngine::~ALGreenleafEngine()
|
|
{
|
|
AL_ASSERT( GoodTag(), "~ALGreenleafEngine: attempt to delete invalid object" );
|
|
}
|
|
|
|
//
|
|
// int ALGreenleafEngine::Compress( ALStorage &input,
|
|
// ALStorage &output )
|
|
//
|
|
// ARGUMENTS:
|
|
//
|
|
// input : A reference to the storage object that will be compressed.
|
|
//
|
|
// output : A reference to the storage object that will receive the
|
|
// compressed data.
|
|
//
|
|
// RETURNS
|
|
//
|
|
//
|
|
// AL_SUCCESS in the event of a success, an error code < AL_SUCCESS
|
|
// if a failure occurred.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// This is the virtual function that is called to compress data. The
|
|
// This section of code is really just a front end to the real engine,
|
|
// which is found in _RC.CPP. The first thing we do here
|
|
// is create an RCompress object, which allocates all of the
|
|
// storage we need to perform the compression. In a tight memory
|
|
// situation, that may well fail, so we check its status before moving
|
|
// on. If it succeeded, we can call the low level compression function
|
|
// to do the real work.
|
|
//
|
|
// After the compress function returns, we have to check for errors on
|
|
// any of the other objects involved in the compression, and return the
|
|
// cumulative result.
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// May 26, 1994 1.0A : First release
|
|
//
|
|
|
|
int AL_PROTO ALGreenleafEngine::Compress( ALStorage AL_DLL_FAR &input,
|
|
ALStorage AL_DLL_FAR &output )
|
|
{
|
|
ALOpenFiles files( input, output );
|
|
|
|
input.InitCrc32();
|
|
RCompress rc( input,
|
|
output,
|
|
miCompressionLevel + 10,
|
|
miFailUncompressible );
|
|
|
|
if ( rc.mStatus < 0 )
|
|
return mStatus = rc.mStatus;
|
|
else
|
|
rc.Compress();
|
|
if ( rc.mStatus < 0 )
|
|
return mStatus = rc.mStatus;
|
|
else if ( input.mStatus < 0 )
|
|
return mStatus = input.mStatus;
|
|
else if ( output.mStatus < 0 )
|
|
return mStatus = output.mStatus;
|
|
return mStatus;
|
|
}
|
|
|
|
//
|
|
// int ALGreenleafEngine::Decompress( ALStorage &input,
|
|
// ALStorage &output,
|
|
// long compressed_length )
|
|
//
|
|
// ARGUMENTS:
|
|
//
|
|
// input : A reference to the storage object that will be
|
|
// expanded.
|
|
//
|
|
// output : A reference to the storage object that will receive
|
|
// the expanded data.
|
|
//
|
|
// compressed_length : A long value indicating how long the compressed
|
|
// object is. This helps to tell the decompressor
|
|
// when to quit.
|
|
// RETURNS
|
|
//
|
|
//
|
|
// AL_SUCCESS in the event of a success, an error code < AL_SUCCESS
|
|
// if a failure occurred.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// This is the virtual function that is called to expand a compressed
|
|
// object. This section of code is really just a front end to the real
|
|
// engine, which is found in _RE.CPP. The first thing we do here
|
|
// is create an RExpand object, which allocates all of the
|
|
// storage we need to perform the decompression. In a tight memory
|
|
// situation, that may well fail, so we check its status before moving
|
|
// on. If it succeeded, we can call the low level expansion function
|
|
// to do the real work.
|
|
//
|
|
// After the expand function returns, we have to check for errors on
|
|
// any of the other objects involved in the expansion, and return the
|
|
// cumulative result.
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// May 26, 1994 1.0A : First release
|
|
//
|
|
|
|
int AL_PROTO ALGreenleafEngine::Decompress( ALStorage AL_DLL_FAR &input,
|
|
ALStorage AL_DLL_FAR &output,
|
|
long compressed_length )
|
|
{
|
|
ALOpenFiles files( input, output );
|
|
|
|
output.InitCrc32();
|
|
RExpand re( input, output, compressed_length, miCompressionLevel + 10 );
|
|
|
|
if ( re.mStatus < 0 )
|
|
return mStatus = re.mStatus;
|
|
else
|
|
re.Expand();
|
|
if ( re.mStatus < 0 )
|
|
return mStatus = re.mStatus;
|
|
else if ( input.mStatus < 0 )
|
|
return mStatus = input.mStatus;
|
|
else if ( output.mStatus < 0 )
|
|
return mStatus = output.mStatus;
|
|
return mStatus;
|
|
}
|
|
|
|
//
|
|
// int ALGreenleafEngine::WriteEngineData( ALStorage * archive )
|
|
//
|
|
// ARGUMENTS:
|
|
//
|
|
// A pointer to the storage area where the data is to be written.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// AL_SUCCESS if the data was written properly, else an error code
|
|
// less than AL_SUCCESS.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// Every compression engine used in ArchiveLib gets the opportunity
|
|
// to store data it needs to save in order to characterize its compression
|
|
// process. The Greenleaf compression engine only needs to save a single
|
|
// integer, which contains the compression level used. This is the
|
|
// function that does so.
|
|
//
|
|
// Data like this is stored in string format, which consists of a single
|
|
// short integer describing the number of bytes in the string, followed
|
|
// by the string. We store in this portable format so that even a program
|
|
// that doesn't know about compression engines would be able to read in
|
|
// archive directory data.
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// May 26, 1994 1.0A : First release
|
|
//
|
|
|
|
int AL_PROTO ALGreenleafEngine::
|
|
WriteEngineData( ALStorage AL_DLL_FAR * archive )
|
|
{
|
|
archive->WritePortableShort( 2 );
|
|
return archive->WritePortableShort( miCompressionLevel );
|
|
}
|
|
|
|
//
|
|
// int ALGreenleafEngine::ReadEngineData( ALStorage * archive )
|
|
//
|
|
// ARGUMENTS:
|
|
//
|
|
// A pointer to the storage area where the data is to be read.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// AL_SUCCESS if the data was read properly, else an error code
|
|
// less than AL_SUCCESS.
|
|
//
|
|
// DESCRIPTION
|
|
//
|
|
// Every compression engine used in ArchiveLib gets the opportunity
|
|
// to store data it needs to save in order to characterize its compression
|
|
// process. The Greenleaf compression engine only needs to save a single
|
|
// integer, which contains the compression level used.
|
|
//
|
|
// During the creation of the compression engine, this function gets called
|
|
// in order to load the engine's private data. All we do is read in
|
|
// the compression level, along with a little error checking.
|
|
//
|
|
// Data like this is stored in string format, which consists of a single
|
|
// short integer describing the number of bytes in the string, followed
|
|
// by the string. We store in this portable format so that even a program
|
|
// that doesn't know about compression engines would be able to read in
|
|
// archive directory data.
|
|
//
|
|
// REVISION HISTORY
|
|
//
|
|
// May 26, 1994 1.0A : First release
|
|
//
|
|
|
|
int AL_PROTO ALGreenleafEngine::ReadEngineData( ALStorage AL_DLL_FAR * archive )
|
|
{
|
|
short temp;
|
|
archive->ReadPortableShort( temp );
|
|
AL_ASSERT( temp == 2, "ReadEngineData: engine data size is not 2, it should be" );
|
|
return archive->ReadPortableShort( miCompressionLevel );
|
|
}
|
|
|