filespecutils.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:31k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "filespec.h"
  36. #include "filespecutils.h"
  37. #include "hxstring.h"
  38. #include "hxtick.h"
  39. #include "hxrand.h"
  40. #include "carray.h"
  41. #ifndef _CARBON
  42. #include "morefilesextras.h"
  43. #else
  44. #include "MoreFilesX.h"
  45. #endif
  46. // ------------------------------------------------------------------------------------
  47. //
  48. // GetFreeSpaceOnDisk
  49. //
  50. // ------------------------------------------------------------------------------------
  51. HX_RESULT CHXFileSpecUtils::GetFreeSpaceOnDisk(const CHXDirSpecifier& volSpec, INT64& freeSpace)
  52. {
  53. HX_RESULT err;
  54. FSSpec targetSpec;
  55. #ifdef _CARBON
  56. UInt64 freeBytes;
  57. UInt64 totalBytes;
  58. #else
  59. short foundVRefNum;
  60. UnsignedWide freeBytes;
  61. UnsignedWide totalBytes;
  62. #endif
  63. require_return(volSpec.IsSet(), HXR_INVALID_PARAMETER);
  64. targetSpec = volSpec;
  65. const StringPtr kDontCareVolName = NULL;
  66. #ifndef _CARBON
  67. err = XGetVInfo(targetSpec.vRefNum, kDontCareVolName, &foundVRefNum, &freeBytes, &totalBytes);
  68. #else
  69. err = FSGetVInfo(targetSpec.vRefNum, (HFSUniStr255*) kDontCareVolName, &freeBytes, &totalBytes);
  70. #endif
  71. if (err == noErr)
  72. {
  73. freeSpace = *(long long *) &freeBytes;
  74. }
  75. return err;
  76. }
  77. // ------------------------------------------------------------------------------------
  78. //
  79. // GetTotalSpaceOnDisk
  80. //
  81. // ------------------------------------------------------------------------------------
  82. HX_RESULT CHXFileSpecUtils::GetTotalSpaceOnDisk(const CHXDirSpecifier& volSpec, INT64& totalSpace)
  83. {
  84. HX_RESULT err;
  85. FSSpec targetSpec;
  86. #ifdef _CARBON
  87. UInt64 freeBytes;
  88. UInt64 totalBytes;
  89. #else
  90. UnsignedWide freeBytes;
  91. UnsignedWide totalBytes;
  92. short foundVRefNum;
  93. #endif
  94. require_return(volSpec.IsSet(), HXR_INVALID_PARAMETER);
  95. targetSpec = volSpec;
  96. const StringPtr kDontCareVolName = NULL;
  97. #ifndef _CARBON
  98. err = XGetVInfo(targetSpec.vRefNum, kDontCareVolName, &foundVRefNum, &freeBytes, &totalBytes);
  99. #else
  100. err = FSGetVInfo(targetSpec.vRefNum, (HFSUniStr255*) kDontCareVolName, &freeBytes, &totalBytes);
  101. #endif
  102. if (err == noErr)
  103. {
  104. totalSpace = *(long long *) &totalBytes;
  105. }
  106. return err;
  107. }
  108. // ------------------------------------------------------------------------------------
  109. //
  110. // IsFileLocal
  111. // IsDirectoryLocal
  112. //
  113. // ------------------------------------------------------------------------------------
  114. BOOL CHXFileSpecUtils::IsDiskLocal(const CHXDirSpecifier& volSpec)
  115. {
  116. HParamBlockRec pb;
  117. HX_RESULT err;
  118. FSSpec targetSpec;
  119. GetVolParmsInfoBuffer buff;
  120. BOOL bLocalVol;
  121. require_return(volSpec.IsSet(), FALSE);
  122. targetSpec = volSpec;
  123. ZeroInit(&pb);
  124. pb.ioParam.ioVRefNum = targetSpec.vRefNum;
  125. pb.ioParam.ioBuffer = (Ptr) &buff;
  126. pb.ioParam.ioReqCount = sizeof(buff);
  127. err = PBHGetVolParmsSync(&pb);
  128. check_noerr(err);
  129. if (err == noErr)
  130. {
  131. bLocalVol = (buff.vMServerAdr == 0);
  132. }
  133. else
  134. {
  135. // error occurred, default to true
  136. bLocalVol = TRUE;
  137. }
  138. return bLocalVol;
  139. }
  140. // ------------------------------------------------------------------------------------
  141. //
  142. // IsDiskEjectable
  143. //
  144. // ------------------------------------------------------------------------------------
  145. BOOL CHXFileSpecUtils::IsDiskEjectable(const CHXDirSpecifier& volSpec)
  146. {
  147. #ifdef _CARBON
  148. OSErr err;
  149. FSSpec targetSpec;
  150. GetVolParmsInfoBuffer  volParmsInfo;
  151. HParamBlockRec pb;
  152. require_return(volSpec.IsSet(), FALSE);
  153. targetSpec = volSpec;
  154. ZeroInit(&volParmsInfo);
  155. ZeroInit(&pb);
  156. pb.ioParam.ioVRefNum = targetSpec.vRefNum;
  157. pb.ioParam.ioBuffer = (Ptr) &volParmsInfo;
  158. pb.ioParam.ioReqCount = sizeof(volParmsInfo);
  159. err = PBHGetVolParmsSync(&pb);
  160. if (err == noErr)
  161. {
  162. // we require version 3 of the info buffer to rely on the vMExtendedAttributes
  163. if (volParmsInfo.vMVersion >= 3)
  164. {
  165. if (volParmsInfo.vMExtendedAttributes & (1L << bIsEjectable))
  166. {
  167. return TRUE;
  168. }
  169. }
  170. }
  171. return FALSE;
  172. #else
  173. HX_RESULT err;
  174. FSSpec targetSpec;
  175. Boolean driverWantsEject, driveEjectable, volumeEjected, volumeOnline;
  176. require_return(volSpec.IsSet(), FALSE);
  177. targetSpec = volSpec;
  178. const StringPtr kDontCareVolName = NULL;
  179. err = GetVolState(kDontCareVolName, targetSpec.vRefNum, &volumeOnline, &volumeEjected,
  180. &driveEjectable, &driverWantsEject);
  181. check_noerr(err);
  182. if (err == noErr)
  183. {
  184. return driveEjectable;
  185. }
  186. else
  187. {
  188. return FALSE;
  189. }
  190. #endif
  191. }
  192. // ------------------------------------------------------------------------------------
  193. //
  194. // IsDiskWritable
  195. //
  196. // ------------------------------------------------------------------------------------
  197. BOOL CHXFileSpecUtils::IsDiskWritable(const CHXDirSpecifier& volSpec)
  198. {
  199. OSErr err;
  200. FSSpec targetSpec;
  201. require_return(volSpec.IsSet(), FALSE);
  202. targetSpec = volSpec;
  203. HParamBlockRec hpb;
  204. ZeroInit(&hpb);
  205. hpb.volumeParam.ioVolIndex = 0;
  206. hpb.volumeParam.ioVRefNum = targetSpec.vRefNum;
  207. err = PBHGetVInfoSync(&hpb);
  208. check_noerr(err);
  209. if (err == noErr)
  210. {
  211. if ((hpb.volumeParam.ioVAtrb & 0x8080) != 0) // locked, software or hardware, per tech note FL 530
  212. {
  213. return FALSE; // not writable
  214. }
  215. }
  216. return TRUE;
  217. }
  218. // ------------------------------------------------------------------------------------
  219. //
  220. // GetFileSize
  221. //
  222. // ------------------------------------------------------------------------------------
  223. HX_RESULT CHXFileSpecUtils::GetFileSize(const CHXFileSpecifier& fileSpec, INT64& fSize)
  224. {
  225. require_return(fileSpec.IsSet(), HXR_INVALID_PARAMETER);
  226. #ifdef USE_FSREFS
  227. HX_RESULT err;
  228. FSRef targetRef;
  229. UInt64 logicalSize, physicalSize;
  230. ItemCount numForks;
  231. targetRef = fileSpec;
  232. err = FSGetTotalForkSizes(&targetRef, &logicalSize, &physicalSize, &numForks);
  233. if (err == noErr)
  234. {
  235. fSize = (INT64) logicalSize;
  236. }
  237. return err;
  238. #else
  239. HX_RESULT err;
  240. FSSpec targetSpec;
  241. targetSpec = fileSpec;
  242. HParamBlockRec pb;
  243. ZeroInit(&pb);
  244. pb.fileParam.ioVRefNum = targetSpec.vRefNum;
  245. pb.fileParam.ioDirID = targetSpec.parID;
  246. pb.fileParam.ioNamePtr = targetSpec.name;
  247. pb.fileParam.ioFDirIndex = 0;
  248. err = PBHGetFInfoSync(&pb);
  249. check_noerr(err);
  250. if ( err == noErr )
  251. {
  252. fSize = (INT64) pb.fileParam.ioFlLgLen;
  253. fSize += (INT64) pb.fileParam.ioFlRLgLen;
  254. }
  255. return err;
  256. #endif
  257. }
  258. // ------------------------------------------------------------------------------------
  259. //
  260. // GetDirectorySize
  261. //
  262. // ------------------------------------------------------------------------------------
  263. HX_RESULT CHXFileSpecUtils::GetDirectorySize(const CHXDirSpecifier& dirSpec, BOOL shouldDescend, INT64& fSize)
  264. {
  265. // rather than literally recurse through the directory tree, this routine
  266. // will keep an array of directories yet to be added to the total size
  267. require_return(dirSpec.IsSet(), HXR_INVALID_PARAMETER);
  268. CHXPtrArray specArray;
  269. CHXDirSpecifier *pCurrDirSpec;
  270. INT64 totalSize;
  271. // push a copy of the initial directory spec into the array; 
  272. // it will be deleted when it is popped off
  273. pCurrDirSpec = new CHXDirSpecifier(dirSpec);
  274. require_nonnull_return(pCurrDirSpec, HXR_OUTOFMEMORY);
  275. specArray.Add(pCurrDirSpec);
  276. totalSize = 0;
  277. while (!specArray.IsEmpty())
  278. {
  279. FSSpec targetFSSpec;
  280. OSErr err;
  281. CInfoPBRec pb;
  282. short vRefNum;
  283. long currentDirID, index;
  284. Str63 fileName;
  285. Boolean bDoneWithThisDirectory;
  286. // grab a dirSpec from the array, delete the object, 
  287. // and step through all items in the directory
  288. pCurrDirSpec = (CHXDirSpecifier *) specArray.ElementAt(0);
  289. check_nonnull(pCurrDirSpec);
  290. if (pCurrDirSpec)
  291. {
  292. targetFSSpec = *pCurrDirSpec;
  293. currentDirID = pCurrDirSpec->GetDirID();
  294. vRefNum = targetFSSpec.vRefNum;
  295. // remove this dirSpec from our array and delete the object
  296. specArray.RemoveAt(0);
  297. HX_DELETE(pCurrDirSpec);
  298. check(vRefNum != 0 && currentDirID != 0);
  299. if (vRefNum != 0 && currentDirID != 0)
  300. {
  301. // step through all items in this directory
  302. index = 0;
  303. bDoneWithThisDirectory = false;
  304. while (!bDoneWithThisDirectory)
  305. {
  306. index++;
  307. ZeroInit(&pb);
  308. fileName[0] = 0;
  309. pb.hFileInfo.ioVRefNum = vRefNum;
  310. pb.hFileInfo.ioDirID = currentDirID;
  311. pb.hFileInfo.ioNamePtr = fileName;
  312. pb.hFileInfo.ioFDirIndex = index;
  313. err = PBGetCatInfoSync(&pb);
  314. if (err != noErr)
  315. {
  316. // no more items in this directory
  317. bDoneWithThisDirectory = true;
  318. }
  319. else
  320. {
  321. if ((pb.hFileInfo.ioFlAttrib & ioDirMask) == 0)
  322. {
  323. // it's a file; add its size
  324. totalSize += (INT64) pb.hFileInfo.ioFlLgLen; // data fork
  325. totalSize += (INT64) pb.hFileInfo.ioFlRLgLen; // resource fork
  326. }
  327. else
  328. {
  329. // it's a directory; add a dirSpec for it to the array
  330. if (shouldDescend)
  331. {
  332. CHXDirSpecifier *pNewDirSpec;
  333. err = FSMakeFSSpec(vRefNum, currentDirID, fileName, &targetFSSpec);
  334. check_noerr(err);
  335. pNewDirSpec = new CHXDirSpecifier(targetFSSpec);
  336. check_nonnull(pNewDirSpec);
  337. if (pNewDirSpec)
  338. {
  339. specArray.Add(pNewDirSpec);
  340. }
  341. }
  342. }
  343. }
  344. } // while (!bDoneWithThisDirectory)
  345. }
  346. }
  347. } // while(!specArray.IsEmpty())
  348. fSize = totalSize;
  349. return HXR_OK;
  350. }
  351. // ------------------------------------------------------------------------------------
  352. //
  353. // GetCurrentApplication
  354. // GetCurrentApplicationDir
  355. //
  356. // ------------------------------------------------------------------------------------
  357. CHXFileSpecifier CHXFileSpecUtils::GetCurrentApplication()
  358. {
  359. OSErr err;
  360. FSSpec  appFSSpec;
  361. ProcessSerialNumber  appPSN = { 0, kCurrentProcess };
  362. ProcessInfoRec  appPIR;
  363. CHXFileSpecifier  appSpec;
  364. appPIR.processInfoLength = sizeof(ProcessInfoRec);
  365. appPIR.processAppSpec = &appFSSpec;
  366. appPIR.processName = NULL;
  367. err = GetProcessInformation(&appPSN, &appPIR);
  368. check_noerr(err);
  369. if (err == noErr)
  370. {
  371. appSpec = appFSSpec;
  372. }
  373. return appSpec;
  374. }
  375. CHXDirSpecifier CHXFileSpecUtils::GetCurrentApplicationDir()
  376. {
  377. CHXFileSpecifier  appSpec;
  378. CHXDirSpecifier  dirSpec;
  379. appSpec = GetCurrentApplication();
  380. if (appSpec.IsSet())
  381. {
  382. dirSpec = appSpec.GetParentDirectory();
  383. }
  384. return dirSpec;
  385. }
  386. // ------------------------------------------------------------------------------------
  387. //
  388. // FileExists
  389. // DirectoryExists
  390. //
  391. // ------------------------------------------------------------------------------------
  392. #ifndef USE_FSREFS
  393. static BOOL FSSpecExists(FSSpecPtr itemSpec, BOOL *isDirectory); // Forward declaration
  394. BOOL CHXFileSpecUtils::FileExists(const CHXFileSpecifier& fileSpec)
  395. {
  396. FSSpec  fileFSSpec;
  397. BOOL isDirectory;
  398. require_return(fileSpec.IsSet(), FALSE);
  399. fileFSSpec = fileSpec;
  400. return FSSpecExists(&fileFSSpec, &isDirectory) && !isDirectory;
  401. }
  402. BOOL CHXFileSpecUtils::DirectoryExists(const CHXDirSpecifier& dirSpec)
  403. {
  404. FSSpec  dirFSSpec;
  405. BOOL isDirectory;
  406. require_return(dirSpec.IsSet(), FALSE);
  407. dirFSSpec = dirSpec;
  408. return FSSpecExists(&dirFSSpec, &isDirectory) && isDirectory;
  409. }
  410. static BOOL FSSpecExists(FSSpecPtr itemSpec, BOOL *isDirectory)
  411. {
  412. OSErr err;
  413. CInfoPBRec cInfo;
  414. FSSpec tempSpec;
  415. BOOL bExists;
  416. bExists = FALSE;
  417. // copy the provided file spec so PBGetCatInfo doesn't change the name
  418. tempSpec = *itemSpec;
  419. cInfo.dirInfo.ioVRefNum = tempSpec.vRefNum;
  420. cInfo.dirInfo.ioDrDirID = tempSpec.parID;
  421. cInfo.dirInfo.ioNamePtr = tempSpec.name;
  422. cInfo.dirInfo.ioFDirIndex = 0; // use name, vRefNum, and dirID
  423. err = PBGetCatInfoSync(&cInfo);
  424. if (err == noErr)
  425. {
  426. bExists = TRUE;
  427. if (isDirectory)
  428. {
  429. if ((cInfo.hFileInfo.ioFlAttrib & ioDirMask) != 0)
  430. {
  431. *isDirectory = TRUE;
  432. }
  433. else
  434. {
  435. *isDirectory = FALSE;
  436. }
  437. }
  438. }
  439. return bExists;
  440. }
  441. #else // defined USE_FSREFS
  442. static BOOL FSRefExists(const FSRef * itemSpec, BOOL *isDirectory); // Forward declaration
  443. BOOL CHXFileSpecUtils::FileExists(const CHXFileSpecifier& fileSpec)
  444. {
  445. FSRef  fileRef;
  446. BOOL isDirectory;
  447. require_return(fileSpec.IsSet(), FALSE);
  448. fileRef = fileSpec;
  449.   return FSRefExists(&fileRef, &isDirectory) && !isDirectory;
  450. }
  451. BOOL CHXFileSpecUtils::DirectoryExists(const CHXDirSpecifier& dirSpec)
  452. {
  453. FSRef  dirRef;
  454. BOOL isDirectory;
  455. require_return(dirSpec.IsSet(), FALSE);
  456. dirRef = dirSpec;
  457. return FSRefExists(&dirRef, &isDirectory) && isDirectory;
  458. }
  459. static BOOL FSRefExists(const FSRef *itemRef, BOOL *isDirectory)
  460. {
  461. OSErr err;
  462. BOOL bExists;
  463. FSCatalogInfo  catInfo;
  464. const FSCatalogInfoBitmap whichInfo = kFSCatInfoNodeID | kFSCatInfoNodeFlags;
  465. HFSUniStr255 * kDontWantName = NULL;
  466. FSSpec * kDontWantFSSpec = NULL;
  467. FSRef * kDontWantParentRef = NULL;
  468. bExists = FALSE;
  469. err = ::FSGetCatalogInfo(itemRef, whichInfo, &catInfo,
  470. kDontWantName, kDontWantFSSpec, kDontWantParentRef);
  471. if (err == noErr)
  472. {
  473. bExists = TRUE;
  474. if (isDirectory)
  475. {
  476. if ((catInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0)
  477. {
  478. *isDirectory = TRUE;
  479. }
  480. else
  481. {
  482. *isDirectory = FALSE;
  483. }
  484. }
  485. }
  486. return bExists;
  487. }
  488. #endif // defined USE_FSREFS
  489. // ------------------------------------------------------------------------------------
  490. //
  491. // CreateDirectory
  492. //
  493. // ------------------------------------------------------------------------------------
  494. HX_RESULT CHXFileSpecUtils::CreateDir(const CHXDirSpecifier& dirSpec)
  495. {
  496. FSSpec  dirFSSpec;
  497. long dirID;
  498. OSErr err;
  499. require_return(dirSpec.IsSet(), HXR_INVALID_PARAMETER);
  500. dirFSSpec = dirSpec;
  501. err = FSpDirCreate(&dirFSSpec, smSystemScript, &dirID);
  502. return err;
  503. }
  504. // ------------------------------------------------------------------------------------
  505. //
  506. // RemoveDir - deletes an empty directory
  507. //
  508. // ------------------------------------------------------------------------------------
  509. HX_RESULT CHXFileSpecUtils::RemoveDir(const CHXDirSpecifier& dirSpec)
  510. {
  511. FSSpec  dirFSSpec;
  512. OSErr err;
  513. require_return(dirSpec.IsSet(), HXR_INVALID_PARAMETER);
  514. dirFSSpec = dirSpec;
  515. err = FSpDelete(&dirFSSpec);
  516. return err;
  517. }
  518. // ------------------------------------------------------------------------------------
  519. //
  520. // RemoveFile
  521. //
  522. // ------------------------------------------------------------------------------------
  523. HX_RESULT CHXFileSpecUtils::RemoveFile(const CHXFileSpecifier& fileSpec)
  524. {
  525. FSSpec  fileFSSpec;
  526. OSErr err;
  527. require_return(fileSpec.IsSet(), HXR_INVALID_PARAMETER);
  528. fileFSSpec = fileSpec;
  529. err = FSpDelete(&fileFSSpec);
  530. return err;
  531. }
  532. // ------------------------------------------------------------------------------------
  533. //
  534. // GetFileType
  535. //
  536. // ------------------------------------------------------------------------------------
  537. FOURCC CHXFileSpecUtils::GetFileType(const CHXFileSpecifier& fileSpec)
  538. {
  539. FOURCC fileType;
  540. OSErr err;
  541. require_return(fileSpec.IsSet(), HXR_INVALID_PARAMETER);
  542. fileType = 0;
  543. if (fileSpec.IsSet())
  544. {
  545. #ifdef USE_FSREFS
  546. FSRef fileRef;
  547. FinderInfo fndrInfo;
  548. Boolean isDir;
  549. ExtendedFinderInfo * kDontWantExtendedInfo = NULL;
  550. fileRef = fileSpec;
  551. err = FSGetFinderInfo(&fileRef, &fndrInfo, kDontWantExtendedInfo, &isDir);
  552. if ((err == noErr) && !isDir)
  553. {
  554. fileType = fndrInfo.file.fileType;
  555. }
  556. #else
  557. FSSpec fileFSSpec;
  558. FInfo fndrInfo;
  559. fileFSSpec = fileSpec;
  560. err = FSpGetFInfo(&fileFSSpec, &fndrInfo);
  561. check_noerr(err);
  562. if (err == noErr)
  563. {
  564. fileType = fndrInfo.fdType;
  565. }
  566. #endif
  567. }
  568. return fileType;
  569. }
  570. // ------------------------------------------------------------------------------------
  571. //
  572. // MakeNameLegal
  573. //
  574. // returns TRUE if the name was changed
  575. //
  576. // ------------------------------------------------------------------------------------
  577. BOOL CHXFileSpecUtils::MakeNameLegal(char *pszName)
  578. {
  579. const char *badChars = ":";
  580. const char replacementChar = '-';
  581. const long maxNameLength = 31;
  582. long len, idx;
  583. BOOL bChanged;
  584. require_nonnull_return(pszName, FALSE);
  585. bChanged = FALSE;
  586. len = strlen(pszName);
  587. // replace any illegal characters
  588. for (idx = 0; idx < len; idx++)
  589. {
  590. if (strchr(badChars, pszName[idx]))
  591. {
  592. pszName[idx] = replacementChar;
  593. bChanged = TRUE;
  594. }
  595. }
  596. // be sure the name isn't too long
  597. if (len > maxNameLength)
  598. {
  599. pszName[maxNameLength] = 0;
  600. bChanged = TRUE;
  601. }
  602. return bChanged;
  603. }
  604. // ------------------------------------------------------------------------------------
  605. //
  606. // FindFolder
  607. //
  608. // ------------------------------------------------------------------------------------
  609. CHXDirSpecifier CHXFileSpecUtils::MacFindFolder(short vRefNum, FolderType foldType)
  610. {
  611. short  foundVRefNum;
  612. long  foundDirID;
  613. FSSpec targetSpec;
  614. CHXDirSpecifier foundDirSpec;
  615. OSErr err;
  616. err = ::FindFolder(vRefNum, foldType, kCreateFolder, &foundVRefNum, &foundDirID);
  617. if (err == noErr)
  618. {
  619. err = FSMakeFSSpec(foundVRefNum, foundDirID, "p", &targetSpec);
  620. check_noerr(err);
  621. if (err == noErr)
  622. {
  623. foundDirSpec = targetSpec;
  624. }
  625. }
  626. return foundDirSpec;
  627. }
  628. CHXFileSpecifier CHXFileSpecUtils::SpecifyFileWithMacFindFolder(short vRefNum, FolderType foldType, const char *pszChildFile)
  629. {
  630. CHXDirSpecifier parentDir;
  631. CHXFileSpecifier targetFile;
  632. parentDir = CHXFileSpecUtils::MacFindFolder(vRefNum, foldType);
  633. check(parentDir.IsSet());
  634. if (CHXFileSpecUtils::DirectoryExists(parentDir))
  635. {
  636. targetFile = parentDir.SpecifyChildFile(pszChildFile);
  637. }
  638. return targetFile;
  639. }
  640. CHXDirSpecifier CHXFileSpecUtils::SpecifyFolderWithMacFindFolder(short vRefNum, FolderType foldType, const char *pszChildFolder)
  641. {
  642. CHXDirSpecifier parentDir;
  643. CHXDirSpecifier targetDir;
  644. parentDir = CHXFileSpecUtils::MacFindFolder(vRefNum, foldType);
  645. check(parentDir.IsSet());
  646. if (CHXFileSpecUtils::DirectoryExists(parentDir))
  647. {
  648. targetDir = parentDir.SpecifyChildDirectory(pszChildFolder);
  649. }
  650. return targetDir;
  651. }
  652. // ------------------------------------------------------------------------------------
  653. //
  654. // ResolveFileSpecifierAlias
  655. // ResolveDirSpecifierAlias
  656. //
  657. // These resolve a file spec to an alias file in place
  658. //
  659. // ------------------------------------------------------------------------------------
  660. HX_RESULT CHXFileSpecUtils::ResolveFileSpecifierAlias(CHXFileSpecifier& fileSpec)
  661. {
  662. HX_RESULT res;
  663. res = HXR_FAIL;
  664. if (fileSpec.IsSet())
  665. {
  666. FSSpec fileFSSpec;
  667. OSErr err;
  668. Boolean bIsFolder;
  669. Boolean bWasAliased;
  670. const Boolean kShouldResolveChains = true;
  671. fileFSSpec = fileSpec;
  672. err = ResolveAliasFileWithMountFlags(&fileFSSpec, kShouldResolveChains,
  673. &bIsFolder, &bWasAliased, kResolveAliasFileNoUI);
  674. check(err == noErr);
  675. if ((err == noErr) && !bIsFolder)
  676. {
  677. res = HXR_OK;
  678. if (bWasAliased)
  679. {
  680. fileSpec = fileFSSpec;
  681. }
  682. }
  683. else
  684. {
  685. // error occurred
  686. }
  687. }
  688. return res;
  689. }
  690. HX_RESULT CHXFileSpecUtils::ResolveDirSpecifierAlias(CHXDirSpecifier& dirSpec)
  691. {
  692. HX_RESULT res;
  693. res = HXR_FAIL;
  694. if (dirSpec.IsSet())
  695. {
  696. FSSpec dirFSSpec;
  697. OSErr err;
  698. Boolean bIsFolder;
  699. Boolean bWasAliased;
  700. const Boolean kShouldResolveChains = true;
  701. dirFSSpec = dirSpec;
  702. err = ResolveAliasFileWithMountFlags(&dirFSSpec, kShouldResolveChains,
  703. &bIsFolder, &bWasAliased, kResolveAliasFileNoUI);
  704. if ((err == noErr) && bIsFolder)
  705. {
  706. res = HXR_OK;
  707. if (bWasAliased)
  708. {
  709. dirSpec = dirFSSpec;
  710. }
  711. }
  712. else
  713. {
  714. // error occurred
  715. }
  716. }
  717. return res;
  718. }
  719. // ------------------------------------------------------------------------------------
  720. //
  721. // MoveFileToTrash
  722. // MoveFolderToTrash
  723. // MoveFileToFolderWithRenaming
  724. // MoveFolderToFolderWithRenaming
  725. //
  726. // ------------------------------------------------------------------------------------
  727. static HX_RESULT MoveToFolderWithRenamingInternal(const FSSpec* itemFSSpec, const CHXDirSpecifier& targetSpec, BOOL bDeleteIfCantMove);
  728. HX_RESULT CHXFileSpecUtils::MoveFileToTrash(const CHXFileSpecifier& fileSpec) 
  729. {
  730. if (!CHXFileSpecUtils::FileExists(fileSpec)) return HXR_INVALID_PARAMETER;
  731. CHXDirSpecifier trashSpec;
  732. FSSpec itemFSSpec;
  733. itemFSSpec = fileSpec;
  734. trashSpec = CHXFileSpecUtils::MacFindFolder(itemFSSpec.vRefNum, kTrashFolderType);
  735. return MoveToFolderWithRenamingInternal(&itemFSSpec, trashSpec, TRUE);
  736. }
  737. HX_RESULT CHXFileSpecUtils::MoveFolderToTrash(const CHXDirSpecifier& dirSpec) 
  738. {
  739. if (!CHXFileSpecUtils::DirectoryExists(dirSpec)) return HXR_INVALID_PARAMETER;
  740. CHXDirSpecifier trashSpec;
  741. FSSpec itemFSSpec;
  742. itemFSSpec = dirSpec;
  743. trashSpec = CHXFileSpecUtils::MacFindFolder(itemFSSpec.vRefNum, kTrashFolderType);
  744. return MoveToFolderWithRenamingInternal(&itemFSSpec, trashSpec, TRUE);
  745. }
  746. HX_RESULT CHXFileSpecUtils::MoveFileToCleanupAtStartup(const CHXFileSpecifier& fileSpec, BOOL bDeleteIfCantMove) 
  747. {
  748. CHXFileSpecifier nonConstFileSpec(fileSpec);
  749. return MoveFileToCleanupAtStartup(nonConstFileSpec, bDeleteIfCantMove);
  750. }
  751. HX_RESULT CHXFileSpecUtils::MoveFileToCleanupAtStartup(CHXFileSpecifier& fileSpec, BOOL bDeleteIfCantMove) 
  752. {
  753. if (!CHXFileSpecUtils::FileExists(fileSpec)) return HXR_INVALID_PARAMETER;
  754. CHXDirSpecifier cleanupSpec;
  755. FSSpec itemFSSpec;
  756. itemFSSpec = fileSpec;
  757. cleanupSpec = CHXFileSpecUtils::MacFindFolder(itemFSSpec.vRefNum, kChewableItemsFolderType);
  758. return MoveToFolderWithRenamingInternal(&itemFSSpec, cleanupSpec, TRUE);
  759. }
  760. HX_RESULT CHXFileSpecUtils::MoveFolderToCleanupAtStartup(const CHXDirSpecifier& dirSpec, BOOL bDeleteIfCantMove) 
  761. {
  762. CHXDirSpecifier nonConstDirSpec(dirSpec);
  763. return MoveFolderToCleanupAtStartup(nonConstDirSpec, bDeleteIfCantMove);
  764. }
  765. HX_RESULT CHXFileSpecUtils::MoveFolderToCleanupAtStartup(CHXDirSpecifier& dirSpec, BOOL bDeleteIfCantMove) 
  766. {
  767. if (!CHXFileSpecUtils::DirectoryExists(dirSpec)) return HXR_INVALID_PARAMETER;
  768. CHXDirSpecifier cleanupSpec;
  769. FSSpec itemFSSpec;
  770. itemFSSpec = dirSpec;
  771. cleanupSpec = CHXFileSpecUtils::MacFindFolder(itemFSSpec.vRefNum, kChewableItemsFolderType);
  772. return MoveToFolderWithRenamingInternal(&itemFSSpec, cleanupSpec, TRUE);
  773. }
  774. HX_RESULT CHXFileSpecUtils::MoveFileToFolderWithRenaming(CHXFileSpecifier& fileSpec, const CHXDirSpecifier& targetSpec, BOOL bDeleteIfCantMove) 
  775. {
  776. if (!CHXFileSpecUtils::FileExists(fileSpec)) return HXR_INVALID_PARAMETER;
  777. if (!CHXFileSpecUtils::DirectoryExists(targetSpec)) return HXR_INVALID_PARAMETER;
  778. FSSpec fsSpec;
  779. fsSpec = fileSpec;
  780. return MoveToFolderWithRenamingInternal(&fsSpec, targetSpec, bDeleteIfCantMove);
  781. }
  782. HX_RESULT CHXFileSpecUtils::MoveFolderToFolderWithRenaming(CHXDirSpecifier& dirSpec, const CHXDirSpecifier& targetSpec, BOOL bDeleteIfCantMove) 
  783. {
  784. if (!CHXFileSpecUtils::DirectoryExists(dirSpec)) return HXR_INVALID_PARAMETER;
  785. if (!CHXFileSpecUtils::DirectoryExists(targetSpec)) return HXR_INVALID_PARAMETER;
  786. FSSpec fsSpec;
  787. fsSpec = dirSpec;
  788. return MoveToFolderWithRenamingInternal(&fsSpec, targetSpec, bDeleteIfCantMove);
  789. }
  790. static HX_RESULT MoveToFolderWithRenamingInternal(const FSSpec* itemFSSpec, const CHXDirSpecifier& targetSpec, BOOL bDeleteIfCantMove) 
  791. {
  792. check_nonnull(itemFSSpec);
  793. HX_RESULT pnres;
  794. OSErr err;
  795. FSSpec targetFSSpec;
  796. pnres = HXR_FAILED;
  797. // find the trash for the disk containing the file
  798. if (!targetSpec.IsSet())
  799. {
  800. // targetSpec wasn't set, nowhere to move to
  801. if (bDeleteIfCantMove)
  802. {
  803. err = FSpDelete(itemFSSpec);
  804. if (err == noErr)
  805. {
  806. pnres = HXR_OK;
  807. }
  808. }
  809. }
  810. else
  811. {
  812. // targetSpec is set
  813. //
  814. // try to move the file to the target
  815. targetFSSpec = targetSpec;
  816. err = CatMove(itemFSSpec->vRefNum, itemFSSpec->parID, itemFSSpec->name, targetFSSpec.parID, targetFSSpec.name);
  817. if (err == noErr)
  818. {
  819. pnres = HXR_OK;
  820. }
  821. else if (err == dupFNErr)
  822. {
  823. // there's a name conflict; find a unique name for the file we're moving in the
  824. // target folder, rename it, and then move it again
  825. CHXString strName, strTemplate;
  826. CHXFileSpecifier specNewNamedFile;
  827. strName.SetFromStr255(itemFSSpec->name); // make a template like "filename_N"
  828. strTemplate = strName + "_%-%-%";
  829. specNewNamedFile = CHXFileSpecUtils::GetUniqueFileSpec(targetSpec, strName, strTemplate, "%-%-%");
  830. err = FSpRename(itemFSSpec, (ConstStr255Param) specNewNamedFile.GetName());
  831. if (err == noErr)
  832. {
  833. err = CatMove(itemFSSpec->vRefNum, itemFSSpec->parID, (ConstStr255Param) specNewNamedFile.GetName(), 
  834. targetFSSpec.parID, targetFSSpec.name);
  835. if (err == noErr)
  836. {
  837. pnres = HXR_OK;
  838. }
  839. else if (err != noErr && bDeleteIfCantMove)
  840. {
  841. // couldn't move it; delete the renamed file
  842. err = HDelete(itemFSSpec->vRefNum, itemFSSpec->parID, (ConstStr255Param) specNewNamedFile.GetName());
  843. if (err == noErr)
  844. {
  845. pnres = HXR_OK;
  846. }
  847. }
  848. else
  849. {
  850. // couldn't move it; change the name back
  851. err = FSpRename((FSSpec *) specNewNamedFile, itemFSSpec->name);
  852. }
  853. }
  854. else
  855. {
  856. // rename failed for some reason
  857. if (bDeleteIfCantMove)
  858. {
  859. err = FSpDelete(itemFSSpec);
  860. if (err == noErr)
  861. {
  862. pnres = HXR_OK;
  863. }
  864. }
  865. }
  866. else
  867. {
  868. // catmove failed for some unknown reason, not a name conflict
  869. if (bDeleteIfCantMove)
  870. {
  871. err = FSpDelete(itemFSSpec);
  872. if (err == noErr)
  873. {
  874. pnres = HXR_OK;
  875. }
  876. }
  877. }
  878. }
  879. return pnres;
  880. }
  881. // ------------------------------------------------------------------------------------
  882. //
  883. // GetSystemTempDirectory
  884. //
  885. // ------------------------------------------------------------------------------------
  886. CHXDirSpecifier CHXFileSpecUtils::GetSystemTempDirectory()
  887. {
  888. return CHXFileSpecUtils::MacFindFolder(kOnSystemDisk, kChewableItemsFolderType);
  889. }
  890. // ------------------------------------------------------------------------------------
  891. //
  892. // GetUniqueFileSpec
  893. // GetUniqueTempFileSpec
  894. //
  895. // ------------------------------------------------------------------------------------
  896. static CHXFileSpecifier GetUniqueFileSpecInternal(const CHXDirSpecifier& locationSpec, 
  897. const char *pszNameFirst, const char *pszTemplate, 
  898. const char *pszWildcard, UINT32 nStartNum);
  899. const UINT32 kNumWrapValue = 9999+1; // limit insertions to 4-digit numbers
  900. CHXFileSpecifier CHXFileSpecUtils::GetUniqueFileSpec(const CHXDirSpecifier& locationSpec, 
  901. const char *pszNameFirst, const char *pszTemplate, 
  902. const char *pszWildcard)
  903. {
  904. return GetUniqueFileSpecInternal(locationSpec, pszNameFirst, pszTemplate, pszWildcard, 0);
  905. }
  906. CHXFileSpecifier CHXFileSpecUtils::GetUniqueTempFileSpec(const CHXDirSpecifier& locationSpec, 
  907. const char *pszTemplate, const char *pszWildcard)
  908. {
  909. CMultiplePrimeRandom  rand(HX_GET_TICKCOUNT());
  910. UINT32 num;
  911. num = rand.GetRandomNumber();
  912. num %= kNumWrapValue;
  913. // skip 0, which means "don't substitute for the wildcard", and 1
  914. if (num == 0 || num == 1) num = 2;
  915. return GetUniqueFileSpecInternal(locationSpec, NULL, pszTemplate, pszWildcard, num);
  916. }
  917. static CHXFileSpecifier GetUniqueFileSpecInternal(const CHXDirSpecifier& locationSpec, 
  918. const char *pszNameFirst, const char *pszTemplate, 
  919. const char *pszWildcard, UINT32 nStartNum)
  920. {
  921. CHXFileSpecifier  resultFileSpec;
  922. require_return(locationSpec.IsSet(), resultFileSpec);
  923. require_return(pszTemplate != NULL && pszWildcard != NULL, resultFileSpec);
  924. require_return(pszNameFirst != NULL || nStartNum != 0, resultFileSpec);
  925. CHXFileSpecifier  testFileSpec;
  926. CHXDirSpecifier  testDirSpec;
  927. CHXString strNumber;
  928. CHXString strName;
  929. UINT32 nCurrentNum;
  930. nCurrentNum = nStartNum;
  931. while (1) 
  932. {
  933. // if the number is non-zero, make a string from the template;
  934. // if the number is zero, user the initial name string
  935. if (nCurrentNum == 0)
  936. {
  937. // replace the wildcard in the template with the number string
  938. strName = pszNameFirst;
  939. }
  940. else
  941. {
  942. // replace the wildcard in the template with the number string
  943. strNumber.Empty();
  944. strNumber.AppendULONG(nCurrentNum);
  945. strName = pszTemplate;
  946. strName.FindAndReplace(pszWildcard, strNumber); // replace first wildcard with number string
  947. }
  948. // test if a file or directory exists with that name
  949. testFileSpec = locationSpec.SpecifyChildFile(strName);
  950. testDirSpec = locationSpec.SpecifyChildDirectory(strName);
  951. if (CHXFileSpecUtils::FileExists(testFileSpec)
  952. || CHXFileSpecUtils::DirectoryExists(testDirSpec))
  953. {
  954. // an item already has that name, so increment & wrap the number
  955. nCurrentNum++;
  956. nCurrentNum %= kNumWrapValue;
  957. // don't use 0 again, and skip 1 since "MyFile2.txt" logically follows "MyFile.txt"
  958. if (nCurrentNum == 0 || nCurrentNum == 1) 
  959. {
  960. nCurrentNum = 2; 
  961. }
  962. // a quick sanity check
  963. if (nCurrentNum == nStartNum)
  964. {
  965. check(!"GetUniqueFileSpecInternal number wrapped");
  966. break;
  967. }
  968. }
  969. else
  970. {
  971. // the name is unique
  972. resultFileSpec = testFileSpec;
  973. break;
  974. }
  975. } // while
  976. return resultFileSpec;
  977. }
  978. CHXDirSpecifier 
  979. CHXFileSpecUtils::GetAppDataDir(const char* szAppName)
  980. {
  981. // XXXSEH: Placeholder.
  982. check(!"GetAppDataDir doesn't find anyplace useful on the Mac");
  983. // GR 3/19/02  What is supposed to go in the "app data dir"?
  984. //
  985. // We could make an appName folder in the users documents directory 
  986. // with MacFindFolder(kUserDomain, kDocumentsFolderType), 
  987. // but it's not normal for applications to hardcode that location for anything.
  988. //
  989. // The windows implementation finds someplace in the user directories, but this implementation doesn't.
  990. return GetCurrentApplicationDir();
  991. }
  992. #ifdef _DEBUG
  993. void CHXFileSpecUtils::TestMacFileSpecUtils()
  994. {
  995. }
  996. #endif