1467 lines
42 KiB
C++
Executable File
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 ) );
|
|
}
|