Coercions.c

/*------------------------------------------------------------------------------
*
*  Apple Developer Technical Support
*
*  AppleEvent Coercion Handler and INIT sample
*
*  Program:    AECoercionINIT
*  File: Coercions.c -    C Source
*
*  by:   C.K. Haun <TR>
*
*  Copyright © 1991 Apple Computer, Inc.
*  All rights reserved.
*
*------------------------------------------------------------------------------
*   This file contains the actual coercion routines, which will be BlockMoved
*   into the System Heap and installed as System Level coercions
*   at INIT time
*------------------------------------------------------------------------------
*/
/* Our includes */
#include <Types.h>
#include <memory.h>
#include <Errors.h>
#include <AppleEvents.h> 
 
#define typeMyPString 'MPST'    
 
/* A structure I use in my Boolean to Char coercion */
struct myBtoCData {
    Handle falseString;
    Handle trueString;
};
typedef struct myBtoCData myBtoCData, *myBtoCDataPtr, **myBtoCDataHdl;
 
/* These first two routines coerce a PString to typeChar and back */
/* they work on a typeMyPString, which I made up for this example */
/* For this example, I created a typePString.  A typePString would be... */
/* descriptorType = 'MPST' 
dataHandle = (handle containing a Pascal-type string) */
pascal OSErr CoerceCharToPString(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result)
{
#pragma unused (refCon)
    OSErr myErr = noErr;
    Str255 theString;
    Size newSize;
    /* This check isn't really necessary, since the AEM won't call you  */
    /* if the data types don't match, but I wanted to used the parameters */
    /* see the Note at the end of this file for what you Can use these for */
    if ((origData == typeChar) && (toType == typeMyPString)) {
        /* first make sure the char block isn't over a PString size.  If it is, I'll */
        /* truncate it to a PString and continue */
        if (theSize > 255)
            newSize = 255;
        else
            newSize = theSize;
        theString[0] = newSize;
        /* Move what we were given into my string */
        BlockMove(inPtr, (Ptr)&theString[1], newSize);
        /* Make an AppleEvent descriptor out of it */
        myErr = AECreateDesc(typeMyPString, (Ptr)&theString[0], theString[0] + 1, result);
    } else {
        myErr = errAECoercionFail;
    }
    return(myErr);
}
 
pascal OSErr CoercePStringToChar(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result)
{
#pragma unused (origData,toType,refCon)
    OSErr myErr = noErr;
    /* This check isn't really necessary, since the AEM won't call you  */
    /* if the data types don't match, but I wanted to used the parameters */
    /* see the Note at the end of this file for what you Can use these for */
    if ((origData == typeMyPString) && (toType == typeChar)) {
        /* Don't have to worry about the size here, since a typeChar can be much larger */
        /* than a PString, just make the desriptor */
        myErr = AECreateDesc(typeChar, (Ptr)(inPtr + 1), theSize - 1, result);
    } else {
        myErr = errAECoercionFail;
    }
    return(myErr);
}
 
/*  CoerceBooleanToChar creates a desc that says True or False. */
/* nice for human (well, non-programmer) reading */
/* NOTE:  This coercion uses the refCon field to hold a handle */
pascal OSErr CoerceBooleanToChar(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result)
{
    
    OSErr myErr = noErr;
    /* Our string data is in our refCon, (see the Install routine) */
    /* so coerce it to something we can work with */
    myBtoCDataHdl myStrings = (myBtoCDataHdl)refCon;
    /* make sure everything is fine first */
    if (origData != typeBoolean || toType != typeChar) {
        /* something is goofy here */
        myErr = errAECoercionFail;
    } else {
        /* a boolean should be two bytes. if it isn't, I'm confused */
        if (theSize == sizeof(short)) {
            Ptr theText;
            short theBool = *((short *)inPtr);
            HLock((Handle)myStrings);
            /* I'm locking both of these even though I'll only use one */
            /* You can count cycles and see if doing two compares (before and after) */
            /* and one lock/unlock is faster, but I don't think it matters much */
            HLock((*myStrings)->falseString);
            HLock((*myStrings)->trueString);
            /* decide which string we're using */
            if (theBool)
                theText = *((*myStrings)->trueString);
            else
                theText = *((*myStrings)->falseString);
            /* And make a descriptor */
            myErr = AECreateDesc(typeChar, (theText + 1), *theText, result);
            HUnlock((*myStrings)->falseString);
            HUnlock((*myStrings)->trueString);
            HUnlock((Handle)myStrings);
        } else {
            myErr = errAECoercionFail;
        }
    }
    return(myErr);
}
 
 
 
/* Dummy is just a placemarker so I know where the end of  is.  I could  */
/* have done that a different way, but this left me some flexibility */
void Dummy(void)
{
}
 
/* ¥¥¥ Note:  The AEM always passes the fromType and toType to your coercion */
/* routines.  Why?  You know you're not going to be called if the types aren't */
/* correct, so why bother? */
/* THe reason is to allow you to put all your coercions in one big function. */
/* You can case off them, and do everything you want in one place, instead of */
/* in scattered routines. */
/* I am _not_ doing this in this example, because I'm grabbing memory from the  */
/* System heap to do this stuff, and the smaller I can keep the */
/* chuncks the more likely I am to get them low in the heap, and reduce fragmentation. */