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

794 lines
21 KiB
C++
Executable File

//
// GLARC.CPP
//
// Source file for ArchiveLib 2.0
//
// Copyright (c) Greenleaf Software, Inc. 1994-1996
// All Rights Reserved
//
// CONTENTS
//
// ALGlArchive::operator new()
// ALGlArchive::ALGlArchive()
// newALGlArchiveFromStorage()
// ALGlArchive::~ALGlArchive()
// ALGlArchive::PreWriteDir()
// ALGlArchive::PostWriteDir()
// ALGlArchive::WriteDirEntry()
// ALGlArchive::ReadDirectory()
// ALGlArchive::PreCreate()
//
// DESCRIPTION
//
// This file contains all of the source code for the base class,
// ALGlArchive. The details on how things get inserted and extracted from an
// archive will all be found here.
//
// REVISION HISTORY
//
// May 23, 1994 1.0A : First release
//
// July 7, 1994 1.0B : Minor change to handle a snag with the sun
// compilers.
//
// February 14, 1996 2.0A : New Release
//
#include "arclib.h"
#if !defined( AL_IBM )
#pragma hdrstop
#endif
#include "glarc.h"
#include "_openf.h"
//
// NAME
//
// ALGlArchive::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 "glarc.h"
//
// void * ALGlArchive::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 ALGlArchive 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
// ALGlArchive 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
ALGlArchive::operator new( size_t size ) /* Tag internal function */
{
return ::new char[ size ];
}
#endif
//
// NAME
//
// ALGlArchive::ALGlArchive()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++ C VB Delphi
//
// SHORT DESCRIPTION
//
// The Greenleaf Archive constructors.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "glarc.h"
//
// ALGlArchive::ALGlArchive( ALStorage &storage_object );
//
// C SYNOPSIS
//
// #include "arclib.h"
// #include "glarc.h"
//
// hALArchive newALGlArchiveFromStorage( hALStorage storage );
//
// VB SYNOPSIS
//
// Declare Function newALGlArchiveFromStorage Lib "AL20LW"
// (ByVal storage&) As Long
//
// DELPHI SYNOPSIS
//
// function newALGlArchiveFromStorage( storage : hALStorage ) : hALArchive;
//
// ARGUMENTS
//
// storage_object : A pointer to the storage object that will/does
// hold the archive.
//
//
// DESCRIPTION
//
// This function creates a new ALGlArchive object, using a storage object
// as the underlying physical container. GlArchives are siblings to
// Pk 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.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
AL_PROTO
ALGlArchive::ALGlArchive( ALStorage AL_DLL_FAR &storage_object ) /* Tag public function */
: ALArchive( &storage_object, 0)
{
miVersion = 0x100;
}
#if !defined( AL_NO_C )
extern "C" AL_LINKAGE hALArchive AL_FUNCTION
newALGlArchiveFromStorage( hALStorage storage ) /* Tag public function */
{
AL_ASSERT( ( (ALStorage *) storage)->GoodTag(),
"storage argument is not a valid ALStorageObject" );
ALArchive *archive;
archive = new ALGlArchive( *(ALStorage *) storage );
return (hALArchive) archive;
}
#endif
//
// NAME
//
// ALGlArchive::~ALGlArchive()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Destructor for the Greenleaf Archive.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "glarc.h"
//
// ALGlArchive::~ALGlArchive()
//
// 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 ALGlArchive. 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
ALGlArchive::~ALGlArchive() /* Tag public function */
{
AL_ASSERT( GoodTag(), "~ALGlArchive(): Attempting to delete invalid ALGlArchive" );
}
//
// NAME
//
// ALGlArchive::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 ALGlArchive::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.
//
// Greenleaf archives store three items directly ahead of the
// directory: the archive version, any customized archive data, and
// the archive comment. This routine just writes all those out, then
// returns to the calling routine. The caller is presumably the
// write directory code in ALArchive, and it should continue by writing
// out all of its directory entries.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALGlArchive::PreWriteDir() /* Tag protected function */
{
mpArchiveStorageObject->WriteGlShort( miVersion );
WriteArchiveData();
mpArchiveStorageObject->WriteString( mComment );
}
//
// NAME
//
// ALGlArchive::PostWriteDir()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Write out the archive data that follows the directory.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "glarc.h"
//
// void ALGlArchive::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.
//
// Greenleaf archives store three items directly ahead of the
// directory: the archive version, any customized archive data, and
// the archive comment. This routine just writes all those out, then
// returns to the calling routine. The caller is presumably the
// write directory code in ALArchive, and it should continue by writing
// out all of its directory entries.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALGlArchive::PostWriteDir() /* Tag protected function */
{
long keeper = mpArchiveStorageObject->Tell();
mpArchiveStorageObject->WriteString( "" );
mpArchiveStorageObject->Seek( 0L );
mpArchiveStorageObject->WriteGlLong( mlDirectoryOffset );
mpArchiveStorageObject->Seek( keeper );
}
//
// NAME
//
// ALGlArchive::WriteDirEntry()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Write an individual object entry to the archive directory.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "glarc.h"
//
// void ALGlArchive::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
// Greenleaf archives use.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALGlArchive::WriteDirEntry( ALEntry AL_DLL_FAR &entry ) /* Tag protected function */
{
mpArchiveStorageObject->WriteString( entry.mpStorageObject->mName.GetSafeName() );
if ( entry.mpCompressor ) {
mpArchiveStorageObject->WriteChar( entry.mpCompressor->miCompressionType );
entry.mpCompressor->WriteEngineData( mpArchiveStorageObject );
} else if ( entry.mpDecompressor ) {
mpArchiveStorageObject->WriteChar( entry.mpDecompressor->miCompressionType );
entry.mpDecompressor->WriteEngineData( mpArchiveStorageObject );
} else {
mStatus.SetError( AL_UNKNOWN_COMPRESSION_TYPE,
"No compressor or decompressor for archive"
" entry %s",
entry.mpStorageObject->mName.GetSafeName() );
return;
}
mpArchiveStorageObject->WriteChar( entry.mpStorageObject->miStorageObjectType );
entry.mpStorageObject->WriteStorageObjectData( mpArchiveStorageObject );
mpArchiveStorageObject->WriteGlLong( entry.mpStorageObject->GetSize() );
mpArchiveStorageObject->WriteGlLong( entry.GetCompressedSize() );
mpArchiveStorageObject->WriteGlLong( entry.GetCrc32() );
mpArchiveStorageObject->WriteGlLong( entry.mlCompressedObjectPosition );
mpArchiveStorageObject->WriteString( entry.GetComment() );
mpArchiveStorageObject->WriteGlLong( entry.mpStorageObject->mTimeDate.GetUnixTime() );
mpArchiveStorageObject->WriteGlShort( entry.mpStorageObject->mAttributes.PackedAttributes() );
if ( mpArchiveStorageObject->mStatus < 0 )
mStatus = mpArchiveStorageObject->mStatus;
}
//
// NAME
//
// ALGlArchive::ReadDirectory()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Read in the directory for a GL format archive.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "glarc.h"
//
// int ALGlArchive::ReadDirectory( ALEntryList &list )
//
// C SYNOPSIS
//
// None, internal function.
//
// VB SYNOPSIS
//
// None, internal function.
//
// DELPHI SYNOPSIS
//
// None, internal function.
//
// ARGUMENTS
//
// list : An ALEntryList object that is going to receive all the
// new ALEntry objects created from reading the directory.
//
// DESCRIPTION
//
// 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 < AL_SUCCESS if things don't work.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
int AL_PROTO
ALGlArchive::ReadDirectory( ALEntryList AL_DLL_FAR &list ) /* Tag protected function */
{
list.mrMonitor.ArchiveOperation( AL_START_DIRECTORY_READ, this, 0 );
ALOpenInputFile archive( *mpArchiveStorageObject );
if ( mpArchiveStorageObject->mStatus < 0 )
return mStatus = mpArchiveStorageObject->mStatus;
//
// First I seek to the start of the directory (offset found at 0), and
// read in the version. This function only supports the directory
// structure defined in version 0x100.
//
mpArchiveStorageObject->Seek( 0 );
mpArchiveStorageObject->ReadGlLong( mlDirectoryOffset );
mpArchiveStorageObject->Seek( mlDirectoryOffset );
mpArchiveStorageObject->ReadGlShort( miVersion );
if ( miVersion != 0x100 )
return mStatus.SetError( AL_INVALID_ARCHIVE,
"%s is not a valid archive file",
mpArchiveStorageObject->mName.GetSafeName() );
//
// Read in any customized archive data defined by a derived class.
//
ReadArchiveData();
//
// Read in the comment, deleting the old one if necessary.
//
mpArchiveStorageObject->ReadString( mComment );
//
// 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 ( ; ; ) {
if ( mpArchiveStorageObject->mStatus < 0 )
return mStatus = mpArchiveStorageObject->mStatus;
ALName name;
mpArchiveStorageObject->ReadString( name );
//
// The directory ends with a blank name.
//
if ( strlen( name ) == 0 )
break;
//
// 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.
//
int engine_type = mpArchiveStorageObject->ReadChar();
ALCompressor *compressor = 0;
ALDecompressor *decompressor = list.mToolKit.CreateDecompressor( engine_type );
if ( decompressor )
decompressor->ReadEngineData( mpArchiveStorageObject );
else {
compressor = list.mToolKit.CreateCompressor( engine_type );
if ( compressor )
compressor->ReadEngineData( mpArchiveStorageObject );
else {
ALName temp;
mpArchiveStorageObject->ReadString( temp );
//
// I used to treat this as an error, now I don't. The error will come about
// when you actually try to decompress the object.
//
#if 0
return mStatus.SetError( AL_CANT_CREATE_ENGINE,
"Failure creating compression engine for object %s",
(const char *) name );
#endif
}
}
//
// 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.
//
int object_type = mpArchiveStorageObject->ReadChar();
ALStorage *storage_object = list.mToolKit.CreateStorageObject( name, object_type );
if ( storage_object )
storage_object->ReadStorageObjectData( mpArchiveStorageObject );
else {
ALName temp;
mpArchiveStorageObject->ReadString( temp );
//
// I used to treat this as an error, now I don't. The error will come about
// when you actually try to compress the object.
//
#if 0
return mStatus.SetError( AL_CANT_CREATE_STORAGE_OBJECT,
"Failure creating storage object for object %s",
(const char *) name );
#endif
}
//
// The rest of the stuff in the entry is pretty straightforward.
//
mpArchiveStorageObject->ReadGlLong( storage_object->mlSize );
ALEntry *job = new ALEntry( list, storage_object, compressor, decompressor );
mpArchiveStorageObject->ReadGlLong( job->mlCompressedSize );
mpArchiveStorageObject->ReadGlLong( job->mlCrc32 );
mpArchiveStorageObject->ReadGlLong( job->mlCompressedObjectPosition );
ALName comment;
mpArchiveStorageObject->ReadString( comment );
job->SetComment( comment );
long unix_time;
mpArchiveStorageObject->ReadGlLong( unix_time );
storage_object->mTimeDate.SetTimeDate( unix_time );
short int packed_attributes;
mpArchiveStorageObject->ReadGlShort( packed_attributes );
storage_object->mAttributes.SetFromPackedAttributes( packed_attributes );
}
list.mrMonitor.ArchiveOperation( AL_END_DIRECTORY_READ, this, 0 );
return mStatus;
}
//
// NAME
//
// ALEntryList::ClearError()
//
// PLATFORMS/ENVIRONMENTS
//
// Console Windows PM
// C++
//
// SHORT DESCRIPTION
//
// Reset the error status for an entry list.
//
// C++ SYNOPSIS
//
// #include "arclib.h"
// #include "glarc.h"
//
// void ALGlArchive::PreCreate()
//
// C SYNOPSIS
//
// None, internal support function.
//
// VB SYNOPSIS
//
// None, internal support function.
//
// DELPHI SYNOPSIS
//
// None, internal support function.
//
// ARGUMENTS
//
// None.
//
// DESCRIPTION
//
// The Create() function is found in the base class. It takes care of
// sticking a bunch of compressed objects into an archive. It gets
// ready to do this, then class this function first.
//
// Since this is a virtual function, the derived class can put any
// specialized behavior here. For Greenleaf archives, the only
// specialized behavior needed is to save enough space for a long
// in the file. After the archive is created, the long at offset 0
// will get a pointer to the start of the directory.
//
// RETURNS
//
// Nothing.
//
// EXAMPLE
//
// SEE ALSO
//
// REVISION HISTORY
//
// February 14, 1996 2.0A : New Release
//
void AL_PROTO
ALGlArchive::PreCreate() /* Tag protected function */
{
//
// The first four bytes in the archive are a long that points to the
// first byte of the directory. I don't know where the directory is
// going to be, so I just reserve space at this time with a dummy value.
//
mpArchiveStorageObject->WriteGlLong( 0x12345678L );
}