/* 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: © 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 #include /*----------------------------------------------------------------------------------------------------------*/ /* | 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Ő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; } /*----------------------------------------------------------------------------------------------------------*/