// // ARC.CPP // // Source file for ArchiveLib 2.0 // // Copyright (c) Greenleaf Software, Inc. 1994-1996 // All Rights Reserved // // CONTENTS // // ALArchive::ALArchive( ALStorage * ) // ALArchive::operator new() // ALArchive::ScanStatus() // ALArchive::CalculateJobSize() // ALArchive::CalculateCompressedJobSize() // ALArchive::WriteArchiveData() // ALArchive::ReadArchiveData() // ALArchive::~ALArchive() // deleteALArchive() // // DESCRIPTION // // This file contains the ALArchive ctor, dtor, and any functions // that will *always* be linked (mostly because they are virtual.) // // REVISION HISTORY // // February 14, 1996 2.0A : New release #include "arclib.h" #if !defined( AL_IBM ) #pragma hdrstop #endif // // NAME // // ALArchive::ALArchive() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ // // SHORT DESCRIPTION // // Constructor for ALArchive, the base Archive class. // // C++ SYNOPSIS // // #include "arclib.h" // // ALArchive::ALArchive( ALStorage *storage_object, // short int delete_in_dtor ) // // C SYNOPSIS // // None. // // VB SYNOPSIS // // None. // // DELPHI SYNOPSIS // // None. // // ARGUMENTS // // storage_object : A pointer to the storage object that will contain // the archive. // // delete_in_dtor : When a user creates an archive, it will ordinarily // be with a storage object that will be managed by // their code. When that's the case, we will ordinarily // expect them to be responsible for its destruction. // However, there are times when a temporary archive // might be created that isn't under the users control. // This flag controls whether the Archive destructor // will destroy the storage object as well. // // DESCRIPTION // // The base class ALArchive is very simple. It has a few data members // to initialize, and not much else. The complexity in Archive classes // is found in the derived classes ALGlArchive and ALPkArchive. Both // of them use this base class to initialize their storage object // and the flag that indicates whether the storage object should be // destroyed in the ALArchive destructor. // // Although this is a public function, it isn't likely that there will // ever be a good reason for an end user to call it. It really isn't much // good to anyone but the constructors for the archiving classes. // // For this reason, there also isn't any reason to have a C/VB/Delphi // translation routine. Any attempt to construct an ALArchive by itself // is doomed to failure anyway, since it has numerous pure virtual // functions. // // RETURNS // // Nothing. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release, added the members to control // whether or not to strip path information. // AL_PROTO ALArchive::ALArchive( ALStorage AL_DLL_FAR *storage_object, /* Tag public function */ short int delete_in_dtor ) : mfDeleteStorageObject( delete_in_dtor ) { mfStripPathOnInsert = 0; mfStripPathOnExtract = 0; mpArchiveStorageObject = storage_object; mlDirectoryOffset = -1L; miVersion = -1; } // // NAME // // ALArchive::operator new() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ // // SHORT DESCRIPTION // // Memory allocator used when ArchiveLib resides in a 16 bit DLL. // // C++ SYNOPSIS // // #include "arclib.h" // // void * ALArchive::operator new( size_t size ) // // C SYNOPSIS // // None. // // VB SYNOPSIS // // None. // // DELPHI SYNOPSIS // // None. // // ARGUMENTS // // size : The number of bytes that the compiler has decided will be // necessary to construct a new ALArchive object. // // 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. // // Incidentally, I suspect that this function never gets called. If an // object of a derived archive class is being created, it should use // its own new operator, rendering this one useless. // // RETURNS // // A pointer to some memory that should have been pulled out of the // heap for the DLL. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release // #if defined( AL_BUILDING_DLL ) void AL_DLL_FAR * AL_PROTO ALArchive::operator new( size_t size ) /* Tag internal function */ { return ::new char[ size ]; } #endif // // NAME // // ALArchive::ScanStatus() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ // // SHORT DESCRIPTION // // Scan the list of entries for errors after an archiving operation // // C++ SYNOPSIS // // #include "arclib.h" // // void ALArchive::ScanStatus( ALEntryList &list ) // // C SYNOPSIS // // None. // // VB SYNOPSIS // // None. // // DELPHI SYNOPSIS // // None. // // ARGUMENTS // // list : The list of entries that have just been processed, in one of // the exciting functions, such as Create(), Delete(), etc. // // DESCRIPTION // // After an archive operation, I use this function to update the // status member of the archive. If the archive doesn't already // have an error, I check through all the storage objects and // compression engines to see if any of them hosed up. Any error // of any sort by any of them is copied into the archive status. // The whole point of this is to ensure that if // ALArchive.mStatus == AL_SUCCESS, it means everything worked. // // RETURNS // // None. This function sort of has a return, it will update // the member mStatus with an error code if one is found. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release // void AL_PROTO ALArchive::ScanStatus( ALEntryList AL_DLL_FAR &list ) /* Tag protected function */ { if ( mStatus < AL_SUCCESS ) return; ALEntry *job = list.GetFirstEntry(); while ( job ) { if ( job->mpStorageObject->mStatus < AL_SUCCESS ) { mStatus.SetError( job->mpStorageObject->mStatus, "%s: %s", job->mpStorageObject->mName.GetSafeName(), job->mpStorageObject->mStatus.GetStatusDetail() ); return; } job = job->GetNextEntry(); } } // // NAME // // ALArchive::CalculateJobSize() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ // // SHORT DESCRIPTION // // Calculate the total number of bytes in a job. // // C++ SYNOPSIS // // #include "arclib.h" // // long ALArchive::CalculateJobSize( ALEntryList &list ) // // C SYNOPSIS // // None. // // VB SYNOPSIS // // None. // // DELPHI SYNOPSIS // // None. // // ARGUMENTS // // list : The list of entries in the job. The calculation function // will iterator through this list. // // DESCRIPTION // // If a monitor is running in AL_MONITOR_JOB mode, we need to add up // the sizes of all the storage objects we are going to process, so // that we can accurately track our progress from 0 to 100%. In many // cases, the sizes of all the files will not yet be known, which means // this routine will have to open the files up and check the values. // That is why we only call this routine when we have to. // // RETURNS // // This function is used to calculate the total number of bytes that // are going to have to be moved when performing a Create() or Append() // operation. We need that info in order to set up a monitor properly // when its mode is AL_MONITOR_JOB. Naturally, we don't really care // about the total size when the monitor is in AL_MONITOR_OBJECTS mode. // Anyway, it returns the total unocmpressed size of all the objects added up. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release // long AL_PROTO ALArchive::CalculateJobSize( ALEntryList AL_DLL_FAR &list ) /* Tag protected function */ { long total = 0; ALEntry *job = list.GetFirstEntry(); while ( job ) { if ( job->miMark ) { long obj_size; if ( ( obj_size = job->mpStorageObject->GetSize() ) == -1 ) { job->mpStorageObject->Open(); obj_size = job->mpStorageObject->GetSize(); job->mpStorageObject->Close(); if ( obj_size == -1 ) return -1; } total += obj_size; } job = job->GetNextEntry(); } return total; } // // NAME // // ALArchive::CalculateCompressedJobSize() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ // // SHORT DESCRIPTION // // Calculate the total number of bytes in a job. // // C++ SYNOPSIS // // #include "arclib.h" // // long ALArchive::CalculateCompressedJobSize( ALEntryList &list ) // // C SYNOPSIS // // None. // // VB SYNOPSIS // // None. // // DELPHI SYNOPSIS // // None. // // ARGUMENTS // // list : The list of entries in the job. The calculation function // will iterator through this list. // // DESCRIPTION // // When we are monitoring an Extract() command, the monitor object // gets attached to the Archive, not to the objects that are getting // sucked out of it. This means that progress is being measured // against the compressed objects, not the true size objects. So // before I start the extract, I call this function to see just how // much compressed space is taken up by the compressed objects in // the archive. // // RETURNS // // The total size of a bunch of compressed objects, not the uncompressed // size. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release // long AL_PROTO ALArchive::CalculateCompressedJobSize( ALEntryList AL_DLL_FAR &list ) /* Tag protected function */ { long total = 0; ALEntry *job = list.GetFirstEntry(); while ( job ) { if ( job->miMark ) { if ( job->mlCompressedSize == -1 ) return -1; else total += job->mlCompressedSize; } job = job->GetNextEntry(); } return total; } // // NAME // // ALArchive::WriteArchiveData() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ // // SHORT DESCRIPTION // // Write out any customized archive data. // // C++ SYNOPSIS // // #include "arclib.h" // // int ALArchive::WriteArchiveData() // // C SYNOPSIS // // None. // // VB SYNOPSIS // // None. // // DELPHI SYNOPSIS // // None. // // ARGUMENTS // // None. // // DESCRIPTION // // Derived classes can write out customized archive data, for whatever // reasons they deem necessary. Our base class has nothing that it // needs to save, so it just writes out a zero length string, which takes // two bytes to save. Instead of using WriteString like I ought to, for // some reason I write the 0 out directly. // // RETURNS // // AL_SUCCESS if everything writes out okay, or < AL_SUCCESS for trouble. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release // int AL_PROTO ALArchive::WriteArchiveData() /* Tag protected function */ { return mpArchiveStorageObject->WriteGlShort( 0 ); } // // NAME // // ALArchive::ReadArchiveData() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ // // SHORT DESCRIPTION // // Read in any customized archive data. // // C++ SYNOPSIS // // int ALArchive::ReadArchiveData() // // C SYNOPSIS // // None. // // VB SYNOPSIS // // None. // // DELPHI SYNOPSIS // // None. // // ARGUMENTS // // None. // // DESCRIPTION // // The base class doesn't store anything in the archive specific // data area. That means that when I am reading the archive specific // data in, I should see a zero length string, which is the same thing // as a single short of value 0. I read it in and verify it here. // // Note that derived classes are free to override this function, but // nothing we ship with ArchiveLib does so. // // RETURNS // // AL_SUCCESS if things went well, < AL_SUCCESS it things go sour. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release // int AL_PROTO ALArchive::ReadArchiveData() /* Tag protected function */ { short temp; mpArchiveStorageObject->ReadGlShort( temp ); AL_ASSERT( temp == 0, "ReadArchiveData(): archive data != 0" ); return mpArchiveStorageObject->mStatus; } // // NAME // // ALArchive::~ALArchive() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ C VB Delphi // // SHORT DESCRIPTION // // The base class destructor for ALArchive. // // C++ SYNOPSIS // // #include "arclib.h" // // ALArchive::~ALArchive() // // C SYNOPSIS // // #include "arclib.h" // // void deleteALArchive( hALArchive this_object ); // // VB SYNOPSIS // // Declare Sub deleteALArchive Lib "AL20LW" (ByVal this_object&) // // DELPHI SYNOPSIS // // procedure deleteALArchive( this_object : hALArchive ); // // ARGUMENTS // // this_object : A reference or pointer to the ALArchive object that // is going to be destroyed. The C++ version of this // function doesn't have an argument, because it knows // implicitly who to destroy. // // DESCRIPTION // // The destructor for the base class doesn't have to do too much work. // All it has to do is destroy the storage object, if that service was // requested when the object was constructed. // // It's a little deceptive to show the C/VB/Delphi translation here // as well. Since the archive being destroyed will always be in a base // class, the virtual function call will direct a call to deleteALArchive // down to the derived class destructor before coming back up here. But // I don't really have a better place to put it. // // RETURNS // // Nothing. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release // AL_PROTO ALArchive::~ALArchive() /* Tag public function */ { AL_ASSERT( GoodTag(), "~ALArchive(): Attempting to delete invalid ALArchive" ); if ( mpArchiveStorageObject && mfDeleteStorageObject ) delete mpArchiveStorageObject; AL_ASSERT( GoodTag(), "~ALArchive::Attempting to delete invalid ALArchive" ); } #if !defined( AL_NO_C ) extern "C" AL_LINKAGE void AL_FUNCTION deleteALArchive( hALArchive this_object ) /* Tag public function */ { AL_ASSERT_OBJECT( this_object, ALArchive, "deleteALArchive()" ); delete (ALArchive *) this_object; } #endif