fullpathname.cp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:17k
源码类别:

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 "platform/mac/FullPathName.h"
  36. #if defined(_MAC_UNIX) || defined(_CARBON)
  37. #include "platform/mac/MoreFilesX.h"
  38. #include "platform/mac/cfwrappers.h"
  39. #endif
  40. /*
  41.  * Pascal string utilities
  42.  */
  43. #ifdef __cplusplus
  44. extern "C" {
  45. #endif 
  46. #if defined(_MAC_UNIX) || defined(_CARBON)
  47. // prototypes for internal routines
  48. static OSErr PathFromFSRefInternal(CFURLPathStyle pathStyle, const FSRef *ref, CHXString& fullPathName);
  49. static OSErr FSRefFromPathInternal(CFURLPathStyle pathStyle, const char *path, FSRef *outRef);
  50. static OSErr AlternateFSRefFromHFSPathInternal(const char* hfspath, FSRef* outRef);
  51. static OSStatus URLFromPathInternal(CFURLPathStyle pathStyle, const char *pszPath, CHXString& strURL);
  52. static OSStatus PathFromURLInternal(CFURLPathStyle pathStyle, const char *pszURL, CHXString& fullPathName);
  53. OSStatus PathFromCFURLInternal(CFURLPathStyle pathStyle, CFURLRef urlRef, CHXString& fullPathName);
  54. OSErr PathFromFSRefInternal(CFURLPathStyle pathStyle, const FSRef *ref, CHXString& fullPathName)
  55. {
  56. CHXCFString cfs;
  57. CHXCFURL cfurl;
  58. require_nonnull(ref, BadParam);
  59. // make a CFURL from the FSRef
  60. cfurl = ref;
  61. require(cfurl.IsSet(), CantSetURLToRef);
  62. return PathFromCFURLInternal(pathStyle, cfurl, fullPathName);
  63. CantSetURLToRef:
  64. BadParam:
  65. return errFSBadFSRef;
  66. }
  67. OSErr FSRefFromPathInternal(CFURLPathStyle pathStyle, const char *path, FSRef *outRef) 
  68. {
  69. CHXCFURL cfurl;
  70. CHXCFString cfstr;
  71. Boolean bSuccess;
  72. CFStringEncoding encoding;
  73. const Boolean kDirectoryDoesntMatter = false; // we could look at the last char of the string if it mattered
  74. require_nonnull(outRef, BadOutputParam);
  75. // copy the path to a CFString
  76. encoding = (pathStyle == kCFURLHFSPathStyle ? CFStringGetSystemEncoding() : (CFStringEncoding) kCFStringEncodingUTF8);
  77. cfstr = CHXCFString(path, encoding);
  78. require(cfstr.IsSet(), CantMakeCFString);
  79. // make a CFURL from the CFString
  80. cfurl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfstr, pathStyle, kDirectoryDoesntMatter);
  81. require(cfurl.IsSet(), CantSetURL);
  82. // get an FSRef from the URL; this will fail if the item doesn't really exist
  83. bSuccess = CFURLGetFSRef(cfurl, outRef);
  84. //if (!bSuccess) CFShow(cfurl);
  85. if ((!bSuccess) && (pathStyle == kCFURLHFSPathStyle))
  86. {
  87. OSErr err = AlternateFSRefFromHFSPathInternal(path, outRef);
  88. bSuccess = (err == noErr);
  89. }
  90. require_quiet(bSuccess, CantGetRefFromURL);
  91. // now make an FSRef
  92. return noErr;
  93. CantGetRefFromURL:
  94. CantSetURL:
  95. CantMakeCFString:
  96. BadOutputParam:
  97. return paramErr;
  98. }
  99. // GR 7/23/02 blech...
  100. // AlternateFSRefFromHFSPathInternal exists only because Mac OS X 10.1.5 and maybe later
  101. // can't make CFURLs and then FSRefs from HFS paths that have volume names with high-8 bit
  102. // characters in them.
  103. OSErr AlternateFSRefFromHFSPathInternal(const char* hfspath, FSRef* outRef)
  104. {
  105. require_nonnull_return(outRef, paramErr);
  106. require_nonnull_return(hfspath, paramErr);
  107. OSErr err = -1;
  108. // use FSMakeFSSpec for short paths, NewAliasMinimalFromFullPath for long paths
  109. if (strlen(hfspath) < 256)
  110. {
  111. Str255 pascPath;
  112. FSSpec spec;
  113. c2pstrcpy(pascPath, hfspath);
  114. err = FSMakeFSSpec(0, 0, pascPath, &spec);
  115. if (err == noErr || err == fnfErr)
  116. {
  117. err = FSpMakeFSRef(&spec, outRef);
  118. }
  119. }
  120. else
  121. {
  122. AliasHandle aliasH;
  123. Boolean wasChanged;
  124. err = NewAliasMinimalFromFullPath(strlen(hfspath), hfspath, "p", "p", &aliasH);
  125. if (err == noErr)
  126. {
  127. err = FSResolveAliasWithMountFlags(nil, aliasH, outRef, &wasChanged, kResolveAliasFileNoUI);
  128. DisposeHandle((Handle) aliasH);
  129. }
  130. }
  131. return err;
  132. }
  133. OSStatus URLFromPathInternal(CFURLPathStyle pathStyle, const char *pszPath, CHXString& strURL)
  134. {
  135. CHXCFURL cfurl;
  136. CHXCFString cfstr;
  137. CFStringRef cfsNoRelease;
  138. CFStringEncoding encoding;
  139. const Boolean kDirectoryDoesntMatter = false; // we could look at the last char of the string if it mattered
  140. // copy the path into a CFString
  141. encoding = (pathStyle == kCFURLHFSPathStyle ? CFStringGetSystemEncoding() : (CFStringEncoding) kCFStringEncodingUTF8);
  142. cfstr = CHXCFString(pszPath, encoding);
  143. // make a CFURL from the CFString of the path
  144. cfurl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfstr, pathStyle, kDirectoryDoesntMatter);
  145. require(cfurl.IsSet(), CantSetURL);
  146. // get the URL as a CFString
  147. cfsNoRelease = ::CFURLGetString(cfurl); // we are NOT supposed to release the CFString obtained here
  148. require_nonnull(cfsNoRelease, CantGetURLString);
  149. // copy the URL from the CFString into the output CHXString
  150. strURL.SetFromCFString(cfsNoRelease, kCFStringEncodingUTF8);
  151. return noErr;
  152. CantGetURLString:
  153. CantSetURL:
  154. return paramErr;
  155. }
  156. OSStatus PathFromURLInternal(CFURLPathStyle pathStyle, const char *pszURL, CHXString& fullPathName)
  157. {
  158. CHXCFURL cfurl;
  159. CHXCFString cfs;
  160. // make a CFURL from the input url
  161. cfurl = pszURL;
  162. require(cfurl.IsSet(), CantMakeURL);
  163. return PathFromCFURLInternal(pathStyle, cfurl, fullPathName);
  164. CantMakeURL:
  165. return kNSLBadURLSyntax;
  166. }
  167. OSStatus PathFromCFURLInternal(CFURLPathStyle pathStyle, CFURLRef urlRef, CHXString& fullPathName)
  168. {
  169. if (pathStyle == kCFURLHFSPathStyle)
  170. {
  171. CHXCFString cfs;
  172. // get the HFS path as a CFString from the CFURL
  173. cfs = CFURLCopyFileSystemPath (urlRef, pathStyle);
  174. require(cfs.IsSet(), CantSetStringToURL);
  175. // copy the path to the CHXString
  176. fullPathName.SetFromCFString(cfs, CFStringGetSystemEncoding());
  177. }
  178. else
  179. {
  180. #if defined(_MAC_MACHO)
  181. // POSIX paths are canonical UTF-8, as returned by CFURLGetFileSystemRepresentation
  182. const Boolean kAbsolutePath = true;
  183. UInt8* buff = (UInt8*) fullPathName.GetBuffer(1 + MAXPATHLEN);
  184. Boolean succeeded = ::CFURLGetFileSystemRepresentation(urlRef, kAbsolutePath, buff, MAXPATHLEN);
  185. fullPathName.ReleaseBuffer();
  186. require(succeeded, CantSetStringToURL);
  187. #else
  188. HX_ASSERT(!"CFM builds shouldn't be getting posix paths!");
  189. #endif
  190. }
  191. require_quiet(!fullPathName.IsEmpty(), URLCreationFailed);
  192. return noErr;
  193. URLCreationFailed:
  194. CantSetStringToURL:
  195. return kNSLBadURLSyntax;
  196. }
  197. #pragma mark -
  198. // ref <--> path routines
  199. OSErr PathFromFSRef(const FSRef *ref, CHXString& fullPathName)
  200. {
  201. #ifdef _MAC_CFM
  202. return HFSPathFromFSRef(ref, fullPathName);
  203. #else
  204. return POSIXPathFromFSRef(ref, fullPathName);
  205. #endif
  206. }
  207. OSErr FSRefFromPath(const char *path, FSRef *outRef)
  208. {
  209. #ifdef _MAC_CFM
  210. return FSRefFromHFSPath(path, outRef);
  211. #else
  212. return FSRefFromPosixPath(path, outRef);
  213. #endif
  214. }
  215. OSErr PathFromURL(const char *pszURL, CHXString& fullPathName)
  216. {
  217. #ifdef _MAC_CFM
  218. return HFSPathFromURL(pszURL, fullPathName);
  219. #else
  220. return POSIXPathFromURL(pszURL, fullPathName);
  221. #endif
  222. }
  223. OSErr URLFromPath(const char *pszPath, CHXString& strURL)
  224. {
  225. #ifdef _MAC_CFM
  226. return URLFromHFSPath(pszPath, strURL);
  227. #else
  228. return URLFromPOSIXPath(pszPath, strURL);
  229. #endif
  230. }
  231. OSErr HFSPathFromFSRef(const FSRef *pRef, CHXString& fullPathName)
  232. {
  233. OSErr err;
  234. err = PathFromFSRefInternal(kCFURLHFSPathStyle, pRef, fullPathName);
  235. if (err == noErr)
  236. {
  237. // be sure that directory path names end with ':'
  238. OSErr err2;
  239. Boolean isDir;
  240. long *kDontWantNodeID = NULL;
  241. err2 = FSGetNodeID(pRef, kDontWantNodeID, &isDir);
  242. if ((err2 == noErr) && isDir)
  243. {
  244. if (fullPathName.Right(1) != ":")
  245. {
  246. fullPathName += ':';
  247. }
  248. }
  249. }
  250. return err;
  251. }
  252. OSErr FSRefFromHFSPath(const char *path, FSRef *outRef) 
  253. {
  254. CHXString strPath;
  255. OSErr err;
  256. err = FullFromPartialHFSPath(path, strPath);
  257. // now we have a full path name to convert
  258. // GR 3/26/02
  259. // ick, this fails for paths on mounted volumes due to CFURL bugs, and none
  260. // of the alternatives I can find seem to work, either
  261. err =  FSRefFromPathInternal(kCFURLHFSPathStyle, (const char *) strPath, outRef);
  262. return err;
  263. }
  264. OSStatus POSIXPathFromFSRef (const FSRef *pRef, CHXString& fullPathName)
  265. {
  266. return PathFromFSRefInternal(kCFURLPOSIXPathStyle, pRef, fullPathName);
  267. }
  268. OSStatus FSRefFromPosixPath (const char *path, FSRef *pRef)
  269. {
  270. OSStatus err;
  271. CHXString strPath;
  272. err = FullFromPartialPOSIXPath(path, strPath);
  273. return FSRefFromPathInternal(kCFURLPOSIXPathStyle, path, pRef);
  274. }
  275. // url <--> path routines
  276. OSStatus URLFromPOSIXPath(const char *pszPath, CHXString& strURL)
  277. {
  278. OSStatus err;
  279. CHXString strPath;
  280. err = FullFromPartialPOSIXPath(pszPath, strPath);
  281. return URLFromPathInternal(kCFURLPOSIXPathStyle, pszPath, strURL);
  282. }
  283. OSStatus POSIXPathFromURL(const char *pszURL, CHXString& fullPathName)
  284. {
  285. return PathFromURLInternal(kCFURLPOSIXPathStyle, pszURL, fullPathName);
  286. }
  287. OSStatus URLFromHFSPath(const char *pszPath, CHXString& strURL)
  288. {
  289. OSStatus err;
  290. CHXString strPath;
  291. err = FullFromPartialHFSPath(pszPath, strPath);
  292. return URLFromPathInternal(kCFURLHFSPathStyle, pszPath, strURL);
  293. }
  294. OSStatus HFSPathFromURL(const char *pszURL, CHXString& fullPathName)
  295. {
  296. return PathFromURLInternal(kCFURLHFSPathStyle, pszURL, fullPathName);
  297. }
  298. OSErr FullFromPartialHFSPath(const char *pszPartialOrFullPath, CHXString& fullPathName)
  299. {
  300. // icky; hopefully no one will ever pass in a file name or partial path
  301. //
  302. // If there's no colon in the HFS path, or it begins with a colon,
  303. // we assume it's a local file name or partial path and use the
  304. // current directory to make a full path
  305. CHXString strTemp;
  306. OSErr err;
  307. err = noErr;
  308. strTemp = pszPartialOrFullPath;
  309. INT32 colonOffset = strTemp.Find(':');
  310. if (colonOffset == -1 || colonOffset == 0)
  311. {
  312. FSVolumeRefNum vRefNum;
  313. long dirID;
  314. err = HGetVol(nil, &vRefNum, &dirID);
  315. if (err == noErr)
  316. {
  317. err = PathNameFromDirID(dirID, vRefNum, strTemp);
  318. if (err == noErr)
  319. {
  320. if (colonOffset == 0)
  321. {
  322. // concatenate a partial path starting with :
  323. // (skip the initial colon, though)
  324. strTemp += &pszPartialOrFullPath[1];
  325. }
  326. else
  327. {
  328. // concatenate just a file name
  329. strTemp += pszPartialOrFullPath;
  330. }
  331. }
  332. }
  333. }
  334. fullPathName = strTemp;
  335. return err;
  336. }
  337. OSErr FullFromPartialPOSIXPath(const char *pszPartialOrFullPath, CHXString& fullPathName)
  338. {
  339. // icky; hopefully no one will ever pass in a file name or partial path
  340. //
  341. // If the path does not start with a slash,
  342. // we assume it's a local file name or partial path and use the
  343. // current directory to make a full path
  344. CHXString strTemp;
  345. OSErr err;
  346. err = noErr;
  347. #if defined(_MAC_MACHO)
  348. if (pszPartialOrFullPath[0] != '/')
  349. {
  350. char buff[MAXPATHLEN];
  351. getcwd(buff, MAXPATHLEN);
  352. strTemp = buff;
  353. strTemp += (strTemp.Right(1) == "/" ? "" : "/");
  354. strTemp += pszPartialOrFullPath;
  355. }
  356. else
  357. {
  358. strTemp = pszPartialOrFullPath;
  359. }
  360. #else
  361. strTemp = pszPartialOrFullPath;
  362. #endif
  363. fullPathName = strTemp;
  364. return err;
  365. }
  366. #endif // defined _CARBON
  367. #pragma mark -
  368. #pragma mark [Pre-Carbon routines]
  369. #pragma mark -
  370. OSErr PathNameFromDirID(long dirID, short vRefNum, CHXString &fullPathName)
  371. {
  372. #if defined(_MAC_UNIX) || defined(_CARBON)
  373. FSRef fsref;
  374. OSErr err;
  375. // get the FSRef for this directory
  376. err = FSMakeFSRef(vRefNum, dirID, NULL, &fsref); // MoreFilesX passes null for the name, so we can, too
  377. if (err == noErr)
  378. {
  379. // get the path name from the FSRef
  380. err = HFSPathFromFSRef(&fsref, fullPathName);
  381. }
  382. return err;
  383. #else // !defined _CARBON
  384. DirInfo block;
  385. Str63 directoryName;
  386. OSErr err = noErr;
  387. fullPathName.Empty();
  388. block.ioDrParID = dirID;
  389. block.ioNamePtr = directoryName;
  390. do {
  391. block.ioVRefNum = vRefNum;
  392. block.ioFDirIndex = -1;
  393. block.ioDrDirID = block.ioDrParID;
  394. err = PBGetCatInfoSync ((CInfoPBPtr) &block);
  395. if (noErr != err) return (err);
  396. directoryName[++directoryName[0]] = ':'; // append a colon
  397. if (noErr != err) return (err);
  398. fullPathName.InsertFromStr255(directoryName);
  399. } while (block.ioDrDirID != fsRtDirID);
  400. return (err);
  401. #endif // !defined _CARBON
  402. }
  403. /*
  404. PathNameFromWD
  405. */
  406. OSErr PathNameFromWD(long vRefNum, CHXString &pathName)
  407. {
  408. // Working Directories are obsolete under System 7 and later
  409. //
  410. // We shouldn't be calling this routine
  411. HX_ASSERT(FALSE);
  412. return paramErr;
  413. }
  414. /*
  415. PathNameFromFSSpec
  416. */
  417. OSErr PathNameFromFSSpec (const FSSpec* fsSpec, CHXString &fullPathName)
  418. {
  419. OSErr err;
  420. short leafNameLength;
  421. if (fsSpec->parID == fsRtParID)
  422. {
  423. // parID of 1 means the name is a volume name
  424. //
  425. // just add a colon to the end to make the path (like "Hard Disk:")
  426. fullPathName.SetFromStr255(fsSpec->name);
  427. if (fullPathName.GetAt(fullPathName.GetLength() - 1) != ':')
  428. {
  429. fullPathName += ":";
  430. }
  431. return noErr;
  432. }
  433. // generate the path up to the parent directory
  434. err = PathNameFromDirID (fsSpec->parID, fsSpec->vRefNum, fullPathName);
  435. if (err) return err;
  436. // add the leaf item's name
  437. leafNameLength = fsSpec->name[0];
  438. if (leafNameLength)
  439. {
  440. fullPathName.AppendFromStr255(fsSpec->name);
  441. // if the leaf item doesn't end in a colon, it might
  442. // or might not be a directory.  Let's check, and add a colon if
  443. // necessary
  444. if (fsSpec->name[leafNameLength] != ':')
  445. {
  446. CInfoPBRec catInfo;
  447. Str63 name;
  448. // copy the name to avoid changing the input parameters
  449. BlockMoveData(fsSpec->name, name, 1 + leafNameLength);
  450. catInfo.hFileInfo.ioVRefNum = fsSpec->vRefNum;
  451. catInfo.hFileInfo.ioDirID = fsSpec->parID;
  452. catInfo.hFileInfo.ioNamePtr = name;
  453. catInfo.hFileInfo.ioFDirIndex = 0; // use name and parID
  454. // we might get an error from PBGetCatInfo if the
  455. // leaf item doesn't actually exist
  456. err = PBGetCatInfoSync(&catInfo);
  457. if (err == noErr
  458. && (catInfo.hFileInfo.ioFlAttrib & ioDirMask) != 0)
  459. {
  460. // the leaf item is a directory
  461. fullPathName += ":";
  462. }
  463. }
  464. }
  465. return noErr;
  466. // FSSpecFromPathName converts a full pathname (in a null-terminated
  467. // string) to a Mac file spec.
  468. // 
  469. // The fields of spec are set to zero if the conversion fails.
  470. // This routine returns fnfErr if the conversion succeeded but
  471. // the file doesn't (yet) exist.
  472. OSErr FSSpecFromPathName(const char *path, FSSpecPtr spec) 
  473. {
  474. // revised to remove 255 character limit length path names  
  475. UInt32 len;
  476. OSErr err;
  477. FSSpec fileSpec;
  478. fileSpec.vRefNum = 0;
  479. fileSpec.parID = 0;
  480. fileSpec.name[0] = 0;
  481. len = strlen(path);
  482. if (len == 0)
  483. {
  484. // empty path... leave the fileSpec invalid
  485. err = nsvErr;
  486. }
  487. else if (len <= 255)
  488. {
  489. // path is under 256 characters, so let FSMakeFSSpec make the path for us
  490. //
  491. // Warning: passing zeros as vRefNum and dirID and a *partial* pathname
  492. // is interpreted as being relative to the poorly-defined "current" directory.
  493. // This conversion should really only be used for full paths, starting
  494. // from the drive name.
  495. Str255 name;
  496. name[0] = len;
  497. BlockMoveData(path, &name[1], len);
  498. err = FSMakeFSSpec(0, 0, name, &fileSpec);
  499. }
  500. else {
  501. Boolean wasChanged;
  502. Str32 nullString;
  503. AliasHandle alias;
  504. // longer paths, let the alias manager make the file spec for us
  505. //
  506. // The alias manager expects a full pathname, so this won't
  507. // work on partial paths longer than 255 characters.
  508. HX_ASSERT(path[0] != ':'); // be sure it's not a partial path
  509. nullString[0] = 0; // null string to indicate no zone or server name 
  510. err  = NewAliasMinimalFromFullPath(len, path, nullString, nullString, &alias);
  511. if (err == noErr)
  512. {
  513. // Let the Alias Manager resolve the alias.
  514. err = ResolveAlias(NULL, alias, &fileSpec, &wasChanged);
  515. // ResolveAlias returns fnfErr if the target doesn't exist but
  516. // the fileSpec is valid, just like FSMakeFSSpec does
  517. DisposeHandle((Handle) alias); // we don't really need the alias 
  518. }
  519. }
  520. *spec = fileSpec;
  521. return err;
  522. }
  523. #ifdef __cplusplus
  524. }
  525. #endif