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