home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / APLocation / Sources / MacOS_ConnectixUtils.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-23  |  13.9 KB  |  561 lines

  1. /*==================================================================
  2.     File:        MacOS_ConnectixUtils.cpp
  3.  
  4.     Contains:    Miscellaneous utility routines used in program.
  5.  
  6.     Written by:    Various
  7.  
  8.     Copyright:    © 1995-2001 Connectix Corporation
  9. ==================================================================*/
  10.  
  11. #include "MacOS_ConnectixUtils.h"
  12.  
  13. #include <Folders.h>
  14.  
  15.  
  16. // static functions
  17. static OSErr        DetermineVRefNum(ConstStr255Param inPathname, SInt16 inVRefNum, SInt16 * outRealVRefNum);
  18.  
  19. enum
  20. {
  21.     kAnyFileType                = FOUR_CHAR_CODE('****'),
  22.     kAnyFileCreator                = FOUR_CHAR_CODE('****')
  23. };
  24.     
  25.  
  26. /*------------------------------------------------------------------
  27.     CompareBytes
  28.  
  29.     This function compares two blocks of bytes. If the first block
  30.     is greater than the second, the result is positive. If the
  31.     converse is true. the result is negative. If the blocks are
  32.     equal, the result is zero.
  33.  
  34.     Parameters:
  35.         In:        inSource        - the source bytes
  36.                 inDest            - the destination bytes
  37.                 inByteCount        - number of bytes to compare
  38.         Out:    <return>        - positive if 1st > 2nd;
  39.                                   negative if 1st < 2nd;
  40.                                   zero if equal
  41. ------------------------------------------------------------------*/
  42.  
  43. SInt32
  44. CompareBytes(const void* inSource, const void* inDest, UInt32 inByteCount)
  45. {
  46.     // If count is a multiple of four and source and dest
  47.     // are four-byte aligned, perform a faster search.
  48.     if (((inByteCount | reinterpret_cast<const UInt32>(inSource) | reinterpret_cast<const UInt32>(inDest)) & 0x3) == 0)
  49.     {
  50.         SInt32            longResult;
  51.         UInt32            longsLeft = inByteCount >> 2;
  52.         const UInt32*    curStr1 = reinterpret_cast<const UInt32*>(inSource);
  53.         const UInt32*    curStr2 = reinterpret_cast<const UInt32*>(inDest);
  54.  
  55.         while (longsLeft > 0)
  56.         {
  57.             longResult = *curStr1++ - *curStr2++;
  58.             if (longResult)
  59.                 return longResult;
  60.  
  61.             longsLeft--;
  62.         }
  63.     }
  64.     else
  65.     {
  66.         SInt8            byteResult;
  67.         UInt32            bytesLeft = inByteCount;
  68.         const UInt8*    curStr1 = reinterpret_cast<const UInt8*>(inSource);
  69.         const UInt8*    curStr2 = reinterpret_cast<const UInt8*>(inDest);
  70.  
  71.         while (bytesLeft > 0)
  72.         {
  73.             byteResult = *curStr1++ - *curStr2++;
  74.             if (byteResult)
  75.                 return byteResult;
  76.  
  77.             bytesLeft--;
  78.         }
  79.     }
  80.  
  81.     return 0;
  82. }
  83.  
  84.  
  85. /*------------------------------------------------------------------
  86.     BytesMatch
  87.  
  88.     This function compares two blocks of bytes for exact equality.
  89.  
  90.     Parameters:
  91.         In:        inSource        - source bytes
  92.                 inDest            - destination bytes
  93.                 inByteCount        - number of bytes to compare
  94.         Out:    <return>        - true if match
  95. ------------------------------------------------------------------*/
  96.  
  97. Boolean
  98. BytesMatch(const void* inSource, const void* inDest, UInt32 inByteCount)
  99. {
  100.     return CompareBytes(inSource, inDest, inByteCount) == 0;
  101. }
  102.  
  103.  
  104. /*------------------------------------------------------------------
  105.     FillMemory
  106.  
  107.     This function sets the specified range of memory to zero.
  108.  
  109.     Parameters:
  110.         In:        inBase            - memory base
  111.                 inByteCount        - number of bytes to zero
  112.                 inFillValue        - byte to fill
  113. ------------------------------------------------------------------*/
  114.  
  115. // This alternate version of FillMemory is for 68K.
  116.  
  117. void
  118. FillMemory(    void*         inBase, 
  119.             UInt32         inByteCount, 
  120.             UInt8         inFillValue)
  121. {
  122.     UInt8*            curAddr = (UInt8*)inBase;
  123.     double*            doubleAddr;
  124.     UInt32            longValue;
  125.     UInt32            rounder;
  126.     double            memDouble;
  127.     double            regDouble;
  128.  
  129.     longValue = inFillValue | (inFillValue << 8);
  130.     longValue |= longValue << 16;
  131.  
  132.     // Warning: this code assumes doubles are eight bytes in
  133.     // length. On 68K, it's possible that you may have doubles
  134.     // set to 10 bytes. That would be bad.
  135.     check (sizeof(double) == 8);
  136.  
  137.     if (inByteCount < 15)
  138.     {
  139.         while (inByteCount > 0)
  140.         {
  141.             *curAddr++ = inFillValue;
  142.             inByteCount--;
  143.         }
  144.     }
  145.     else
  146.     {
  147.         // first set up our 8-byte fill double.
  148.         ((UInt32*)&memDouble)[0] = longValue;
  149.         ((UInt32*)&memDouble)[1] = longValue;
  150.  
  151.         // then fill up the first 8 bytes regardless.
  152.         *(UInt32*)curAddr = longValue;
  153.         *(UInt32*)(curAddr+4) = longValue;
  154.  
  155.         // figure out how many bytes we need to skip to get
  156.         // to an 8-byte boundary
  157.         rounder = 8 - (7 & (long)curAddr);
  158.  
  159.         // set doubleAddr to be 8 byte prior to that boundary.
  160.         doubleAddr = ((double *)(-8 & (long)curAddr));
  161.  
  162.         // point curAddr past the end of our fill range and fill
  163.         // the last 8 bytes regardless.
  164.         curAddr += inByteCount;
  165.         *(UInt32*)(curAddr - 4) = longValue;
  166.         *(UInt32*)(curAddr - 8) = longValue;
  167.  
  168.         // adjust inByteCount for the fact that we can ignore the
  169.         // bytes prior to the first 8-byte boundary.
  170.         inByteCount -= rounder;
  171.  
  172.         // setup our 8-byte fill double.
  173.         regDouble = memDouble;
  174.  
  175.         // we're going to fill 16 bytes at a time, so if what we
  176.         // have left to fill isn't a multiple of 16 bytes, we'll
  177.         // need an extr 8 filled.
  178.         if (inByteCount & 8) *++doubleAddr = regDouble;
  179.  
  180.         // finally, as long as we have 16 bytes or more to fill,
  181.         // fill them up.
  182.         while (inByteCount > 15)
  183.         {
  184.             *++doubleAddr = regDouble;
  185.             *++doubleAddr = regDouble;
  186.             inByteCount -= 16;
  187.         }
  188.     }
  189. }
  190.  
  191.  
  192. /*------------------------------------------------------------------
  193.     ZeroMemory
  194.  
  195.     This function sets the specified range of memory to zero.
  196.  
  197.     Parameters:
  198.         In:        inBase            - memory base
  199.                 inByteCount        - number of bytes to zero
  200. ------------------------------------------------------------------*/
  201.  
  202. // Alternate version of ZeroMemory for 68K.
  203.  
  204. void
  205. ZeroMemory(void* inBase, UInt32 inByteCount)
  206. {
  207.     FillMemory(inBase, inByteCount, 0);
  208. }
  209.  
  210.  
  211. /*------------------------------------------------------------------
  212.     FSpGetDirInfo
  213.  
  214.     This routine calls PBGetCatInfoSync with the FSSpec.
  215.  
  216.     Parameters:
  217.         In:        inFileSpec        - file spec
  218.         Out:    outCInfoPB        - ptr to a CInfoPBRec
  219.                 (return)        - noErr or file system error
  220. ------------------------------------------------------------------*/
  221.  
  222. OSErr
  223. FSpGetDirInfo(    const FSSpec *    inFileSpec,
  224.                 CInfoPBPtr         outCInfoPB)
  225. {
  226.     OSErr            err = noErr;
  227.  
  228.     ZeroMemory(outCInfoPB, sizeof(CInfoPBRec));
  229.  
  230.     outCInfoPB->dirInfo.ioVRefNum = inFileSpec->vRefNum;
  231.     outCInfoPB->dirInfo.ioDrDirID = inFileSpec->parID;
  232.     outCInfoPB->dirInfo.ioNamePtr = (StringPtr) inFileSpec->name;
  233.  
  234.     err = PBGetCatInfoSync(outCInfoPB);
  235.  
  236.     if (!err && !(outCInfoPB->hFileInfo.ioFlAttrib & ioDirMask))
  237.         err = dirNFErr;
  238.  
  239.     return err;
  240. }
  241.  
  242.  
  243. /*------------------------------------------------------------------
  244.     FindFolderItemByTypeAndCreator
  245.  
  246.     You may pass a wildcard for either type ('****')
  247. ------------------------------------------------------------------*/
  248.  
  249. OSErr
  250. FindFolderItemByTypeAndCreator(
  251.     short        inVRefNum,
  252.     OSType        inFolderType,
  253.     Boolean        inSearchSubdirectories, 
  254.     OSType        inFileType,
  255.     OSType        inFileCreator,
  256.     FSSpec *    outFileSpec)
  257. {
  258.     OSErr    error = noErr;
  259.     
  260.     short    folderVRefNum;
  261.     long    folderDirID;
  262.     error = ::FindFolder(    inVRefNum,
  263.                             inFolderType,
  264.                             kDontCreateFolder,
  265.                             &folderVRefNum,
  266.                             &folderDirID );
  267.     if (error == noErr)
  268.     {
  269.         error = FindDirectoryItemByTypeAndCreator(    folderVRefNum,
  270.                                                     folderDirID,
  271.                                                     inSearchSubdirectories,
  272.                                                     inFileType,
  273.                                                     inFileCreator,
  274.                                                     outFileSpec);
  275.     }
  276.     
  277.     return error;
  278. }
  279.  
  280. /*------------------------------------------------------------------
  281.     FindDirectoryItemByTypeAndCreator
  282.     
  283.     Returns first match.
  284.     You may pass a wildcard for either type ('****').
  285. ------------------------------------------------------------------*/
  286.  
  287. OSErr
  288. FindDirectoryItemByTypeAndCreator(
  289.     short        inVRefNum,
  290.     long        inDirID,
  291.     Boolean        inSearchSubdirectories, 
  292.     OSType        inFileType,
  293.     OSType        inFileCreator,
  294.     FSSpec *    outFileSpec)
  295. {
  296.     OSErr    error    = noErr;
  297.     
  298.     // Make a spec for the directory
  299.     //
  300.     FSSpec    dirSpec;
  301.     error = ::FSMakeFSSpec(    inVRefNum,
  302.                             inDirID,
  303.                             "\p",
  304.                             &dirSpec );
  305.     require(error == noErr, FatalError);
  306.     
  307.     // Verify the item is a directory, and get the real dirID
  308.     //
  309.     long        dirID;
  310.     error = FSGetDirectoryID(&dirSpec, &dirID);
  311.     require(error == noErr, FatalError);
  312.     
  313.     // Get the real vRefNum
  314.     //
  315.     short        vRefNum;
  316.     error = DetermineVRefNum("\p", inVRefNum, &vRefNum);
  317.     require(error == noErr, FatalError);
  318.     
  319.     // Build the CInfo block
  320.     //
  321.     StrFileName    itemName    = "\p";
  322.     CInfoPBRec    catInfo;
  323.     ::ZeroMemory(&catInfo, sizeof(catInfo));
  324.     catInfo.dirInfo.ioNamePtr    = itemName;
  325.     catInfo.dirInfo.ioVRefNum    = vRefNum;
  326.     
  327.     // Iterate through directory
  328.     //
  329.     Boolean    found    = false;
  330.     for (short index = 1; !found && error == noErr; index++)
  331.     {
  332.         // Get catalog info for indexed item
  333.         //
  334.         catInfo.dirInfo.ioFDirIndex    = index;
  335.         catInfo.dirInfo.ioDrDirID    = dirID;
  336.         error = ::PBGetCatInfoSync(&catInfo);    // will generete fnfErr at end of iteration
  337.         require(error == noErr || error == fnfErr, FatalError);
  338.         
  339.         if (error == noErr)
  340.         {
  341.             // Determine if item is a file or a directory
  342.             //
  343.             if ((catInfo.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0)    // a file
  344.             {
  345.                 // Check for match
  346.                 //
  347.                 OSType    fileType    = catInfo.hFileInfo.ioFlFndrInfo.fdType;
  348.                 OSType    fileCreator    = catInfo.hFileInfo.ioFlFndrInfo.fdCreator;
  349.                 if ( (inFileType == kAnyFileType || inFileType == fileType)
  350.                     && (inFileCreator == kAnyFileCreator || inFileCreator == fileCreator ) )
  351.                 {
  352.                     // Match found: Set quit flag and output spec
  353.                     //
  354.                     found    = true;
  355.                     error = ::FSMakeFSSpec(    catInfo.hFileInfo.ioVRefNum,
  356.                                             catInfo.hFileInfo.ioFlParID,
  357.                                             itemName,
  358.                                             outFileSpec );
  359.                 }
  360.             }
  361.             else                                                        // a directory
  362.             {
  363.                 if (inSearchSubdirectories)    // recurse to subdirectories
  364.                 {
  365.                     error = FindDirectoryItemByTypeAndCreator(    catInfo.hFileInfo.ioVRefNum,
  366.                                                                 catInfo.dirInfo.ioDrDirID,
  367.                                                                 inSearchSubdirectories, 
  368.                                                                 inFileType,
  369.                                                                 inFileCreator,
  370.                                                                 outFileSpec );
  371.                     if (error == noErr)    // a match was found: stop search
  372.                         { found    = true; }
  373.                     else if (error == fnfErr)    // normal termination of iteration: keep looking
  374.                         { error = noErr; }
  375.                     else if (error == afpAccessDenied)    // non-fatal permission error: keep looking
  376.                         { error = noErr; }
  377.                     else    // general error: abort with error
  378.                         {}
  379.                 }
  380.             }
  381.         }
  382.     }
  383.     
  384. FatalError:
  385.     
  386.     return error;
  387. }
  388.  
  389.  
  390. /*------------------------------------------------------------------
  391.     FSGetDirectoryID
  392.  
  393.     This routine gets the ioDrDirID from an FSSpec.
  394.  
  395.     Parameters:
  396.         In:        inFileSpec        - file spec
  397.         Out:    dirID            - ioDrDirID
  398.                 (return)        - noErr or file system error
  399. ------------------------------------------------------------------*/
  400.  
  401. OSErr
  402. FSGetDirectoryID(    const FSSpec *    inFileSpec,
  403.                     long *            outDirID)
  404. {
  405.     OSErr             err = noErr;
  406.     CInfoPBRec        cInfoPB;
  407.  
  408.     err = FSpGetDirInfo(inFileSpec, &cInfoPB);
  409.     if (err == noErr)
  410.         *outDirID = cInfoPB.dirInfo.ioDrDirID;
  411.  
  412.     return err;
  413. }
  414.  
  415.  
  416. /*------------------------------------------------------------------
  417.     GetVolumeInfoNoName
  418.  
  419.     Stolen from MoreFilesExtras for use in GetParentID.
  420. ------------------------------------------------------------------*/
  421.  
  422. static OSErr
  423. GetVolumeInfoNoName(
  424.     ConstStr255Param    inPathname,
  425.     SInt16                inVRefNum,
  426.     HParmBlkPtr            outPB)
  427. {
  428.     Str255    tempPathname;
  429.     OSErr    err;
  430.     
  431.     /* Make sure pb parameter is not NULL */
  432.     if (outPB != NULL)
  433.     {
  434.         outPB->volumeParam.ioVRefNum = inVRefNum;
  435.         if (inPathname == NULL)
  436.         {
  437.             outPB->volumeParam.ioNamePtr    = NULL;
  438.             outPB->volumeParam.ioVolIndex    = 0;    /* use ioVRefNum only */
  439.         }
  440.         else
  441.         {
  442.             ::BlockMoveData(inPathname, tempPathname, inPathname[0] + 1);    /* make a copy of the string and */
  443.             outPB->volumeParam.ioNamePtr    = tempPathname;                    /* use the copy so the original isn't trashed */
  444.             outPB->volumeParam.ioVolIndex    = -1;    /* use ioNamePtr/ioVRefNum combination */
  445.         }
  446.         err = ::PBHGetVInfoSync(outPB);
  447.         outPB->volumeParam.ioNamePtr = NULL;    /* ioNamePtr may point to local tempPathname, so don't return it */
  448.     }
  449.     else
  450.     {
  451.         err = paramErr;
  452.     }
  453.     
  454.     return err;
  455. }
  456.  
  457.  
  458. /*------------------------------------------------------------------
  459.     DetermineVRefNum
  460.  
  461.     Stolen from MoreFilesExtras for use in GetParentID.
  462. ------------------------------------------------------------------*/
  463.  
  464. static OSErr
  465. DetermineVRefNum(
  466.     ConstStr255Param    inPathname,
  467.     SInt16                inVRefNum,
  468.     SInt16 *            outRealVRefNum)
  469. {
  470.     HParamBlockRec    pb;
  471.     OSErr            err;
  472.     
  473.     err = GetVolumeInfoNoName(inPathname, inVRefNum, &pb);
  474.     
  475.     if (err == noErr)
  476.     {
  477.         *outRealVRefNum = pb.volumeParam.ioVRefNum;
  478.     }
  479.     
  480.     return err;
  481. }
  482.  
  483.  
  484. /*------------------------------------------------------------------
  485.     MakeFSSpec
  486.  
  487.     This routine creates a file specification record from the given
  488.     parameters. It replaces the API call FSMakeFSSpec() because
  489.     FSMakeFSSpec() does not properly handle creating an fsspec for
  490.     the root directory of a    PC Exchange volume.
  491.  
  492.     Parameters:
  493.         In:        inVRefNum        - the volume
  494.                 inDirID            - the directory ID
  495.                 inName            - the item name or partial pathname
  496.         Out:    outFileSpec        - file spec to folder
  497.                 (return)        - true if found
  498. ------------------------------------------------------------------*/
  499.  
  500. OSErr
  501. MakeFSSpec(    SInt16                inVRefNum,
  502.             SInt32                inDirID,
  503.             ConstStr255Param    inName,
  504.             FSSpec*                outFileSpec)
  505. {
  506.     OSErr status;
  507.     HParamBlockRec params;
  508.     Str255 name;
  509.  
  510.     if (inDirID != fsRtDirID || StrLength(inName) != 0)
  511.     {
  512.         status = ::FSMakeFSSpec(inVRefNum, inDirID, inName, outFileSpec);
  513.     }
  514.     else
  515.     {
  516.         // Get the root directory name
  517.         params.volumeParam.ioCompletion = NULL;
  518.         BlockMoveData(inName, name, 256);
  519.         params.volumeParam.ioNamePtr     = name;
  520.         params.volumeParam.ioVRefNum     = inVRefNum;
  521.         params.volumeParam.ioVolIndex    = 0;    // find using vRefNum only
  522.  
  523.         status = ::PBHGetVInfoSync(¶ms);
  524.         if (status != noErr)
  525.             return(status);
  526.  
  527.         status = ::FSMakeFSSpec(inVRefNum,
  528.                                 fsRtParID, 
  529.                                 name, 
  530.                                 outFileSpec);
  531.     }
  532.  
  533.     return status;
  534. }
  535.  
  536.  
  537. /*------------------------------------------------------------------
  538.     FSpGetCatInfo
  539.  
  540.     This function returns the catalog info for a specified file.
  541.  
  542.     Parameter:
  543.         In:        inSpec        - a file system spec
  544.         Out:    outCatInfo    - the catalog info
  545.                 (return)    - non-zero indicates an error
  546. ------------------------------------------------------------------*/
  547.  
  548. OSErr
  549. FSpGetCatInfo(    const FSSpec*    inSpec,
  550.                 CInfoPBPtr        outCatInfo)
  551. {
  552.     outCatInfo->hFileInfo.ioCompletion = NULL;
  553.     outCatInfo->hFileInfo.ioVRefNum = inSpec->vRefNum;
  554.     outCatInfo->hFileInfo.ioNamePtr = const_cast<StringPtr>(inSpec->name);
  555.     outCatInfo->hFileInfo.ioFDirIndex = 0;
  556.     outCatInfo->hFileInfo.ioDirID = inSpec->parID;
  557.     return PBGetCatInfoSync(outCatInfo);
  558. }
  559.  
  560.  
  561.