campo-sirio/arch/grenengn.cpp

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