262 lines
7.2 KiB
C
Raw Normal View History

/*
File: puLowLevel.c
Contains: Low level C routines used by the main picture utilities package. This currently contains code
that is called by the built-in color finding methods (Popular and Median), but this will be
moved out later.
Written by: Dave Good. Some ideas stolen from Konstantin Othmer and Bruce Leak. Prototyped by Cris Rys.
Copyright: <EFBFBD> 1990 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<6> 9/21/90 DDG Made changes from code review. Now the buffering routines have a
complete interface (New, SetSize, and Kill). They also allocate
memory in the multifinder heap if they need to.
<5> 8/16/90 DDG Cleaned up the comments and moved FillMemoryBytes to assembly
(puLowLevel.a).
<4> 8/5/90 DDG Fixed a bug in GetBuffer, where it would allocate another buffer
over an existing one, if the buffer type was variable.
<3> 7/30/90 DDG Removed the color utility routine. Note that the built-in
colorPickProcs still use the buffering routines in this file.
<2> 7/29/90 DDG Fixed header.
<1> 7/29/90 DDG First checked in using new structure.
To Do:
*/
/*----------------------------------------------------------------------------------------------------------*/
/*
| Includes
*/
#include "puPrivate.h"
#include <GestaltEqu.h>
#include <Errors.h>
/*----------------------------------------------------------------------------------------------------------*/
/*
| Private Declarations
*/
OSErr CheckForTempMemory( void );
/*----------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------*/
/************************************************************************************************************/
/**** Functions Follow ****/
/************************************************************************************************************/
/*----------------------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine sets the buffer structure to its default values.
*/
void NewEmptyBuffer(
register Buffer *theBufferPtr )
{
theBufferPtr->ref = nil;
theBufferPtr->ptr = nil;
theBufferPtr->size = 0L;
}
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine allocates a new buffer in some heap. It calls SetBufferSize to do all the actual work.
*/
OSErr NewBuffer(
Buffer *theBufferPtr,
unsigned long requestedSize,
short requestedType )
{
NewEmptyBuffer(theBufferPtr);
return( SetBufferSize(theBufferPtr, requestedSize, requestedType) );
}
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine allocates a new clear buffer in some heap. It calls NewBuffer to do the allocation, then
| it clears the buffer that was allocated.
*/
OSErr NewBufferClear(
register Buffer *theBufferPtr,
unsigned long requestedSize,
short requestedType )
{
register OSErr error;
if( (error = NewBuffer(theBufferPtr, requestedSize, requestedType)) == 0 )
ClearMemoryBytes(theBufferPtr->ptr, theBufferPtr->size);
return error;
}
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine allocates a buffer in some heap. Buffers can be a fixed size or they can be variable, in
| which case, this routine picks a reasonable buffer size (half the free memory). Note that the buffer
| structure must already be setup when calling this routine.
*/
OSErr SetBufferSize(
register Buffer *theBufferPtr,
register unsigned long requestedSize,
register short requestedType )
{
OSErr error;
/*
| Check to see if there is already a buffer allocated. If there is then make sure that it is big enough. If it
| isn<EFBFBD>t, then kill the buffer and fall into the code that allocates a new one. If the buffer type is
| bufferVariableType and there is already a buffer allocated then just return noErr (use the buffer that is
| already there).
*/
if( theBufferPtr->ref )
{
if( (requestedType == bufferVariableType) || (theBufferPtr->size >= requestedSize) )
return noErr;
if( error = KillBuffer(theBufferPtr) )
return error;
}
/*
| If the buffer is fixed, then
*/
if( requestedType == bufferFixedType )
{
if( (error = CheckForTempMemory()) == 0 )
{
if( theBufferPtr->ref = MFTempNewHandle(requestedSize, &error) )
goto lockTheBuffer;
}
if( (theBufferPtr->ref = NewHandle(requestedSize)) == 0 )
return( MemError() );
}
else if( requestedType == bufferFixedLastingType )
{
if( theBufferPtr->ref = NewHandle(requestedSize) )
goto moveTheBuffer;
if( (error = CheckForTempMemory()) == 0 )
{
if( theBufferPtr->ref = MFTempNewHandle(requestedSize, &error) )
goto lockTheBuffer;
}
return( error );
}
else
{
register long sizeLeft;
long growSize;
if( (error = CheckForTempMemory()) == 0 )
{
sizeLeft = MFMaxMem(&growSize);
requestedSize = ( (sizeLeft >> 1) > 32000 ) ? 32000 : (short)(sizeLeft >> 1);
if( theBufferPtr->ref = MFTempNewHandle(requestedSize, &error) )
goto lockTheBuffer;
}
sizeLeft = MaxBlock();
requestedSize = ( (sizeLeft >> 1) > 32000 ) ? 32000 : (short)(sizeLeft >> 1);
if( (theBufferPtr->ref = NewHandle(requestedSize)) == 0 )
return( MemError() );
}
moveTheBuffer:
MoveHHi( (Handle)(theBufferPtr->ref) );
lockTheBuffer:
HLock( (Handle)(theBufferPtr->ref) );
theBufferPtr->ptr = *((Handle)(theBufferPtr->ref));
theBufferPtr->size = requestedSize;
return noErr;
}
static OSErr CheckForTempMemory( void )
{
#define hasOurTempMem ((1 << gestaltTempMemSupport) | (1 << gestaltRealTempMemory) | (1 << gestaltTempMemTracked))
register OSErr error;
long result;
if( error = Gestalt(gestaltOSAttr, &result) )
return( error );
if( (result & hasOurTempMem) == hasOurTempMem )
return( noErr );
return( memFullErr );
}
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine sets the size for an already existing buffer, and then clears the new buffer. It calls
| SetBufferSize to do all the actual work.
*/
OSErr SetBufferSizeClear(
register Buffer *theBufferPtr,
unsigned long requestedSize,
short requestedType )
{
register OSErr error;
if( (error = SetBufferSize(theBufferPtr, requestedSize, requestedType)) == 0 )
ClearMemoryBytes(theBufferPtr->ptr, theBufferPtr->size);
return error;
}
/*----------------------------------------------------------------------------------------------------------*/
/*
| This routine kills the memory for the passed buffer, no matter which heap it lives in.
*/
OSErr KillBuffer(
register Buffer *theBufferPtr )
{
register OSErr error;
DisposHandle( (Handle)(theBufferPtr->ref) );
if( error = MemError() )
return error;
NewEmptyBuffer(theBufferPtr);
return noErr;
}
/*----------------------------------------------------------------------------------------------------------*/