// // ARCAA.CPP // // Source file for ArchiveLib 2.0 // // Copyright (c) Greenleaf Software, Inc. 1994-1996 // All Rights Reserved // // CONTENTS // // ALArchive::Append() // ALArchiveAppendFromArchive() // // DESCRIPTION // // This file contains the append from archive function. // // REVISION HISTORY // // February 14, 1996 2.0A : New release #include "arclib.h" #if !defined( AL_IBM ) #pragma hdrstop #endif #include "_openf.h" // // NAME // // ALArchive::Append() // // PLATFORMS/ENVIRONMENTS // // Console Windows PM // C++ C VB Delphi // // SHORT DESCRIPTION // // Append a list of objects from an input archive to an existing archive. // // C++ SYNOPSIS // // #include "arclib.h" // // int ALArchive::Append( ALArchive &source_archive, // ALEntryList &source_list ) // // C SYNOPSIS // // #include "arclib.h" // // int ALArchiveAppendFromArchive( hALArchive this_object, // hALArchive input_archive, // hALEntryList list ); // // VB SYNOPSIS // // Declare Function ALArchiveAppendFromArchive Lib "AL20LW" // (ByVal this_object&, // ByVal source_archive&, // ByVal source_list&) As Integer // // DELPHI SYNOPSIS // // function ALArchiveAppendFromArchive( this_object : hALArchive; // source_archive : hALArchive; // source_list : hALEntryList ) : Integer; // // ARGUMENTS // // this_object : A reference or pointer to the ALArchive object that // is going to have the batch of files appended to it. // As always, the C++ version of this function doesn't // need 'this_object' as an argument, since C++ // member functions get an explicit copy of this passed // when they are called. // // source_archive : A reference to the archive that contains the objects // that are going to be added to this. Since these // files are already compressed, this function can // really haul butt by just doing binary copies from the // source archive to this_object. // // list : A reference to the ALEntryList that has copies of // all the storage objects to be inserted. The list also // has the offset of all the objects in the source archive, // and their compressed sizes. // // DESCRIPTION // // This function is called to insert a batch of objects into an archive. // You might have noticed by looking at the header file ARC.H that this // is not a virtual function, which means its behavior has to be // generalized enough to support both Greenleaf and PKWare archives. // All the specialization is done through the virtual functions that // control directory information, object positioning, and so on. // // All of the bookwork is done in this function. Note that in order // for this to work properly, we have to read in the entire directory // into memory, because we are going to append to an existing file, and // we assume the directory is at the end of the archive. So the process // basically consists of first reading the directory, then copying // all the new jobs, then writing out the new combined directory. The // copying is done in another function, CopyJobs(). // // RETURNS // // An ArchiveLib status, ranging from AL_SUCCESS to any number of // reasons for failure. // // EXAMPLE // // SEE ALSO // // REVISION HISTORY // // February 14, 1996 2.0A : New release // int AL_PROTO ALArchive::Append( ALArchive AL_DLL_FAR &source_archive, /* Tag public function */ ALEntryList AL_DLL_FAR &source_list ) { ALEntryList old_list( source_list ); // // Open the storage object for this. // ALOpenInputFile archive( *mpArchiveStorageObject ); // // I read in the current directory for this archive. I am going to // write over the directory with new stuff, so I will have to write it // back out later. // ReadDirectory( old_list ); if ( mStatus < 0 ) return mStatus; // // The list of new objects I am going to add needs to be scanned for // duplicates. First I clear duplicate entries from the list itself. // Then I clear any duplicates between the current list and the // stuff already in the archive. // source_list.UnmarkDuplicates( source_list, "Duplicate entry in list passed to Append()" ); source_list.UnmarkDuplicates( old_list, "Duplicate entry in list passed to Append()" ); // // Here is where I have to add new code to reflect the difference // between the two versions of Append() // // // Set up the monitor. // source_list.mrMonitor.mlJobSoFar = 0L; if ( source_list.mrMonitor.miMonitorType == AL_MONITOR_JOB ) source_list.mrMonitor.mlJobSize = CalculateCompressedJobSize( source_list ); PreCreate(); // // CopyJobs() takes care of actually adding the jobs to the archive. // CopyJobs( source_archive, source_list ); // // All the jobs are written, now I can figure out where the // directory is in the storage object. I copy it, then write // it out to the storage object at position 0. // mlDirectoryOffset = mpArchiveStorageObject->Tell(); // // Once I know the directory offset, it's safe to do // a PostCreate(). // PostCreate(); // // Return without writing the directory if there is an error in the // archive storage object. // if ( mpArchiveStorageObject->mStatus < 0 ) { source_list.mrMonitor.ArchiveOperation( AL_ARCHIVE_CLOSE, this, 0 ); return mStatus = mpArchiveStorageObject->mStatus; } // // Now I write the old directory out, and then add in the new // directory entries. // source_list.mrMonitor.ArchiveOperation( AL_START_DIRECTORY_WRITE, this, 0 ); miCount = 0; PreWriteDir(); ALEntry *job = old_list.GetFirstEntry(); while ( job ) { if ( job->miMark ) { miCount++; WriteDirEntry( *job ); } job = job->GetNextEntry(); } job = source_list.GetFirstEntry(); while ( job ) { if ( job->miMark ) { miCount++; WriteDirEntry( *job ); } job = job->GetNextEntry(); } PostWriteDir(); // // Update the monitor, check for errors, then leave. // source_list.mrMonitor.ArchiveOperation( AL_END_DIRECTORY_WRITE, this, 0 ); source_list.mrMonitor.ArchiveOperation( AL_ARCHIVE_CLOSE, this, 0 ); ScanStatus( source_list ); return mStatus; } #if !defined( AL_NO_C ) extern "C" AL_LINKAGE int AL_FUNCTION ALArchiveAppendFromArchive( hALArchive this_object, /* Tag public function */ hALArchive input_archive, hALEntryList list ) { AL_ASSERT( ((ALArchive *) this_object)->GoodTag(), "archive argument is not a valid ALArchiveBase" ); AL_ASSERT( ((ALArchive *) input_archive)->GoodTag(), "input archive argument is not a valid ALArchiveBase" ); AL_ASSERT( ((ALEntryList *) list)->GoodTag(), "list argument is not a valid ALEntryList" ); return ((ALArchive *) this_object )->Append( *(ALArchive *) input_archive, *( (ALEntryList *) list ) ); } #endif