1010 lines
26 KiB
C++
1010 lines
26 KiB
C++
|
//
|
||
|
// MEMSTD.CPP
|
||
|
//
|
||
|
// Source file for ArchiveLib 2.0
|
||
|
//
|
||
|
// Copyright (c) Greenleaf Software, Inc. 1994-1996
|
||
|
// All Rights Reserved
|
||
|
//
|
||
|
// CONTENTS
|
||
|
//
|
||
|
// ALMemory::operator new()
|
||
|
// ALMemory::ALMemory()
|
||
|
// newALMemory()
|
||
|
// ALMemory::~ALMemory()
|
||
|
// ALMemory::_LoadBuffer()
|
||
|
// ALMemory::Delete()
|
||
|
// ALMemory::GrowUserBuffer()
|
||
|
// ALMemory::_FlushBuffer()
|
||
|
// ALMemory::Close()
|
||
|
// ALMemory::Create()
|
||
|
// ALMemory::Open()
|
||
|
// ALMemory::Clone()
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// This file contains the C++ member functions to support class
|
||
|
// ALMemory. This class works very closely with the parent class,
|
||
|
// ALMemoryBase, found in MEMSTORE.CPP.
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// May 22, 1994 1.0A : First release
|
||
|
//
|
||
|
// July 7, 1994 1.0B : Had to make a lot of changes to support file
|
||
|
// management under UNIX.
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
#include "arclib.h"
|
||
|
#if !defined( AL_IBM )
|
||
|
#pragma hdrstop
|
||
|
#endif
|
||
|
|
||
|
#include "memstore.h"
|
||
|
|
||
|
#include <stdlib.h> // might be using malloc()!
|
||
|
|
||
|
const size_t max_alloc = (size_t) ~0;
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::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 "memstore.h"
|
||
|
//
|
||
|
// void * ALMemory::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 ALMemory 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.
|
||
|
//
|
||
|
// Incidentally, I suspect that this function never gets called. If an
|
||
|
// object of a derived archive class is being created, it should use
|
||
|
// its own new operator, rendering this one useless.
|
||
|
//
|
||
|
// 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
|
||
|
ALMemory::operator new( size_t size ) /* Tag internal function */
|
||
|
{
|
||
|
return ::new char[ size ];
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::ALMemory()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++ C VB Delphi
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Constructs a new ALMemory object.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// ALMemory::ALMemory( const char *buffer_name = "",
|
||
|
// char *user_buffer = 0 ,
|
||
|
// size_t user_buffer_size = 0,
|
||
|
// ALCase name_case = AL_MIXED );
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// hALStorage newALMemory( char *buffer_name,
|
||
|
// char *user_buffer,
|
||
|
// int user_buffer_size );
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// None, VB should use newALWinMemory();
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// None, Delphi should use newALWinMemory();
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// buffer_name : An arbitrary name assigned to the buffer. Buffer
|
||
|
// names don't have to be unique, because buffers aren't
|
||
|
// named at the operating system level. But if you are
|
||
|
// going to insert the storage object into an archive, the
|
||
|
// name needs to be unique so that you will be able to
|
||
|
// extract it properly.
|
||
|
//
|
||
|
// user_buffer : If you want the ALMemory class to automatically
|
||
|
// allocate a buffer for you, and grow it as necessary, just
|
||
|
// leave this pointer set to 0. If you want to use your own
|
||
|
// buffer, which won't have the ability to grow, pass a
|
||
|
// pointer to it in this parameter.
|
||
|
//
|
||
|
// user_buffer_size : If you are passing a pointer to your own buffer,
|
||
|
// you need to indicate how large it is here. Since
|
||
|
// we are dealing with standard buffers here, this is of
|
||
|
// type size_t.
|
||
|
//
|
||
|
// name_case : This decides whether you want the file name to be
|
||
|
// case sensitive when making comparisons. MS-DOS
|
||
|
// file names are case-insensitive. You can make memory
|
||
|
// buffers either mixed case, forced upper, or forced
|
||
|
// lower. The default of mixed case means that comparisons
|
||
|
// will be case sensitive, which is fine.
|
||
|
//
|
||
|
// Note that I don't even give the option of using name_case
|
||
|
// to C users. They are going to get the default
|
||
|
// value assigned to their OS/environment.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// This constructor calls the base class constructor in an initializer
|
||
|
// list, which takes care of most of the dirty work right away. After that
|
||
|
// is done, all the constructor has to do is initialize a few data members.
|
||
|
// That should be self-explanatory. Remember that if the user doesn't
|
||
|
// supply a buffer, we are going to allocate it for her, but not until
|
||
|
// there is actually a demand for memory.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// If memory allocation is being done dynamically, this function returns
|
||
|
// a pointer/handle to a new ALMemory object. If it is called as
|
||
|
// a static or automatic constructor (only possible in C++), it returns
|
||
|
// nothing.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// ALMemoryBase::ALMemoryBase(), ALStorage::ALStorage(),
|
||
|
// ALMemory::~ALMemory()
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
AL_PROTO
|
||
|
ALMemory::ALMemory( const char AL_DLL_FAR *buffer_name /* = "" */, /* Tag public function */
|
||
|
char AL_DLL_FAR *user_buffer /* = 0 */ ,
|
||
|
size_t user_buffer_size /* = 0 */,
|
||
|
ALCase name_case /* = AL_MIXED */ )
|
||
|
: ALMemoryBase( buffer_name, name_case )
|
||
|
{
|
||
|
if ( user_buffer != 0 ) {
|
||
|
mpcUserBuffer = user_buffer;
|
||
|
mfUserOwnsBuffer = 1;
|
||
|
mlUserBufferSize = user_buffer_size;
|
||
|
} else {
|
||
|
mfUserOwnsBuffer = 0;
|
||
|
mpcUserBuffer = 0;
|
||
|
mlUserBufferSize = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if !defined( AL_NO_C )
|
||
|
|
||
|
extern "C" AL_LINKAGE hALStorage AL_FUNCTION
|
||
|
newALMemory( char AL_DLL_FAR *buffer_name, /* Tag public function */
|
||
|
char AL_DLL_FAR *user_buffer,
|
||
|
size_t user_buffer_size )
|
||
|
{
|
||
|
if ( user_buffer_size == 0 )
|
||
|
return (hALStorage) new ALMemory( buffer_name );
|
||
|
else
|
||
|
return (hALStorage) new ALMemory( buffer_name,
|
||
|
user_buffer,
|
||
|
user_buffer_size );
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::~ALMemory()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Destroy an ALMemory object.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// ALMemory::~ALMemory();
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// None, use the base class destructor: deleteALStorage().
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// None, use the base class destructor: deleteALStorage().
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// None, use the base class destructor: deleteALStorage().
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// None, you don't get any for a destructor.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// The destructor has just one thing it has to do before this object
|
||
|
// goes away. If the buffer that it has been using all along doesn't
|
||
|
// belong to the user, then it is the class's responsibility to get
|
||
|
// rid of it. We do so here, using the standard version of free.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// Nothing.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// ALMemory::ALMemory()
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
AL_PROTO
|
||
|
ALMemory::~ALMemory() /* Tag public function */
|
||
|
{
|
||
|
AL_ASSERT( GoodTag(), "~ALMemory: attempting to delete invalid object" );
|
||
|
if ( !mfUserOwnsBuffer ) {
|
||
|
if ( mpcUserBuffer ) {
|
||
|
free( mpcUserBuffer );
|
||
|
mpcUserBuffer = 0;
|
||
|
}
|
||
|
}
|
||
|
AL_ASSERT( GoodTag(), "~ALMemory: attempting to delete invalid object" );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::_LoadBuffer()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Read memory from the big buffer into the local I/O buffer.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// void ALMemory::_LoadBuffer( long address );
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// None, internal protected function.
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// None, internal protected function.
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// None, internal protected functoin.
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// address : The offset in the memory object that is going to be
|
||
|
// loaded.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// External users of an ALStorage class perform all of their access via
|
||
|
// a local I/O buffer. Functions such as ReadChar() and WriteChar() look
|
||
|
// at a thing called mpcBuffer for their data. When reading from
|
||
|
// mpcBuffer, you are going to run out of data from time to time. When
|
||
|
// this happens, you will generate a call to the virtual function
|
||
|
// LoadBuffer().
|
||
|
//
|
||
|
// As it happens, all of the ALMemory objects share a common version
|
||
|
// of LoadBuffer(). LoadBuffer() still has to call something a little
|
||
|
// more specialized though, and that's where this version of _LoadBuffer()
|
||
|
// comes into play. It just performs a memcpy() routine to actually move
|
||
|
// data out of the big memory buffer and into the local I/O buffer
|
||
|
// used by ReadChar() et. al.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// Nothing.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
void AL_PROTO
|
||
|
ALMemory::_LoadBuffer( long address ) /* Tag protected function */
|
||
|
{
|
||
|
memcpy( mpcBuffer, mpcUserBuffer + (size_t) address, muBufferValidData );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::Delete()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Delete the underlying buffer for the memory object.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// int ALMemory::Delete();
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// None, C programs use the base class function deleteALStorage().
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// None, VB programs use the base class function deleteALStorage().
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// None, Delphi programs use the base class function deleteALStorage().
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// None.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// This function is analogous to the unlink() RTL function for files. It
|
||
|
// has to close the file, and get rid of its big buffer. This is fairly
|
||
|
// easy with memory buffers, we just call the appropriate version of
|
||
|
// free() to delete the buffer.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// Nothing.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// ALMemory::Create(), ALStorage::Delete()
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
int AL_PROTO
|
||
|
ALMemory::Delete() /* Tag public function */
|
||
|
{
|
||
|
if ( !mfUserOwnsBuffer ) {
|
||
|
free( mpcUserBuffer );
|
||
|
mpcUserBuffer = 0;
|
||
|
}
|
||
|
return AL_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::GrowUserBuffer()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Enlarge the user buffer.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// int ALMemory::GrowUserBuffer( long minimum_new_size );
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// None, this is an internal protected C++ function.
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// None, this is an internal protected C++ function.
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// None, this is an internal protected C++ function.
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// minimum_new_size : This is the size that the caller absolutely must
|
||
|
// have to successfully perform a write. Anything
|
||
|
// less than this won't do.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// Sometimes a write to a memory object goes past the current end of the
|
||
|
// buffer. When this happens, code in the base class calls this
|
||
|
// function to attempt to enlarge the buffer.
|
||
|
//
|
||
|
// Enlarging the buffer is tricky, because you have to allocate new space,
|
||
|
// then copy the old buffer into the new buffer. This means you
|
||
|
// temporarily need a boot-load of space. If you are lucky, the realloc()
|
||
|
// function might be able to attempt to avoid this situation.
|
||
|
//
|
||
|
// We try to enlarge things by a fixed amount, large enough to prevent
|
||
|
// thrashing. But if that doesn't fly, we can fall back and try to
|
||
|
// enlarge to the minimum acceptable size.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// AL_SUCCESS if all went well, some error code < AL_SUCCESS if not.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
int AL_PROTO
|
||
|
ALMemory::GrowUserBuffer( long minimum_new_size ) /* Tag protected function */
|
||
|
{
|
||
|
if ( mStatus < AL_SUCCESS )
|
||
|
return mStatus;
|
||
|
if ( mfUserOwnsBuffer )
|
||
|
return mStatus.SetError( AL_CANT_ALLOCATE_MEMORY,
|
||
|
"Attempt to write past the end of a "
|
||
|
"user owned buffer for ALMemory "
|
||
|
"%s",
|
||
|
mName.GetSafeName() );
|
||
|
if ( minimum_new_size >= max_alloc )
|
||
|
return mStatus.SetError( AL_CANT_ALLOCATE_MEMORY,
|
||
|
"Attempt to allocate a buffer "
|
||
|
"of %ld bytes for ALMemory "
|
||
|
"%s",
|
||
|
minimum_new_size,
|
||
|
mName.GetSafeName() );
|
||
|
long trial_size = mlUserBufferSize + 16384;
|
||
|
if ( trial_size >= max_alloc )
|
||
|
trial_size = max_alloc - 16;
|
||
|
if ( trial_size >= minimum_new_size ) {
|
||
|
char *new_buf = (char *) realloc( mpcUserBuffer, (size_t) trial_size );
|
||
|
if ( new_buf ) {
|
||
|
mpcUserBuffer = new_buf;
|
||
|
mlUserBufferSize = (size_t) trial_size;
|
||
|
return AL_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
char *new_buf = (char *) realloc( mpcUserBuffer, (size_t) minimum_new_size );
|
||
|
if ( new_buf ) {
|
||
|
mpcUserBuffer = new_buf;
|
||
|
mlUserBufferSize = (size_t) minimum_new_size;
|
||
|
return AL_SUCCESS;
|
||
|
}
|
||
|
return mStatus.SetError( AL_CANT_ALLOCATE_MEMORY,
|
||
|
"Allocation failure when attempting to "
|
||
|
"allocate a buffer "
|
||
|
"of %ld bytes for ALMemory "
|
||
|
"%s",
|
||
|
minimum_new_size,
|
||
|
mName.GetSafeName() );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::_FlushBuffer()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Flush data to the big buffer.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// void ALMemory::_FlushBuffer( long address )
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// None, internal protected C++ function.
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// None, internal protected C++ function.
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// None, internal protected C++ function.
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// address : The address in the big buffer where the flush should write
|
||
|
// to.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// When performing WriteChar() or WriteBuffer() operations, ALStorage
|
||
|
// causes output to be directed to a small I/O buffer. When this I/O
|
||
|
// buffer gets full, a call to ALFlushBuffer() is generated, which is
|
||
|
// supposed to dump that memory to a physical device.
|
||
|
//
|
||
|
// When ALMemoryBase gets a call to FlushBuffer(), it handles almost
|
||
|
// everything on its own. The one thing it can't handle, however, is
|
||
|
// the routine to copy the I/O buffer out to the big memory object.
|
||
|
// It has to really on this dinky virtual function to do the job.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// Nothing.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
void AL_PROTO
|
||
|
ALMemory::_FlushBuffer( long address ) /* Tag protected function */
|
||
|
{
|
||
|
memcpy( mpcUserBuffer + (size_t) address, mpcBuffer, muWriteIndex );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::Close()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Close an open memory buffer object
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// int ALMemory::Close()
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// C programs should use the base class function ALStorageClose().
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// VB programs should use the base class function ALStorageClose().
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// Delphi programs should use the base class function ALStorageClose().
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// None.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// Close() is supposed to do the same thing to a memory buffer as fclose()
|
||
|
// in the RTL does to a file. The most important thing we are concerned
|
||
|
// about is that the I/O buffer gets freed up by the base class, so this
|
||
|
// suddenly might not be a giant heavyweight object any more.
|
||
|
//
|
||
|
// After freeing things up in the base class, we check to see if
|
||
|
// we have allocated more space than we really need. If so, we do
|
||
|
// a realloc() of some sort to give space back to the O/S.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// Nothing.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// ALMemory::Open(), ALStorage::Close()
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
int AL_PROTO
|
||
|
ALMemory::Close() /* Tag public function */
|
||
|
{
|
||
|
ALMemoryBase::Close();
|
||
|
if ( mStatus < AL_SUCCESS )
|
||
|
return mStatus;
|
||
|
if ( ! mfUserOwnsBuffer ) {
|
||
|
if ( mlSize != 0 ) {
|
||
|
char *new_buf = (char *) realloc( mpcUserBuffer, (size_t) mlSize );
|
||
|
if ( new_buf ) {
|
||
|
mpcUserBuffer = new_buf;
|
||
|
mlUserBufferSize = mlSize;
|
||
|
}
|
||
|
} else {
|
||
|
free( mpcUserBuffer );
|
||
|
mpcUserBuffer = 0;
|
||
|
}
|
||
|
}
|
||
|
return AL_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::Create()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Create the memory storage object big buffer.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// int ALMemory::Create( long init_size );
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// C programs should use the base class function ALStorageCreate().
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// VB programs should use the base class function ALStorageCreate().
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// Delphi programs should use the base class function ALStorageCreate().
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// init_size : When you create an ALMemory object of any kind, you can
|
||
|
// write out data to it at your own pace, without having any
|
||
|
// idea how much space you will need. The storage object
|
||
|
// tries to increase its size every time you fill up
|
||
|
// the current huge buffer. Well, if you know in advance how
|
||
|
// much space you are going to need, you can allocate the
|
||
|
// whole buffer at once, and avoid all that extra work. So
|
||
|
// some calls to Create() now pass on an initial size using
|
||
|
// this argument.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// This is like creating a new file. If there isn't a memory buffer
|
||
|
// already assigned to this object, we create one, with an initial
|
||
|
// allocation of 16Kbytes, or more if requested.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// Either AL_SUCCESS, or an unfriendly error code.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// ALStorage::Create(), ALMemory::Open()
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
int AL_PROTO
|
||
|
ALMemory::Create( long init_size ) /* Tag public function */
|
||
|
{
|
||
|
ALMemoryBase::Create();
|
||
|
if ( mStatus < AL_SUCCESS )
|
||
|
return mStatus;
|
||
|
if ( mpcUserBuffer )
|
||
|
return AL_SUCCESS; //If a buffer was already created somewhere down the
|
||
|
//line, we won't do it again.
|
||
|
if ( init_size == -1L )
|
||
|
init_size = 16384;
|
||
|
if ( init_size > max_alloc )
|
||
|
return mStatus.SetError( AL_CANT_ALLOCATE_MEMORY,
|
||
|
"Allocation failure when attempting to "
|
||
|
"initialize a buffer "
|
||
|
"of %ld bytes for ALMemory "
|
||
|
"%s in _Create()",
|
||
|
init_size,
|
||
|
mName.GetSafeName() );
|
||
|
mpcUserBuffer = (char *) malloc( (size_t) init_size );
|
||
|
mlUserBufferSize = init_size;
|
||
|
if ( mpcUserBuffer == 0 )
|
||
|
return mStatus.SetError( AL_CANT_ALLOCATE_MEMORY,
|
||
|
"Allocation failure when attempting to "
|
||
|
"create a buffer "
|
||
|
"of %ld bytes for ALMemory "
|
||
|
"%s in _Create()",
|
||
|
mlUserBufferSize,
|
||
|
mName.GetSafeName() );
|
||
|
return AL_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::Open()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Open an existing memory storage object.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// int ALMemory::Open();
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// C programs should use the base class function ALStorageOpen().
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// VB programs should use the base class function ALStorageOpen().
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// Delphi programs should use the base class function ALStorageOpen().
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// None.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// This is like opening an existing file. Since there is supposed to be
|
||
|
// an existing memory buffer already, we gripe if we can't find one.
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// Either AL_SUCCESS, or an unfriendly error code.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// ALStorage::Open(), ALMemory::Create()
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
int AL_PROTO
|
||
|
ALMemory::Open() /* Tag public function */
|
||
|
{
|
||
|
ALMemoryBase::Open();
|
||
|
if ( mStatus < AL_SUCCESS )
|
||
|
return mStatus;
|
||
|
if ( mpcUserBuffer == 0 )
|
||
|
return mStatus.SetError( AL_CANT_OPEN_FILE,
|
||
|
"Attempt to open ALMemory %s "
|
||
|
"with no buffer allocated",
|
||
|
mName.GetSafeName() );
|
||
|
else
|
||
|
mlSize = mlUserBufferSize;
|
||
|
return AL_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NAME
|
||
|
//
|
||
|
// ALMemory::Clone()
|
||
|
//
|
||
|
// PLATFORMS/ENVIRONMENTS
|
||
|
//
|
||
|
// Console Windows PM
|
||
|
// C++
|
||
|
//
|
||
|
// SHORT DESCRIPTION
|
||
|
//
|
||
|
// Clone this memory based storage object.
|
||
|
//
|
||
|
// C++ SYNOPSIS
|
||
|
//
|
||
|
// #include "arclib.h"
|
||
|
// #include "memstore.h"
|
||
|
//
|
||
|
// ALStorage ALMemory::Clone( const char *name,
|
||
|
// int object_type ) const;
|
||
|
//
|
||
|
// C SYNOPSIS
|
||
|
//
|
||
|
// None, this is an internal C++ function
|
||
|
//
|
||
|
// VB SYNOPSIS
|
||
|
//
|
||
|
// None.
|
||
|
//
|
||
|
// DELPHI SYNOPSIS
|
||
|
//
|
||
|
// None.
|
||
|
//
|
||
|
// ARGUMENTS
|
||
|
//
|
||
|
// name : The desired name of the new object. Usually this will
|
||
|
// be a name found in an Archive directory.
|
||
|
//
|
||
|
// object_type : The type of object we want to create. Only
|
||
|
// AL_STORAGE_DEFAULT and AL_MEMORY_OBJECT will cause this
|
||
|
// function to succeed.
|
||
|
//
|
||
|
// DESCRIPTION
|
||
|
//
|
||
|
// The virtual Clone() function is used by archiving programs to act
|
||
|
// as a virtual constructor. When preparing to create storage objects
|
||
|
// based on the contents of an Archive directory, the archiving code can
|
||
|
// call Clone() for all the storage objects in its toolkit until it finds
|
||
|
// one that responds to its object type.
|
||
|
//
|
||
|
// For example, if an archive contained an AL_MEMORY object, and we were
|
||
|
// extracting, and an ALFile object was in the toolkit, it would call
|
||
|
// ALFile::Clone() from the toolkit object, with an object type of
|
||
|
// AL_MEMORY_OBJECT. This Clone() function would fail. Hopefully, there
|
||
|
// would be a memory based storage object in the toolkit that would
|
||
|
// respond properly to the Clone() call.
|
||
|
//
|
||
|
// Another object in the same archive might have an AL_FILE_OBJECT type.
|
||
|
// When the archiving code called Clone() again with that object type,
|
||
|
// we would successfully create the new File object in Clone().
|
||
|
//
|
||
|
// RETURNS
|
||
|
//
|
||
|
// Either a pointer to a newly constructed ALHugeMemory object, or a zero
|
||
|
// in case of error.
|
||
|
//
|
||
|
// EXAMPLE
|
||
|
//
|
||
|
// SEE ALSO
|
||
|
//
|
||
|
// REVISION HISTORY
|
||
|
//
|
||
|
// February 14, 1996 2.0A : New Release
|
||
|
//
|
||
|
|
||
|
ALStorage AL_DLL_FAR *
|
||
|
ALMemory::Clone( const char AL_DLL_FAR *name, /* Tag public function */
|
||
|
int object_type ) const
|
||
|
{
|
||
|
switch ( object_type ) {
|
||
|
case AL_STORAGE_DEFAULT :
|
||
|
case AL_MEMORY_OBJECT :
|
||
|
return new ALMemory( name );
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|