home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Utilities / PlfmFile.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  53.1 KB  |  1,800 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PlfmFile.cpp
  3.  
  4.     Contains:    Implmentation for PlatformFile class
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <14>    27.09.1996    NP        1377649, 1379135: Fix error handling in
  13.                                     routines
  14.         <13>     9/27/96    EL        1353486: Add LockError to report how a file
  15.                                     is locked.
  16.         <12>     9/24/96    eeh        1315787: Allow non-OD files with
  17.                                     31-character names
  18.         <11>    11.09.1996    NP        1386083: fix mem leak
  19.         <10>     7/28/96    DH        Bug#1372834: Cyberdog: Drag to Finder fails
  20.                                     when MacOS scraptype used.
  21.          <9>      6/4/96    EL        Remove debug statement left in from last
  22.                                     check in.
  23.          <8>      6/4/96    EL        1289557: Truncate comment but don't split
  24.                                     two byte character if comment is too long.
  25.          <7>     5/31/96    JA        CW68K: Fixed mem leak/app-heap usage in
  26.                                     GetCustomIconFamily.
  27.          <6>     5/31/96    jpa        T10012: Added IsOpenDocDocument.
  28.          <5>     5/23/96    DH        1352221: Document Info dialog is
  29.                                     disabled/acts flaky. Fixed GetCustomIcon so
  30.                                     that it doesn't manually fiddle with the
  31.                                     resource fork of the file.
  32.          <4>      5/8/96    NP        1282265: saving as stationery looks like
  33.                                     document
  34.          <3>     3/15/96    DH        1329039 - OpenDoc's routine
  35.                                     PlatformFile::HasCustomIcon() does not
  36.                                     work.
  37.          <2>      3/1/96    JP        1314798: Made CreateResFile get type &
  38.                                     creator first
  39.  
  40.     To Do:
  41.     In Progress:
  42.         
  43. */
  44.  
  45. #ifndef _ODTYPES_
  46. #include "ODTypes.h"
  47. #endif
  48.  
  49. #ifndef _PLFMFILE_
  50. #include "PlfmFile.h"
  51. #endif
  52.  
  53. #ifndef _ODMEMORY_
  54. #include "ODMemory.h"
  55. #endif
  56.  
  57. #ifndef _EXCEPT_
  58. #include "Except.h"
  59. #endif
  60.  
  61. #ifndef _ODDEBUG_
  62. #include "ODDebug.h"
  63. #endif
  64.  
  65. #ifndef _PASCLSTR_
  66. #include "PasclStr.h"
  67. #endif
  68.  
  69. #ifndef _ITEXT_
  70. #include "IText.h"
  71. #endif
  72.  
  73. #ifndef _DOCUTILS_
  74. #include "DocUtils.h"
  75. #endif
  76.  
  77. #ifndef _DLOGUTIL_
  78. #include <DlogUtil.h>
  79. #endif
  80.  
  81. #ifndef _UTILDEFS_
  82. #include "UtilDefs.h"
  83. #endif
  84.  
  85. #ifndef _TEMPOBJ_
  86. #include "TempObj.h"
  87. #endif
  88.  
  89. #ifndef _UTILERRS_
  90. #include "UtilErrs.h"
  91. #endif
  92.  
  93. #ifndef __FILES__
  94. #include <Files.h>
  95. #endif
  96.  
  97. #ifndef __FOLDERS__
  98. #include <Folders.h>
  99. #endif
  100.  
  101. #ifndef __FINDER__
  102. #include <Finder.h>
  103. #endif
  104.  
  105. #ifndef __ICONS__
  106. #include <Icons.h>
  107. #endif
  108.  
  109. #ifndef __STRING__
  110. #include <string.h>
  111. #endif
  112.  
  113. #ifndef __ERRORS__
  114. #include <Errors.h>
  115. #endif
  116.  
  117. #ifndef __TEXTUTILS__
  118. #include "TextUtils.h"
  119. #endif
  120.  
  121. #ifndef _USERSRCM_
  122. #include <UseRsrcM.h>
  123. #endif
  124.  
  125. #ifndef __TEXTUTILS__
  126. #include "TextUtils.h"
  127. #endif
  128.  
  129. #include <ctype.h>    /* for islower( ) */
  130.  
  131.  
  132. #pragma segment PlatformFile
  133.  
  134. //==============================================================================
  135. // Constants
  136. //==============================================================================
  137.  
  138. const    ODSShort    kMaxFileNameSize        = 64;
  139. const    ODULong        kMaxCommentSize            = 199;
  140.  
  141. #define    kFileContainerType                    'ctyp'
  142. #define    kFileContainerTypeResID                1
  143.  
  144. const ODULong    kMaxCopyBufferSize            = 32 * 1024L;
  145. const ODULong    kMinCopyBufferSize            = 512;
  146.  
  147. static const ResType            kIconType[6] = {'ICN#','icl4','icl8','ics#','ics4','ics8'};
  148. static const short                kIconSize[6] = {256,   512,   1024,  64,    128,   256   };
  149.  
  150. #define kODCyberdogSignature                'dogz'
  151.  
  152. //==============================================================================
  153. // Scalar Types
  154. //==============================================================================
  155.  
  156. //==============================================================================
  157. // Local Classes
  158. //==============================================================================
  159.  
  160. //==============================================================================
  161. // Global Variables
  162. //==============================================================================
  163.  
  164. //==============================================================================
  165. // Function Prototype
  166. //==============================================================================
  167.  
  168. //==============================================================================
  169. // PlatformFile
  170. //==============================================================================
  171.  
  172. const ODOSType kBogusOSType = 0;    // Default type/creator value until it's read
  173.  
  174. //------------------------------------------------------------------------------
  175. // PlatformFile::PlatformFile
  176. //------------------------------------------------------------------------------
  177. PlatformFile::PlatformFile()
  178. {
  179.     fContainerType = kODNULL;
  180.     fCreator = kBogusOSType;
  181.     fFileType = kBogusOSType;
  182.     fScriptTag = smSystemScript;
  183.     
  184.     fFileSpec.vRefNum = 0;
  185.     fFileSpec.parID = 0;
  186.     fFileSpec.name[0] = 0;
  187.     fDataRefNum = 0;
  188.     fFileID = kODNoFileID;
  189.     fPermission = fsCurPerm;
  190.     fResRefNum = kODNoFileRefNum;
  191.     fResOpenStack = 0;
  192.     fNeedToClose = kODFalse;
  193.     
  194.     fVolModDate = fTimeLastChecked = 0;
  195. }
  196.  
  197. //------------------------------------------------------------------------------
  198. // PlatformFile::~PlatformFile
  199. //------------------------------------------------------------------------------
  200. PlatformFile::~PlatformFile()
  201. {
  202.     ODDisposePtr(fContainerType);
  203. }
  204.  
  205. //------------------------------------------------------------------------------
  206. // PlatformFile::Specify
  207. //------------------------------------------------------------------------------
  208. void PlatformFile::Specify(const ODFileSpec* fileSpec)
  209. {
  210.     fFileSpec = *fileSpec;
  211.     WASSERT( fFileSpec.name[0] <= 31 );
  212.     fCreator = kBogusOSType;
  213.     fFileType = kBogusOSType;
  214.     fFileID = kODNoFileID;
  215. }
  216.  
  217. void PlatformFile::SpecifyFromFile(PlatformFile* file)
  218. {
  219.     const ODFileSpec &fileSpec = file->GetFileSpec();
  220.     this->Specify(&fileSpec);
  221. }
  222.  
  223. //------------------------------------------------------------------------------
  224. // PlatformFile::SetAsciiname
  225. //------------------------------------------------------------------------------
  226. void PlatformFile::SetAsciiName(const char* asciiName)
  227. {
  228.     ODSByte pname[kMaxFileNameSize+1];
  229.     strncpy(pname,asciiName,kMaxFileNameSize);
  230.     pname[kMaxFileNameSize] = 0;
  231.     
  232.     CToPascalString(pname);
  233.     if (fFileSpec.vRefNum == 0 &&
  234.         fFileSpec.parID == 0 &&
  235.         fFileSpec.name[0] == 0)
  236.     {
  237.         FSMakeFSSpec(0, 0, (StringPtr)pname, &fFileSpec);
  238.     }
  239.     else
  240.     {
  241.         CopyPascalString(fFileSpec.name,(StringPtr)pname);
  242.     }    
  243.     this->Specify(&fFileSpec);
  244. }
  245.  
  246. //------------------------------------------------------------------------------
  247. // PlatformFile::LockError
  248. //------------------------------------------------------------------------------
  249. ODError PlatformFile::LockError()
  250. {
  251.     CInfoPBRec    pbBlock;
  252.     ODError        result = noErr;
  253.  
  254.     // Check to see whether the volume is locked
  255.     // if it is locked, return an error indicating how it is locked
  256.     
  257.     // Eric's original code with slight modifications.
  258.     // Appears to be needed in the case of a locked floppy. -TÇ
  259.     HParamBlockRec pb;
  260.     pb.volumeParam.ioCompletion = kODNULL;
  261.     pb.volumeParam.ioNamePtr = kODNULL;
  262.     pb.volumeParam.ioVRefNum = fFileSpec.vRefNum;
  263.     pb.volumeParam.ioVolIndex = 0;
  264.  
  265.     THROW_IF_ERROR(PBHGetVInfoSync(&pb));
  266.  
  267.     // <eeh> I have no clue if this "0x80"is right!!!  Find out what
  268.     // the constant is for write-access possible....
  269.  
  270.     if (pb.volumeParam.ioVAtrb & 0x80)
  271.         result = wPrErr;
  272.     else {
  273.         // Check to see whether the directory is locked
  274.         // first assume it is a file share volume
  275.         HParamBlockRec    paramBlk;
  276.         paramBlk.accessParam.ioCompletion = kODNULL;
  277.         paramBlk.accessParam.ioNamePtr = kODNULL;
  278.         paramBlk.accessParam.ioVRefNum = fFileSpec.vRefNum;
  279.         paramBlk.accessParam.ioDirID = fFileSpec.parID;
  280.         paramBlk.accessParam.ioACAccess = 0;
  281.         OSErr err = PBHGetDirAccessSync(¶mBlk);
  282.         
  283.         if (err == noErr) {        /* it is a file share volume, look at the access right */
  284.             if ((paramBlk.accessParam.ioACAccess & 0x04000000) == 0) /* no write access */
  285.                 result = vLckdErr;
  286.         }
  287.         else if (err == paramErr) { /* it is not file share, look at directory */
  288.             pbBlock.dirInfo.ioCompletion = kODNULL;
  289.             pbBlock.dirInfo.ioNamePtr = kODNULL;
  290.             pbBlock.dirInfo.ioVRefNum = fFileSpec.vRefNum;
  291.             pbBlock.dirInfo.ioFDirIndex = -1;
  292.             pbBlock.dirInfo.ioDrDirID = fFileSpec.parID;
  293.             pbBlock.dirInfo.ioFlAttrib = 0;
  294.             THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  295.             if (pbBlock.dirInfo.ioFlAttrib & 1)
  296.                 result = vLckdErr;
  297.         }
  298.         else
  299.             THROW(err);
  300.     }
  301.  
  302.     // Check to see whether the file is locked
  303.     if (result == noErr) {    
  304.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  305.         pbBlock.hFileInfo.ioFDirIndex = 0;
  306.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  307.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  308.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  309.         
  310.         THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  311.  
  312.         if (pbBlock.hFileInfo.ioFlAttrib & 1)
  313.             result = fLckdErr;
  314.     }
  315.     
  316.     return result;
  317. }
  318.  
  319. //------------------------------------------------------------------------------
  320. // PlatformFile::IsLocked
  321. //------------------------------------------------------------------------------
  322. ODBoolean PlatformFile::IsLocked()
  323. {
  324.     return     (this->LockError() != noErr) ? kODTrue : kODFalse;
  325. }
  326.  
  327. //------------------------------------------------------------------------------
  328. // PlatformFile::Lock
  329. //------------------------------------------------------------------------------
  330. void PlatformFile::Lock()
  331. {
  332.     THROW_IF_ERROR( FSpSetFLock(&fFileSpec) );
  333. }
  334.  
  335. //------------------------------------------------------------------------------
  336. // PlatformFile::Unlock
  337. //------------------------------------------------------------------------------
  338. void PlatformFile::Unlock()
  339. {
  340.     THROW_IF_ERROR( FSpRstFLock(&fFileSpec) );
  341. }
  342.  
  343.  
  344. //------------------------------------------------------------------------------
  345. // PlatformFile::IsStationery
  346. //------------------------------------------------------------------------------
  347. ODBoolean PlatformFile::IsStationery()
  348. {
  349.     FInfo fileInfo;
  350.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec,&fileInfo) );
  351.     return (((fileInfo.fdFlags)&kIsStationary)!=0);
  352. }
  353.  
  354. //------------------------------------------------------------------------------
  355. // PlatformFile::SetStationery
  356. //------------------------------------------------------------------------------
  357.  
  358. void PlatformFile::SetStationery(ODBoolean isStationery)
  359. {
  360.     if (isStationery)
  361.         this->SetFinderFlag(kIsStationery);
  362.     else
  363.         this->UnsetFinderFlag(kIsStationery);
  364.  
  365. //    FInfo fileInfo;
  366.  
  367. //    THROW_IF_ERROR( FSpGetFInfo(&fFileSpec,&fileInfo) );
  368. //    if (isStationery)
  369. //        (fileInfo.fdFlags) |= kIsStationery;
  370. //    else
  371. //        (fileInfo.fdFlags) &= ~kIsStationery;
  372. //    THROW_IF_ERROR( FSpSetFInfo(&fFileSpec,&fileInfo) );
  373.     // Finder bug prevents this from helping to update the icon in the Finder
  374. //    BumpFolderModDate();
  375. }
  376.  
  377. //------------------------------------------------------------------------------
  378. // PlatformFile::SetCustomIcon
  379. //------------------------------------------------------------------------------
  380.  
  381. void PlatformFile::SetCustomIcon(ODBoolean hasCustomIcon)
  382. {
  383.     if (hasCustomIcon)
  384.         this->SetFinderFlag(kHasCustomIcon);
  385.     else
  386.         this->UnsetFinderFlag(kHasCustomIcon);
  387. //    FInfo fileInfo;
  388.  
  389. //    THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  390. //    if (hasCustomIcon)
  391. //        (fileInfo.fdFlags) |= kHasCustomIcon;
  392. //    else
  393. //        (fileInfo.fdFlags) &= ~kHasCustomIcon;
  394. //    THROW_IF_ERROR( FSpSetFInfo(&fFileSpec, &fileInfo) );
  395. //    BumpFolderModDate();
  396. }
  397.  
  398. //------------------------------------------------------------------------------
  399. // PlatformFile::SetFinderFlag
  400. //------------------------------------------------------------------------------
  401.  
  402. void PlatformFile::SetFinderFlag(ODUShort flag)
  403. {
  404.     FInfo fileInfo;
  405.  
  406.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  407.     (fileInfo.fdFlags) |= flag;
  408.     THROW_IF_ERROR( FSpSetFInfo(&fFileSpec, &fileInfo) );
  409. //    if (flag != kIsStationery)
  410.         BumpFolderModDate();
  411. }
  412.  
  413. //------------------------------------------------------------------------------
  414. // PlatformFile::UnsetFinderFlag
  415. //------------------------------------------------------------------------------
  416.  
  417. void PlatformFile::UnsetFinderFlag(ODUShort flag)
  418. {
  419.     FInfo fileInfo;
  420.  
  421.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  422.     (fileInfo.fdFlags) &= ~flag;
  423.     THROW_IF_ERROR( FSpSetFInfo(&fFileSpec, &fileInfo) );
  424. //    if (flag != kIsStationery)
  425.         BumpFolderModDate();
  426. }
  427.  
  428. //------------------------------------------------------------------------------
  429. // PlatformFile::HasCustomIcon
  430. //------------------------------------------------------------------------------
  431.  
  432. ODBoolean PlatformFile::HasCustomIcon()
  433. {
  434.     FInfo fileInfo;
  435.     
  436.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  437.     return ( (fileInfo.fdFlags & kHasCustomIcon) ? kODTrue : kODFalse);
  438. }
  439.  
  440. //------------------------------------------------------------------------------
  441. // PlatformFile::IsDirectory
  442. //------------------------------------------------------------------------------
  443. ODBoolean PlatformFile::IsDirectory()
  444. {    
  445.     ODBoolean isDirectory = kODFalse;
  446.     
  447.     if( fFileID == kODNoFileID ) {
  448.         CInfoPBRec    pbBlock;
  449.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  450.         pbBlock.hFileInfo.ioFDirIndex = 0;
  451.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  452.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  453.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  454.         THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  455.         isDirectory = pbBlock.dirInfo.ioFlAttrib & 0x10 ? kODTrue : kODFalse;
  456.     }
  457.     return isDirectory;
  458. }
  459.  
  460. //------------------------------------------------------------------------------
  461. // PlatformFile::IsEqualTo
  462. //------------------------------------------------------------------------------
  463. ODBoolean PlatformFile::IsEqualTo(PlatformFile* file)
  464. {
  465.     return (fFileSpec.parID == file->fFileSpec.parID &&
  466.             fFileSpec.vRefNum == file->fFileSpec.vRefNum &&
  467.             EqualPascalStrings(fFileSpec.name, file->fFileSpec.name));
  468. }
  469.  
  470. //------------------------------------------------------------------------------
  471. // PlatformFile::GetFInfoFlags
  472. //------------------------------------------------------------------------------
  473. ODUShort    PlatformFile::GetFInfoFlags()
  474. {
  475.     FInfo fileInfo;
  476.  
  477.     THROW_IF_ERROR( FSpGetFInfo(&fFileSpec, &fileInfo) );
  478.     return fileInfo.fdFlags;
  479. }
  480.  
  481. //------------------------------------------------------------------------------
  482. // PlatformFile::Create
  483. //------------------------------------------------------------------------------
  484. void PlatformFile::Create(ODOSType creator, ODOSType fileType, ODScriptCode scriptCode)
  485. {    
  486.     
  487.     if (fDataRefNum == kODNoFileRefNum) {
  488.         THROW_IF_ERROR( FSpCreate(&fFileSpec, creator, fileType, scriptCode) );
  489.     }
  490.     fCreator = creator;
  491.     fFileType = fileType;
  492.     fScriptTag = scriptCode;
  493.     
  494.     this->GetFileID();
  495. }
  496.  
  497. //------------------------------------------------------------------------------
  498. // PlatformFile::CreateResFile
  499. //------------------------------------------------------------------------------
  500. void PlatformFile::CreateResFile()
  501. {
  502.     if (fResRefNum == kODNoFileRefNum)
  503.     {
  504.         this->GetPlatformType();    // make sure the type and creator are known
  505.         FSpCreateResFile(&fFileSpec, fCreator, fFileType, fScriptTag);
  506.         THROW_IF_ERROR(ResError());
  507.     }
  508.     this->GetFileID();
  509. }
  510.  
  511. //------------------------------------------------------------------------------
  512. // PlatformFile::OpenResFile
  513. //------------------------------------------------------------------------------
  514. void PlatformFile::OpenResFile()
  515. {
  516.     ASSERT(fResOpenStack >= 0, kODErrAssertionFailed);
  517.     if (fResRefNum == kODNoFileRefNum)
  518.     {
  519.         ASSERT(fResOpenStack == 0, fResOpenStack);
  520.         fResRefNum = GetFirstLocalPath(kODResourceFork);
  521.         if (fResRefNum != kODNoFileRefNum)
  522.         {
  523.             // Resource fork is already open
  524.             UseResFile(fResRefNum);
  525.             fNeedToClose = kODFalse;
  526.         }
  527.         else
  528.         {
  529.             // Resource fork is closed
  530.             fResRefNum = FSpOpenResFile(&fFileSpec, fPermission);
  531.             if (fResRefNum == -1 && fPermission != fsRdPerm)
  532.             {
  533.                 fResRefNum = kODNoFileRefNum;
  534.                 CreateResFile();
  535.                 fResRefNum = FSpOpenResFile(&fFileSpec, fPermission);
  536.             }
  537.             OSErr err = ResError();
  538.             if (err != eofErr)
  539.             {
  540.                 if (fResRefNum == -1)
  541.                     fResRefNum = kODNoFileRefNum;
  542.                 THROW_IF_ERROR(ResError());
  543.             }
  544.             if (fResRefNum == -1)
  545.             {
  546.                 fResRefNum = kODNoFileRefNum;
  547.                 THROW(resFNotFound);
  548.             }
  549.             fNeedToClose = kODTrue;
  550.         }
  551.     }
  552.     else
  553.         UseResFile(fResRefNum);
  554.     ++fResOpenStack;
  555. }
  556.  
  557. //------------------------------------------------------------------------------
  558. // PlatformFile::CloseResFile
  559. //------------------------------------------------------------------------------
  560. void PlatformFile::CloseResFile()
  561. {
  562.     ASSERT(fResOpenStack > 0, fResOpenStack);
  563.     if (--fResOpenStack == 0 && fNeedToClose)
  564.     {
  565.         ::CloseResFile(fResRefNum);
  566.         THROW_IF_ERROR(ResError());
  567.         fResRefNum = kODNoFileRefNum;
  568.     }
  569. }
  570.  
  571. //------------------------------------------------------------------------------
  572. // PlatformFile::GetFileID
  573. //------------------------------------------------------------------------------
  574. void PlatformFile::GetFileID()
  575. {
  576.     if( fFileID == kODNoFileID ) {
  577.         CInfoPBRec    pbBlock;
  578.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  579.         pbBlock.hFileInfo.ioFDirIndex = 0;
  580.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  581.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  582.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  583.         THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  584.         fFileID = pbBlock.hFileInfo.ioDirID;    /* for tracking the file later */
  585.     }
  586. }
  587.  
  588. //------------------------------------------------------------------------------
  589. // PlatformFile::UpdateSpecFromID
  590. //------------------------------------------------------------------------------
  591. void PlatformFile::UpdateSpecFromID()
  592. {
  593.     if (fFileID != kODNoFileID) {    /* make sure got the latest name in file spec */
  594.         HParamBlockRec hPB;
  595.         hPB.fidParam.ioCompletion = kODNULL;
  596.         hPB.fidParam.ioNamePtr = fFileSpec.name;
  597.         hPB.fidParam.ioVRefNum = fFileSpec.vRefNum;
  598.         hPB.fidParam.ioFileID = fFileID;
  599.         if (PBResolveFileIDRefSync(&hPB) == noErr)    /* ignore any error */
  600.             fFileSpec.parID = hPB.fidParam.ioSrcDirID;
  601.         WASSERT( fFileSpec.name[0] <= 31 );
  602.     }
  603. }
  604.  
  605.  
  606. //------------------------------------------------------------------------------
  607. // PlatformFile::Exists
  608. //------------------------------------------------------------------------------
  609. ODBoolean PlatformFile::Exists()
  610. {
  611.     const ODFileSpec &filespec = this->GetFileSpec();
  612.     FInfo ignore ;
  613.     OSErr err = FSpGetFInfo( &filespec, &ignore );
  614.     if ( err == noErr )
  615.         return kODTrue ;
  616.     else {
  617.         if ( err != fnfErr )
  618.             THROW( err );
  619.         return kODFalse ;
  620.     }
  621. }
  622.  
  623. //------------------------------------------------------------------------------
  624. // PlatformFile::Open
  625. //------------------------------------------------------------------------------
  626. void PlatformFile::Open()
  627. {    
  628.     if (fDataRefNum == kODNoFileRefNum) {
  629.         this->GetFileID();
  630.         THROW_IF_ERROR(FSpOpenDF(&fFileSpec, fPermission, &fDataRefNum));
  631.     }
  632.     else
  633.         THROW(kODErrFileOpened);
  634. }
  635.  
  636. //------------------------------------------------------------------------------
  637. // PlatformFile::Close
  638. //------------------------------------------------------------------------------
  639. void PlatformFile::Close()
  640. {    
  641.     if (fDataRefNum != kODNoFileRefNum) {
  642.         THROW_IF_ERROR(FSClose(fDataRefNum));
  643.         fDataRefNum = kODNoFileRefNum;
  644.     }
  645.     else
  646.         THROW(kODErrFileClosed);
  647. }
  648.  
  649. //------------------------------------------------------------------------------
  650. // PlatformFile::Delete
  651. //------------------------------------------------------------------------------
  652. void PlatformFile::Delete()
  653. {    
  654.     THROW_IF_ERROR(FSpDelete(&fFileSpec));
  655.     fFileID = kODNoFileID;
  656. }
  657.  
  658.  
  659. //------------------------------------------------------------------------------
  660. // PlatformFile::FlushVolume
  661. //------------------------------------------------------------------------------
  662. void PlatformFile::FlushVolume()
  663. {    
  664.     if (fDataRefNum != kODNoFileRefNum) {
  665.         ParamBlockRec    pb;
  666.     
  667.         pb.ioParam.ioCompletion = kODNULL;
  668.         pb.ioParam.ioRefNum = fDataRefNum;
  669.         (void) PBFlushFileSync(&pb);
  670.     }
  671.  
  672.     (void) FlushVol(kODNULL, fFileSpec.vRefNum);
  673. }
  674.  
  675. //------------------------------------------------------------------------------
  676. // PlatformFile::SetFilePos
  677. //------------------------------------------------------------------------------
  678. void PlatformFile::SetFilePos(ODSShort posMode, ODSLong posOff)
  679. {    
  680.     THROW_IF_ERROR(SetFPos(fDataRefNum, posMode, posOff));
  681. }
  682.  
  683. //------------------------------------------------------------------------------
  684. // PlatformFile::GetFilePos
  685. //------------------------------------------------------------------------------
  686. ODSLong PlatformFile::GetFilePos()
  687. {
  688.     ODSLong    posOff;
  689.     
  690.     THROW_IF_ERROR(GetFPos(fDataRefNum, &posOff));
  691.     return posOff;
  692. }
  693.  
  694. //------------------------------------------------------------------------------
  695. // PlatformFile::Read
  696. //------------------------------------------------------------------------------
  697. void PlatformFile::Read(void* buffer, ODSLong* count)
  698. {    
  699.     THROW_IF_ERROR(FSRead(fDataRefNum, count, buffer));
  700. }
  701.  
  702. //------------------------------------------------------------------------------
  703. // PlatformFile::Write
  704. //------------------------------------------------------------------------------
  705. void PlatformFile::Write(const void* buffer, ODSLong* count)
  706. {    
  707.     THROW_IF_ERROR(FSWrite(fDataRefNum, count, buffer));
  708. }
  709.  
  710. //------------------------------------------------------------------------------
  711. // PlatformFile::GetEndOfFile
  712. //------------------------------------------------------------------------------
  713. ODSLong PlatformFile::GetEndOfFile()
  714. {    
  715.     ODSLong    length;
  716.     
  717.     THROW_IF_ERROR(GetEOF(fDataRefNum, &length));
  718.     return length;
  719. }
  720.  
  721. //------------------------------------------------------------------------------
  722. // PlatformFile::SetEndOfFile
  723. //------------------------------------------------------------------------------
  724. void  PlatformFile::SetEndOfFile(ODSLong length)
  725. {    
  726.     THROW_IF_ERROR(SetEOF(fDataRefNum, length));
  727. }
  728.  
  729. //------------------------------------------------------------------------------
  730. // PlatformFile::GetName
  731. //------------------------------------------------------------------------------
  732. ODName* PlatformFile::GetName()
  733. {
  734.     this->UpdateSpecFromID();
  735.  
  736.     return CreateIText(fScriptTag, 0, fFileSpec.name);
  737. }
  738.  
  739. //------------------------------------------------------------------------------
  740. // PlatformFile::GetAsciiName
  741. //------------------------------------------------------------------------------
  742. void PlatformFile::GetAsciiName(char* asciiName, ODULong maxLength)
  743. {
  744.     this->UpdateSpecFromID();
  745.  
  746.     ODULong n = fFileSpec.name[0];
  747.     if( n > maxLength )
  748.         n = maxLength;
  749.     ODBlockMove(&(fFileSpec.name[1]), asciiName, n);
  750.     asciiName[n] = '\0';
  751. }
  752.  
  753. //------------------------------------------------------------------------------
  754. // PlatformFile::GetPlatformCreator
  755. //------------------------------------------------------------------------------
  756. ODOSType PlatformFile::GetPlatformCreator()
  757. {
  758.     if (fCreator == kBogusOSType) {
  759.         FInfo    fileInfo;
  760.         THROW_IF_ERROR(FSpGetFInfo(&fFileSpec, &fileInfo));
  761.         fCreator = fileInfo.fdCreator;
  762.         fFileType = fileInfo.fdType;
  763.     }
  764.     return fCreator;
  765. }    
  766.  
  767. //------------------------------------------------------------------------------
  768. // PlatformFile::SetPlatformCreator
  769. //------------------------------------------------------------------------------
  770. void PlatformFile::SetPlatformCreator(ODOSType creator)
  771. {
  772.     FInfo    fileInfo;
  773.     THROW_IF_ERROR(FSpGetFInfo(&fFileSpec, &fileInfo));
  774.     if( fileInfo.fdCreator != creator ) {
  775.         fileInfo.fdCreator = creator;
  776.         THROW_IF_ERROR(FSpSetFInfo(&fFileSpec, &fileInfo));
  777.         fCreator = creator;
  778.         this->BumpFolderModDate();
  779.     }
  780. }    
  781.  
  782. //------------------------------------------------------------------------------
  783. // PlatformFile::GetPlatformType
  784. //------------------------------------------------------------------------------
  785. ODOSType PlatformFile::GetPlatformType()
  786. {
  787.     if (fFileType == kBogusOSType) {
  788.         FInfo    fileInfo;
  789.         THROW_IF_ERROR(FSpGetFInfo(&fFileSpec, &fileInfo));
  790.         fCreator = fileInfo.fdCreator;
  791.         fFileType = fileInfo.fdType;
  792.     }
  793.     return fFileType;
  794. }    
  795.  
  796. //------------------------------------------------------------------------------
  797. // PlatformFile::SetPlatformType
  798. //------------------------------------------------------------------------------
  799. void PlatformFile::SetPlatformType(ODOSType fileType)
  800. {
  801.     FInfo    fileInfo;
  802.     THROW_IF_ERROR(FSpGetFInfo(&fFileSpec, &fileInfo));
  803.     if( fileInfo.fdType != fileType ) {
  804.         fileInfo.fdType = fileType;
  805.         THROW_IF_ERROR(FSpSetFInfo(&fFileSpec, &fileInfo));
  806.         fFileType = fileType;
  807.         this->BumpFolderModDate();
  808.     }
  809. }    
  810.  
  811. //------------------------------------------------------------------------------
  812. // PlatformFile::IsOpenDocDocument
  813. //------------------------------------------------------------------------------
  814. ODBoolean    PlatformFile::IsOpenDocDocument( )
  815. {
  816.     return IsOpenDocDocument(this->GetPlatformType(),this->GetPlatformCreator());
  817. }
  818.  
  819. ODBoolean
  820. PlatformFile::IsOpenDocDocument( OSType type, OSType creator ) /* static method */
  821. {
  822.     /*    In OpenDoc 1.0, all documents had 'odtm' as their creator. To support
  823.         CyberDog and container applications, we need to allow other creators.
  824.         To support this, we define a space of filetypes that are known to be
  825.         OpenDoc containers. The first (high-order) byte of the filetype is
  826.         a magic constant value. */
  827.     
  828.     // There's some big-endian fu here but this is Mac specific code anyway.
  829.     
  830.     if( (type>>24)==kODMagicFileTypeChar )
  831.         return true;
  832.     if( ( creator==kODShellSignature || creator==kODCyberdogSignature ) && type!='APPL' && type!='shlb' )
  833.         if( !( (type>>8)=='edt' && islower(type&0xFF) ) )    // not an edition file
  834.             return true;
  835.     return false;
  836. }
  837.  
  838.  
  839. //------------------------------------------------------------------------------
  840. // PlatformFile::GetContainerType
  841. //------------------------------------------------------------------------------
  842.  
  843. ODContainerType PlatformFile::GetContainerType()
  844. {
  845.     if (fContainerType == kODNULL)
  846.         fContainerType =
  847.             (ODContainerType)
  848.             (this->ReadResourcePtr(kFileContainerType, kFileContainerTypeResID, kODNULL));
  849.  
  850.     return fContainerType;
  851. }
  852.  
  853. //------------------------------------------------------------------------------
  854. // PlatformFile::SetContainerType
  855. //------------------------------------------------------------------------------
  856.  
  857. void PlatformFile::SetContainerType(ODContainerType containerType)
  858. {
  859.     ODDisposePtr(fContainerType);
  860.     fContainerType = containerType;
  861.  
  862.     this->WriteResourcePtr(kFileContainerType, kFileContainerTypeResID, 
  863.                         (ODPtr)containerType, strlen(containerType)+1);
  864. }
  865.  
  866.  
  867. //------------------------------------------------------------------------------
  868. // CWithActiveResources class
  869. //------------------------------------------------------------------------------
  870.  
  871. class CWithActiveResources :Destructo {
  872.     public:
  873.     CWithActiveResources( PlatformFile* );
  874.    ~CWithActiveResources( );
  875.     private:
  876.     PlatformFile    *fFile;
  877.     ODFileRefNum    fCurResFile;
  878.     ODBoolean        fSuccessfullyOpened;
  879. };
  880.  
  881. CWithActiveResources::CWithActiveResources( PlatformFile *pf )
  882. {
  883.     fSuccessfullyOpened = kODFalse;
  884.     fFile = pf;
  885.     fCurResFile = CurResFile();
  886.     fFile->OpenResFile();
  887.     fSuccessfullyOpened = kODTrue;
  888. }
  889.  
  890. CWithActiveResources::~CWithActiveResources( )
  891. {
  892.     if (fSuccessfullyOpened)
  893.         fFile->CloseResFile();
  894.     UseResFile(fCurResFile);
  895. }
  896.         
  897.  
  898. //------------------------------------------------------------------------------
  899. // PlatformFile::ReadResourcePtr
  900. //------------------------------------------------------------------------------
  901. ODPtr PlatformFile::ReadResourcePtr(ODPlatformType resType, ODSShort resID, ODULong* size)
  902. {
  903.     ODPtr resPtr = kODNULL;
  904.     
  905.     TRY
  906.         CWithActiveResources w(this); // this throws if no resfile
  907.         
  908.         Handle resHandle = Get1Resource(resType, resID);
  909.         if (resHandle != kODNULL)
  910.         {
  911.             HNoPurge(resHandle);
  912.             ODULong hsize = GetHandleSize(resHandle);
  913.             if (size != kODNULL)
  914.                 *size = hsize;
  915.             resPtr = ODNewPtrClear(hsize,0);
  916.             ODBlockMove(*resHandle,resPtr, hsize);
  917.             ReleaseResource(resHandle);
  918.         } else if( ResError() != resNotFound )
  919.             THROW_IF_ERROR(ResError());
  920.  
  921.     CATCH_ALL
  922.     ENDTRY
  923.     
  924.     return resPtr;  // Method Specific
  925. }
  926.  
  927. //------------------------------------------------------------------------------
  928. // PlatformFile::WriteResourcePtr
  929. //------------------------------------------------------------------------------
  930. void PlatformFile::WriteResourcePtr(ODPlatformType resType, ODSShort resID, 
  931.                                     const void *resPtr, ODULong size)
  932. {
  933.     ASSERT(resPtr!=kODNULL,kODErrIllegalNullInput);
  934.     
  935.     SetPermission(fsRdWrPerm);
  936.     CWithActiveResources w(this);
  937.     
  938.     Handle resHandle = Get1Resource(resType,resID);
  939.     if( ResError() != resNotFound )
  940.         THROW_IF_ERROR(ResError());
  941.         
  942.     ODBoolean needsAdding = (resHandle == kODNULL);
  943.     if (needsAdding)
  944.         resHandle = ODNewHandle(size);
  945.     else {
  946.         HNoPurge(resHandle);
  947.         ODSetHandleSize(resHandle, size);
  948.     }
  949.     
  950.     ODBlockMove(resPtr,*resHandle, size);
  951.     
  952.     if (needsAdding)
  953.         AddResource(resHandle,resType,resID,"\p");
  954.     else
  955.         ChangedResource(resHandle);
  956.     THROW_IF_ERROR(ResError());
  957. }
  958.  
  959.  
  960. //------------------------------------------------------------------------------
  961. // PlatformFile::DeleteResource
  962. //------------------------------------------------------------------------------
  963. void PlatformFile::DeleteResource(ODPlatformType resType, ODSShort resID)
  964. {
  965.     SetPermission(fsRdWrPerm);
  966.     CWithActiveResources w(this);
  967.  
  968.     Handle resHandle = Get1Resource(resType, resID);
  969.     OSErr err= ResError();
  970.     if( resHandle ) {
  971.         RemoveResource(resHandle);
  972.         err= ResError();
  973.         if( !err )
  974.             DisposeHandle(resHandle);    // After RemoveResource it's not a rsrc
  975.     } else {
  976.         if( err == resNotFound )
  977.             err = noErr;
  978.     }
  979.     THROW_IF_ERROR(err);
  980. }
  981.  
  982. //------------------------------------------------------------------------------
  983. // PlatformFile::GetAllocationBlockSize
  984. //------------------------------------------------------------------------------
  985. ODULong PlatformFile::GetAllocationBlockSize()
  986. {
  987.     HParamBlockRec pb;
  988.     
  989.     pb.volumeParam.ioCompletion = kODNULL;
  990.     pb.volumeParam.ioNamePtr = kODNULL;
  991.     pb.volumeParam.ioVRefNum = fFileSpec.vRefNum;
  992.     pb.volumeParam.ioVolIndex = 0;
  993.  
  994.     THROW_IF_ERROR(PBHGetVInfoSync(&pb));
  995.  
  996.     return pb.volumeParam.ioVAlBlkSiz;
  997. }
  998.  
  999. //------------------------------------------------------------------------------
  1000. // PlatformFile::CopyFrom
  1001. //------------------------------------------------------------------------------
  1002. void PlatformFile::CopyFrom( PlatformFile* src )
  1003. {
  1004.     ODError    error = kODNoError;
  1005.  
  1006.     ODBoolean srcIsOpen = (src->GetFileRefNum() != kODNoFileRefNum);
  1007.     if ( !srcIsOpen )
  1008.         src->Open();
  1009.     TRY
  1010.         this->SetPermission( fsRdWrPerm );        // currently this is the default value
  1011.         if (!this->Exists())
  1012.             this->Create(src->GetPlatformCreator(), src->GetPlatformType(), 0 /*$$$$$ scriptcode?*/);
  1013.     
  1014.         this->Open();
  1015.         
  1016.         TRY
  1017.             src->SetFilePos( fsFromStart, 0 );
  1018.             this->SetFilePos( fsFromStart, 0 );
  1019.             
  1020.             ODSLong bytesLeft = src->GetEndOfFile();
  1021.         
  1022.             TempODHandle hbuffer = kODNULL;
  1023.             ODSLong bufferSize = kMaxCopyBufferSize;
  1024.             if( bufferSize > bytesLeft )
  1025.                 bufferSize = bytesLeft;
  1026.             for( ; bufferSize>=kMinCopyBufferSize; bufferSize /= 2 ) {
  1027.                 OSErr err;
  1028.                 hbuffer= TempNewHandle(bufferSize,&err);
  1029.                 if( hbuffer ) break;
  1030.             }
  1031.             WASSERT(bufferSize > 0);
  1032.             THROW_IF_NULL(hbuffer);
  1033.             void *buffer = *hbuffer;
  1034.             
  1035.             ODSLong count;
  1036.         
  1037.             while( bytesLeft > 0 )
  1038.             {
  1039.                 count = bytesLeft < bufferSize? bytesLeft: bufferSize ;
  1040.                 WASSERT(count > 0);
  1041.                 src->Read( buffer, &count );
  1042.                 this->Write( buffer, &count );
  1043.                 bytesLeft -= count ;
  1044.             }
  1045.         CATCH_ALL
  1046.             error = ErrorCode();
  1047.         ENDTRY
  1048.     CATCH_ALL
  1049.         error = ErrorCode();
  1050.     ENDTRY
  1051.  
  1052.     if ( !srcIsOpen )
  1053.         src->Close();
  1054.     this->Close();
  1055.     
  1056.     THROW_IF_ERROR(error);
  1057. }
  1058.  
  1059. //------------------------------------------------------------------------------
  1060. // PlatformFile::MoveRename
  1061. //------------------------------------------------------------------------------
  1062. void PlatformFile::MoveRename( ODFileSpec* newSpec, ODBoolean isDuplicate )
  1063. {
  1064.     // This will fail if a file with the old name already exists in the
  1065.     // target directory. MoreFiles (DTS) has a more robust version of this.
  1066.     
  1067.     ASSERT(newSpec->vRefNum == fFileSpec.vRefNum, kODErrAssertionFailed);
  1068.  
  1069.     if ( isDuplicate )
  1070.     {
  1071.         THROW_IF_ERROR( FSpDelete( newSpec ) ); 
  1072.     }
  1073.  
  1074.     this->Move( newSpec->parID );
  1075.     this->Rename( newSpec->name );
  1076.     WASSERT( fFileSpec.name[0] <= 31 );
  1077. }    // MoveRename()
  1078.  
  1079.  
  1080. //------------------------------------------------------------------------------
  1081. // PlatformFile::Move
  1082. //------------------------------------------------------------------------------
  1083.  
  1084. void PlatformFile::Move( ODSLong targetParID )
  1085. {
  1086.     CMovePBRec paramBlock ;
  1087.     memset( ¶mBlock, 0, sizeof(paramBlock) );
  1088.     
  1089.     paramBlock.ioNamePtr = fFileSpec.name ;
  1090.     paramBlock.ioVRefNum = fFileSpec.vRefNum ;
  1091.     paramBlock.ioNewDirID = targetParID ;
  1092.     paramBlock.ioDirID = fFileSpec.parID ;
  1093.     
  1094.     (void) HDelete(fFileSpec.vRefNum,targetParID,fFileSpec.name);     // ignore error (may not exist)
  1095.     OSErr err = PBCatMoveSync( ¶mBlock );
  1096.     THROW_IF_ERROR( err );
  1097.  
  1098.     fFileSpec.parID = targetParID ;
  1099.     WASSERT( fFileSpec.name[0] <= 31 );
  1100. }
  1101.  
  1102. //------------------------------------------------------------------------------
  1103. // PlatformFile::UniquifyName
  1104. // Given in this a platformfile (whose filespec only is used) that may conflict
  1105. // with an existing file, deal with this conflict in one of two ways depending
  1106. // on the value of action.  The two values are:
  1107. // 1. kSpecifyNewNameOnly: just change the name field of the filespec so that the
  1108. // platform file represents a file that would be unique if created
  1109. // 2. kRenameInPlace: this file already exists, but we want it to have a different
  1110. // name so we can reuse this one.  Find that name, and rename the actual file.
  1111. // 
  1112. // Two string templates are expected, and the caller can either pass in their
  1113. // resource IDs or StringHandles to the strings themselves, signifying the latter
  1114. // with a resource ID of kODNoResourceID.  The first of these strings is used
  1115. // the first time through the renaming loop (which typically sticks something
  1116. // like " copy" on the end of the file name, and the second is used thereafter
  1117. // (when increasingly large numbers are put into the string in an attempt to
  1118. // make it unique.
  1119. //------------------------------------------------------------------------------
  1120.  
  1121. void PlatformFile::UniquifyName( ODSShort uniquifyingStringID,
  1122.             StringHandle uniquifyingString, 
  1123.             ODSShort uniquifyingNumberID,
  1124.             StringHandle uniquifyingNumberString, 
  1125.             short copyCount,
  1126.             PFUniquifyAction action, 
  1127.             ODBoolean forceNewName)
  1128. {
  1129.     if ((forceNewName!=kODTryCurrentName) || this->Exists() )
  1130.     {
  1131.         PlatformFile* possibleOther = new PlatformFile;
  1132.         TempPlatformFile t = possibleOther;        // save so will get deconstructed
  1133. //        possibleOther->SpecifyFromFile( this );
  1134.     
  1135.         // Get the strings to be used in substitution if they weren't passed in.
  1136.         // Assign them to tempobjs so we don't have to dispose later.  Don't assign
  1137.         // if they're passed in (of course....)
  1138.         TempODHandle registerNoNumHandleIfLocal = kODNULL;
  1139.         TempODHandle registerNumHandleIfLocal = kODNULL;
  1140.         CUsingLibraryResources r;
  1141.         if ( uniquifyingStringID != kODNoResourceID )
  1142.         {
  1143.             WASSERT( !uniquifyingString );
  1144.             uniquifyingString = GetString( uniquifyingStringID );
  1145.             DetachResource( (Handle)uniquifyingString );
  1146.             registerNoNumHandleIfLocal = (Handle)uniquifyingString;
  1147.             WASSERT( uniquifyingString );
  1148.         }
  1149.         if ( uniquifyingNumberID != kODNoResourceID )
  1150.         {
  1151.             WASSERT(!uniquifyingNumberString);
  1152.             uniquifyingNumberString = GetString( uniquifyingNumberID );
  1153.             DetachResource( (Handle)uniquifyingNumberString );
  1154.             registerNumHandleIfLocal = (Handle)uniquifyingNumberString;
  1155.         }
  1156.         WASSERT(uniquifyingNumberString);
  1157.     
  1158.         ODFileSpec localCopy = this->GetFileSpec();
  1159.         // save the name (as we'll be munging localCopy)
  1160.         Str63 originalName;
  1161.         ODBlockMove( localCopy.name, originalName, localCopy.name[0]+1 );
  1162.     
  1163.         TempODHandle baseText = ODNewHandle(kMaxFileNameSize+1);
  1164.         THROW_IF_NULL(baseText);
  1165.         TempODHandle substitutionText = ODNewHandle(kMaxFileNameSize+1);
  1166.         THROW_IF_NULL(substitutionText);
  1167.     
  1168.         ODBoolean nameNeedsNumber = (uniquifyingString == kODNULL);
  1169.             // if there is no uniquifyingString, we immediately need to start using
  1170.             // the uniquifyingNumberString, or in other words nameNeedsNumber==true.
  1171.             
  1172.         for ( ; ; nameNeedsNumber = kODTrue)
  1173.         {
  1174.             // nameNeedsNumber = copyCount > 1;
  1175.             StringHandle templateToUse = nameNeedsNumber ?
  1176.                     uniquifyingNumberString : uniquifyingString;
  1177.     
  1178.             short thisTemplateLen = **templateToUse;
  1179.             // <eeh> NOTE that this forces callers to have two ^number tuples in the
  1180.             // second template.
  1181.             thisTemplateLen -= nameNeedsNumber? 4 : 2;
  1182.     
  1183.             short numberLen;
  1184.             Str32 numberString;
  1185.             if ( nameNeedsNumber )
  1186.             {
  1187.                 NumToString( copyCount, numberString );
  1188.                 numberLen = numberString[0];
  1189.             }
  1190.             else
  1191.                 numberLen = 0;
  1192.     
  1193.             // truncate the name if after appending it will be too long
  1194.             Str63 localName;
  1195.             ODBlockMove( originalName, localName, originalName[0] + 1 );
  1196.             short postAppendLen = localName[0] + thisTemplateLen + numberLen;
  1197.             if ( postAppendLen > kODMaxFileNameSize )
  1198.                 ClipStringToBytes( localName,
  1199.                         kODMaxFileNameSize - thisTemplateLen - numberLen, fScriptTag );
  1200.     
  1201.             // copy the template into the base handle, then pass in the possible file
  1202.             // name
  1203.             short len;
  1204.             SetHandleSize( baseText, len = **templateToUse );
  1205.             ODBlockMove( (*templateToUse)+1, *baseText, len );
  1206.             SetHandleSize( substitutionText, len = localName[0] );
  1207.             ODBlockMove( &localName[1], *substitutionText, len );
  1208.             short err = ReplaceText( baseText, substitutionText, "\p^0" );
  1209.             WASSERT( err >= 0 );
  1210.             
  1211.             if ( nameNeedsNumber )        // do same for number
  1212.             {
  1213.                 SetHandleSize( substitutionText, len = numberString[0] );
  1214.                 ODBlockMove( &numberString[1], *substitutionText, len );
  1215.                 err = ReplaceText( baseText, substitutionText, "\p^1" );
  1216.                 WASSERT( err >= 0 );
  1217.             }
  1218.     
  1219.             ODBlockMove( *baseText, &localCopy.name[1], len = GetHandleSize(baseText) );
  1220.             localCopy.name[0] = len;
  1221.     
  1222.             possibleOther->Specify( &localCopy );
  1223.             if ( !possibleOther->Exists() )
  1224.             {
  1225.                 WASSERT( localCopy.name[0] <= kODMaxFileNameSize );
  1226.                 if ( action == kSpecifyNewNameOnly )
  1227.                 {
  1228.                     // set up this so that when created it will represent a unique file
  1229.                     PascalToCString( localCopy.name );
  1230.                     this->SetAsciiName( (char*)localCopy.name );
  1231.                 }
  1232.                 else if ( action == kRenameInPlace )
  1233.                 {
  1234.                     // put the original file spec back in the target, then call
  1235.                     // Rename passing in the new name
  1236.                     WASSERT(this->Exists());
  1237.                     this->Rename( localCopy.name );
  1238.                 }
  1239.                 else
  1240.                     WARN( "unknown PFUniquifyAction" );
  1241.                 break;
  1242.             }
  1243.             if (nameNeedsNumber)
  1244.                 ++copyCount;        
  1245.                 // Gets executed after 2nd time through loop if there was a valid
  1246.                 // uniquifyString.  
  1247.                 // Otherwise gets executed after 1st time through loop.
  1248.         }
  1249.     }
  1250. }    // UniquifyName
  1251.  
  1252. //------------------------------------------------------------------------------
  1253. // PlatformFile::MoveToTrash
  1254. //------------------------------------------------------------------------------
  1255.  
  1256. void PlatformFile::MoveToTrash()
  1257. {
  1258.     ODSLong parID = fFileSpec.parID;
  1259.     ODSLong            trashDirID;
  1260.     THROW_IF_ERROR(FindFolder(fFileSpec.vRefNum, kTrashFolderType, kCreateFolder,
  1261.                             &(fFileSpec.vRefNum), &trashDirID));
  1262.                             
  1263.     // Move deletes any file that may conflict with the file once moved, but
  1264.     // in this case that isn't what we want.  So check if such a file exists,
  1265.     // and if so rename the conflicting file first (following the Finder's
  1266.     // model.)
  1267.     ODFileSpec possibleOtherFS = this->GetFileSpec();
  1268.     possibleOtherFS.parID = trashDirID;
  1269.     PlatformFile target;        // represents a file that *may* be in the trash
  1270.     target.Specify( &possibleOtherFS );
  1271.     
  1272. #if 1
  1273. //    if ( target.Exists() )
  1274.     {
  1275.         CUsingLibraryResources r;
  1276.         target.UniquifyName( kCopyDefaultNameNoNumStrID, kODNULL,
  1277.                 kCopyDefaultNameWithNumStrID, kODNULL, 2, kRenameInPlace,
  1278.                 kODTryCurrentName ) ;
  1279.     }
  1280. #else
  1281.     Str32 uniqueName;
  1282.     if ( MakeUniqueFileName( &target, kCopyDefaultNameNoNumStrID,
  1283.             kCopyDefaultNameWithNumStrID, 31, uniqueName ) )
  1284.         target.Rename( uniqueName );
  1285. #endif
  1286.     this->Move(trashDirID);
  1287.  
  1288.     CInfoPBRec pbRec;
  1289.     pbRec.hFileInfo.ioCompletion = NULL;
  1290.     pbRec.hFileInfo.ioNamePtr = fFileSpec.name;
  1291.     pbRec.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1292.     pbRec.hFileInfo.ioFDirIndex = 0;
  1293.     pbRec.hFileInfo.ioDirID = fFileSpec.parID;
  1294.     
  1295.     
  1296.     if ( PBGetCatInfoSync( &pbRec ) == noErr )
  1297.     {
  1298.         // <eeh> stuffing this field *may* not work under Copland
  1299.         pbRec.hFileInfo.ioFlXFndrInfo.fdPutAway = parID;
  1300.         // this was changed by PBGetCatInfoSync...
  1301.         pbRec.hFileInfo.ioDirID = fFileSpec.parID;
  1302.         (void)PBSetCatInfoSync( &pbRec );    // ignore the error
  1303.     }
  1304. }
  1305.  
  1306. //------------------------------------------------------------------------------
  1307. // PlatformFile::Rename
  1308. //        This routine will not yet delete a file that will prevent the
  1309. //            renaming (as Move() does above.)
  1310. //------------------------------------------------------------------------------
  1311. void PlatformFile::Rename( Str63 newName )
  1312. {
  1313.     this->UpdateSpecFromID();
  1314.     
  1315.     THROW_IF_ERROR( FSpRename( &fFileSpec, newName ) );
  1316.      CopyPascalString(fFileSpec.name, newName);
  1317.     BumpFolderModDate();
  1318.     WASSERT( fFileSpec.name[0] <= 31 );
  1319. }
  1320.  
  1321.  
  1322. //------------------------------------------------------------------------------
  1323. // PlatformFile::GetFileModDate
  1324. //        This routine will set the file modification date to the input parameter
  1325. //------------------------------------------------------------------------------
  1326. ODTime PlatformFile::GetFileModDate()
  1327. {
  1328.     this->UpdateSpecFromID();
  1329.     
  1330.     CInfoPBRec    pbBlock;
  1331.     pbBlock.hFileInfo.ioCompletion = kODNULL;
  1332.     pbBlock.hFileInfo.ioFDirIndex = 0;
  1333.     pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  1334.     pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1335.     pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1336.     THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  1337.     return pbBlock.hFileInfo.ioFlMdDat;
  1338. }
  1339.  
  1340.  
  1341. //------------------------------------------------------------------------------
  1342. // PlatformFile::SetFileModDate
  1343. //        This routine will set the file modification date to the input parameter
  1344. //------------------------------------------------------------------------------
  1345. void PlatformFile::SetFileModDate(ODTime date)
  1346. {
  1347.     this->UpdateSpecFromID();
  1348.     
  1349.     if (!this->IsLocked()) {
  1350.         CInfoPBRec    pbBlock;
  1351.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  1352.         pbBlock.hFileInfo.ioFDirIndex = 0;
  1353.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  1354.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1355.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1356.         if (PBGetCatInfoSync(&pbBlock) == noErr) {
  1357.             pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1358.             pbBlock.hFileInfo.ioFlMdDat = date;
  1359.             (void) PBSetCatInfoSync(&pbBlock); /* who cares if it fails */
  1360.         }
  1361.     }
  1362. }
  1363.  
  1364. //------------------------------------------------------------------------------
  1365. // PlatformFile::SetFileCreationDate
  1366. //        This routine will set the file creation date to the input parameter
  1367. //------------------------------------------------------------------------------
  1368. void PlatformFile::SetFileCreationDate(ODTime date)
  1369. {
  1370.     this->UpdateSpecFromID();
  1371.  
  1372.     CInfoPBRec    pbBlock;
  1373.  
  1374.     if (!this->IsLocked()) {
  1375.         pbBlock.hFileInfo.ioCompletion = kODNULL;
  1376.         pbBlock.hFileInfo.ioFDirIndex = 0;
  1377.         pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  1378.         pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1379.         pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1380.         if (PBGetCatInfoSync(&pbBlock) == noErr) {
  1381.             pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1382.             pbBlock.hFileInfo.ioFlCrDat = date;
  1383.             (void) PBSetCatInfoSync(&pbBlock); /* who cares if it fails */
  1384.         }
  1385.     }
  1386. }
  1387.                 
  1388. //------------------------------------------------------------------------------
  1389. // PlatformFile::GetFileCreationDate
  1390. //        This routine will get the file creation date and return it.
  1391. //------------------------------------------------------------------------------
  1392. ODTime PlatformFile::GetFileCreationDate()
  1393. {
  1394.     this->UpdateSpecFromID();
  1395.     
  1396.     CInfoPBRec    pbBlock;
  1397.     pbBlock.hFileInfo.ioCompletion = kODNULL;
  1398.     pbBlock.hFileInfo.ioFDirIndex = 0;
  1399.     pbBlock.hFileInfo.ioNamePtr = fFileSpec.name;
  1400.     pbBlock.hFileInfo.ioVRefNum = fFileSpec.vRefNum;
  1401.     pbBlock.hFileInfo.ioDirID = fFileSpec.parID;
  1402.     THROW_IF_ERROR(PBGetCatInfoSync(&pbBlock));
  1403.     return pbBlock.hFileInfo.ioFlCrDat;
  1404. }
  1405.             
  1406. //------------------------------------------------------------------------------
  1407. // PlatformFile::BumpFolderModDate
  1408. //        This routine will set the file modification date of the parent folder
  1409. //        to the current time so as to cause the Finder to refresh the folder if
  1410. //        it is open.  It only has WARNs if it errors.
  1411. //------------------------------------------------------------------------------
  1412. void PlatformFile::BumpFolderModDate()
  1413. {
  1414.     CInfoPBRec    theParamBlock;
  1415.  
  1416.     memset (&theParamBlock, 0, sizeof(theParamBlock));
  1417.     // ioNamePtr = 0
  1418.     theParamBlock.dirInfo.ioFDirIndex = -1;
  1419.     theParamBlock.dirInfo.ioVRefNum = fFileSpec.vRefNum;
  1420.     theParamBlock.dirInfo.ioDrDirID = fFileSpec.parID;
  1421.     OSErr err = PBGetCatInfoSync(&theParamBlock);
  1422.     if( err )
  1423.         WARN("Couldn't get dir mod date, err %hd",err);
  1424.     else
  1425.     {
  1426.         ODULong newTime;
  1427.  
  1428.         GetDateTime(&newTime);
  1429.         // set to the future if it is now
  1430.         if (theParamBlock.dirInfo.ioDrMdDat >= newTime)
  1431.             ++newTime;
  1432.         theParamBlock.dirInfo.ioDrMdDat = newTime;
  1433.         err = PBSetCatInfoSync(&theParamBlock);
  1434.         if( err )
  1435.             WARN("Couldn't bump dir mod date, err %hd",err);
  1436.     }
  1437. }
  1438.                 
  1439. //------------------------------------------------------------------------------
  1440. // PlatformFile::GetFirstLocalPath
  1441. //------------------------------------------------------------------------------
  1442.  
  1443. ODFileRefNum PlatformFile::GetFirstLocalPath( ODForkType fork )
  1444. {
  1445.     ODFileSpec* spec = &fFileSpec;
  1446.     
  1447.     OSErr        result;
  1448.     FCBPBRec    pb;
  1449.     short        index;
  1450.     Str31        tempName;
  1451.     
  1452.     /* Get FCB name in tempName */
  1453.     pb.ioNamePtr = tempName;
  1454.     
  1455.     /* Index through the open paths on the volume specified by fFileSpec.vRefNum */
  1456.     pb.ioVRefNum = fFileSpec.vRefNum;
  1457.     index = 1;
  1458.     do
  1459.     {
  1460.         pb.ioRefNum = 0;
  1461.         pb.ioFCBIndx = index;
  1462.         result = PBGetFCBInfoSync(&pb);
  1463.         if ( result == noErr )
  1464.         {
  1465.             /*
  1466.             **    See if parent directory ID matches and
  1467.             **    file name matches and
  1468.             **    the file fork (resource or data) matches
  1469.             */
  1470.             if ( (pb.ioFCBParID == fFileSpec.parID) &&
  1471.                  EqualString(fFileSpec.name, tempName, false, true) &&
  1472.                  ((fork == kODResourceFork) == ((pb.ioFCBFlags & (1 << 9)) != 0)) )
  1473.             {
  1474.                 return pb.ioRefNum;            // Found it!
  1475.             }
  1476.             ++index;    /* next FCB index */
  1477.         }
  1478.     } while ( result == noErr );
  1479.     
  1480.     return kODNoFileRefNum;
  1481. }
  1482.  
  1483.  
  1484. //------------------------------------------------------------------------------
  1485. // PlatformFile::GetLocalPaths
  1486. //------------------------------------------------------------------------------
  1487.  
  1488. ODError        PlatformFile::GetLocalPaths(
  1489.                               ODForkType fork,
  1490.                               ODULong *refNumCount,
  1491.                               ODFileRefNumPtr *refNums)
  1492. {
  1493.     const ODULong kMaxFCBs = 348;    /* The maximum number of local access paths under System 7 */
  1494.     
  1495.     OSErr        result;
  1496.     FCBPBRec    pb;
  1497.     short        index;
  1498.     Str31        tempName;
  1499.     ODFileRefNumPtr    tempRefNums;
  1500.     
  1501.     /* initialize returned values */
  1502.     *refNumCount = 0;
  1503.     *refNums = NULL;
  1504.     
  1505.     /* Allocate temp storage for refNum matches */
  1506.     tempRefNums = (ODFileRefNumPtr)ODNewPtr(kMaxFCBs * sizeof(short));
  1507.     
  1508.     if ( tempRefNums != NULL )
  1509.     {
  1510.         /* Get FCB name in tempName */
  1511.         pb.ioNamePtr = tempName;
  1512.         
  1513.         /* Index through the open paths on the volume specified by fFileSpec.vRefNum */
  1514.         pb.ioVRefNum = fFileSpec.vRefNum;
  1515.         index = 1;
  1516.         do
  1517.         {
  1518.             pb.ioRefNum = 0;
  1519.             pb.ioFCBIndx = index;
  1520.             result = PBGetFCBInfoSync(&pb);
  1521.             if ( result == noErr )
  1522.             {
  1523.                 /*
  1524.                 **    See if parent directory ID matches and
  1525.                 **    file name matches and
  1526.                 **    the file fork (resource or data) matches
  1527.                 */
  1528.                 if ( (pb.ioFCBParID == fFileSpec.parID) &&
  1529.                      EqualString(fFileSpec.name, tempName, false, true) &&
  1530.                      ((fork == kODResourceFork) == ((pb.ioFCBFlags & (1 << 9)) != 0)) )
  1531.                 {
  1532.                     /* It's a match - add it to the array of matches */
  1533.                     tempRefNums[*refNumCount] = pb.ioRefNum;
  1534.                     ++(*refNumCount);
  1535.                 }
  1536.                 ++index;    /* next FCB index */
  1537.             }
  1538.         } while ( result == noErr );
  1539.         
  1540.         /* These errors are OK - they mean we hit the end of the FCB list */
  1541.         if ( (result == rfNumErr) || (result == fnOpnErr) )
  1542.         {
  1543.             result = noErr;
  1544.         }
  1545.         
  1546.         if ( (result == noErr) && (*refNumCount != 0) )
  1547.         {
  1548.             // Note: the below two lines were a gratuitous change from the tested code
  1549.             // given to me by Jim Luther.  Therefore I have commented them out and returned
  1550.             // the original code. -Tantek
  1551.             //*refNums = (ODFileRefNumPtr) ODReallocate( tempRefNums, *refNumCount * sizeof(short) );
  1552.             //*tempRefNums = kODNULL;
  1553.             /* Allocate memory to return refNum matches in */
  1554.             TRY
  1555.                 *refNums = (ODFileRefNumPtr)ODNewPtr(*refNumCount * sizeof(short));
  1556.             CATCH_ALL
  1557.                 ODDisposePtr((Ptr)tempRefNums);
  1558.                 RERAISE;
  1559.             ENDTRY
  1560.             if ( *refNums != NULL )
  1561.             {
  1562.                 /* Move refNums from tempRefNums to *refNums */
  1563.                 ODBlockMove((Ptr)tempRefNums, (Ptr)*refNums, (*refNumCount * sizeof(short)));
  1564.             }
  1565.             else
  1566.             {
  1567.                 /* Couldn't allocate memory for refNum array */
  1568.                 result = memFullErr;
  1569.             }
  1570.  
  1571.         }
  1572.         
  1573.         /* Free up tempRefNums storage */ 
  1574.         ODDisposePtr((Ptr)tempRefNums);
  1575.     }
  1576.     else
  1577.     {
  1578.         /* Couldn't allocate temp memory */
  1579.         result = memFullErr;
  1580.     }
  1581.     
  1582.     return ( result );
  1583. }
  1584.  
  1585. //------------------------------------------------------------------------------
  1586. // PlatformFile::GetComments
  1587. //
  1588. //    If a pointer is passed in, the text is placed there and a pointer to it is
  1589. //    returned.  If the comments pointer is null, then a new pointer is allocated
  1590. //    and returned.
  1591. //------------------------------------------------------------------------------
  1592.  
  1593. enum {
  1594.     uppPBDTInfo = kRegisterBased
  1595.          | RESULT_SIZE(sizeof(OSErr))
  1596.          | REGISTER_RESULT_LOCATION(kRegisterD0)
  1597.          
  1598.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(kTwoByteCode))    // trap word
  1599.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(kTwoByteCode))    // selector
  1600.          
  1601.          | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(DTPBRec*)))
  1602.          | REGISTER_ROUTINE_PARAMETER(4, kRegisterA3, SIZE_CODE(sizeof(void*)))
  1603. };
  1604.  
  1605. #if GENERATING68K && GENERATINGCFM
  1606. OSErr PBDTGetCommentSyncGlue(DTPBRec *pb);
  1607. OSErr PBDTGetCommentSyncGlue(DTPBRec *pb)
  1608. {
  1609.     void* hfsdispatch = GetOSTrapAddress(0xA260);
  1610.     return CallOSTrapUniversalProc((UniversalProcPtr) hfsdispatch,
  1611.                                     uppPBDTInfo,
  1612.                                     (short) 0xA260,    // trap word
  1613.                                     (short) 0x002A,    // selector
  1614.                                     pb,                // a1, the param block ptr
  1615.                                     pb                // a3 should be ignored
  1616.                                   );
  1617. }
  1618. #endif
  1619.  
  1620. #if GENERATING68K && GENERATINGCFM
  1621. OSErr PBDTSetCommentSyncGlue(DTPBRec *pb);
  1622. OSErr PBDTSetCommentSyncGlue(DTPBRec *pb)
  1623. {
  1624.     void* hfsdispatch = GetOSTrapAddress(0xA260);
  1625.     return CallOSTrapUniversalProc((UniversalProcPtr) hfsdispatch,
  1626.                                     uppPBDTInfo,
  1627.                                     (short) 0xA260,    // trap word
  1628.                                     (short) 0x0028,    // selector
  1629.                                     pb,                // a1, the param block ptr
  1630.                                     pb                // a3 should be ignored
  1631.                                   );
  1632. }
  1633. #endif
  1634.  
  1635. ODIText*    PlatformFile::GetComments(ODIText* comments)
  1636. {
  1637.     DTPBRec            pb;    
  1638.     memset( &pb, 0, sizeof(pb) );
  1639.     
  1640.     pb.ioVRefNum = fFileSpec.vRefNum;
  1641.     OSErr err = PBDTGetPath(&pb);
  1642.     if (err == noErr)
  1643.     {
  1644.         pb.ioNamePtr = fFileSpec.name;
  1645.         pb.ioDirID = fFileSpec.parID;
  1646.         char buffer[256];
  1647.         pb.ioDTBuffer = buffer;
  1648.  
  1649.         // avoid the crash on 68K if the PlatformFile is remote
  1650. #if GENERATING68K && GENERATINGCFM
  1651.         err = PBDTGetCommentSyncGlue(&pb);
  1652. #else
  1653.         err = PBDTGetCommentSync(&pb);
  1654. #endif
  1655.         if (err == noErr) {
  1656.             buffer[pb.ioDTActCount] = 0; // make it a c string
  1657.             if (comments == kODNULL)
  1658.             {
  1659.                 ODScriptCode script = FontToScript( GetSysFont() );
  1660.                 comments = CreateITextCString(script, 
  1661.                         GetScriptVariable( script, smScriptLang ), buffer);
  1662.             }
  1663.             else
  1664.                 SetITextCString(comments, buffer);
  1665.         }
  1666.     }
  1667.     
  1668.     return comments;
  1669. }
  1670.  
  1671. //------------------------------------------------------------------------------
  1672. // PlatformFile::SetComments
  1673. //------------------------------------------------------------------------------
  1674.  
  1675. void
  1676. PlatformFile::SetComments(ODIText* comments)
  1677. {
  1678.     DTPBRec        pb;
  1679.     OSErr        err = noErr;    // PBDTGetPath seems not to return anything,
  1680.                                 // so must init
  1681.     
  1682.     pb.ioNamePtr = kODNULL;
  1683.     pb.ioVRefNum = fFileSpec.vRefNum;
  1684.     err = PBDTGetPath(&pb);
  1685.     if (err == noErr)
  1686.     {
  1687.         Str255    commentStr;
  1688.             
  1689.         pb.ioNamePtr = fFileSpec.name;
  1690.         pb.ioDirID = fFileSpec.parID;
  1691.         pb.ioDTBuffer = (char *)&commentStr[1];
  1692.         if (comments) {
  1693.             
  1694.             ODULong numBytes = GetITextStringLength(comments);
  1695.             if (numBytes > kMaxCommentSize) {
  1696.                 GetITextPString(comments, commentStr);
  1697.                 pb.ioDTReqCount = ClipStringToBytes(commentStr, kMaxCommentSize,
  1698.                                                     GetITextScriptCode(comments) );
  1699.             } else {
  1700.                 pb.ioDTBuffer = GetITextPtr(comments);
  1701.                 pb.ioDTReqCount = numBytes;
  1702.             }
  1703.         }
  1704.         else
  1705.             pb.ioDTReqCount = 0;
  1706.         // avoid the crash on 68K if the PlatformFile is remote
  1707. #if GENERATING68K && GENERATINGCFM
  1708.         err = PBDTSetCommentSyncGlue(&pb);
  1709. #else
  1710.         err = PBDTSetCommentSync(&pb);
  1711. #endif
  1712.         }
  1713. }
  1714.  
  1715. //------------------------------------------------------------------------------
  1716. // PlatformFile::GetCustomIconFamily
  1717. //------------------------------------------------------------------------------
  1718.  
  1719. ODIconFamily
  1720. PlatformFile::GetCustomIconFamily()
  1721. {
  1722.     ODIconFamily icons = kODNULL; ODVolatile(icons);
  1723.     
  1724.     if (HasCustomIcon())
  1725.     {
  1726.         // read icons from the file
  1727.         SetPermission(fsRdPerm);
  1728. //        OpenResFile();
  1729.         TRY
  1730.             for( long i=5; i>=0; i-- )
  1731.             {
  1732.                 ODULong    size;
  1733.                 TempODPtr ptr = this->ReadResourcePtr(kIconType[i], kCustomIconResource, &size);
  1734.                 if (ptr != kODNULL)
  1735.                 {
  1736.                     if (icons == kODNULL)
  1737.                         THROW_IF_ERROR( NewIconSuite(&icons) );
  1738.                     Handle icon = (Handle) ODNewHandle(size);
  1739.                     ODBlockMove(ptr,*icon,size);
  1740.                     OSErr err = AddIconToSuite(icon, icons, kIconType[i]);
  1741.                     if( err ) {
  1742.                         ODDisposePtr(icon);
  1743.                         THROW(err);
  1744.                     }
  1745.                 }
  1746.             }
  1747.         CATCH_ALL
  1748.             WARN("Ignoring error %ld",ErrorCode());
  1749.             if( icons ) DisposeIconSuite(icons,kODTrue);
  1750.         ENDTRY
  1751. //        CloseResFile();
  1752.     }
  1753.     return icons;
  1754. }
  1755.  
  1756. //------------------------------------------------------------------------------
  1757. // PlatformFile::SetCustomIconFamily
  1758. //------------------------------------------------------------------------------
  1759.  
  1760. void
  1761. PlatformFile::SetCustomIconFamily(ODIconFamily icons)
  1762. {
  1763.     // set with kODNULL as the icons to delete the custom icons
  1764.     TRY
  1765.         if (!icons)
  1766.         {
  1767.             // check to see if there's a resFile so that we don't
  1768.             // create one while trying to delete nonexistant icons
  1769.             SetPermission(fsRdPerm);
  1770.             OpenResFile();        // THROW if no resFile
  1771.             CloseResFile();
  1772.         }
  1773.         // write icons to the file
  1774.         SetPermission(fsRdWrPerm);
  1775.         OpenResFile();
  1776.         for( long i=5; i>=0; i-- )
  1777.         {
  1778.             Handle    icon;
  1779.             char    state;
  1780.             
  1781.             if( icons )
  1782.                 THROW_IF_ERROR( GetIconFromSuite(&icon, icons, kIconType[i]) );
  1783.             else
  1784.                 icon = kODNULL;
  1785.             if (icon)
  1786.             {
  1787.                 state = HGetState(icon);
  1788.                 HLock(icon);
  1789.                 WASSERT(GetHandleSize(icon) == kIconSize[i]);
  1790.                 WriteResourcePtr(kIconType[i], kCustomIconResource, *icon, kIconSize[i]);
  1791.                 HSetState(icon, state);
  1792.             } else
  1793.                 DeleteResource(kIconType[i], kCustomIconResource);
  1794.         }
  1795.         CloseResFile();
  1796.     CATCH_ALL
  1797.     ENDTRY
  1798.     SetCustomIcon(icons != kODNULL);
  1799. }
  1800.