campo-sirio/al/cpp_all/pkarc.cpp
alex 714dd74636 Archive Library versione 2.00
git-svn-id: svn://10.65.10.50/trunk@5350 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-10-09 16:09:54 +00:00

1467 lines
42 KiB
C++
Executable File

//
// PKARC.CPP
//
// Source file for ArchiveLib 2.0
//
// Copyright (c) Greenleaf Software, Inc. 1994-1996
// All Rights Reserved
//
// CONTENTS
//
// ALPkArchive::operator new()
// ALPkArchive::ALPkArchive()
// newALPkArchiveFromStorage()
// ALPkArchive::~ALPkArchive()
// ALPkArchive::WriteArchiveData()
// ALPkArchive::ReadArchiveData()
// ALPkArchive::LocateEcd()
// ALPkArchive::ReadEcd()
// ALGlArchive::ReadDirectory()
// ALPkArchive::PreCompress()
// ALPkArchive::PreDecompress()
// ALPkArchive::PostCompress()
// ALPkArchive::PreWriteDir()
// ALPkArchive::WriteDirEntry()
// ALPkArchive::PostWriteDir()
//
// DESCRIPTION
//
// This file contains all of the source code for the class ALPkArchive.
// The details on how things get inserted and extracted from a PKZip
// archive will all be found here.
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
#include "arclib.h"
#if !defined( AL_IBM )
#pragma hdrstop
#endif
#include <time.h>
#include <ctype.h>
#include "filestor.h"
#include "pkarc.h"
#include "pkengn.h"
#include "_openf.h"
//
// NAME
//
// ALPkArchive::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"
// #include "pkarc.h"
//
// void * ALPkArchive::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 ALPkArchive 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.
//
// This function will be called whenever you dynamically create a new
// ALPkArchive object (using the new operator.)
//
// 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
ALPkArchive::operator new( size_t size ) /* Tag protected function */
{
return ::new char[ size ];
}
#endif
//
// NAME
//
// ALPkArchive::ALPkArchive()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++ C VB Delphi
//
// SHORT DESCRIPTION
//
// The PKWare Archive constructor.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// ALPkArchive::ALPkArchive( ALStorage &storage_object );
//
// C SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// hALArchive newALPkArchiveFromStorage( hALStorage storage );
//
// VB SYNOPSIS
//
// Declare Function newALPkArchiveFromStorage Lib "AL20LW"
// (ByVal storage&) As Long
//
// DELPHI SYNOPSIS
//
// function newALPkArchiveFromStorage( storage : hALStorage ) : hALArchive;
//
// ARGUMENTS
//
// storage_object : A pointer to the storage object that will/does
// hold the archive.
//
//
// DESCRIPTION
//
// This function creates a new ALPkArchive object, using a storage object
// as the underlying physical container. PkArchives are siblings to
// Gl archives. While they both use the same base class, and support many
// functions in common, they are essentially incompatible.
//
// You call this constructor to manipulate any archive, including ones
// that haven't even been created yet.
//
// Recall that the base class, ALArchive, has a single argument to *its*
// constructor that determines whether or not it destroys the underlying
// storage object in its destructor. Since we are using user-specified
// storage in this case, we pass a 0, indicating that we don't want the
// destructor to destroy the underlying storage object.
//
// RETURNS
//
// When called from C/VB/Delphi, the translation function returns a handle
// to a newly created archive object. When called using the new operator
// in C++, this function returns a pointer to a newly created archive
// object. O/w it returns nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
AL_PROTO
ALPkArchive::ALPkArchive( ALStorage AL_DLL_FAR &storage_object ) /* Tag public function */
: ALArchive( &storage_object, 0)
{
miVersion = 0x020;
}
#if !defined( AL_NO_C )
extern "C" AL_LINKAGE hALArchive AL_FUNCTION
newALPkArchiveFromStorage( hALStorage storage ) /* Tag public function */
{
AL_ASSERT( ( (ALStorage *) storage)->GoodTag(),
"storage argument is not a valid ALStorageObject" );
ALArchive *archive;
archive = new ALPkArchive( *(ALStorage *) storage );
return (hALArchive) archive;
}
#endif
//
// NAME
//
// ALPkArchive::~ALPkArchive()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Destructor for the PKWare Archive.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// ALPkArchive::~ALPkArchive()
//
// C SYNOPSIS
//
// None, use deleteALArchive();
//
// VB SYNOPSIS
//
// None, use deleteALArchive();
//
// DELPHI SYNOPSIS
//
// None, use deleteALArchive();
//
// ARGUMENTS
//
// None.
//
// DESCRIPTION
//
// This is a virtual destructor for the derived class ALPkArchive. It
// has absolutely nothing to do, since all of the important work is done
// by the base class destructor, ALArchive::~ALArchive(). Note that
// there is no translation function for C/VB/Delphi to call this function
// directly. Instead, they will get here by way of a virtual function
// call to the base class destructor.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
AL_PROTO
ALPkArchive::~ALPkArchive() /* Tag public function */
{
AL_ASSERT( GoodTag(), "~ALPkArchive(): Attempting to delete invalid ALPkArchive" );
}
//
// NAME
//
// ALPkArchive::WriteArchiveData()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Virtual function to write class-specific archive data.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// int ALPkArchive::WriteArchiveData()
//
// C SYNOPSIS
//
// None, this is a C++ specific callback virtual function.
//
// VB SYNOPSIS
//
// None, this is a C++ specific callback virtual function.
//
// DELPHI SYNOPSIS
//
// None, this is a C++ specific callback virtual function.
//
// ARGUMENTS
//
// None.
//
// DESCRIPTION
//
// ArchiveLib supports this virtual function in its base class. It is
// here to allow the user to derive new archive classes, and then store
// additional archive-specific info when creating archives. PKWare
// archives don't really have any space on hand for archive specific
// data, so this function turns into a nop. We can't just nuke it though,
// because the base class writes a couple of bytes out. Those two bytes
// would destroy any PKWare archives.
//
// RETURNS
//
// AL_SUCCESS, guaranteed.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
int AL_PROTO
ALPkArchive::WriteArchiveData() /* Tag protected function */
{
return AL_SUCCESS;
}
//
// NAME
//
// ALPkArchive::ReadArchiveData()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Virtual function to read class-specific archive data.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// int ALPkArchive::ReadArchiveData()
//
// C SYNOPSIS
//
// None, this is a C++ specific callback virtual function.
//
// VB SYNOPSIS
//
// None, this is a C++ specific callback virtual function.
//
// DELPHI SYNOPSIS
//
// None, this is a C++ specific callback virtual function.
//
// ARGUMENTS
//
// None.
//
// DESCRIPTION
//
// ArchiveLib supports this virtual function in its base class. It is
// here to allow the user to derive new archive classes, and then store
// and retrieve additional archive-specific info to/from archives. PKWare
// archives don't really have any space on hand for archive specific
// data, so this function turns into a nop. We can't just nuke it though,
// because the base class tries to read in a couple of bytes. Those two bytes
// aren't there in any PKWare format archives.
//
// RETURNS
//
// AL_SUCCESS, guaranteed.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
int AL_PROTO
ALPkArchive::ReadArchiveData() /* Tag protected function */
{
return AL_SUCCESS;
}
//
// NAME
//
// ALPkArchive::LocateEcd()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Find the end of the central directory.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// int ALPkArchive::LocateEcd()
//
// C SYNOPSIS
//
// None, this is an internal protected support function.
//
// VB SYNOPSIS
//
// None, this is an internal protected support function.
//
// DELPHI SYNOPSIS
//
// None, this is an internal protected support function.
//
// ARGUMENTS
//
// None.
//
// DESCRIPTION
//
// The first step in reading a PKWare format archive is to find the
// end of the central directory. Unfortunately, this is kind of an
// iffy proposition. Why? Because you just have to blindly search
// from the end of the ZIP file, working backwards, until you find
// a magic cookie: 'P', 'K', 5, 6.
//
// The 5 and 6 are not printable ASCII, which helps, but it is still
// a pretty gruesome way to handle things. Yuck. Anyway, it is the
// job of this function to search backwards through the archive, looking
// for the magic cookie. If I find it, I save it in the class member
// that keeps track of the ECD offset.
//
// I limit the search to around 64K, because that's what the InfoZip
// guys do. I think they are counting on it not being legal to have
// a central directory bigger than 64K.
//
// RETURNS
//
// AL_SUCCESS if the ECD was found, AL_INVALID_ARCHIVE if not. If
// it was found, mEcd.mlOffset is set to the file offset.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
int AL_PROTO
ALPkArchive::LocateEcd() /* Tag protected function */
{
const int BUF_SIZE = 256;
char buf[ BUF_SIZE + 4 ];
long offset = mpArchiveStorageObject->GetSize();
long left_to_check = offset < 66000L ? offset : 66000L;
buf[ 0 ] = '\0'; //prevent false trigger the first time through
for ( ; ; ) {
int number_to_read;
if ( left_to_check == 0 )
break;
if ( left_to_check < BUF_SIZE )
number_to_read = (int) left_to_check;
else
number_to_read = BUF_SIZE;
offset -= number_to_read;
memcpy( buf + BUF_SIZE, buf, 4 );
mpArchiveStorageObject->Seek( offset );
mpArchiveStorageObject->ReadBuffer( (unsigned char *) buf, number_to_read );
for ( int i = number_to_read ; i >= 0 ; i-- ) {
if ( buf[ i + 0 ] == 'P' &&
buf[ i + 1 ] == 'K' &&
buf[ i + 2 ] == 5 &&
buf[ i + 3 ] == 6 ) {
mEcd.mlOffset = offset + i;
return AL_SUCCESS;
}
}
left_to_check -= number_to_read;
}
mEcd.mlOffset = -1L;
return mStatus.SetError( AL_INVALID_ARCHIVE,
"Can't locate end of central directory in "
"ZIP file %s",
mpArchiveStorageObject->mName.GetSafeName() );
}
//
// NAME
//
// ALPkArchive::ReadEcd()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Read in the End of Central Directory record from a PKWare archive.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// int ALPkArchive::ReadEcd()
//
// C SYNOPSIS
//
// None, this is an internal protected support function.
//
// VB SYNOPSIS
//
// None, this is an internal protected support function.
//
// DELPHI SYNOPSIS
//
// None, this is an internal protected support function.
//
// ARGUMENTS
//
// None.
//
// DESCRIPTION
//
// Once the PKWare code finds the ECD, this routine is called to
// read in some important data items. These are all crucial to the
// successful use of the archive later. Note that most of the stuff
// goes into the mEcd member, which is unique to this derived class.
// However, the comment and directory offset are universal, and go
// into members of the base class.
//
// RETURNS
//
// AL_SUCCESS, always. Any error in reading will be reflected into
// the ALArchive object itself, and should be picked up later.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
int AL_PROTO
ALPkArchive::ReadEcd() /* Tag protected function */
{
mpArchiveStorageObject->Seek( mEcd.mlOffset + 4 );
mpArchiveStorageObject->ReadPkShort( mEcd.muThisDiskNumber );
mpArchiveStorageObject->ReadPkShort( mEcd.muStartCentralDirDiskNumber );
mpArchiveStorageObject->ReadPkShort( mEcd.muThisDiskCentralDirEntries );
mpArchiveStorageObject->ReadPkShort( mEcd.muTotalCentralDirEntries );
mpArchiveStorageObject->ReadPkLong( mEcd.mlSizeCentralDir );
mpArchiveStorageObject->ReadPkLong( mlDirectoryOffset );
short int comment_length;
mpArchiveStorageObject->ReadPkShort( comment_length );
mpArchiveStorageObject->ReadString( mComment, comment_length );
return AL_SUCCESS;
}
//
// NAME
//
// ALPkArchive::ReadDirectory()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Read in the directory of a PKWare archive.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// int ALPkArchive::ReadDirectory( ALEntryList &list );
//
// C SYNOPSIS
//
// C programs call this function via a translation function from
// the base class: ALArchiveReadDirectory()
//
// VB SYNOPSIS
//
// VB programs call this function via a translation function from
// the base class: ALArchiveReadDirectory()
//
// DELPHI SYNOPSIS
//
// Delphi programs call this function via a translation function from
// the base class: ALArchiveReadDirectory()
//
// ARGUMENTS
//
// list : An ALEntryList object that is going to receive all the
// new ALEntry objects created from reading the directory.
//
// DESCRIPTION
//
// ReadDirectory has to rip through the directory of the PKWare archive,
// creating an ALEntry for every single entry in the directory. While
// this is conceptually pretty simple, there is a lot of crap in the
// directory that has to be read in and massaged. Hence, it is an
// exceptionally long piece of code.
//
// During the process of creating ArchiveLib 2.0, the WriteDirectory()
// function was moved up into the base class. The addition of three
// virtual helper functions takes care of all the specialized aspects
// needed to make it happen.
//
// Well, I haven't gotten around to that for the ReadDirectory function.
// Maybe in the final release of 2.0, but more likely in the release
// of ArchiveLib 3.0. It's not a critical issue, it just helps break
// the code down into smaller pieces, and is somewhat more efficient by
// sharing common code.
//
// RETURNS
//
// AL_SUCCESS, or some other miscellaneous error code.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
int AL_PROTO
ALPkArchive::ReadDirectory( ALEntryList AL_DLL_FAR &list ) /* Tag public function */
{
list.mrMonitor.ArchiveOperation( AL_START_DIRECTORY_READ, this, 0 );
ALOpenInputFile archive( *mpArchiveStorageObject );
if ( mpArchiveStorageObject->mStatus < 0 )
return mStatus = mpArchiveStorageObject->mStatus;
if ( LocateEcd() < AL_SUCCESS )
return mStatus;
//
// Now I have to read in the end of central directory information
//
ReadEcd();
mpArchiveStorageObject->Seek( mlDirectoryOffset );
//
// Now, the big loop. I have to read in each entry, one at a time, and
// add it to the list. If I broke this out into a separate routine it
// would make the whole thing a lot more manageable.
//
for ( ; ; ) {
char buf[ 4 ];
if ( mpArchiveStorageObject->ReadBuffer( (unsigned char *) buf, 4 ) != 4 )
return mStatus = mpArchiveStorageObject->mStatus;
//
// Remember that 'P', 'K', 5, 6 is the End of Central Directory record.
//
if ( buf[ 0 ] == 'P' && buf[ 1 ] == 'K' && buf[ 2 ] == 5 && buf[ 3 ] == 6 )
break;
if ( buf[ 0 ] != 'P' || buf[ 1 ] != 'K' || buf[ 2 ] != 1 || buf[ 3 ] != 2 )
return mStatus.SetError( AL_INVALID_ARCHIVE,
"Bad record in central directory of "
"ZIP file %s",
mpArchiveStorageObject->mName.GetSafeName() );
//
// Skip over the next four bytes, then get the compression method
//
int k;
for ( k = 0 ; k < 4 ; k++ )
mpArchiveStorageObject->ReadChar();
short int gp_bits;
mpArchiveStorageObject->ReadPkShort( gp_bits );
short int method;
mpArchiveStorageObject->ReadPkShort( method );
//
// Derived classes are responsible for providing a version of
// CreateCompressionEngine() that will convert the engine_type
// integer into a created compression engine. The derived class is
// then also responsible for reading in the engine data from the archive.
//
if ( gp_bits & 1 )
method = -1;
else if ( method == 8 )
method = (short int) (method + ( ( gp_bits >> 1 ) & 3 ));
method = (short int)( method + 100 );
ALDecompressor *decompressor = list.mToolKit.CreateDecompressor( method );
#if 0
//
// We'll be letting this slide from now on
//
if ( !decompressor )
return mStatus.SetError( AL_CANT_CREATE_ENGINE,
"Failure creating compression engine "
"in ZIP file %s",
mpArchiveStorageObject->mName.GetSafeName() );
#endif
ALCompressor *compressor = list.mToolKit.CreateCompressor( method );
//
// Now we go through a nearly identical process to create the storage object.
// The derived class is responsible for writing a CreateStorageObject()
// function that converts an object_type integer to a created storage
// object. The derived class also has to read in the storage object
// data.
//
ALStorage *storage_object = list.mToolKit.CreateStorageObject( "", AL_FILE_OBJECT );
if ( !storage_object ) {
if ( compressor )
delete compressor;
delete decompressor;
return mStatus.SetError( AL_CANT_CREATE_STORAGE_OBJECT,
"Failure creating storage object in "
"ZIP file %s",
mpArchiveStorageObject->mName.GetSafeName() );
}
ALEntry *job = new ALEntry( list, storage_object, compressor, decompressor );
short int pktime;
short int pkdate;
mpArchiveStorageObject->ReadPkShort( pktime );
mpArchiveStorageObject->ReadPkShort( pkdate );
struct tm tblock;
tblock.tm_year = ( ( pkdate >> 9 ) & 0x7f ) + 1980 - 1900;
tblock.tm_mon = ( ( pkdate >> 5 ) & 0xf ) - 1;
tblock.tm_mday = pkdate & 0x1f;
tblock.tm_hour = (pktime >> 11) & 0x1f;
tblock.tm_min = (pktime >> 5 ) & 0x3f;
tblock.tm_sec = (pktime & 0x1f) * 2;
tblock.tm_wday = 0;
tblock.tm_yday = 0;
tblock.tm_isdst = 0;
storage_object->mTimeDate.SetTimeDate( &tblock );
mpArchiveStorageObject->ReadPkLong( job->mlCrc32 );
job->mlCrc32 = ~job->mlCrc32;
mpArchiveStorageObject->ReadPkLong( job->mlCompressedSize );
mpArchiveStorageObject->ReadPkLong( storage_object->mlSize );
short int filename_length;
mpArchiveStorageObject->ReadPkShort( filename_length );
short int extra_length;
mpArchiveStorageObject->ReadPkShort( extra_length );
short int comment_length;
mpArchiveStorageObject->ReadPkShort( comment_length );
short int disk_number_start;
mpArchiveStorageObject->ReadPkShort( disk_number_start );
short int internal_attributes;
long int external_attributes;
mpArchiveStorageObject->ReadPkShort( internal_attributes );
mpArchiveStorageObject->ReadPkLong( external_attributes );
int packed = 0;
if ( external_attributes & 1 )
packed |= ATTR_READ_ONLY;
if ( external_attributes & 4 )
packed |= ATTR_SYSTEM;
if ( external_attributes & 2 )
packed |= ATTR_HIDDEN;
if ( external_attributes & 0x20 )
packed |= ATTR_ARCHIVE;
if ( external_attributes & 0x10 )
packed |= ATTR_DIRECTORY;
if ( external_attributes & 0x08 )
packed |= ATTR_LABEL;
storage_object->mAttributes.SetFromPackedAttributes( (short int) packed );
mpArchiveStorageObject->ReadPkLong( job->mlCompressedObjectPosition );
mpArchiveStorageObject->ReadString( storage_object->mName, filename_length );
for ( k = 0 ; k < extra_length ; k++ )
mpArchiveStorageObject->ReadChar();
ALName comment;
mpArchiveStorageObject->ReadString( comment, comment_length );
job->SetComment( comment );
if ( mpArchiveStorageObject->mStatus < 0 )
return mStatus = mpArchiveStorageObject->mStatus;
}
list.mrMonitor.ArchiveOperation( AL_END_DIRECTORY_READ, this, 0 );
return mStatus;
}
//
// NAME
//
// ALPkArchive::PreCompress()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Take care of details before inserting an object in an archive.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// void ALPkArchive::PreCompress( ALEntry &entry )
//
// C SYNOPSIS
//
// This is a protected callback routine, and has no C equivalent.
//
// VB SYNOPSIS
//
// This is a protected callback routine, and has no VB equivalent.
//
// DELPHI SYNOPSIS
//
// This is a protected callback routine, and has no Delphi equivalent.
//
// ARGUMENTS
//
// entry : This is the ALEntry that describes the object that is
// about to be compressed.
//
// DESCRIPTION
//
// This is a virtual function that gets called by the CompressJobs()
// function in the base class. The virtual function is supposed to
// take care of any odds and ends that need to be done immediately
// before an object is compressed into the archive.
//
// In the case of PKWare archives, this means seeking past the local
// directory entry, which is going to be 30 bytes long, plus the length
// of the object name.
//
// When done compressing, we will jump back to the original spot and write
// out the directory information.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALPkArchive::PreCompress( ALEntry AL_DLL_FAR &entry ) /* Tag protected function */
{
const char *name = entry.mpStorageObject->mName.GetSafeName();
mpArchiveStorageObject->Seek( mpArchiveStorageObject->Tell() +
30 + strlen( name ) );
}
//
// NAME
//
// ALPkArchive::PreDecompress()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Take care of details before extracting a file.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// void ALPkArchive::PreDecompress( ALEntry &entry );
//
// C SYNOPSIS
//
// This is an internal C++ support routine, no C equivalent.
//
// VB SYNOPSIS
//
// This is an internal C++ support routine, no C equivalent.
//
// DELPHI SYNOPSIS
//
// This is an internal C++ support routine, no C equivalent.
//
// ARGUMENTS
//
// entry : A reference to the ALEntry object that is about to be
// decompressed. Note that this function doesn't use this
// argument.
//
// DESCRIPTION
//
// Extracting a batch of jobs is left up to the base class. As the
// base class code is busy extracting jobs, it calls this routine
// *before* the extraction, and PostDecompress *after* the extraction.
//
// Unlike GL Archvies, PKWare archives have a local directory entry
// that sits right in front of the compressed data. So this virtual
// function takes care of skipping over that local data, and leaving
// the file pointer sitting right at the start of the compressed object.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALPkArchive::PreDecompress( ALEntry AL_DLL_FAR &/*entry*/ ) /* Tag protected function */
{
int ii;
for ( ii = 0 ; ii < 26 ; ii++ )
mpArchiveStorageObject->ReadChar();
short int filename_length;
short int extra_length;
mpArchiveStorageObject->ReadPkShort( filename_length );
mpArchiveStorageObject->ReadPkShort( extra_length );
for ( ii = 0 ; ii < (filename_length + extra_length ) ; ii++ )
mpArchiveStorageObject->ReadChar();
}
//
// NAME
//
// ALPkArchive::PreCopyInput()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Take care of details before copying a compressed object.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// void ALPkArchive::PreCopyInput( ALEntry &entry );
//
// C SYNOPSIS
//
// This is an internal C++ support routine, no C equivalent.
//
// VB SYNOPSIS
//
// This is an internal C++ support routine, no C equivalent.
//
// DELPHI SYNOPSIS
//
// This is an internal C++ support routine, no C equivalent.
//
// ARGUMENTS
//
// entry : A reference to the ALEntry object that is about to be
// copied.
//
// DESCRIPTION
//
// Copying a batch of compressed objects from one archive to another is
// left up to the base class. As the base class code is busy copying jobs,
// it calls this routine *before* the copy, and PostCoppyInput *after* the
// copy.
//
// Unlike GL Archvies, PKWare archives have a local directory entry
// that sits right in front of the compressed data. So this virtual
// function takes care of skipping over that local data, and leaving
// the file pointer sitting right at the start of the compressed object.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALPkArchive::PreCopyInput( ALEntry AL_DLL_FAR &entry ) /* Tag protected function */
{
const char *name = entry.mpStorageObject->mName.GetSafeName();
mpArchiveStorageObject->Seek( mpArchiveStorageObject->Tell() +
30 + strlen( name ) );
}
//
// NAME
//
// ALPkArchive::PostCompress()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Take care of details after inserting a compressed object in an archive.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkarc.h"
//
// void ALPkArchive::PostCompress( ALEntry &entry )
//
// C SYNOPSIS
//
// This is a protected callback routine, and has no C equivalent.
//
// VB SYNOPSIS
//
// This is a protected callback routine, and has no VB equivalent.
//
// DELPHI SYNOPSIS
//
// This is a protected callback routine, and has no Delphi equivalent.
//
// ARGUMENTS
//
// entry : This is the ALEntry that describes the object that has
// just been compressed.
//
// DESCRIPTION
//
// This is a virtual function that gets called by the CompressJobs()
// function in the base class. The virtual function is supposed to
// take care of any odds and ends that need to be done immediately
// after object is compressed into the archive.
//
// In the case of PKWare archives, this means seeking back to the
// correct spot in the archive, then writing out local directory
// information.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALPkArchive::PostCompress( ALEntry AL_DLL_FAR &entry ) /* Tag protected function */
{
const char *name = entry.mpStorageObject->mName.GetSafeName();
entry.mlCompressedSize = mpArchiveStorageObject->Tell() -
entry.mlCompressedObjectPosition -
30 - strlen( name );
//
// Now I have to write the local file header
//
long keeper = mpArchiveStorageObject->Tell();
mpArchiveStorageObject->Seek( entry.mlCompressedObjectPosition );
mpArchiveStorageObject->WriteChar( 'P' );
mpArchiveStorageObject->WriteChar( 'K' );
mpArchiveStorageObject->WriteChar( 3 );
mpArchiveStorageObject->WriteChar( 4 );
mpArchiveStorageObject->WritePkShort( 20 );
short int flags;
short int method;
switch ( entry.mpCompressor->miCompressionType ) {
case AL_COMPRESSION_COPY :
method = 0;
flags = 0;
break;
case AL_COMPRESSION_DEFLATE :
method = 8;
switch ( ( (ALPkCompressor AL_DLL_FAR *) entry.mpCompressor)->miLevel ) {
case 9 : flags = 2; break;
case 1 : flags = 4; break;
default : flags = 0; break;
}
break;
default :
method = -1;
flags = 0;
}
mpArchiveStorageObject->WritePkShort( flags );
mpArchiveStorageObject->WritePkShort( method );
mpArchiveStorageObject->WritePkShort( entry.mpStorageObject->mTimeDate.GetDosTime() );
mpArchiveStorageObject->WritePkShort( entry.mpStorageObject->mTimeDate.GetDosDate() );
mpArchiveStorageObject->WritePkLong( ~entry.mlCrc32 ); //CRC
mpArchiveStorageObject->WritePkLong( entry.mlCompressedSize ); //compressed size
mpArchiveStorageObject->WritePkLong( entry.mpStorageObject->GetSize() ); //un compressed size
mpArchiveStorageObject->WritePkShort( (short int) strlen( name ) ); //un compressed size
mpArchiveStorageObject->WritePkShort( 0 );
mpArchiveStorageObject->WriteBuffer( (unsigned char *) name, strlen( name ) );
mpArchiveStorageObject->Seek( keeper );
}
//
// NAME
//
// ALPkArchive::PreWriteDir()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Write out the archive data that precedes the directory.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "glarc.h"
//
// void ALPkArchive::PreWriteDir()
//
// C SYNOPSIS
//
// None, this is an internal function.
//
// VB SYNOPSIS
//
// None, this is an internal function.
//
// DELPHI SYNOPSIS
//
// None, this is an internal function.
//
// ARGUMENTS
//
// None.
//
// DESCRIPTION
//
// The base class, ALArchive, is responsible for all the work done when
// creating an archive. However, since Greenleaf and PKWare archives
// are fairly different, the base class relies on a few virtual functions
// to perform archive specific chores.
//
// PreWriteDir() is one of those functions. It is called after the
// file pointer has been positioned to write the directory out, but
// before any directory entries have been written.
//
// PKWare archives don't have to write anything special out at the
// start of the central directory, but they do have one important
// thing to do in this routine. They need to keep track of exactly
// where the start of the directory is. That gets figured out here
// and stored in the archive object, for later use.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALPkArchive::PreWriteDir() /* Tag protected function */
{
mlStartOfCentralDir = mpArchiveStorageObject->Tell();
}
//
// NAME
//
// ALPkArchive::WriteDirEntry()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Write an individual object entry to the archive directory.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkkrc.h"
//
// void ALPkArchive::WriteDirEntry( ALEntry &entry );
//
// C SYNOPSIS
//
// None, internal support function.
//
// VB SYNOPSIS
//
// None, internal support function.
//
// DELPHI SYNOPSIS
//
// None, internal support function.
//
// ARGUMENTS
//
// entry : A reference to an entry. This should correspond to an actual
// object that is present in the archive.
//
// DESCRIPTION
//
// The base class function, ALArchive::WriteDirectory(), sits in a loop
// writing out directory entries, one after the other. Since it is in
// the base class, you can't expect it to know the exact format for an
// entry. So instead, it relies on this virtual function in derived
// classes to do the job.
//
// This function takes care of writing out a directory entry in the format
// PKWare archives use. There is a lot of crud to write out, but
// it is all fairly straightforward.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALPkArchive::WriteDirEntry( ALEntry AL_DLL_FAR &entry ) /* Tag protected function */
{
mpArchiveStorageObject->WriteChar( 'P' );
mpArchiveStorageObject->WriteChar( 'K' );
mpArchiveStorageObject->WriteChar( 1 );
mpArchiveStorageObject->WriteChar( 2 );
mpArchiveStorageObject->WritePkShort( 20 );
mpArchiveStorageObject->WritePkShort( 20 );
short int flags;
short int method;
ALCompressionType ctype;
if ( entry.mpCompressor )
ctype = entry.mpCompressor->miCompressionType;
else if ( entry.mpDecompressor )
ctype = entry.mpDecompressor->miCompressionType;
else
ctype = AL_COMPRESSION_DEFAULT;
switch ( ctype ) {
case AL_COMPRESSION_COPY :
method = 0;
flags = 0;
break;
case AL_COMPRESSION_DEFLATE :
method = 8;
int pk_option;
if ( entry.mpCompressor )
pk_option = ((ALPkCompressor AL_DLL_FAR *) entry.mpCompressor)->option;
else
pk_option = ((ALPkDecompressor AL_DLL_FAR *) entry.mpDecompressor)->option;
switch ( pk_option ) {
case ALPkCompressor::FAST : flags = 4; break;
case ALPkCompressor::SUPER_FAST : flags = 6; break;
case ALPkCompressor::MAXIMUM : flags = 2; break;
case ALPkCompressor::NORMAL :
default : flags = 0; break;
}
break;
default :
method = -1;
flags = 0;
}
mpArchiveStorageObject->WritePkShort( flags );
mpArchiveStorageObject->WritePkShort( method );
mpArchiveStorageObject->WritePkShort( entry.mpStorageObject->mTimeDate.GetDosTime() );
mpArchiveStorageObject->WritePkShort( entry.mpStorageObject->mTimeDate.GetDosDate() );
mpArchiveStorageObject->WritePkLong( ~entry.mlCrc32 ); //CRC
mpArchiveStorageObject->WritePkLong( entry.mlCompressedSize ); //compressed size
mpArchiveStorageObject->WritePkLong( entry.mpStorageObject->GetSize() ); //un compressed size
const char *name = entry.mpStorageObject->mName.GetSafeName();
//
// PKWare doesn't like absolute path information, so I have to strip the
// info from the name
//
if ( strlen( name ) > 2 && isalpha( name[ 0 ] ) && name[ 1 ] == ':' )
name += 2;
if ( strlen( name ) > 1 && name[ 0 ] == '\\' )
name++;
mpArchiveStorageObject->WritePkShort( (short int) strlen( name ) );
mpArchiveStorageObject->WritePkShort( 0 );
const char *comment = entry.mszComment;
if ( comment == 0 )
comment = "";
mpArchiveStorageObject->WritePkShort( (short int) strlen( comment ) );
mpArchiveStorageObject->WritePkShort( 1 );
mpArchiveStorageObject->WritePkShort( 0 ); //internal attributes
short int packed_attributes = entry.mpStorageObject->mAttributes.PackedAttributes();
long int external_attributes = 0;
if ( packed_attributes & ATTR_READ_ONLY )
external_attributes |= 1;
if ( packed_attributes & ATTR_SYSTEM )
external_attributes |= 4;
if ( packed_attributes & ATTR_HIDDEN )
external_attributes |= 2;
if ( packed_attributes & ATTR_ARCHIVE )
external_attributes |= 0x20;
if ( packed_attributes & ATTR_DIRECTORY )
external_attributes |= 0x10;
if ( packed_attributes & ATTR_LABEL )
external_attributes |= 0x08;
mpArchiveStorageObject->WritePkLong( external_attributes );
mpArchiveStorageObject->WritePkLong( entry.mlCompressedObjectPosition );
mpArchiveStorageObject->WriteBuffer( (unsigned char *) name, strlen( name ) );
mpArchiveStorageObject->WriteBuffer( (unsigned char * ) comment, strlen( comment ) );
}
//
// NAME
//
// ALPkGlArchive::PostWriteDir()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Write out the archive data that follows the directory.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "pkglarc.h"
//
// void ALPkGlArchive::PostWriteDir()
//
// C SYNOPSIS
//
// None, this is an internal function.
//
// VB SYNOPSIS
//
// None, this is an internal function.
//
// DELPHI SYNOPSIS
//
// None, this is an internal function.
//
// ARGUMENTS
//
// None.
//
// DESCRIPTION
//
// The base class, ALArchive, is responsible for all the work done when
// creating an archive. However, since Greenleaf and PKWare archives
// are fairly different, the base class relies on a few virtual functions
// to perform archive specific chores.
//
// PostWriteDir() is one of those functions. It is called after the
// directory entires for the archive have all been written out.
//
// PKWare archives have a special end of central directory record
// that needs to be added to the end of the archive. It has a fair
// amount of junk in it, but it is all pretty straightforward.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALPkArchive::PostWriteDir() /* Tag protected function */
{
//
// Now I'm going to write the end of central dir record
//
long size_of_cdir = mpArchiveStorageObject->Tell() - mlStartOfCentralDir;
mpArchiveStorageObject->WriteChar( 'P' );
mpArchiveStorageObject->WriteChar( 'K' );
mpArchiveStorageObject->WriteChar( 5 );
mpArchiveStorageObject->WriteChar( 6 );
mpArchiveStorageObject->WritePkShort( 0 ); //number of this disk
mpArchiveStorageObject->WritePkShort( 0 ); //number of disk w/central dir
mpArchiveStorageObject->WritePkShort( (short int) miCount );
mpArchiveStorageObject->WritePkShort( (short int) miCount );
mpArchiveStorageObject->WritePkLong( size_of_cdir );
mpArchiveStorageObject->WritePkLong( mlStartOfCentralDir );
const char *comment = mComment.GetSafeName();
mpArchiveStorageObject->WritePkShort( (short int) strlen( comment ) );
mpArchiveStorageObject->WriteBuffer( (unsigned char *) comment, strlen( comment ) );
}