home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / mac / MoreFiles / MoreDesktopMgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  31.2 KB  |  1,154 lines

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    A collection of useful high-level Desktop Manager routines.
  5. **    If the Desktop Manager isn't available, use the Desktop file
  6. **    for 'read' operations.
  7. **
  8. **    We do more because we can...
  9. **
  10. **    by Jim Luther and Nitin Ganatra, Apple Developer Technical Support Emeriti
  11. **
  12. **    File:    MoreDesktopMgr.c
  13. **
  14. **    Copyright ⌐ 1992-1996 Apple Computer, Inc.
  15. **    All rights reserved.
  16. **
  17. **    You may incorporate this sample code into your applications without
  18. **    restriction, though the sample code has been provided "AS IS" and the
  19. **    responsibility for its operation is 100% yours.  However, what you are
  20. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  21. **    after having made changes. If you're going to re-distribute the source,
  22. **    we require that you make it clear in the source that the code was
  23. **    descended from Apple Sample Code, but that you've made changes.
  24. */
  25.  
  26. /* 
  27.  * This code, which was decended from Apple Sample Code, has been modified by 
  28.  * Netscape.
  29.  */
  30.  
  31. #include <Types.h>
  32. #include <Errors.h>
  33. #include <Memory.h>
  34. #include <Files.h>
  35. #include <Resources.h>
  36. #include <Icons.h>
  37.  
  38. #define    __COMPILINGMOREFILES
  39.  
  40. #include "MoreFiles.h"
  41. #include "MoreFilesExtras.h"
  42. #include "MoreFilesSearch.h"
  43. #include "MoreDesktopMgr.h"
  44.  
  45. /*****************************************************************************/
  46.  
  47. /*    Desktop file notes:
  48. **
  49. **    Ñ    The Desktop file is owned by the Finder and is normally open by the
  50. **        Finder. That means that we only have read-only access to the Desktop
  51. **        file.
  52. **    Ñ    Since the Resource Manager doesn't support shared access to resource
  53. **        files and we're using read-only access, we don't ever leave the
  54. **        Desktop file open.  We open a path to it, get the data we want out
  55. **        of it, and then close the open path. This is the only safe way to
  56. **        open a resource file with read-only access since some other program
  57. **        could have it open with write access.
  58. **    Ñ    The bundle related resources in the Desktop file are normally
  59. **        purgable, so when we're looking through them, we don't bother to
  60. **        release resources we're done looking at - closing the resource file
  61. **        (which we always do) will release them.
  62. **    Ñ    Since we can't assume the Desktop file is named "Desktop"
  63. **        (it probably is everywhere but France), we get the Desktop
  64. **        file's name by searching the volume's root directory for a file
  65. **        with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
  66. **        this scheme is that someone could create another file with that type
  67. **        and creator in the root directory and we'd find the wrong file.
  68. **        The chances of this are very slim.
  69. */
  70.  
  71. /*****************************************************************************/
  72.  
  73. /* local defines */
  74.  
  75. enum
  76. {
  77.     kBNDLResType    = 'BNDL',
  78.     kFREFResType    = 'FREF',
  79.     kIconFamResType    = 'ICN#',
  80.     kFCMTResType    = 'FCMT',
  81.     kAPPLResType    = 'APPL'
  82. };
  83.  
  84. /*****************************************************************************/
  85.  
  86. /* local data structures */
  87.  
  88. #if PRAGMA_ALIGN_SUPPORTED
  89. #pragma options align=mac68k
  90. #endif
  91.  
  92. struct IDRec
  93. {
  94.     short        localID;
  95.     short        rsrcID;
  96. };
  97. typedef struct IDRec IDRec;
  98. typedef    IDRec *IDRecPtr;
  99.  
  100. struct BundleType
  101. {
  102.     OSType        type;            /* 'ICN#' or 'FREF' */
  103.     short        count;            /* number of IDRecs - 1 */
  104.     IDRec        idArray[1];
  105. };
  106. typedef struct BundleType BundleType;
  107. typedef BundleType *BundleTypePtr;
  108.  
  109. struct BNDLRec
  110. {
  111.     OSType        signature;        /* creator type signature */
  112.     short        versionID;        /* version - should always be 0 */
  113.     short        numTypes;        /* number of elements in typeArray - 1 */
  114.     BundleType    typeArray[1];
  115. };
  116. typedef struct BNDLRec BNDLRec;
  117. typedef BNDLRec **BNDLRecHandle;
  118.  
  119. struct FREFRec
  120. {
  121.     OSType        fileType;        /* file type */
  122.     short        iconID;            /* icon local ID */
  123.     Str255        fileName;        /* file name */
  124. };
  125. typedef struct FREFRec FREFRec;
  126. typedef FREFRec **FREFRecHandle;
  127.  
  128. struct APPLRec
  129. {
  130.     OSType        creator;        /* creator type signature */
  131.     long        parID;            /* parent directory ID */
  132.     Str255        applName;        /* application name */
  133. };
  134. typedef struct APPLRec APPLRec;
  135. typedef APPLRec *APPLRecPtr;
  136.  
  137. #if PRAGMA_ALIGN_SUPPORTED
  138. #pragma options align=reset
  139. #endif
  140.  
  141. /*****************************************************************************/
  142.  
  143. /* static prototypes */
  144.  
  145. static    OSErr    GetDesktopFileName(short vRefNum,
  146.                                    Str255 desktopName);
  147.  
  148. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  149.                                        short vRefNum,
  150.                                        OSType creator,
  151.                                        short *applVRefNum,
  152.                                        long *applParID,
  153.                                        Str255 applName);
  154.  
  155. static    OSErr    FindBundleGivenCreator(OSType creator,
  156.                                        BNDLRecHandle *returnBndl);
  157.                                        
  158. static    OSErr    FindTypeInBundle(OSType typeToFind,
  159.                                  BNDLRecHandle theBndl,
  160.                                  BundleTypePtr *returnBundleType);
  161.                                          
  162. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  163.                                    OSType fileType,
  164.                                    short *iconLocalID);
  165.  
  166. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  167.                                          short iconLocalID,
  168.                                          short *iconRsrcID);
  169.  
  170. pascal    OSType    DTIconToResIcon(short iconType);
  171.  
  172. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  173.                                        short vRefNum,
  174.                                        short iconType,
  175.                                        OSType fileCreator,
  176.                                        OSType fileType,
  177.                                        Handle *iconHandle);
  178.  
  179. static    OSErr    GetCommentID(short vRefNum,
  180.                              long dirID,
  181.                              StringPtr name,
  182.                              short *commentID);
  183.  
  184. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  185.                                           long dirID,
  186.                                           StringPtr name,
  187.                                           Str255 comment);
  188.  
  189. /*****************************************************************************/
  190.  
  191. /*
  192. **    GetDesktopFileName
  193. **
  194. **    Get the name of the Desktop file.
  195. */
  196. static    OSErr    GetDesktopFileName(short vRefNum,
  197.                                    Str255 desktopName)
  198. {
  199.     OSErr            error;
  200.     HParamBlockRec    pb;
  201.     short            index;
  202.     Boolean            found = false;
  203.     
  204.     pb.fileParam.ioNamePtr = desktopName;
  205.     pb.fileParam.ioVRefNum = vRefNum;
  206.     pb.fileParam.ioFVersNum = 0;
  207.     index = 1;
  208.     do
  209.     {
  210.         pb.fileParam.ioDirID = fsRtDirID;
  211.         pb.fileParam.ioFDirIndex = index;
  212.         error = PBHGetFInfoSync(&pb);
  213.         if ( error == noErr )
  214.         {
  215.             if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
  216.                  (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
  217.             {
  218.                 found = true;
  219.             }
  220.         }
  221.         ++index;
  222.     } while ( (error == noErr) && !found );
  223.     
  224.     return ( error );
  225. }
  226.  
  227. /*****************************************************************************/
  228.  
  229. pascal    OSErr    DTOpen(StringPtr volName,
  230.                        short vRefNum,
  231.                        short *dtRefNum,
  232.                        Boolean *newDTDatabase)
  233. {
  234.     OSErr error;
  235.     GetVolParmsInfoBuffer volParmsInfo;
  236.     long infoSize;
  237.     DTPBRec pb;
  238.     
  239.     /* Check for volume Desktop Manager support before calling */
  240.     infoSize = sizeof(GetVolParmsInfoBuffer);
  241.     error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
  242.     if ( error == noErr )
  243.     {
  244.         if ( hasDesktopMgr(volParmsInfo) )
  245.         {
  246.             pb.ioNamePtr = volName;
  247.             pb.ioVRefNum = vRefNum;
  248.             error = PBDTOpenInform(&pb);
  249.             /* PBDTOpenInform informs us if the desktop was just created */
  250.             /* by leaving the low bit of ioTagInfo clear (0) */
  251.             *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
  252.             if ( error == paramErr )
  253.             {
  254.                 error = PBDTGetPath(&pb);
  255.                 /* PBDTGetPath doesn't tell us if the database is new */
  256.                 /* so assume it is not new */
  257.                 *newDTDatabase = false;
  258.             }
  259.             *dtRefNum = pb.ioDTRefNum;
  260.         }
  261.         else
  262.             error = paramErr;
  263.     }
  264.     return ( error );
  265. }
  266.  
  267. /*****************************************************************************/
  268.  
  269. /*
  270. **    GetAPPLFromDesktopFile
  271. **
  272. **    Get a application's location from the
  273. **    Desktop file's 'APPL' resources.
  274. */
  275. static    OSErr    GetAPPLFromDesktopFile(StringPtr volName,
  276.                                        short vRefNum,
  277.                                        OSType creator,
  278.                                        short *applVRefNum,
  279.                                        long *applParID,
  280.                                        Str255 applName)
  281. {
  282.     OSErr error;
  283.     short realVRefNum;
  284.     Str255 desktopName;
  285.     short savedResFile;
  286.     short dfRefNum;
  287.     Handle applResHandle;
  288.     Boolean foundCreator;
  289.     Ptr applPtr;
  290.     long applSize;
  291.     
  292.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  293.     if ( error == noErr )
  294.     {
  295.         error = GetDesktopFileName(realVRefNum, desktopName);
  296.         if ( error == noErr )
  297.         {
  298.             savedResFile = CurResFile();
  299.             /*
  300.             **    Open the 'Desktop' file in the root directory. (because
  301.             **    opening the resource file could preload unwanted resources,
  302.             **    bracket the call with SetResLoad(s))
  303.             */
  304.             SetResLoad(false);
  305.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  306.             SetResLoad(true);
  307.             
  308.             if ( dfRefNum != -1)
  309.             {
  310.                 /* Get 'APPL' resource ID 0 */
  311.                 applResHandle = Get1Resource(kAPPLResType, 0);
  312.                 if ( applResHandle != NULL )
  313.                 {
  314.                     applSize = GetHandleSize((Handle)applResHandle);
  315.                     if ( applSize != 0 )    /* make sure the APPL resource isn't empty */
  316.                     {
  317.                         foundCreator = false;
  318.                         applPtr = *applResHandle;
  319.                         
  320.                         /* APPL's don't have a count so I have to use the size as the bounds */
  321.                         while ( (foundCreator == false) &&
  322.                                 (applPtr < (*applResHandle + applSize)) )
  323.                         {
  324.                             if ( ((APPLRecPtr)applPtr)->creator == creator )
  325.                             {
  326.                                 foundCreator = true;
  327.                             }
  328.                             else
  329.                             {
  330.                                 /* fun with pointer math... */
  331.                                 applPtr += sizeof(OSType) +
  332.                                            sizeof(long) +
  333.                                            ((APPLRecPtr)applPtr)->applName[0] + 1;
  334.                                 /* application mappings are word aligned within the resource */
  335.                                 if ( ((unsigned long)applPtr % 2) != 0 )
  336.                                     applPtr += 1;
  337.                             }
  338.                         }
  339.                         if ( foundCreator == true )
  340.                         {
  341.                             *applVRefNum = realVRefNum;
  342.                             *applParID = ((APPLRecPtr)applPtr)->parID;
  343.                             BlockMoveData(((APPLRecPtr)applPtr)->applName,
  344.                                           applName,
  345.                                           ((APPLRecPtr)applPtr)->applName[0] + 1);
  346.                             error = noErr;
  347.                         }
  348.                     }
  349.                     else
  350.                         error = afpItemNotFound;    /* no APPL mapping available */
  351.                 }
  352.                 else
  353.                     error = afpItemNotFound;    /* no APPL mapping available */
  354.                 
  355.                 /* restore the resource chain and close the Desktop file */
  356.                 UseResFile(savedResFile);
  357.                 CloseResFile(dfRefNum);
  358.             }
  359.             else
  360.                 error = afpItemNotFound;
  361.         }
  362.     }
  363.     return ( error );
  364. }
  365.  
  366. /*****************************************************************************/
  367.  
  368. pascal    OSErr    DTGetAPPL(StringPtr volName,
  369.                           short vRefNum,
  370.                           OSType creator,
  371.                           short *applVRefNum,
  372.                           long *applParID,
  373.                           Str255 applName)
  374. {
  375.     OSErr error;
  376.     UniversalFMPB pb;
  377.     short dtRefNum;
  378.     Boolean newDTDatabase;
  379.     short realVRefNum;
  380.     short index;
  381.     Boolean applFound;
  382.     FSSpec spec;
  383.     long actMatchCount;
  384.     
  385.     /* get the real vRefNum */
  386.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  387.     if ( error == noErr )
  388.     {
  389.         error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  390.         if ( error == noErr )
  391.         {
  392.             if ( !newDTDatabase )
  393.             {
  394.                 index = 0;
  395.                 applFound = false;
  396.                 do
  397.                 {
  398.                     pb.dtPB.ioNamePtr = applName;
  399.                     pb.dtPB.ioDTRefNum = dtRefNum;
  400.                     pb.dtPB.ioIndex = index;
  401.                     pb.dtPB.ioFileCreator = creator;
  402.                     error = PBDTGetAPPLSync(&pb.dtPB);
  403.                     if ( error == noErr )
  404.                     {
  405.                         /* got a match - see if it is valid */
  406.                         
  407.                         *applVRefNum = realVRefNum; /* get the vRefNum now */
  408.                         *applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
  409.     
  410.                         /* pb.hPB.fileParam.ioNamePtr is already set */
  411.                         pb.hPB.fileParam.ioVRefNum = realVRefNum;
  412.                         pb.hPB.fileParam.ioFVersNum = 0;
  413.                         pb.hPB.fileParam.ioDirID = *applParID;
  414.                         pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  415.                         if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  416.                         {
  417.                             if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
  418.                                  (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
  419.                             {
  420.                                 applFound = true;
  421.                             }
  422.                         }
  423.                     }
  424.                     ++index;
  425.                 } while ( (error == noErr) && !applFound );
  426.                 if ( error != noErr )
  427.                     error = afpItemNotFound;
  428.             }
  429.             else
  430.                 /* Desktop database is empty (new), set error to try CatSearch */
  431.                 error = afpItemNotFound;
  432.         }
  433.         /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
  434.         if ( error == paramErr )
  435.         {
  436.             /* if paramErr, the volume didn't support the Desktop Manager */
  437.             /* try the Desktop file */
  438.             
  439.             error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
  440.                                             applVRefNum, applParID, applName);
  441.             if ( error == noErr )
  442.             {
  443.                 /* got a match - see if it is valid */
  444.                 
  445.                 pb.hPB.fileParam.ioNamePtr = applName;
  446.                 pb.hPB.fileParam.ioVRefNum = *applVRefNum;
  447.                 pb.hPB.fileParam.ioFVersNum = 0;
  448.                 pb.hPB.fileParam.ioDirID = *applParID;
  449.                 pb.hPB.fileParam.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  450.                 if ( PBHGetFInfoSync(&pb.hPB) == noErr )
  451.                 {
  452.                     if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
  453.                          (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
  454.                     {
  455.                         error = afpItemNotFound;
  456.                     }
  457.                 }
  458.                 else if ( error == fnfErr )
  459.                     error = afpItemNotFound;
  460.             }
  461.         }
  462.         /* acceptable error from DesktopFile code to continue is afpItemNotFound */
  463.         if ( error == afpItemNotFound )
  464.         {
  465.             /* Couldn't be found in the Desktop file either, try searching with CatSearch */
  466.             
  467.             error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
  468.                                             &actMatchCount, true);
  469.             if ( (error == noErr) || (error == eofErr) )
  470.             {
  471.                 if ( actMatchCount > 0 )
  472.                 {
  473.                     *applVRefNum = spec.vRefNum;
  474.                     *applParID = spec.parID;
  475.                     BlockMoveData(spec.name, applName, spec.name[0] + 1);
  476.                 }
  477.                 else
  478.                     error = afpItemNotFound;
  479.             }
  480.         }
  481.     }
  482.     return ( error );
  483. }
  484.  
  485. /*****************************************************************************/
  486.  
  487. pascal    OSErr    FSpDTGetAPPL(StringPtr volName,
  488.                              short vRefNum,
  489.                              OSType creator,
  490.                              FSSpec *spec)
  491. {
  492.     return ( DTGetAPPL(volName, vRefNum, creator,
  493.                         &(spec->vRefNum), &(spec->parID), spec->name) );
  494. }
  495.  
  496. /*****************************************************************************/
  497.  
  498. /*
  499. **    FindBundleGivenCreator
  500. **
  501. **    Search the current resource file for the 'BNDL' resource with the given
  502. **    creator and return a handle to it.
  503. */
  504. static    OSErr    FindBundleGivenCreator(OSType creator,
  505.                                        BNDLRecHandle *returnBndl)
  506. {
  507.     OSErr            error;
  508.     short            numOfBundles;
  509.     short            index;
  510.     BNDLRecHandle    theBndl;
  511.     
  512.     error = afpItemNotFound;    /* default to not found */
  513.     
  514.     /* Search each BNDL resource until we find the one with a matching creator. */
  515.     
  516.     numOfBundles = Count1Resources(kBNDLResType);
  517.     index = 1;
  518.     *returnBndl = NULL;
  519.     
  520.     while ( (index <= numOfBundles) && (*returnBndl == NULL) )
  521.     {
  522.         theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
  523.         
  524.         if ( theBndl != NULL )
  525.         {
  526.             if ( (*theBndl)->signature == creator )
  527.             {
  528.                 /* numTypes and typeArray->count will always be the actual count minus 1, */
  529.                 /* so 0 in both fields is valid. */
  530.                 if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
  531.                 {
  532.                     /* got it */
  533.                     *returnBndl = theBndl;
  534.                     error = noErr;
  535.                 }
  536.             }
  537.         }    
  538.         
  539.         index ++;
  540.     }
  541.     
  542.     return ( error );
  543. }
  544.  
  545. /*****************************************************************************/
  546.  
  547. /*
  548. **    FindTypeInBundle
  549. **
  550. **    Given a Handle to a BNDL return a pointer to the desired type
  551. **    in it. If the type is not found, or if the type's count < 0,
  552. **    return afpItemNotFound.
  553. */
  554. static    OSErr    FindTypeInBundle(OSType typeToFind,
  555.                                  BNDLRecHandle theBndl,
  556.                                  BundleTypePtr *returnBundleType)
  557. {
  558.     OSErr            error;
  559.     short            index;
  560.     Ptr                ptrIterator;    /* use a Ptr so we can do ugly pointer math */
  561.     
  562.     error = afpItemNotFound;    /* default to not found */
  563.     
  564.     ptrIterator = (Ptr)((*theBndl)->typeArray);
  565.     index = 0;
  566.     *returnBundleType = NULL;
  567.  
  568.     while ( (index < ((*theBndl)->numTypes + 1)) &&
  569.             (*returnBundleType == NULL) )
  570.     {
  571.         if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
  572.              (((BundleTypePtr)ptrIterator)->count >= 0) )
  573.         {
  574.                 *returnBundleType = (BundleTypePtr)ptrIterator;
  575.                 error = noErr;
  576.         }
  577.         else
  578.         {
  579.             ptrIterator += ( sizeof(OSType) +
  580.                              sizeof(short) +
  581.                              ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
  582.             ++index;
  583.         }
  584.     }
  585.         
  586.     return ( error );
  587. }
  588.  
  589. /*****************************************************************************/
  590.  
  591. /*
  592. **    GetLocalIDFromFREF
  593. **
  594. **    Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
  595. **    looking for a matching fileType. If a matching fileType is found, return
  596. **    its icon local ID. If no match is found, return afpItemNotFound as the
  597. **    function result.
  598. */
  599. static    OSErr    GetLocalIDFromFREF(BundleTypePtr theBundleType,
  600.                                    OSType fileType,
  601.                                    short *iconLocalID)
  602. {
  603.     OSErr            error;
  604.     short            index;
  605.     IDRecPtr        idIterator;
  606.     FREFRecHandle    theFref;
  607.     
  608.     error = afpItemNotFound;    /* default to not found */
  609.     
  610.     /* For each localID in this type, get the FREF resource looking for fileType */
  611.     index = 0;
  612.     idIterator = &theBundleType->idArray[0];
  613.     *iconLocalID = 0;
  614.     
  615.     while ( (index <= (theBundleType->count + 1)) && (*iconLocalID == 0) )
  616.     {
  617.         theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
  618.         if ( theFref != NULL )
  619.         {
  620.             if ( (*theFref)->fileType == fileType )
  621.             {
  622.                 *iconLocalID = (*theFref)->iconID;
  623.                 error = noErr;
  624.             }
  625.         }
  626.         
  627.         ++idIterator;
  628.         ++index;
  629.     }
  630.     
  631.     return ( error );
  632. }
  633.  
  634. /*****************************************************************************/
  635.  
  636. /*
  637. **    GetIconRsrcIDFromLocalID
  638. **
  639. **    Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
  640. **    the localID that matches iconLocalID. If a matching IDRec is found,
  641. **    return the IDRec's rsrcID field value. If no match is found, return
  642. **    afpItemNotFound as the function result.
  643. */
  644. static    OSErr    GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
  645.                                          short iconLocalID,
  646.                                          short *iconRsrcID)
  647. {
  648.     OSErr        error;
  649.     short        index;
  650.     IDRecPtr    idIterator;
  651.     
  652.     error = afpItemNotFound;    /* default to not found */
  653.     
  654.     /* Find the rsrcID of the icon family type, given the localID */
  655.     index = 0;
  656.     idIterator = &theBundleType->idArray[0];
  657.     *iconRsrcID = 0;
  658.     
  659.     while ( (index <= (theBundleType->count+1)) && (*iconRsrcID == 0) )
  660.     {
  661.         if ( idIterator->localID == iconLocalID )
  662.         {
  663.             *iconRsrcID = idIterator->rsrcID;
  664.             error = noErr;
  665.         }
  666.         
  667.         idIterator ++;
  668.         index ++;
  669.     }
  670.     
  671.     return ( error );
  672. }
  673.  
  674. /*****************************************************************************/
  675.  
  676. /*
  677. **    DTIconToResIcon
  678. **
  679. **    Map a Desktop Manager icon type to the corresponding resource type.
  680. **    Return (OSType)0 if there is no corresponding resource type.
  681. */
  682. pascal OSType    DTIconToResIcon(short iconType)
  683. {
  684.     OSType    resType;
  685.     
  686.     switch ( iconType )
  687.     {
  688.         case kLargeIcon:
  689.             resType = large1BitMask;
  690.             break;
  691.         case kLarge4BitIcon:
  692.             resType = large4BitData;
  693.             break;
  694.         case kLarge8BitIcon:
  695.             resType = large8BitData;
  696.             break;
  697.         case kSmallIcon:
  698.             resType = small1BitMask;
  699.             break;
  700.         case kSmall4BitIcon:
  701.             resType = small4BitData;
  702.             break;
  703.         case kSmall8BitIcon:
  704.             resType = small8BitData;
  705.             break;
  706.         default:
  707.             resType = (OSType)0;
  708.             break;
  709.     }
  710.     
  711.     return ( resType );
  712. }
  713.  
  714. /*****************************************************************************/
  715.  
  716. /*
  717. **    GetIconFromDesktopFile
  718. **
  719. **    INPUT a pointer to a non-existent Handle, because we'll allocate one
  720. **
  721. **    search each BNDL resource for the right fileCreator and once we get it
  722. **        find the 'FREF' type in BNDL
  723. **        for each localID in the type, open the FREF resource
  724. **            if the FREF is the desired fileType
  725. **                get its icon localID
  726. **                get the ICN# type in BNDL
  727. **                get the icon resource number from the icon localID
  728. **                get the icon resource type from the desktop mgr's iconType
  729. **                get the icon of that type and number
  730. */
  731. static    OSErr    GetIconFromDesktopFile(StringPtr volName,
  732.                                        short vRefNum,
  733.                                        short iconType,
  734.                                        OSType fileCreator,
  735.                                        OSType fileType,
  736.                                        Handle *iconHandle)
  737. {
  738.     OSErr            error;
  739.     short            realVRefNum;
  740.     Str255            desktopName;
  741.     short            savedResFile;
  742.     short            dfRefNum;
  743.     BNDLRecHandle    theBndl = NULL;
  744.     BundleTypePtr    theBundleType;
  745.     short            iconLocalID;
  746.     short            iconRsrcID;
  747.     OSType            iconRsrcType;
  748.     Handle            returnIconHandle;    
  749.     char            bndlState;
  750.     
  751.     *iconHandle = NULL;
  752.     
  753.     error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
  754.     if ( error == noErr )
  755.     {
  756.         error = GetDesktopFileName(realVRefNum, desktopName);
  757.         if ( error == noErr )
  758.         {
  759.             savedResFile = CurResFile();
  760.         
  761.             /*
  762.             **    Open the 'Desktop' file in the root directory. (because
  763.             **    opening the resource file could preload unwanted resources,
  764.             **    bracket the call with SetResLoad(s))
  765.             */
  766.             SetResLoad(false);
  767.             dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  768.             SetResLoad(true);
  769.         
  770.             if ( dfRefNum != -1 )
  771.             {
  772.                 /*
  773.                 **    Find the BNDL resource with the specified creator.
  774.                 */
  775.                 error = FindBundleGivenCreator(fileCreator, &theBndl);
  776.                 if ( error == noErr )
  777.                 {
  778.                     /* Lock the BNDL resource so it won't be purged when other resources are loaded */
  779.                     bndlState = HGetState((Handle)theBndl);
  780.                     HLock((Handle)theBndl);
  781.                     
  782.                     /* Find the 'FREF' BundleType record in the BNDL resource. */
  783.                     error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
  784.                     if ( error == noErr )
  785.                     {
  786.                         /* Find the local ID in the 'FREF' resource with the specified fileType */
  787.                         error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
  788.                         if ( error == noErr )
  789.                         {
  790.                             /* Find the 'ICN#' BundleType record in the BNDL resource. */
  791.                             error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
  792.                             if ( error == noErr )
  793.                             {
  794.                                 /* Find the icon's resource ID in the 'ICN#' BundleType record */
  795.                                 error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
  796.                                 if ( error == noErr )
  797.                                 {
  798.                                     /* Map Desktop Manager icon type to resource type */
  799.                                     iconRsrcType = DTIconToResIcon(iconType);
  800.                                     
  801.                                     if ( iconRsrcType != (OSType)0 )
  802.                                     {
  803.                                         /* Load the icon */
  804.                                         returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
  805.                                         if ( returnIconHandle != NULL )
  806.                                         {
  807.                                             /* Copy the resource handle, and return the copy */
  808.                                             HandToHand(&returnIconHandle);
  809.                                             if ( MemError() == noErr )
  810.                                                 *iconHandle = returnIconHandle;
  811.                                             else
  812.                                                 error = afpItemNotFound;
  813.                                         }
  814.                                         else
  815.                                             error = afpItemNotFound;
  816.                                     }
  817.                                 }
  818.                             }
  819.                         }
  820.                     }
  821.                     /* Restore the state of the BNDL resource */ 
  822.                     HSetState((Handle)theBndl, bndlState);
  823.                 }
  824.                 /* Restore the resource chain and close the Desktop file */
  825.                 UseResFile(savedResFile);
  826.                 CloseResFile(dfRefNum);
  827.             }
  828.             else
  829.                 error = ResError(); /* could not open Desktop file */
  830.         }
  831.         if ( (error != noErr) && (error != memFullErr) )
  832.         {
  833.             error = afpItemNotFound;    /* force an error we should return */
  834.         }
  835.     }
  836.     
  837.     return ( error );
  838. }
  839.  
  840. /*****************************************************************************/
  841.  
  842. pascal    OSErr    DTGetIcon(StringPtr volName,
  843.                           short vRefNum,
  844.                           short iconType,
  845.                           OSType fileCreator,
  846.                           OSType fileType,
  847.                           Handle *iconHandle)
  848. {
  849.     OSErr error;
  850.     DTPBRec pb;
  851.     short dtRefNum;
  852.     Boolean newDTDatabase;
  853.     Size bufferSize;
  854.     
  855.     *iconHandle = NULL;
  856.     error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
  857.     if ( error == noErr )
  858.     {
  859.         /* there was a desktop database and it's now open */
  860.         
  861.         if ( !newDTDatabase )    /* don't bother to look in a new (empty) database */
  862.         {
  863.             /* get the buffer size for the requested icon type */
  864.             switch ( iconType )
  865.             {
  866.                 case kLargeIcon:
  867.                     bufferSize = kLargeIconSize;
  868.                     break;
  869.                 case kLarge4BitIcon:
  870.                     bufferSize = kLarge4BitIconSize;
  871.                     break;
  872.                 case kLarge8BitIcon:
  873.                     bufferSize = kLarge8BitIconSize;
  874.                     break;
  875.                 case kSmallIcon:
  876.                     bufferSize = kSmallIconSize;
  877.                     break;
  878.                 case kSmall4BitIcon:
  879.                     bufferSize = kSmall4BitIconSize;
  880.                     break;
  881.                 case kSmall8BitIcon:
  882.                     bufferSize = kSmall8BitIconSize;
  883.                     break;
  884.                 default:
  885.                     iconType = 0;
  886.                     bufferSize = 0;
  887.                     break;
  888.             }
  889.             if ( bufferSize != 0 )
  890.             {
  891.                 *iconHandle = NewHandle(bufferSize);
  892.                 if ( *iconHandle != NULL )
  893.                 {
  894.                     HLock(*iconHandle);
  895.         
  896.                     pb.ioDTRefNum = dtRefNum;
  897.                     pb.ioTagInfo = 0;
  898.                     pb.ioDTBuffer = **iconHandle;
  899.                     pb.ioDTReqCount = bufferSize;
  900.                     pb.ioIconType = iconType;
  901.                     pb.ioFileCreator = fileCreator;
  902.                     pb.ioFileType = fileType;
  903.                     error = PBDTGetIconSync(&pb);
  904.     
  905.                     HUnlock(*iconHandle);
  906.                     
  907.                     if ( error != noErr )
  908.                     {
  909.                         DisposeHandle(*iconHandle);    /* dispose of the allocated memory */
  910.                         *iconHandle = NULL;
  911.                     }
  912.                 }
  913.                 else
  914.                     error = memFullErr;    /* handle could not be allocated */
  915.             }
  916.             else
  917.                 error = paramErr;    /* unknown icon type requested */
  918.         }
  919.         else
  920.             error = afpItemNotFound;    /* the desktop database was empty - nothing to return */
  921.     }
  922.     else
  923.     {
  924.         /* There is no desktop database - try the Desktop file */
  925.         
  926.         error = GetIconFromDesktopFile(volName, vRefNum, iconType,
  927.                                         fileCreator, fileType, iconHandle);
  928.     }
  929.     
  930.     return ( error );
  931. }
  932.  
  933. /*****************************************************************************/
  934.  
  935. pascal    OSErr    DTSetComment(short vRefNum,
  936.                              long dirID,
  937.                              StringPtr name,
  938.                              ConstStr255Param comment)
  939. {
  940.     DTPBRec pb;
  941.     OSErr error;
  942.     short dtRefNum;
  943.     Boolean newDTDatabase;
  944.  
  945.     error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  946.     if ( error == noErr )
  947.     {
  948.         pb.ioDTRefNum = dtRefNum;
  949.         pb.ioNamePtr = name;
  950.         pb.ioDirID = dirID;
  951.         pb.ioDTBuffer = (Ptr)&comment[1];
  952.         /* Truncate the comment to 200 characters just in case */
  953.         /* some file system doesn't range check */
  954.         if ( comment[0] <= 200 )
  955.             pb.ioDTReqCount = comment[0];
  956.         else
  957.             pb.ioDTReqCount = 200;
  958.         error = PBDTSetCommentSync(&pb);
  959.     }
  960.     return (error);
  961. }
  962.  
  963. /*****************************************************************************/
  964.  
  965. pascal    OSErr    FSpDTSetComment(const FSSpec *spec,
  966.                               ConstStr255Param comment)
  967. {
  968.     return (DTSetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  969. }
  970.  
  971. /*****************************************************************************/
  972.  
  973. /*
  974. **    GetCommentID
  975. **
  976. **    Get the comment ID number for the Desktop file's 'FCMT' resource ID from
  977. **    the file or folders fdComment (frComment) field.
  978. */
  979. static    OSErr    GetCommentID(short vRefNum,
  980.                              long dirID,
  981.                              StringPtr name,
  982.                              short *commentID)
  983. {
  984.     CInfoPBRec pb;
  985.     OSErr error;
  986.  
  987.     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
  988.     *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
  989.     return ( error );
  990. }
  991.  
  992. /*****************************************************************************/
  993.  
  994. /*
  995. **    GetCommentFromDesktopFile
  996. **
  997. **    Get a file or directory's Finder comment field (if any) from the
  998. **    Desktop file's 'FCMT' resources.
  999. */
  1000. static    OSErr    GetCommentFromDesktopFile(short vRefNum,
  1001.                                           long dirID,
  1002.                                           StringPtr name,
  1003.                                           Str255 comment)
  1004. {
  1005.     OSErr error;
  1006.     short commentID;
  1007.     short realVRefNum;
  1008.     Str255 desktopName;
  1009.     short savedResFile;
  1010.     short dfRefNum;
  1011.     StringHandle commentHandle;
  1012.     
  1013.     /* Get the comment ID number */
  1014.     error = GetCommentID(vRefNum, dirID, name, &commentID);
  1015.     if ( error == noErr )
  1016.     {
  1017.         if ( commentID != 0 )    /* commentID == 0 means there's no comment */
  1018.         {
  1019.             error = DetermineVRefNum(name, vRefNum, &realVRefNum);
  1020.             if ( error == noErr )
  1021.             {
  1022.                 error = GetDesktopFileName(realVRefNum, desktopName);
  1023.                 if ( error == noErr )
  1024.                 {
  1025.                     savedResFile = CurResFile();
  1026.                     /*
  1027.                     **    Open the 'Desktop' file in the root directory. (because
  1028.                     **    opening the resource file could preload unwanted resources,
  1029.                     **    bracket the call with SetResLoad(s))
  1030.                     */
  1031.                     SetResLoad(false);
  1032.                     dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
  1033.                     SetResLoad(true);
  1034.                     
  1035.                     if ( dfRefNum != -1)
  1036.                     {
  1037.                         /* Get the comment resource */
  1038.                         commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
  1039.                         if ( commentHandle != NULL )
  1040.                         {
  1041.                             if ( GetHandleSize((Handle)commentHandle) > 0 )
  1042.                                 BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
  1043.                             else
  1044.                                 error = afpItemNotFound;    /* no comment available */
  1045.                         }
  1046.                         else
  1047.                             error = afpItemNotFound;    /* no comment available */
  1048.                         
  1049.                         /* restore the resource chain and close the Desktop file */
  1050.                         UseResFile(savedResFile);
  1051.                         CloseResFile(dfRefNum);
  1052.                     }
  1053.                     else
  1054.                         error = afpItemNotFound;
  1055.                 }
  1056.                 else
  1057.                     error = afpItemNotFound;
  1058.             }
  1059.         }
  1060.         else
  1061.             error = afpItemNotFound;    /* no comment available */
  1062.     }
  1063.     
  1064.     return ( error );
  1065. }
  1066.  
  1067. /*****************************************************************************/
  1068.  
  1069. pascal    OSErr    DTGetComment(short vRefNum,
  1070.                              long dirID,
  1071.                              StringPtr name,
  1072.                              Str255 comment)
  1073. {
  1074.     DTPBRec pb;
  1075.     OSErr error;
  1076.     short dtRefNum;
  1077.     Boolean newDTDatabase;
  1078.  
  1079.     if (comment != NULL)
  1080.     {
  1081.         comment[0] = 0;    /* return nothing by default */
  1082.         
  1083.         /* attempt to open the desktop database */
  1084.         error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  1085.         if ( error == noErr )
  1086.         {
  1087.             /* There was a desktop database and it's now open */
  1088.             
  1089.             if ( !newDTDatabase )
  1090.             {
  1091.                 pb.ioDTRefNum = dtRefNum;
  1092.                 pb.ioNamePtr = name;
  1093.                 pb.ioDirID = dirID;
  1094.                 pb.ioDTBuffer = (Ptr)&comment[1];
  1095.                 error = PBDTGetCommentSync(&pb);
  1096.                 if (error == noErr)
  1097.                     comment[0] = (unsigned char)pb.ioDTActCount;
  1098.             }
  1099.         }
  1100.         else
  1101.         {
  1102.             /* There is no desktop database - try the Desktop file */
  1103.             error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
  1104.             if ( error != noErr )
  1105.                 error = afpItemNotFound;    /* return an expected error */
  1106.         }
  1107.     }
  1108.     else
  1109.         error = paramErr;
  1110.     
  1111.     return (error);
  1112. }
  1113.  
  1114. /*****************************************************************************/
  1115.  
  1116. pascal    OSErr    FSpDTGetComment(const FSSpec *spec,
  1117.                               Str255 comment)
  1118. {
  1119.     return (DTGetComment(spec->vRefNum, spec->parID, (StringPtr)spec->name, comment));
  1120. }
  1121.  
  1122. /*****************************************************************************/
  1123.  
  1124. pascal    OSErr    DTCopyComment(short srcVRefNum,
  1125.                               long srcDirID,
  1126.                               StringPtr srcName,
  1127.                               short dstVRefNum,
  1128.                               long dstDirID,
  1129.                               StringPtr dstName)
  1130. /* The destination volume must support the Desktop Manager for this to work */
  1131. {
  1132.     OSErr error;
  1133.     Str255 comment;
  1134.  
  1135.     error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
  1136.     if ( (error == noErr) && (comment[0] > 0) )
  1137.     {
  1138.         error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
  1139.     }
  1140.     return (error);
  1141. }
  1142.  
  1143. /*****************************************************************************/
  1144.  
  1145. pascal    OSErr    FSpDTCopyComment(const FSSpec *srcSpec,
  1146.                                const FSSpec *dstSpec)
  1147. /* The destination volume must support the Desktop Manager for this to work */
  1148. {
  1149.     return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, (StringPtr)srcSpec->name,
  1150.                         dstSpec->vRefNum, dstSpec->parID, (StringPtr)dstSpec->name));
  1151. }
  1152.  
  1153. /*****************************************************************************/
  1154.