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