// // ARCHIVE.CPP // // Source file for ArchiveLib 1.0 // // Copyright (c) Greenleaf Software, Inc. 1994 // All Rights Reserved // // CONTENTS // // ALArchive::operator new() // ALArchive::ALArchive() // ALArchive::~ALArchive() // ALArchive::CreateCompressionEngine() // ALArchive::CreateStorageObject() // ALArchive::AddWildCardFiles() // ALArchive::MakeEntriesFromListBox() // // DESCRIPTION // // This file contains all the source code for class ALArchive. ALArchive // is a class derived from ALArchiveBase that knows how to create ALFile // and ALMemory objects. Remember that ALArchiveBase doesn't know how // to create any kind of storage object, so we need derived classes to // bind ourselves to certain types of objects. // // REVISION HISTORY // // May 23, 1994 1.0A : First release // // #include "arclib.h" #pragma hdrstop #include "archive.h" #include "grenengn.h" #include "copyengn.h" #include "filestor.h" #include "memstore.h" #include "wildcard.h" // // void * ALArchive::operator new( size_t size ) // // ARGUMENTS: // // size : The number of bytes needed to create a new ALArchive 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 create 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 23, 1994 1.0A : First release // #if defined( AL_BUILDING_DLL ) void AL_DLL_FAR * AL_PROTO ALArchive::operator new( size_t size ) { return ::new char[ size ]; } #endif // // ALArchive::ALArchive( const char *file_name ) // // ARGUMENTS: // // name : The name of the ALFile object that is going to hold the // ALArchive. // // RETURNS // // Nothing, this is a constructor. // // DESCRIPTION // // This is one of two constructors for ALArchive. (The other one // follows immediately in this source file.) It is used // when the archive you are working with or are going to create will // reside in an ALFile object, which should be often. It simply // calls the constructor for the base class with the appropriately // created ALFile object and returns. It doesn't have to initialize // any data members of its own, so life is really simple. // // REVISION HISTORY // // May 23, 1994 1.0A : First release // AL_PROTO ALArchive::ALArchive( const char AL_DLL_FAR *file_name ) : ALArchiveBase( new ALFile( file_name ), 1 ) { } // // ALArchive::ALArchive( ALStorage &so ) // // ARGUMENTS: // // so : A storage object that will used as the storage for the archive. // // RETURNS // // Nothing, this is a constructor. // // DESCRIPTION // // This is one of two constructors for ALArchive. (The other one // immediately precedes this function in the same source file.) It is used // when the archive you are working with or are going to create will // reside in an object that you have already constructed. // It doesn't have to initialize any data members of its own, so // all it does is call the base class constructor from an // initializer list, and then return. // // The storage object used for this archive is your responsibility to delete. // // REVISION HISTORY // // May 23, 1994 1.0A : First release // AL_PROTO ALArchive::ALArchive( ALStorage AL_DLL_FAR &so ) : ALArchiveBase( &so, 0 ) { } // // ALArchive::~ALArchive() // // ARGUMENTS: // // None. // // RETURNS // // Nothing, destructor. // // DESCRIPTION // // This destructor has an easy life of it, since it has no data // members to clean up after. Instead, it leaves all of the heavy // lifting to the base class destructor. In debug mode we at least // do *something*, which is just to verify that this is the correct // type of object. // // REVISION HISTORY // // May 23, 1994 1.0A : First release // AL_PROTO ALArchive::~ALArchive() { AL_ASSERT( GoodTag(), "~ALArchive: attempt to delete invalid object" ); } // // ALCompressionEngine *ALArchive::CreateCompressionEngine( int engine_type ) // // ARGUMENTS: // // engine_type : An integer from ALDEFS.H that defines the type of compression // to be created. // // RETURNS // // A pointer to a newly created compression engine. If things go bad, // a value of 0 is possible. // // DESCRIPTION // // ALArchiveBase doesn't know how to create compression engines or // storage objects. That knowledge is left up to derived classes like // this one. When extracting objects from an archive, this class has // to be able to create a compression engine with no more information // than the integer engine type stored in the archive directory. // This is where we do it. // // REVISION HISTORY // // May 23, 1994 1.0A : First release // ALCompressionEngine AL_DLL_FAR * AL_PROTO ALArchive::CreateCompressionEngine( int engine_type ) { switch ( engine_type ) { case AL_COMPRESSION_COPY : return new ALCopyEngine(); case AL_COMPRESSION_GREENLEAF : return new ALGreenleafEngine(); default : mStatus.SetError( AL_UNKNOWN_COMPRESSION_TYPE, "Unknown compression type (%d) found in archive", engine_type ); break; //Break instead of return because of bogus warnings } return 0; } // // ALStorage * ALArchive::CreateStorageObject( const char *name, // int object_type ) // // ARGUMENTS: // // name : The name of the storage object to be created. // // object_type : The object type, from ALStorageType in STORAGE.H. // // RETURNS // // A pointer to a newly storage object. If things go bad, // a value of 0 is possible. // // DESCRIPTION // // ALArchiveBase doesn't know how to create compression engines or // storage objects. That knowledge is left up to derived classes like // this one. When extracting objects from an archive, this class has // to be able to create a storage object with no more information // than the integer object type stored in the archive directory. // This is where we do it. // // REVISION HISTORY // // May 23, 1994 1.0A : First release // ALStorage AL_DLL_FAR * AL_PROTO ALArchive::CreateStorageObject( const char AL_DLL_FAR *name, int object_type ) { switch ( object_type ) { case AL_MEMORY_OBJECT : return new ALMemory( name ); case AL_FILE_OBJECT : return new ALFile( name ); default : mStatus.SetError( AL_UNKNOWN_STORAGE_OBJECT, "Unknown storage object type (%d) " "found in archive", object_type ); break; } return 0; } // STATIC MEMBER FUNCTION // // int ALArchive::AddWildCardFiles( // ALEntryList & list, // const char *wild_spec = "*.*", // int traverse_flag = 0, // short int compression_level = AL_GREENLEAF_LEVEL_2 ) // // ARGUMENTS: // // list : The list that is going to receive the newly created // ALEntry objects. // // wild_spec : The wild card file spec to expand into a list of // files. Note that this string can contain multiple // file specs, separated by commas or spaces. // // traverse_flag : A flag to indicate whether wild card expansion // should traverse subdirectories. // // compression_level : The compression level that will be used to create // compression engines for the new entries. // // RETURNS // // The number of entries created by the wild card expansion. // // DESCRIPTION // // It is handy to have a function that will create a bunch of ALEntry // objects and add them to a list of your choosing. We can't do this // in the base class of ALArchiveBase, because it doesn't know anything // about specific storage objects or compression engines. So the // logical place to turn is to this derived class, which does know about // ALFile and ALMemory. // // The only bad thing here is that this is a static public functions, // so it is kind of confusing. You might think that this ought to be // a member function of ALEntryList. The problem is, we don't want // ALEntryList to know about specific engines or compression classes, // because then they would get linked in to any application created // with ArchiveLib. // // So anyway, this function creates a bunch of new ALEntry objects, // with the storage object being an instance of class ALFile, and the // compression engine being an object of class ALGreenleafEngine. It // then adds the new ALEntry to the specified ALEntryList, so you don't // have to do any work at all. // // REVISION HISTORY // // May 23, 1994 1.0A : First release // int AL_PROTO ALArchive::AddWildCardFiles( ALEntryList AL_DLL_FAR & list, const char AL_DLL_FAR *wild_spec /* = "*.*" */, int traverse_flag /* = 0 */, short int compression_level /* = AL_GREENLEAF_LEVEL_2 */ ) { AL_ASSERT( wild_spec != 0, "AddWildCardFiles: null parameter for wild_spec" ); ALWildCardExpander files( wild_spec, traverse_flag ); int count = 0; char *new_name; ALEntry* dummy; while ( ( new_name = files.GetNextFile() ) != 0 ) { dummy = new ALEntry( list, new ALFile( new_name ), new ALGreenleafEngine( compression_level ) ); count++; } return count; } // // int ALArchive::MakeEntriesFromListBox( ALEntryList &list, // HWND hDlg, // int list_box /* = -1 */ ) // // ARGUMENTS: // // list : The list that is going to get the new entries. // // hDlg : The handle of the dialog box that contains the list box // control. If you aren't using a dialog box, you can pass // the handle of the list box control directly, and set // the list_box parameter to -1. // // list_box : The id of the list box control in the dialog box. If this // parameter is set to -1, it means that hDlg doesn't refer // to a dialog, it refers to the actual handle of a list box // control. // // RETURNS // // The number of new entries created from the list box. // // DESCRIPTION // // This function goes through a list box, and picks out all the // highlighted entries. It creates a new ALEntry object for each // of the marked entires, using ALFile and ALGreenleafEngine objects. // For purposes of orthogonality, I probably should have had a // compression_level parameter here, but I neglected to include that. // We could do it in the next release using a default parameter and // nobody would even notice. // // REVISION HISTORY // // May 23, 1994 1.0A : First release // #if defined( AL_WINDOWS_GUI ) int AL_PROTO ALArchive:: MakeEntriesFromListBox( ALEntryList AL_DLL_FAR &list, HWND hDlg, int list_box /* = -1 */ ) { HWND window; if ( list_box != -1 ) window = GetDlgItem( hDlg, (short int) list_box ); else window = hDlg; int count = (WORD) SendMessage( window, LB_GETSELCOUNT, 0, 0L ); if ( count == LB_ERR ) return AL_GETSEL_ERROR; int *items = new int[ count ]; if ( items == 0 ) return AL_CANT_ALLOCATE_MEMORY; #ifdef AL_FLAT_MODEL if ( count != SendMessage( window, LB_GETSELITEMS, (short int) count, (LPARAM) items ) ) { #else if ( count != SendMessage( window, LB_GETSELITEMS, (short int) count, (LPARAM)(int _far *) items ) ) { #endif delete items; return AL_GETSEL_ERROR; } for ( WORD i = 0 ; i < (WORD) count ; i++ ) { WORD length = (WORD) SendMessage( window, LB_GETTEXTLEN, (short int) items[ i ], 0L ); if ( length > 0 ) { char *name = new char[ length + 1 ]; if ( name ) { if ( SendMessage( window, LB_GETTEXT, (short int) items[ i ], (LPARAM)( (LPSTR) name ) ) >= 0 ) { new ALEntry( list, new ALFile( name ), new ALGreenleafEngine() ); } delete name; SendMessage( window, LB_SETSEL, 0, items[ i ] ); } } } delete items; return count; } #endif //#ifdef AL_WINDOWS_GUI