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 ) );
 | |
| }
 |