Logo Search packages:      
Sourcecode: xaos version File versions  Download package

MoreDesk.cpp

/*
**    Apple Macintosh Developer Technical Support
**
**    A collection of useful high-level Desktop Manager routines.
**    If the Desktop Manager isn't available, use the Desktop file
**    for 'read' operations.
**
**    We do more because we can...
**
**    by Jim Luther and Nitin Ganatra, Apple Developer Technical Support Emeriti
**
**    File: MoreDesktopMgr.c
**
**    Copyright  1992-1998 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.
*/

#include <Types.h>
#include <Errors.h>
#include <Memory.h>
#include <Files.h>
#include <Resources.h>
#include <Icons.h>

#define     __COMPILINGMOREFILES

#include "morefile.h"
#include "moreextr.h"
#include "mfsearch.h"
#include "moredesk.h"

/*****************************************************************************/

/*    Desktop file notes:
**
**         The Desktop file is owned by the Finder and is normally open by the
**          Finder. That means that we only have read-only access to the Desktop
**          file.
**         Since the Resource Manager doesn't support shared access to resource
**          files and we're using read-only access, we don't ever leave the
**          Desktop file open.  We open a path to it, get the data we want out
**          of it, and then close the open path. This is the only safe way to
**          open a resource file with read-only access since some other program
**          could have it open with write access.
**         The bundle related resources in the Desktop file are normally
**          purgable, so when we're looking through them, we don't bother to
**          release resources we're done looking at - closing the resource file
**          (which we always do) will release them.
**         Since we can't assume the Desktop file is named "Desktop"
**          (it probably is everywhere but France), we get the Desktop
**          file's name by searching the volume's root directory for a file
**          with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
**          this scheme is that someone could create another file with that type
**          and creator in the root directory and we'd find the wrong file.
**          The chances of this are very slim.
*/

/*****************************************************************************/

/* local defines */

enum
{
      kBNDLResType      = 'BNDL',
      kFREFResType      = 'FREF',
      kIconFamResType   = 'ICN#',
      kFCMTResType      = 'FCMT',
      kAPPLResType      = 'APPL'
};

/*****************************************************************************/

/* local data structures */

#if PRAGMA_STRUCT_ALIGN
    #pragma options align=mac68k
#elif PRAGMA_STRUCT_PACKPUSH
    #pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
    #pragma pack(2)
#endif

struct IDRec
{
      short       localID;
      short       rsrcID;
};
typedef struct IDRec IDRec;
typedef     IDRec *IDRecPtr;

struct BundleType
{
      OSType            type;             /* 'ICN#' or 'FREF' */
      short       count;                  /* number of IDRecs - 1 */
      IDRec       idArray[1];
};
typedef struct BundleType BundleType;
typedef BundleType *BundleTypePtr;

struct BNDLRec
{
      OSType            signature;        /* creator type signature */
      short       versionID;        /* version - should always be 0 */
      short       numTypes;         /* number of elements in typeArray - 1 */
      BundleType  typeArray[1];
};
typedef struct BNDLRec BNDLRec;
typedef BNDLRec **BNDLRecHandle;

struct FREFRec
{
      OSType            fileType;         /* file type */
      short       iconID;                 /* icon local ID */
      Str255            fileName;         /* file name */
};
typedef struct FREFRec FREFRec;
typedef FREFRec **FREFRecHandle;

struct APPLRec
{
      OSType            creator;          /* creator type signature */
      long        parID;                  /* parent directory ID */
      Str255            applName;         /* application name */
};
typedef struct APPLRec APPLRec;
typedef APPLRec *APPLRecPtr;

#if PRAGMA_STRUCT_ALIGN
    #pragma options align=reset
#elif PRAGMA_STRUCT_PACKPUSH
    #pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
    #pragma pack()
#endif

/*****************************************************************************/

/* static prototypes */

static      OSErr GetDesktopFileName(short vRefNum,
                                                   Str255 desktopName);

static      OSErr GetAPPLFromDesktopFile(ConstStr255Param volName,
                                                         short vRefNum,
                                                         OSType creator,
                                                         short *applVRefNum,
                                                         long *applParID,
                                                         Str255 applName);

static      OSErr FindBundleGivenCreator(OSType creator,
                                                         BNDLRecHandle *returnBndl);
                                                         
static      OSErr FindTypeInBundle(OSType typeToFind,
                                                 BNDLRecHandle theBndl,
                                                 BundleTypePtr *returnBundleType);
                                                             
static      OSErr GetLocalIDFromFREF(BundleTypePtr theBundleType,
                                                   OSType fileType,
                                                   short *iconLocalID);

static      OSErr GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
                                                             short iconLocalID,
                                                             short *iconRsrcID);

static      OSType      DTIconToResIcon(short iconType);

static      OSErr GetIconFromDesktopFile(ConstStr255Param volName,
                                                         short vRefNum,
                                                         short iconType,
                                                         OSType fileCreator,
                                                         OSType fileType,
                                                         Handle *iconHandle);

static      OSErr GetCommentID(short vRefNum,
                                           long dirID,
                                           ConstStr255Param name,
                                           short *commentID);

static      OSErr GetCommentFromDesktopFile(short vRefNum,
                                                              long dirID,
                                                              ConstStr255Param name,
                                                              Str255 comment);

/*****************************************************************************/

/*
**    GetDesktopFileName
**
**    Get the name of the Desktop file.
*/
static      OSErr GetDesktopFileName(short vRefNum,
                                                   Str255 desktopName)
{
      OSErr             error;
      HParamBlockRec    pb;
      short             index;
      Boolean                 found;
      
      pb.fileParam.ioNamePtr = desktopName;
      pb.fileParam.ioVRefNum = vRefNum;
      pb.fileParam.ioFVersNum = 0;
      index = 1;
      found = false;
      do
      {
            pb.fileParam.ioDirID = fsRtDirID;
            pb.fileParam.ioFDirIndex = index;
            error = PBHGetFInfoSync(&pb);
            if ( error == noErr )
            {
                  if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
                         (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
                  {
                        found = true;
                  }
            }
            ++index;
      } while ( (error == noErr) && !found );
      
      return ( error );
}

/*****************************************************************************/

pascal      OSErr DTOpen(ConstStr255Param volName,
                                 short vRefNum,
                                 short *dtRefNum,
                                 Boolean *newDTDatabase)
{
      OSErr error;
      GetVolParmsInfoBuffer volParmsInfo;
      long infoSize;
      DTPBRec pb;
      
      /* Check for volume Desktop Manager support before calling */
      infoSize = sizeof(GetVolParmsInfoBuffer);
      error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
      if ( error == noErr )
      {
            if ( hasDesktopMgr(volParmsInfo) )
            {
                  pb.ioNamePtr = (StringPtr)volName;
                  pb.ioVRefNum = vRefNum;
                  error = PBDTOpenInform(&pb);
                  /* PBDTOpenInform informs us if the desktop was just created */
                  /* by leaving the low bit of ioTagInfo clear (0) */
                  *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
                  if ( error == paramErr )
                  {
                        error = PBDTGetPath(&pb);
                        /* PBDTGetPath doesn't tell us if the database is new */
                        /* so assume it is not new */
                        *newDTDatabase = false;
                  }
                  *dtRefNum = pb.ioDTRefNum;
            }
            else
            {
                  error = paramErr;
            }
      }
      return ( error );
}

/*****************************************************************************/

/*
**    GetAPPLFromDesktopFile
**
**    Get a application's location from the
**    Desktop file's 'APPL' resources.
*/
static      OSErr GetAPPLFromDesktopFile(ConstStr255Param volName,
                                                         short vRefNum,
                                                         OSType creator,
                                                         short *applVRefNum,
                                                         long *applParID,
                                                         Str255 applName)
{
      OSErr error;
      short realVRefNum;
      Str255 desktopName;
      short savedResFile;
      short dfRefNum;
      Handle applResHandle;
      Boolean foundCreator;
      Ptr applPtr;
      long applSize;
      
      error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
      if ( error == noErr )
      {
            error = GetDesktopFileName(realVRefNum, desktopName);
            if ( error == noErr )
            {
                  savedResFile = CurResFile();
                  /*
                  **    Open the 'Desktop' file in the root directory. (because
                  **    opening the resource file could preload unwanted resources,
                  **    bracket the call with SetResLoad(s))
                  */
                  SetResLoad(false);
                  dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
                  SetResLoad(true);
                  
                  if ( dfRefNum != -1)
                  {
                        /* Get 'APPL' resource ID 0 */
                        applResHandle = Get1Resource(kAPPLResType, 0);
                        if ( applResHandle != NULL )
                        {
#if !TARGET_CARBON
                              applSize = InlineGetHandleSize((Handle)applResHandle);
#else
                              applSize = GetHandleSize((Handle)applResHandle);
#endif
                              if ( applSize != 0 )    /* make sure the APPL resource isn't empty */
                              {
                                    foundCreator = false;
                                    applPtr = *applResHandle;
                                    
                                    /* APPL's don't have a count so I have to use the size as the bounds */
                                    while ( (foundCreator == false) &&
                                                (applPtr < (*applResHandle + applSize)) )
                                    {
                                          if ( ((APPLRecPtr)applPtr)->creator == creator )
                                          {
                                                foundCreator = true;
                                          }
                                          else
                                          {
                                                /* fun with pointer math... */
                                                applPtr += sizeof(OSType) +
                                                               sizeof(long) +
                                                               ((APPLRecPtr)applPtr)->applName[0] + 1;
                                                /* application mappings are word aligned within the resource */
                                                if ( ((unsigned long)applPtr % 2) != 0 )
                                                {
                                                      applPtr += 1;
                                                }
                                          }
                                    }
                                    if ( foundCreator == true )
                                    {
                                          *applVRefNum = realVRefNum;
                                          *applParID = ((APPLRecPtr)applPtr)->parID;
                                          BlockMoveData(((APPLRecPtr)applPtr)->applName,
                                                              applName,
                                                              ((APPLRecPtr)applPtr)->applName[0] + 1);
                                          /* error is already noErr */
                                    }
                                    else
                                    {
                                          error = afpItemNotFound;      /* didn't find a creator match */
                                    }
                              }
                              else
                              {
                                    error = afpItemNotFound;      /* no APPL mapping available */
                              }
                        }
                        else
                        {
                              error = afpItemNotFound;      /* no APPL mapping available */
                        }
                        
                        /* restore the resource chain and close the Desktop file */
                        UseResFile(savedResFile);
                        CloseResFile(dfRefNum);
                  }
                  else
                  {
                        error = afpItemNotFound;
                  }
            }
      }
      
      return ( error );
}

/*****************************************************************************/

pascal      OSErr DTXGetAPPL(ConstStr255Param volName,
                                       short vRefNum,
                                       OSType creator,
                                       Boolean searchCatalog,
                                       short *applVRefNum,
                                       long *applParID,
                                       Str255 applName)
{
      OSErr error;
      UniversalFMPB pb;
      short dtRefNum;
      Boolean newDTDatabase;
      short realVRefNum;
      short index;
      Boolean applFound;
      FSSpec spec;
      long actMatchCount;
      
      /* get the real vRefNum */
      error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
      if ( error == noErr )
      {
            error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
            if ( error == noErr )
            {
                  if ( !newDTDatabase )
                  {
                        index = 0;
                        applFound = false;
                        do
                        {
                              pb.dtPB.ioNamePtr = applName;
                              pb.dtPB.ioDTRefNum = dtRefNum;
                              pb.dtPB.ioIndex = index;
                              pb.dtPB.ioFileCreator = creator;
                              error = PBDTGetAPPLSync(&pb.dtPB);
                              if ( error == noErr )
                              {
                                    /* got a match - see if it is valid */
                                    
                                    *applVRefNum = realVRefNum; /* get the vRefNum now */
                                    *applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
      
                                    /* pb.hPB.fileParam.ioNamePtr is already set */
                                    pb.hPB.fileParam.ioVRefNum = realVRefNum;
                                    pb.hPB.fileParam.ioFVersNum = 0;
                                    pb.hPB.fileParam.ioDirID = *applParID;
                                    pb.hPB.fileParam.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
                                    if ( PBHGetFInfoSync(&pb.hPB) == noErr )
                                    {
                                          if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
                                                 (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
                                          {
                                                applFound = true;
                                          }
                                    }
                              }
                              ++index;
                        } while ( (error == noErr) && !applFound );
                        if ( error != noErr )
                        {
                              error = afpItemNotFound;
                        }
                  }
                  else
                  {
                        /* Desktop database is empty (new), set error to try CatSearch */
                        error = afpItemNotFound;
                  }
            }
            /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
            if ( error == paramErr )
            {
                  /* if paramErr, the volume didn't support the Desktop Manager */
                  /* try the Desktop file */
                  
                  error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
                                                                  applVRefNum, applParID, applName);
                  if ( error == noErr )
                  {
                        /* got a match - see if it is valid */
                        
                        pb.hPB.fileParam.ioNamePtr = applName;
                        pb.hPB.fileParam.ioVRefNum = *applVRefNum;
                        pb.hPB.fileParam.ioFVersNum = 0;
                        pb.hPB.fileParam.ioDirID = *applParID;
                        pb.hPB.fileParam.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
                        if ( PBHGetFInfoSync(&pb.hPB) == noErr )
                        {
                              if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
                                     (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
                              {
                                    error = afpItemNotFound;
                              }
                        }
                        else if ( error == fnfErr )
                        {
                              error = afpItemNotFound;
                        }
                  }
            }
            /* acceptable error from DesktopFile code to continue is afpItemNotFound */
            if ( (error == afpItemNotFound) && searchCatalog)
            {
                  /* Couldn't be found in the Desktop file either, */
                  /* try searching with CatSearch if requested */
                  
                  error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
                                                                  &actMatchCount, true);
                  if ( (error == noErr) || (error == eofErr) )
                  {
                        if ( actMatchCount > 0 )
                        {
                              *applVRefNum = spec.vRefNum;
                              *applParID = spec.parID;
                              BlockMoveData(spec.name, applName, spec.name[0] + 1);
                        }
                        else
                        {
                              error = afpItemNotFound;
                        }
                  }
            }
      }
      
      return ( error );
}

/*****************************************************************************/

pascal      OSErr FSpDTXGetAPPL(ConstStr255Param volName,
                                            short vRefNum,
                                            OSType creator,
                                            Boolean searchCatalog,
                                            FSSpec *spec)
{
      return ( DTXGetAPPL(volName, vRefNum, creator, searchCatalog,
                                    &(spec->vRefNum), &(spec->parID), spec->name) );
}

/*****************************************************************************/

pascal      OSErr DTGetAPPL(ConstStr255Param volName,
                                      short vRefNum,
                                      OSType creator,
                                      short *applVRefNum,
                                      long *applParID,
                                      Str255 applName)
{
      /* Call DTXGetAPPL with the "searchCatalog" parameter true */ 
      return ( DTXGetAPPL(volName, vRefNum, creator, true,
                                    applVRefNum, applParID, applName) );
}

/*****************************************************************************/

pascal      OSErr FSpDTGetAPPL(ConstStr255Param volName,
                                           short vRefNum,
                                           OSType creator,
                                           FSSpec *spec)
{
      /* Call DTXGetAPPL with the "searchCatalog" parameter true */ 
      return ( DTXGetAPPL(volName, vRefNum, creator, true,
                                    &(spec->vRefNum), &(spec->parID), spec->name) );
}

/*****************************************************************************/

/*
**    FindBundleGivenCreator
**
**    Search the current resource file for the 'BNDL' resource with the given
**    creator and return a handle to it.
*/
static      OSErr FindBundleGivenCreator(OSType creator,
                                                         BNDLRecHandle *returnBndl)
{
      OSErr             error;
      short             numOfBundles;
      short             index;
      BNDLRecHandle     theBndl;
      
      error = afpItemNotFound;      /* default to not found */
      
      /* Search each BNDL resource until we find the one with a matching creator. */
      
      numOfBundles = Count1Resources(kBNDLResType);
      index = 1;
      *returnBndl = NULL;
      
      while ( (index <= numOfBundles) && (*returnBndl == NULL) )
      {
            theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
            
            if ( theBndl != NULL )
            {
                  if ( (*theBndl)->signature == creator )
                  {
                        /* numTypes and typeArray->count will always be the actual count minus 1, */
                        /* so 0 in both fields is valid. */
                        if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
                        {
                              /* got it */
                              *returnBndl = theBndl;
                              error = noErr;
                        }
                  }
            }     
            
            index ++;
      }
      
      return ( error );
}

/*****************************************************************************/

/*
**    FindTypeInBundle
**
**    Given a Handle to a BNDL return a pointer to the desired type
**    in it. If the type is not found, or if the type's count < 0,
**    return afpItemNotFound.
*/
static      OSErr FindTypeInBundle(OSType typeToFind,
                                                 BNDLRecHandle theBndl,
                                                 BundleTypePtr *returnBundleType)
{
      OSErr             error;
      short             index;
      Ptr                     ptrIterator;      /* use a Ptr so we can do ugly pointer math */
      
      error = afpItemNotFound;      /* default to not found */
      
      ptrIterator = (Ptr)((*theBndl)->typeArray);
      index = 0;
      *returnBundleType = NULL;

      while ( (index < ((*theBndl)->numTypes + 1)) &&
                  (*returnBundleType == NULL) )
      {
            if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
                   (((BundleTypePtr)ptrIterator)->count >= 0) )
            {
                        *returnBundleType = (BundleTypePtr)ptrIterator;
                        error = noErr;
            }
            else
            {
                  ptrIterator += ( sizeof(OSType) +
                                           sizeof(short) +
                                           ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
                  ++index;
            }
      }
            
      return ( error );
}

/*****************************************************************************/

/*
**    GetLocalIDFromFREF
**
**    Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
**    looking for a matching fileType. If a matching fileType is found, return
**    its icon local ID. If no match is found, return afpItemNotFound as the
**    function result.
*/
static      OSErr GetLocalIDFromFREF(BundleTypePtr theBundleType,
                                                   OSType fileType,
                                                   short *iconLocalID)
{
      OSErr             error;
      short             index;
      IDRecPtr          idIterator;
      FREFRecHandle     theFref;
      
      error = afpItemNotFound;      /* default to not found */
      
      /* For each localID in this type, get the FREF resource looking for fileType */
      index = 0;
      idIterator = &theBundleType->idArray[0];
      *iconLocalID = 0;
      
      while ( (index <= theBundleType->count) && (*iconLocalID == 0) )
      {
            theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
            if ( theFref != NULL )
            {
                  if ( (*theFref)->fileType == fileType )
                  {
                        *iconLocalID = (*theFref)->iconID;
                        error = noErr;
                  }
            }
            
            ++idIterator;
            ++index;
      }
      
      return ( error );
}

/*****************************************************************************/

/*
**    GetIconRsrcIDFromLocalID
**
**    Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
**    the localID that matches iconLocalID. If a matching IDRec is found,
**    return the IDRec's rsrcID field value. If no match is found, return
**    afpItemNotFound as the function result.
*/
static      OSErr GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
                                                             short iconLocalID,
                                                             short *iconRsrcID)
{
      OSErr       error;
      short       index;
      IDRecPtr    idIterator;
      
      error = afpItemNotFound;      /* default to not found */
      
      /* Find the rsrcID of the icon family type, given the localID */
      index = 0;
      idIterator = &theBundleType->idArray[0];
      *iconRsrcID = 0;
      
      while ( (index <= theBundleType->count) && (*iconRsrcID == 0) )
      {
            if ( idIterator->localID == iconLocalID )
            {
                  *iconRsrcID = idIterator->rsrcID;
                  error = noErr;
            }
            
            idIterator ++;
            index ++;
      }
      
      return ( error );
}

/*****************************************************************************/

/*
**    DTIconToResIcon
**
**    Map a Desktop Manager icon type to the corresponding resource type.
**    Return (OSType)0 if there is no corresponding resource type.
*/
static      OSType      DTIconToResIcon(short iconType)
{
      OSType      resType;
      
      switch ( iconType )
      {
            case kLargeIcon:
                  resType = large1BitMask;
                  break;
            case kLarge4BitIcon:
                  resType = large4BitData;
                  break;
            case kLarge8BitIcon:
                  resType = large8BitData;
                  break;
            case kSmallIcon:
                  resType = small1BitMask;
                  break;
            case kSmall4BitIcon:
                  resType = small4BitData;
                  break;
            case kSmall8BitIcon:
                  resType = small8BitData;
                  break;
            default:
                  resType = (OSType)0;
                  break;
      }
      
      return ( resType );
}

/*****************************************************************************/

/*
**    GetIconFromDesktopFile
**
**    INPUT a pointer to a non-existent Handle, because we'll allocate one
**
**    search each BNDL resource for the right fileCreator and once we get it
**          find the 'FREF' type in BNDL
**          for each localID in the type, open the FREF resource
**                if the FREF is the desired fileType
**                      get its icon localID
**                      get the ICN# type in BNDL
**                      get the icon resource number from the icon localID
**                      get the icon resource type from the desktop mgr's iconType
**                      get the icon of that type and number
*/
static      OSErr GetIconFromDesktopFile(ConstStr255Param volName,
                                                         short vRefNum,
                                                         short iconType,
                                                         OSType fileCreator,
                                                         OSType fileType,
                                                         Handle *iconHandle)
{
      OSErr             error;
      short             realVRefNum;
      Str255                  desktopName;
      short             savedResFile;
      short             dfRefNum;
      BNDLRecHandle     theBndl = NULL;
      BundleTypePtr     theBundleType;
      short             iconLocalID;
      short             iconRsrcID;
      OSType                  iconRsrcType;
      Handle                  returnIconHandle; 
      char              bndlState;
      
      *iconHandle = NULL;
      
      error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
      if ( error == noErr )
      {
            error = GetDesktopFileName(realVRefNum, desktopName);
            if ( error == noErr )
            {
                  savedResFile = CurResFile();
            
                  /*
                  **    Open the 'Desktop' file in the root directory. (because
                  **    opening the resource file could preload unwanted resources,
                  **    bracket the call with SetResLoad(s))
                  */
                  SetResLoad(false);
                  dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
                  SetResLoad(true);
            
                  if ( dfRefNum != -1 )
                  {
                        /*
                        **    Find the BNDL resource with the specified creator.
                        */
                        error = FindBundleGivenCreator(fileCreator, &theBndl);
                        if ( error == noErr )
                        {
                              /* Lock the BNDL resource so it won't be purged when other resources are loaded */
                              bndlState = HGetState((Handle)theBndl);
                              HLock((Handle)theBndl);
                              
                              /* Find the 'FREF' BundleType record in the BNDL resource. */
                              error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
                              if ( error == noErr )
                              {
                                    /* Find the local ID in the 'FREF' resource with the specified fileType */
                                    error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
                                    if ( error == noErr )
                                    {
                                          /* Find the 'ICN#' BundleType record in the BNDL resource. */
                                          error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
                                          if ( error == noErr )
                                          {
                                                /* Find the icon's resource ID in the 'ICN#' BundleType record */
                                                error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
                                                if ( error == noErr )
                                                {
                                                      /* Map Desktop Manager icon type to resource type */
                                                      iconRsrcType = DTIconToResIcon(iconType);
                                                      
                                                      if ( iconRsrcType != (OSType)0 )
                                                      {
                                                            /* Load the icon */
                                                            returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
                                                            if ( returnIconHandle != NULL )
                                                            {
                                                                  /* Copy the resource handle, and return the copy */
                                                                  HandToHand(&returnIconHandle);
                                                                  if ( MemError() == noErr )
                                                                  {
                                                                        *iconHandle = returnIconHandle;
                                                                  }
                                                                  else
                                                                  {
                                                                        error = afpItemNotFound;
                                                                  }
                                                            }
                                                            else
                                                            {
                                                                  error = afpItemNotFound;
                                                            }
                                                      }
                                                }
                                          }
                                    }
                              }
                              /* Restore the state of the BNDL resource */ 
                              HSetState((Handle)theBndl, bndlState);
                        }
                        /* Restore the resource chain and close the Desktop file */
                        UseResFile(savedResFile);
                        CloseResFile(dfRefNum);
                  }
                  else
                  {
                        error = ResError(); /* could not open Desktop file */
                  }
            }
            if ( (error != noErr) && (error != memFullErr) )
            {
                  error = afpItemNotFound;      /* force an error we should return */
            }
      }
      
      return ( error );
}

/*****************************************************************************/

pascal      OSErr DTGetIcon(ConstStr255Param volName,
                                      short vRefNum,
                                      short iconType,
                                      OSType fileCreator,
                                      OSType fileType,
                                      Handle *iconHandle)
{
      OSErr error;
      DTPBRec pb;
      short dtRefNum;
      Boolean newDTDatabase;
      Size bufferSize;
      
      *iconHandle = NULL;
      error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
      if ( error == noErr )
      {
            /* there was a desktop database and it's now open */
            
            if ( !newDTDatabase )   /* don't bother to look in a new (empty) database */
            {
                  /* get the buffer size for the requested icon type */
                  switch ( iconType )
                  {
                        case kLargeIcon:
                              bufferSize = kLargeIconSize;
                              break;
                        case kLarge4BitIcon:
                              bufferSize = kLarge4BitIconSize;
                              break;
                        case kLarge8BitIcon:
                              bufferSize = kLarge8BitIconSize;
                              break;
                        case kSmallIcon:
                              bufferSize = kSmallIconSize;
                              break;
                        case kSmall4BitIcon:
                              bufferSize = kSmall4BitIconSize;
                              break;
                        case kSmall8BitIcon:
                              bufferSize = kSmall8BitIconSize;
                              break;
                        default:
                              iconType = 0;
                              bufferSize = 0;
                              break;
                  }
                  if ( bufferSize != 0 )
                  {
                        *iconHandle = NewHandle(bufferSize);
                        if ( *iconHandle != NULL )
                        {
                              HLock(*iconHandle);
            
                              pb.ioDTRefNum = dtRefNum;
                              pb.ioTagInfo = 0;
                              pb.ioDTBuffer = **iconHandle;
                              pb.ioDTReqCount = bufferSize;
                              pb.ioIconType = iconType;
                              pb.ioFileCreator = fileCreator;
                              pb.ioFileType = fileType;
                              error = PBDTGetIconSync(&pb);
      
                              HUnlock(*iconHandle);
                              
                              if ( error != noErr )
                              {
                                    DisposeHandle(*iconHandle);   /* dispose of the allocated memory */
                                    *iconHandle = NULL;
                              }
                        }
                        else
                        {
                              error = memFullErr;     /* handle could not be allocated */
                        }
                  }
                  else
                  {
                        error = paramErr; /* unknown icon type requested */
                  }
            }
            else
            {
                  error = afpItemNotFound;      /* the desktop database was empty - nothing to return */
            }
      }
      else
      {
            /* There is no desktop database - try the Desktop file */
            
            error = GetIconFromDesktopFile(volName, vRefNum, iconType,
                                                            fileCreator, fileType, iconHandle);
      }
      
      return ( error );
}

/*****************************************************************************/

pascal      OSErr DTSetComment(short vRefNum,
                                           long dirID,
                                           ConstStr255Param name,
                                           ConstStr255Param comment)
{
      DTPBRec pb;
      OSErr error;
      short dtRefNum;
      Boolean newDTDatabase;

      error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
      if ( error == noErr )
      {
            pb.ioDTRefNum = dtRefNum;
            pb.ioNamePtr = (StringPtr)name;
            pb.ioDirID = dirID;
            pb.ioDTBuffer = (Ptr)&comment[1];
            /* Truncate the comment to 200 characters just in case */
            /* some file system doesn't range check */
            if ( comment[0] <= 200 )
            {
                  pb.ioDTReqCount = comment[0];
            }
            else
            {
                  pb.ioDTReqCount = 200;
            }
            error = PBDTSetCommentSync(&pb);
      }
      return (error);
}

/*****************************************************************************/

pascal      OSErr FSpDTSetComment(const FSSpec *spec,
                                            ConstStr255Param comment)
{
      return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
}

/*****************************************************************************/

/*
**    GetCommentID
**
**    Get the comment ID number for the Desktop file's 'FCMT' resource ID from
**    the file or folders fdComment (frComment) field.
*/
static      OSErr GetCommentID(short vRefNum,
                                           long dirID,
                                           ConstStr255Param name,
                                           short *commentID)
{
      CInfoPBRec pb;
      OSErr error;

      error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
      *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
      return ( error );
}

/*****************************************************************************/

/*
**    GetCommentFromDesktopFile
**
**    Get a file or directory's Finder comment field (if any) from the
**    Desktop file's 'FCMT' resources.
*/
static      OSErr GetCommentFromDesktopFile(short vRefNum,
                                                              long dirID,
                                                              ConstStr255Param name,
                                                              Str255 comment)
{
      OSErr error;
      short commentID;
      short realVRefNum;
      Str255 desktopName;
      short savedResFile;
      short dfRefNum;
      StringHandle commentHandle;
      
      /* Get the comment ID number */
      error = GetCommentID(vRefNum, dirID, name, &commentID);
      if ( error == noErr )
      {
            if ( commentID != 0 )   /* commentID == 0 means there's no comment */
            {
                  error = DetermineVRefNum(name, vRefNum, &realVRefNum);
                  if ( error == noErr )
                  {
                        error = GetDesktopFileName(realVRefNum, desktopName);
                        if ( error == noErr )
                        {
                              savedResFile = CurResFile();
                              /*
                              **    Open the 'Desktop' file in the root directory. (because
                              **    opening the resource file could preload unwanted resources,
                              **    bracket the call with SetResLoad(s))
                              */
                              SetResLoad(false);
                              dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
                              SetResLoad(true);
                              
                              if ( dfRefNum != -1)
                              {
                                    /* Get the comment resource */
                                    commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
                                    if ( commentHandle != NULL )
                                    {
#if !TARGET_CARBON
                                          if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
#else
                                          if ( GetHandleSize((Handle)commentHandle) > 0 )
#endif
                                          {
                                                BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
                                          }
                                          else
                                          {
                                                error = afpItemNotFound;      /* no comment available */
                                          }
                                    }
                                    else
                                    {
                                          error = afpItemNotFound;      /* no comment available */
                                    }
                                    
                                    /* restore the resource chain and close the Desktop file */
                                    UseResFile(savedResFile);
                                    CloseResFile(dfRefNum);
                              }
                              else
                              {
                                    error = afpItemNotFound;
                              }
                        }
                        else
                        {
                              error = afpItemNotFound;
                        }
                  }
            }
            else
            {
                  error = afpItemNotFound;      /* no comment available */
            }
      }
      
      return ( error );
}

/*****************************************************************************/

pascal      OSErr DTGetComment(short vRefNum,
                                           long dirID,
                                           ConstStr255Param name,
                                           Str255 comment)
{
      DTPBRec pb;
      OSErr error;
      short dtRefNum;
      Boolean newDTDatabase;

      if (comment != NULL)
      {
            comment[0] = 0;   /* return nothing by default */
            
            /* attempt to open the desktop database */
            error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
            if ( error == noErr )
            {
                  /* There was a desktop database and it's now open */
                  
                  if ( !newDTDatabase )
                  {
                        pb.ioDTRefNum = dtRefNum;
                        pb.ioNamePtr = (StringPtr)name;
                        pb.ioDirID = dirID;
                        pb.ioDTBuffer = (Ptr)&comment[1];
                        /*
                        **    IMPORTANT NOTE #1: Inside Macintosh says that comments
                        **    are up to 200 characters. While that may be correct for
                        **    the HFS file system's Desktop Manager, other file
                        **    systems (such as Apple Photo Access) return up to
                        **    255 characters. Make sure the comment buffer is a Str255
                        **    or you'll regret it.
                        **
                        **    IMPORTANT NOTE #2: Although Inside Macintosh doesn't
                        **    mention it, ioDTReqCount is a input field to
                        **    PBDTGetCommentSync. Some file systems (like HFS) ignore
                        **    ioDTReqCount and always return the full comment --
                        **    others (like AppleShare) respect ioDTReqCount and only
                        **    return up to ioDTReqCount characters of the comment.
                        */
                        pb.ioDTReqCount = sizeof(Str255) - 1;
                        error = PBDTGetCommentSync(&pb);
                        if (error == noErr)
                        {
                              comment[0] = (unsigned char)pb.ioDTActCount;
                        }
                  }
            }
            else
            {
                  /* There is no desktop database - try the Desktop file */
                  error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
                  if ( error != noErr )
                  {
                        error = afpItemNotFound;      /* return an expected error */
                  }
            }
      }
      else
      {
            error = paramErr;
      }
      
      return (error);
}

/*****************************************************************************/

pascal      OSErr FSpDTGetComment(const FSSpec *spec,
                                            Str255 comment)
{
      return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
}

/*****************************************************************************/

pascal      OSErr DTCopyComment(short srcVRefNum,
                                            long srcDirID,
                                            ConstStr255Param srcName,
                                            short dstVRefNum,
                                            long dstDirID,
                                            ConstStr255Param dstName)
/* The destination volume must support the Desktop Manager for this to work */
{
      OSErr error;
      Str255 comment;

      error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
      if ( (error == noErr) && (comment[0] > 0) )
      {
            error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
      }
      return (error);
}

/*****************************************************************************/

pascal      OSErr FSpDTCopyComment(const FSSpec *srcSpec,
                                             const FSSpec *dstSpec)
/* The destination volume must support the Desktop Manager for this to work */
{
      return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
                                    dstSpec->vRefNum, dstSpec->parID, dstSpec->name));
}

/*****************************************************************************/

Generated by  Doxygen 1.6.0   Back to index