SafeNameRegistry.c

/*
    File:       SafeNameRegistry.c
 
    Contains:   Stub routines for name registry calls
 
    Written by: G. Poon
 
    Copyright:  © 1998 by Apple Computer, Inc., all rights reserved.
 
    Change History:
 
        25 Mar 98   gp      Added calls to create and remove name registry proc ptrs
        18 Mar 98   gp      Created
 
    To Do:
*/
 
#ifndef __CODEFRAGMENTS__
#include <CodeFragments.h>
#endif
 
#ifndef __MIXEDMODE__
#include <MixedMode.h>
#endif
 
#ifndef __GESTALT__
#include <Gestalt.h>
#endif
 
#ifndef __ERRORS__
#include <Errors.h>
#endif
 
#ifndef __DIALOGS__
#include <Dialogs.h>
#endif
 
#ifndef __SafeNameRegistry__
#include "SafeNameRegistry.h"
#endif
 
/******************************************************************************
    Prototypes
 ******************************************************************************/
 
// prototypes used to find address of routine in name registry library
OSErr Find_Symbol(Ptr* pSymAddr, Str255 pSymName, ProcInfoType pProcInfo);
pascal OSErr GetSystemArchitecture(OSType *archType);
 
/******************************************************************************
    Typedefs
 ******************************************************************************/
 
// proc typedefs for calling routines in the name registry library
typedef pascal OSStatus (*RegistryEntryIDInitProcPtr) ( RegEntryID* id );
typedef pascal OSStatus (*RegistryCStrEntryLookupProcPtr) ( RegEntryID* searchPointID, 
            RegCStrPathName* pathName, RegEntryID*foundEntry );
typedef pascal OSStatus (*RegistryEntryIterateCreateProcPtr) ( RegEntryIter* cookie );
typedef pascal OSStatus (*RegistryEntryIterateDisposeProcPtr) ( RegEntryIter* cookie );
typedef pascal OSStatus (*RegistryEntryIterateSetProcPtr) ( RegEntryIter* cookie, RegEntryID *startEntryID );
typedef pascal OSStatus (*RegistryEntryIterateProcPtr) ( RegEntryIter *cookie, 
            RegEntryIterationOp relationship, RegEntryID *foundEntry, Boolean *done );
typedef pascal OSStatus (*RegistryEntryIDDisposeProcPtr) ( RegEntryID* id );
typedef pascal OSStatus (*RegistryPropertyGetProcPtr) ( RegEntryID *entryID, 
            RegPropertyName *propertyName, void *propertyValue, RegPropertyValueSize *propertySize );
 
/******************************************************************************
    Constants
 ******************************************************************************/
 
#define kNoNameRegistryAlert        3000
 
// stack descriptors used in the name registry stub calls to pass params
// to the proper routine in the name registry shared library
 
enum {
    kRegistryEntryIDInitProcInfo = kPascalStackBased
    | RESULT_SIZE( SIZE_CODE(sizeof(OSStatus)))
    | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof( RegEntryID*)))
};
enum {
    kRegistryCStrEntryLookupProcInfo = kPascalStackBased
    | RESULT_SIZE( SIZE_CODE(sizeof(OSStatus)))
    | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof( RegEntryID*)))
    | STACK_ROUTINE_PARAMETER( 2, SIZE_CODE(sizeof( RegCStrPathName*)))
    | STACK_ROUTINE_PARAMETER( 3, SIZE_CODE(sizeof( RegEntryID*)))
};
enum {
    kRegistryEntryIterateCreateProcInfo = kPascalStackBased
    | RESULT_SIZE( SIZE_CODE(sizeof(OSStatus)))
    | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof( RegEntryIter*)))
};
enum {
    kRegistryEntryIterateDisposeProcInfo = kPascalStackBased
    | RESULT_SIZE( SIZE_CODE(sizeof(OSStatus)))
    | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof( RegEntryIter*)))
};
enum {
    kRegistryEntryIterateSetProcInfo = kPascalStackBased
    | RESULT_SIZE( SIZE_CODE(sizeof(OSStatus)))
    | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof( RegEntryIter*)))
    | STACK_ROUTINE_PARAMETER( 2, SIZE_CODE(sizeof( RegEntryID*)))
};
enum {
    kRegistryEntryIterateProcInfo = kPascalStackBased
    | RESULT_SIZE( SIZE_CODE(sizeof(OSStatus)))
    | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof( RegEntryIter*)))
    | STACK_ROUTINE_PARAMETER( 2, SIZE_CODE(sizeof( RegEntryIterationOp)))
    | STACK_ROUTINE_PARAMETER( 3, SIZE_CODE(sizeof( RegEntryID*)))
    | STACK_ROUTINE_PARAMETER( 4, SIZE_CODE(sizeof( Boolean*)))
};
enum {
    kRegistryEntryIDDisposeProcInfo = kPascalStackBased
    | RESULT_SIZE( SIZE_CODE(sizeof(OSStatus)))
    | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof( RegEntryID*)))
};
enum {
    kRegistryPropertyGetProcInfo = kPascalStackBased
    | RESULT_SIZE( SIZE_CODE(sizeof(OSStatus)))
    | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE(sizeof( RegEntryID*)))
    | STACK_ROUTINE_PARAMETER( 2, SIZE_CODE(sizeof( RegPropertyName*)))
    | STACK_ROUTINE_PARAMETER( 3, SIZE_CODE(sizeof( void*)))
    | STACK_ROUTINE_PARAMETER( 4, SIZE_CODE(sizeof( RegPropertyValueSize*)))
};
 
typedef struct
{
// address of name registry routines
    ProcPtr     RegistryEntryIDInitAddr;
    ProcPtr     RegistryCStrEntryLookupAddr;
    ProcPtr     RegistryEntryIterateCreateAddr;
    ProcPtr     RegistryEntryIterateDisposeAddr;
    ProcPtr     RegistryEntryIterateSetAddr;
    ProcPtr     RegistryEntryIterateAddr;   
    ProcPtr     RegistryEntryIDDisposeAddr; 
    ProcPtr     RegistryPropertyGetAddr;
 
    Boolean     hasNameRegistry;            // does this cpu have a name registry
    Boolean     checkedForNameRegistry;     // did we check for the name registry already
 
    short       numberOfPrinters;           // total number of printers listed
    short       numberOfUSBPrinters;        // total number of USB printers
    short       numberOfPorts;              // total number of serial ports on this cpu
 
    Boolean     supportsSerial;             // do we support serial
    Boolean     supportsUSB;                // do we support USB
// holds index into our STR# rsrc (name registry model path) for each entry in the printer list
    short*      modelIndex;
} USBGlobals;
 
USBGlobals  gGlobals;
/*-----------------------------------------------------------------------------*
 
    NameRegistryInstalled
    
    Desc:       Test to see if the name registry exists on this machine
 
    In:         None
 
    Out:        True if name registry exists else false
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
Boolean NameRegistryInstalled( void )
{
    OSErr   err=noErr;      // result from gestalt call
    long    result;
    // if not our first time then return previous result
    if( gGlobals.checkedForNameRegistry == true )
        return gGlobals.hasNameRegistry;
    else {
 
    // check to see if name registry exists
        err = Gestalt(gestaltNameRegistryVersion, &result);
        if( err == noErr )
            gGlobals.hasNameRegistry = true;
        else {
            gGlobals.hasNameRegistry = false;
    // put up alert if it isn't installed
            StopAlert(kNoNameRegistryAlert, nil);
        }
        gGlobals.checkedForNameRegistry=true;
    }
    return gGlobals.hasNameRegistry;
}
 
/*-----------------------------------------------------------------------------*
 
    SafeRegistryEntryIDInit
    
    Desc:       Stub code for name registry routine 'RegistryEntryIDInit'
 
    In:         id - pointer to a RegEntryID to initialize
 
    Out:        returns any errors which may have occur
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
 
OSStatus SafeRegistryEntryIDInit(RegEntryID *id)
{
    OSStatus    anErr=-1;               // return value
 
    if( (Ptr) gGlobals.RegistryEntryIDInitAddr != (Ptr) nil )
        anErr = ((RegistryEntryIDInitProcPtr) gGlobals.RegistryEntryIDInitAddr) (id);
    return anErr;
}
 
/*-----------------------------------------------------------------------------*
 
    SafeRegistryCStrEntryLookup
    
    Desc:       Stub code for name registry routine 'RegistryCStrEntryLookup'
 
    In:         searchPointID - the RegEntryID to start searching from
                pathName - the cstring path of the entry to find
                foundEntry - where to store the found entry
 
    Out:        foundEntry - the RegEntryID of any found entry
                returns any errors which may have occur
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
OSStatus SafeRegistryCStrEntryLookup( RegEntryID *searchPointID, RegCStrPathName *pathName, RegEntryID *foundEntry)
{
    OSStatus    anErr=-1;               // return value
    // now call it
    if( (Ptr) gGlobals.RegistryCStrEntryLookupAddr != (Ptr) nil )
        anErr = ((RegistryCStrEntryLookupProcPtr) gGlobals.RegistryCStrEntryLookupAddr) (searchPointID, pathName, foundEntry);
    return anErr;
}
 
/*-----------------------------------------------------------------------------*
 
    SafeRegistryEntryIterateCreate
    
    Desc:       Stub code for name registry routine 'RegistryEntryIterateCreate'
 
    In:         id - pointer to a RegEntryIter to initialize
 
    Out:        returns any errors which may have occur
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
OSStatus SafeRegistryEntryIterateCreate(RegEntryIter *cookie)
{
    OSStatus    anErr=-1;               // return value
    if( (Ptr) gGlobals.RegistryEntryIterateCreateAddr != (Ptr) nil )
        anErr = ((RegistryEntryIterateCreateProcPtr) gGlobals.RegistryEntryIterateCreateAddr) (cookie);
    return anErr;
}
 
/*-----------------------------------------------------------------------------*
 
    SafeRegistryEntryIterateDispose
    
    Desc:       Stub code for name registry routine 'RegistryEntryIterateDispose'
 
    In:         cookie - iterator to dispose
 
    Out:        returns any errors which may have occur
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
OSStatus SafeRegistryEntryIterateDispose(RegEntryIter *cookie)
{
    OSStatus    anErr=-1;               // return value
    if( (Ptr) gGlobals.RegistryEntryIterateDisposeAddr != (Ptr) nil )
        anErr = ((RegistryEntryIterateDisposeProcPtr) gGlobals.RegistryEntryIterateDisposeAddr) (cookie);
    return anErr;
}
 
/*-----------------------------------------------------------------------------*
 
    SafeRegistryEntryIterateSet
    
    Desc:       Stub code for name registry routine 'RegistryEntryIterateSet'
 
    In:         cookie - pointer to iterator to set
                startEntryID - name registry entry to start iterating from
 
    Out:        returns any errors which may have occur
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
OSStatus SafeRegistryEntryIterateSet(RegEntryIter *cookie, RegEntryID *startEntryID)
{
    OSStatus    anErr=-1;               // return value
    if( (Ptr) gGlobals.RegistryEntryIterateSetAddr != (Ptr) nil )
        anErr = ((RegistryEntryIterateSetProcPtr) gGlobals.RegistryEntryIterateSetAddr) (cookie, startEntryID);
    return anErr;
}
 
/*-----------------------------------------------------------------------------*
 
    SafeRegistryEntryIterate
    
    Desc:       Stub code for name registry routine 'RegistryEntryIterate'
 
    In:         cookie - iterator to use
                relationship - direction to iterate
                foundEntry - where to store next name entry found
                done - tells if we're done with iteration
 
    Out:        foundEntry - RegEntryID of name entry found
                done - true if no more entries found
                returns any errors which may have occur
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
OSStatus SafeRegistryEntryIterate(RegEntryIter *cookie, RegEntryIterationOp relationship, 
        RegEntryID *foundEntry, Boolean *done)
{
    OSStatus    anErr=-1;               // return value
    if( (Ptr) gGlobals.RegistryEntryIterateAddr != (Ptr) nil )
        anErr = ((RegistryEntryIterateProcPtr) gGlobals.RegistryEntryIterateAddr) (cookie, relationship, foundEntry, done);
    return anErr;
}
 
/*-----------------------------------------------------------------------------*
 
    SafeRegistryEntryIDDispose
    
    Desc:       Stub code for name registry routine 'RegistryEntryIDDispose'
 
    In:         id - RegEntryID to dispose
 
    Out:        returns any errors which may have occur
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
OSStatus SafeRegistryEntryIDDispose(RegEntryID *id)
{
    OSStatus    anErr=-1;               // return value
    if( (Ptr) gGlobals.RegistryEntryIDDisposeAddr != (Ptr) nil )
        anErr = ((RegistryEntryIDDisposeProcPtr) gGlobals.RegistryEntryIDDisposeAddr) (id);
    return anErr;
}
 
/*-----------------------------------------------------------------------------*
 
    SafeRegistryPropertyGet
    
    Desc:       Stub code for name registry routine 'RegistryPropertyGet'
 
    In:         entryID - RegEntryID value that identifies a name entry
                propertyName - name of the property
                propertyValue - buffer to hold the property
                propertySize - size of the property buffer
 
    Out:        propertySize - size of the property retrieved
                returns any errors which may have occur
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
OSStatus SafeRegistryPropertyGet( RegEntryID *entryID, RegPropertyName *propertyName, 
        void *propertyValue, RegPropertyValueSize *propertySize)
{
    OSStatus    anErr=-1;               // return value
    if( (Ptr) gGlobals.RegistryPropertyGetAddr != (Ptr) nil )
        anErr = ((RegistryPropertyGetProcPtr) gGlobals.RegistryPropertyGetAddr) (entryID, propertyName, propertyValue, propertySize);
    return anErr;
}
 
/*-----------------------------------------------------------------------------*
 
    GetSystemArchitecture
    
    Desc:       Taken from 
                DTS Technote 1077 "Calling CFM Code from Classic 68K Code".
                Returns architect of current cpu during runtime.
 
 
    In:         archType - address of variable to hold architect type
 
    Out:        archType - returns architect of current cpu pointed by this variable
                Also returns any errors
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
 
pascal OSErr GetSystemArchitecture(OSType *archType)
{
    long sSysArchitecture = 0; // static so we only Gestalt once.
    OSErr tOSErr = noErr;
    
    *archType = kAnyCFragArch;   // assume wild architecture
    
    // If we don't know the system architecture yet...
    if (sSysArchitecture == 0)
        // ...Ask Gestalt what kind of machine we are running on.
        tOSErr = Gestalt(gestaltSysArchitecture, &sSysArchitecture);
    
    if (tOSErr == noErr) // if no errors
    {
        if (sSysArchitecture == gestalt68k)   // 68k?
            *archType = kMotorola68KCFragArch;   
        else if (sSysArchitecture == gestaltPowerPC) // PPC?
            *archType = kPowerPCCFragArch;       
        else
            tOSErr = gestaltUnknownErr;  // who knows what might be next?
    }
    return tOSErr;
}
 
/*-----------------------------------------------------------------------------*
 
    Find_Symbol
    
    Desc:       Taken from 
                DTS Technote 1077 "Calling CFM Code from Classic 68K Code".
                Returns the address of a routine in a shared library
 
    In:         pSymAddr - address of variable to hold returned address
                pSymName - a pstring of the name of the routine
                pProcInfo - stack descriptor for the routine
 
    Out:        pSymAddr - the address of the routine pointed by this variable
                Also returns any errors
    
    History:
 
    18 Mar 98   gp      Added.
    
*-----------------------------------------------------------------------------*/
 
OSErr Find_Symbol(Ptr* pSymAddr, Str255 pSymName, ProcInfoType pProcInfo)
{
    CFragConnectionID sCID = 0;
    OSType sArchType = kAnyCFragArch;
    OSErr sOSErr = noErr;
    Str255 errMessage;
    Ptr mainAddr;
    CFragSymbolClass symClass;
          ISAType tISAType;
          
    ProcInfoType used = pProcInfo;  // compiler warning
    
    if( NameRegistryInstalled() == false )
        return -1;          // return general error - gp
    
    if (sArchType == kAnyCFragArch)  // if architecture is undefined...
    {
        sCID = 0;     // ...force (re)connect to library
        sOSErr = GetSystemArchitecture(&sArchType); // determine architecture
        if (sOSErr != noErr)
            return sOSErr; // OOPS!
    }
    
    if (sArchType == kMotorola68KCFragArch) // ...for CFM68K
          tISAType = kM68kISA | kCFM68kRTA;
    else if (sArchType == kPowerPCCFragArch)  // ...for PPC CFM
          tISAType = kPowerPCISA | kPowerPCRTA;
    else
        sOSErr = gestaltUnknownErr; // who knows what might be next?
    
    if (sCID == 0) // If we haven't connected to the library yet...
    {
        // NOTE: The library name is hard coded here.
        // I try to isolate the glue code, one file per library.
        // I have had developers pass in the Library name to allow
        // plug-in type support. Additional code has to be added to
        // each entry points glue routine to support multiple or
        // switching connection IDs.
        sOSErr = GetSharedLibrary("\pNameRegistryLib", sArchType, kLoadCFrag,
                &sCID, &mainAddr, errMessage);
        if (sOSErr != noErr)
            return sOSErr; // OOPS!
    }
    
    // If we haven't looked up this symbol yet...
    if ((Ptr) *pSymAddr == (Ptr) kUnresolvedCFragSymbolAddress)    
    {
        // ...look it up now
        sOSErr = FindSymbol(sCID,pSymName,pSymAddr,&symClass);
        if (sOSErr != noErr) {// in case of error...
         // ...clear the procedure pointer
             *(Ptr*) &pSymAddr = (Ptr) kUnresolvedCFragSymbolAddress;
        }
        #if !GENERATINGCFM // if this is classic 68k code...
         *pSymAddr = (Ptr)NewRoutineDescriptorTrap((ProcPtr) *pSymAddr,
                      pProcInfo, tISAType);  // ...create a routine descriptor...
        #endif
    }
    return sOSErr;
}
 
/*-----------------------------------------------------------------------------*
 
    InitNameRegistryPtrs
    
    Desc:       Create all the proc ptrs to Name Registry calls we will
                need
 
    In:         None
 
    Out:        None
    
    History:
 
    25 Mar 98   gp      Created
    
*-----------------------------------------------------------------------------*/
void    InitNameRegistryPtrs( void )
{
    OSStatus    anErr=noErr;                // error code for Find_Symbol and name registry call
 
    if( NameRegistryInstalled() == true) {
        anErr = Find_Symbol( (Ptr*) &gGlobals.RegistryEntryIDInitAddr, 
                "\pRegistryEntryIDInit", kRegistryEntryIDInitProcInfo );
        anErr = Find_Symbol( (Ptr*) &gGlobals.RegistryCStrEntryLookupAddr, 
                "\pRegistryCStrEntryLookup", kRegistryCStrEntryLookupProcInfo );
        anErr = Find_Symbol( (Ptr*) &gGlobals.RegistryEntryIterateCreateAddr, 
                "\pRegistryEntryIterateCreate", kRegistryEntryIterateCreateProcInfo );
        anErr = Find_Symbol( (Ptr*) &gGlobals.RegistryEntryIterateDisposeAddr, 
                "\pRegistryEntryIterateDispose", kRegistryEntryIterateDisposeProcInfo );
        anErr = Find_Symbol( (Ptr*) &gGlobals.RegistryEntryIterateSetAddr, 
                "\pRegistryEntryIterateSet", kRegistryEntryIterateSetProcInfo );
        anErr = Find_Symbol( (Ptr*) &gGlobals.RegistryEntryIterateAddr, 
                "\pRegistryEntryIterate", kRegistryEntryIterateProcInfo );
        anErr = Find_Symbol( (Ptr*) &gGlobals.RegistryEntryIDDisposeAddr, 
                "\pRegistryEntryIDDispose", kRegistryEntryIDDisposeProcInfo );
        anErr = Find_Symbol( (Ptr*) &gGlobals.RegistryPropertyGetAddr, 
                "\pRegistryPropertyGet", kRegistryPropertyGetProcInfo );
    }
}
 
/*-----------------------------------------------------------------------------*
 
    RemoveNameRegistryPtrs
    
    Desc:       Remove all the proc ptrs we created for Name Registry calls
 
    In:         None
 
    Out:        None
    
    History:
 
    25 Mar 98   gp      Created
    
*-----------------------------------------------------------------------------*/
void    RemoveNameRegistryPtrs(void)
{
        // dispose of proc ptrs
        
    if( gGlobals.RegistryEntryIDInitAddr != nil )
        DisposeRoutineDescriptor( (struct RoutineDescriptor *) gGlobals.RegistryEntryIDInitAddr);
    
    if( gGlobals.RegistryCStrEntryLookupAddr != nil )
        DisposeRoutineDescriptor( (struct RoutineDescriptor *) gGlobals.RegistryCStrEntryLookupAddr);
    
    if( gGlobals.RegistryEntryIterateCreateAddr != nil )
        DisposeRoutineDescriptor( (struct RoutineDescriptor *) gGlobals.RegistryEntryIterateCreateAddr);
    
    if( gGlobals.RegistryEntryIterateDisposeAddr != nil )
        DisposeRoutineDescriptor( (struct RoutineDescriptor *) gGlobals.RegistryEntryIterateDisposeAddr);
    
    if( gGlobals.RegistryEntryIterateSetAddr != nil )
        DisposeRoutineDescriptor( (struct RoutineDescriptor *) gGlobals.RegistryEntryIterateSetAddr);
    
    if( gGlobals.RegistryEntryIterateAddr != nil )
        DisposeRoutineDescriptor( (struct RoutineDescriptor *) gGlobals.RegistryEntryIterateAddr);
    
    if( gGlobals.RegistryEntryIDDisposeAddr != nil )
        DisposeRoutineDescriptor( (struct RoutineDescriptor *) gGlobals.RegistryEntryIDDisposeAddr);
    
    if( gGlobals.RegistryPropertyGetAddr != nil )
        DisposeRoutineDescriptor( (struct RoutineDescriptor *) gGlobals.RegistryPropertyGetAddr);
}