Source/MemoryHandler.c

//¥ ------------------------------------------------------------------------------------------  ¥
//¥
//¥ Copyright © 1996 Apple Computer, Inc., All Rights Reserved
//¥
//¥
//¥     You may incorporate this sample code into your applications without
//¥     restriction, though the sample code has been provided "AS IS" and the
//¥     responsibility for its operation is 100% yours.  However, what you are
//¥     not permitted to do is to redistribute the source as "DSC Sample Code"
//¥     after having made changes. If you're going to re-distribute the source,
//¥     we require that you make it clear in the source that the code was
//¥     descended from Apple Sample Code, but that you've made changes.
//¥
//¥     Authors:
//¥         Chris De Salvo
//¥
//¥ ------------------------------------------------------------------------------------------  ¥
 
/*
    These memory routines are kinda handy and solve a lot of problems on the Mac when dealing
    with memory.  For instance, people often call DisposeHandle() when they mean to call
    ReleaseResource() and it screws up their resource chain.  DisposeHandleZ() checks to see
    if the handle is locked or not, and whether it's a resource or not and takes the appropriate
    action.
    
    All functions ending in 'Z' take the ADDRESS of the Ptr/Handle and set it to nil when it
    disposes of the memory.  This is handy because you can then do things like this:
    
        foo = NewPtr();
        DisposePtrZ(&foo);
            ...
            ...
            
        if (foo)
            ...
    
    Probably the most useful of all this stuff are the tagged Ptr and tagged Handle functions.
    Basically what they do is add 12 bytes to the beginning of every block of memory that you
    allocate.  The first four bytes are the value kBlockTag.  The second is an OSType that
    you provide.  The 3rd group of four bytes is a refcon that you provide.  This is really
    usefull when working with ZoneRanger or other memory watching tool because when you view
    a block of memory you can see your type and refcon and get a clue as to what the memory
    is.  It's really great when you have a memory leak and can't tell what's not getting
    deallocated.  Another use is for tracking resources.  Pass in the resource type as the
    OSType field and the resource number in the refcon.  Then in ZoneRanger you can see
    exactly which resource and number a handle is.
    
    Another use is for reference counting list of similar objects.  If you allocate 200 foos
    then set the OSType to 'foo ' and make the refcon the index of which foo it is.  This is
    helpful for finding off-by-one loop errors when deallocating lists and arrays.
    
    One other thing that has come in really handy is to set the OSType to some identifier saying
    which source file the block was allocated in and setting the refcon to the line number in
    that source file.  That way in ZoneRanger you can tell exactly where that mystery block
    came from.
*/
 
//¥ ------------------------------  Includes
 
#include <Resources.h>
 
#include <string.h>
 
#include "MemoryHandler.h"
 
//¥ ------------------------------  Private Definitions
 
#define kBlockTag                   "TBLK"
 
//¥ ------------------------------  Private Types
//¥ ------------------------------  Private Variables
//¥ ------------------------------  Private Functions
//¥ ------------------------------  Public Variables
 
//¥ --------------------    IsResourceHandle
 
Boolean
IsResourceHandle(Handle theHandle)
{
SInt8   memState;
 
    memState = HGetState(theHandle);
    
    //¥ Check the resource bit in the handle info
    if (memState & 0x20)
        return (true);
        
    return (false);
}
//¥ --------------------    IsLockedHandle
 
Boolean
IsLockedHandle(Handle theHandle)
{
SInt8   memState;
 
    //¥ Check the lock bit in the handle info
    memState = HGetState(theHandle);
    
    if (memState & 0x80)
        return (true);
        
    return (false);
}
 
//¥ --------------------    DisposeControlZ
 
void
DisposeControlZ(ControlHandle *theControl)
{
    if (! (**theControl))
        return;
 
    if (IsLockedHandle((Handle) *theControl))
        HUnlock((Handle) *theControl);
 
    DisposeControl(*theControl);
    *theControl = nil;
}
 
//¥ --------------------    DisposeWindowZ
 
void
DisposeWindowZ(WindowRef *theWindow)
{
    if (! *theWindow)
        return;
 
    DisposeWindow(*theWindow);
    *theWindow = nil;
}
 
//¥ --------------------    DisposeDialogZ
 
void
DisposeDialogZ(DialogPtr *theWindow)
{
    if (! *theWindow)
        return;
 
    DisposeDialog(*theWindow);
    *theWindow = nil;
}
 
//¥ --------------------    DisposeGWorldZ
 
void
DisposeGWorldZ(GWorldPtr *theGWorld)
{
    if (! *theGWorld)
        return;
 
    if (IsLockedHandle((Handle) GetGWorldPixMap(*theGWorld)))
        UnlockPixels(GetGWorldPixMap(*theGWorld));
        
    DisposeGWorld(*theGWorld);
    *theGWorld = nil;
}
 
//¥ --------------------    DisposePaletteZ
 
void
DisposePaletteZ(PaletteHandle *thePal)
{
    if (! *thePal)
        return;
 
    if (IsResourceHandle((Handle) *thePal))
        ReleaseResource((Handle) *thePal);
    else
        DisposePalette(*thePal);
        
    *thePal = nil;
}
 
//¥ --------------------    KillPictureZ
 
void
KillPictureZ(PicHandle *thePicture)
{
    if (! (**thePicture))
        return;
 
    if (IsLockedHandle((Handle) *thePicture))
        HUnlock((Handle) *thePicture);
 
    if (IsResourceHandle((Handle) *thePicture))
        ReleaseResource((Handle) *thePicture);
    else
        KillPicture(*thePicture);
        
    *thePicture = nil;
}
 
//¥ --------------------    DisposePtrZ
 
void
DisposePtrZ(Ptr *thePtr)
{
    if (! *thePtr)
        return;
 
    DisposePtr(*thePtr);
    *thePtr = nil;
}
 
//¥ --------------------    DisposeHandleZ
 
void
DisposeHandleZ(Handle *theHandle)
{
    if (! (**theHandle))
        return;
 
    if (IsLockedHandle(*theHandle))
        HUnlock(*theHandle);
        
    if (IsResourceHandle(*theHandle))
        ReleaseResource(*theHandle);
    else
        DisposeHandle(*theHandle);
        
    *theHandle = nil;
}
 
//¥ --------------------    TEDisposeZ
 
void
TEDisposeZ(TEHandle *theHandle)
{
    if (! (**theHandle))
        return;
 
    if (IsLockedHandle((Handle) *theHandle))
        HUnlock((Handle) *theHandle);
        
    if (IsResourceHandle((Handle) *theHandle))
        ReleaseResource((Handle) *theHandle);
    else
        TEDispose(*theHandle);
}
 
//¥ --------------------    LDisposeZ
 
void
LDisposeZ(ListHandle *theHandle)
{
    if (! (**theHandle))
        return;
 
    if (IsLockedHandle((Handle) *theHandle))
        HUnlock((Handle) *theHandle);
        
    if (IsResourceHandle((Handle) *theHandle))
        ReleaseResource((Handle) *theHandle);
    else
        LDispose(*theHandle);
}
 
//¥ --------------------    PurgeAndCompactMem
 
void
PurgeAndCompactMem()
{
Size    growSize;
 
    MaxMem(&growSize);
}
 
//¥ --------------------    NewTaggedPtr
 
Ptr
NewTaggedPtr(Size size, OSType tag, UInt32 refCon)
{
Ptr thePtr;
 
    size += 12;
 
    thePtr = NewPtr(size);
    if (! thePtr)
        return (nil);
 
    BlockMoveData(kBlockTag, thePtr, 4);
    BlockMoveData(&tag, thePtr + 4, 4);
    BlockMoveData(&refCon, thePtr + 8, 4);
    
    return (thePtr + 12);
}
 
//¥ --------------------    NewTaggedPtrClear
 
Ptr
NewTaggedPtrClear(Size size, OSType tag, UInt32 refCon)
{
Ptr thePtr;
 
    size += 12;
 
    thePtr = NewPtrClear(size);
    if (! thePtr)
        return (nil);
 
    BlockMoveData(kBlockTag, thePtr, 4);
    BlockMoveData(&tag, thePtr + 4, 4);
    BlockMoveData(&refCon, thePtr + 8, 4);
    
    return (thePtr + 12);
}
 
//¥ --------------------    DisposeTaggedPtr
 
void
DisposeTaggedPtr(Ptr thePtr)
{
Ptr ptr2;
 
    if (! thePtr)
        return;
 
    ptr2 = thePtr - 12;
    
    //¥ Confirm that this is one of our tagged blocks first
    if (strncmp(kBlockTag, ptr2, 4) == 0)
        DisposePtr(ptr2);
    else
        DisposePtr(thePtr);
}
 
//¥ --------------------    DisposeTaggedPtrZ
 
void
DisposeTaggedPtrZ(Ptr *thePtr)
{
Ptr ptr2;
 
    if (! *thePtr)
        return;
 
    ptr2 = (*thePtr) - 12;
    if (strncmp(kBlockTag, ptr2, 4) == 0)
        DisposePtr(ptr2);
    else
        DisposePtr(*thePtr);
        
    *thePtr = nil;
}