PageRenderTime 34ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 1ms

/ExtLibs/wxWidgets/src/common/filename.cpp

https://bitbucket.org/cafu/cafu
C++ | 3028 lines | 2121 code | 467 blank | 440 comment | 409 complexity | 96cbc28bd26a1f471022642ecc02e7de MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0, BSD-3-Clause, LGPL-3.0, LGPL-2.1, AGPL-3.0
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: src/common/filename.cpp
  3. // Purpose: wxFileName - encapsulates a file path
  4. // Author: Robert Roebling, Vadim Zeitlin
  5. // Modified by:
  6. // Created: 28.12.2000
  7. // Copyright: (c) 2000 Robert Roebling
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. /*
  11. Here are brief descriptions of the filename formats supported by this class:
  12. wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file
  13. names have the form:
  14. /dir1/dir2/.../dirN/filename, "." and ".." stand for the
  15. current and parent directory respectively, "~" is parsed as the
  16. user HOME and "~username" as the HOME of that user
  17. wxPATH_DOS: DOS/Windows format, absolute file names have the form:
  18. drive:\dir1\dir2\...\dirN\filename.ext where drive is a single
  19. letter. "." and ".." as for Unix but no "~".
  20. There are also UNC names of the form \\share\fullpath and
  21. MSW unique volume names of the form \\?\Volume{GUID}\fullpath.
  22. The latter provide a uniform way to access a volume regardless of
  23. its current mount point, i.e. you can change a volume's mount
  24. point from D: to E:, or even remove it, and still be able to
  25. access it through its unique volume name. More on the subject can
  26. be found in MSDN's article "Naming a Volume" that is currently at
  27. http://msdn.microsoft.com/en-us/library/aa365248(VS.85).aspx.
  28. wxPATH_MAC: Mac OS 8/9 only, not used any longer, absolute file
  29. names have the form
  30. volume:dir1:...:dirN:filename
  31. and the relative file names are either
  32. :dir1:...:dirN:filename
  33. or just
  34. filename
  35. (although :filename works as well).
  36. Since the volume is just part of the file path, it is not
  37. treated like a separate entity as it is done under DOS and
  38. VMS, it is just treated as another dir.
  39. wxPATH_VMS: VMS native format, absolute file names have the form
  40. <device>:[dir1.dir2.dir3]file.txt
  41. or
  42. <device>:[000000.dir1.dir2.dir3]file.txt
  43. the <device> is the physical device (i.e. disk). 000000 is the
  44. root directory on the device which can be omitted.
  45. Note that VMS uses different separators unlike Unix:
  46. : always after the device. If the path does not contain : than
  47. the default (the device of the current directory) is assumed.
  48. [ start of directory specification
  49. . separator between directory and subdirectory
  50. ] between directory and file
  51. */
  52. // ============================================================================
  53. // declarations
  54. // ============================================================================
  55. // ----------------------------------------------------------------------------
  56. // headers
  57. // ----------------------------------------------------------------------------
  58. // For compilers that support precompilation, includes "wx.h".
  59. #include "wx/wxprec.h"
  60. #ifdef __BORLANDC__
  61. #pragma hdrstop
  62. #endif
  63. #ifndef WX_PRECOMP
  64. #ifdef __WINDOWS__
  65. #include "wx/msw/wrapwin.h" // For GetShort/LongPathName
  66. #endif
  67. #include "wx/dynarray.h"
  68. #include "wx/intl.h"
  69. #include "wx/log.h"
  70. #include "wx/utils.h"
  71. #include "wx/crt.h"
  72. #endif
  73. #include "wx/filename.h"
  74. #include "wx/private/filename.h"
  75. #include "wx/tokenzr.h"
  76. #include "wx/config.h" // for wxExpandEnvVars
  77. #include "wx/dynlib.h"
  78. #include "wx/dir.h"
  79. #include "wx/longlong.h"
  80. #if defined(__WIN32__) && defined(__MINGW32__)
  81. #include "wx/msw/gccpriv.h"
  82. #endif
  83. #ifdef __WINDOWS__
  84. #include "wx/msw/private.h"
  85. #include <shlobj.h> // for CLSID_ShellLink
  86. #include "wx/msw/missing.h"
  87. #endif
  88. #if defined(__WXMAC__)
  89. #include "wx/osx/private.h" // includes mac headers
  90. #endif
  91. // utime() is POSIX so should normally be available on all Unices
  92. #ifdef __UNIX_LIKE__
  93. #include <sys/types.h>
  94. #include <utime.h>
  95. #include <sys/stat.h>
  96. #include <unistd.h>
  97. #endif
  98. #ifdef __DJGPP__
  99. #include <unistd.h>
  100. #endif
  101. #ifdef __WATCOMC__
  102. #include <io.h>
  103. #include <sys/utime.h>
  104. #include <sys/stat.h>
  105. #endif
  106. #ifdef __VISAGECPP__
  107. #ifndef MAX_PATH
  108. #define MAX_PATH 256
  109. #endif
  110. #endif
  111. #ifdef __EMX__
  112. #include <os2.h>
  113. #define MAX_PATH _MAX_PATH
  114. #endif
  115. #ifndef S_ISREG
  116. #define S_ISREG(mode) ((mode) & S_IFREG)
  117. #endif
  118. #ifndef S_ISDIR
  119. #define S_ISDIR(mode) ((mode) & S_IFDIR)
  120. #endif
  121. #if wxUSE_LONGLONG
  122. extern const wxULongLong wxInvalidSize = (unsigned)-1;
  123. #endif // wxUSE_LONGLONG
  124. namespace
  125. {
  126. // ----------------------------------------------------------------------------
  127. // private classes
  128. // ----------------------------------------------------------------------------
  129. // small helper class which opens and closes the file - we use it just to get
  130. // a file handle for the given file name to pass it to some Win32 API function
  131. #if defined(__WIN32__) && !defined(__WXMICROWIN__)
  132. class wxFileHandle
  133. {
  134. public:
  135. enum OpenMode
  136. {
  137. ReadAttr,
  138. WriteAttr
  139. };
  140. wxFileHandle(const wxString& filename, OpenMode mode, int flags = 0)
  141. {
  142. // be careful and use FILE_{READ,WRITE}_ATTRIBUTES here instead of the
  143. // usual GENERIC_{READ,WRITE} as we don't want the file access time to
  144. // be changed when we open it because this class is used for setting
  145. // access time (see #10567)
  146. m_hFile = ::CreateFile
  147. (
  148. filename.t_str(), // name
  149. mode == ReadAttr ? FILE_READ_ATTRIBUTES // access mask
  150. : FILE_WRITE_ATTRIBUTES,
  151. FILE_SHARE_READ | // sharing mode
  152. FILE_SHARE_WRITE, // (allow everything)
  153. NULL, // no secutity attr
  154. OPEN_EXISTING, // creation disposition
  155. flags, // flags
  156. NULL // no template file
  157. );
  158. if ( m_hFile == INVALID_HANDLE_VALUE )
  159. {
  160. if ( mode == ReadAttr )
  161. {
  162. wxLogSysError(_("Failed to open '%s' for reading"),
  163. filename.c_str());
  164. }
  165. else
  166. {
  167. wxLogSysError(_("Failed to open '%s' for writing"),
  168. filename.c_str());
  169. }
  170. }
  171. }
  172. ~wxFileHandle()
  173. {
  174. if ( m_hFile != INVALID_HANDLE_VALUE )
  175. {
  176. if ( !::CloseHandle(m_hFile) )
  177. {
  178. wxLogSysError(_("Failed to close file handle"));
  179. }
  180. }
  181. }
  182. // return true only if the file could be opened successfully
  183. bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; }
  184. // get the handle
  185. operator HANDLE() const { return m_hFile; }
  186. private:
  187. HANDLE m_hFile;
  188. };
  189. #endif // __WIN32__
  190. // ----------------------------------------------------------------------------
  191. // private functions
  192. // ----------------------------------------------------------------------------
  193. #if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)
  194. // Convert between wxDateTime and FILETIME which is a 64-bit value representing
  195. // the number of 100-nanosecond intervals since January 1, 1601 UTC.
  196. //
  197. // This is the offset between FILETIME epoch and the Unix/wxDateTime Epoch.
  198. static wxInt64 EPOCH_OFFSET_IN_MSEC = wxLL(11644473600000);
  199. static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
  200. {
  201. wxLongLong t(ft.dwHighDateTime, ft.dwLowDateTime);
  202. t /= 10000; // Convert hundreds of nanoseconds to milliseconds.
  203. t -= EPOCH_OFFSET_IN_MSEC;
  204. *dt = wxDateTime(t);
  205. }
  206. static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
  207. {
  208. // Undo the conversions above.
  209. wxLongLong t(dt.GetValue());
  210. t += EPOCH_OFFSET_IN_MSEC;
  211. t *= 10000;
  212. ft->dwHighDateTime = t.GetHi();
  213. ft->dwLowDateTime = t.GetLo();
  214. }
  215. #endif // wxUSE_DATETIME && __WIN32__
  216. // return a string with the volume par
  217. static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format)
  218. {
  219. wxString path;
  220. if ( !volume.empty() )
  221. {
  222. format = wxFileName::GetFormat(format);
  223. // Special Windows UNC paths hack, part 2: undo what we did in
  224. // SplitPath() and make an UNC path if we have a drive which is not a
  225. // single letter (hopefully the network shares can't be one letter only
  226. // although I didn't find any authoritative docs on this)
  227. if ( format == wxPATH_DOS && volume.length() > 1 )
  228. {
  229. // We also have to check for Windows unique volume names here and
  230. // return it with '\\?\' prepended to it
  231. if ( wxFileName::IsMSWUniqueVolumeNamePath("\\\\?\\" + volume + "\\",
  232. format) )
  233. {
  234. path << "\\\\?\\" << volume;
  235. }
  236. else
  237. {
  238. // it must be a UNC path
  239. path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume;
  240. }
  241. }
  242. else if ( format == wxPATH_DOS || format == wxPATH_VMS )
  243. {
  244. path << volume << wxFileName::GetVolumeSeparator(format);
  245. }
  246. // else ignore
  247. }
  248. return path;
  249. }
  250. // return true if the character is a DOS path separator i.e. either a slash or
  251. // a backslash
  252. inline bool IsDOSPathSep(wxUniChar ch)
  253. {
  254. return ch == wxFILE_SEP_PATH_DOS || ch == wxFILE_SEP_PATH_UNIX;
  255. }
  256. // return true if the format used is the DOS/Windows one and the string looks
  257. // like a UNC path
  258. static bool IsUNCPath(const wxString& path, wxPathFormat format)
  259. {
  260. return format == wxPATH_DOS &&
  261. path.length() >= 4 && // "\\a" can't be a UNC path
  262. IsDOSPathSep(path[0u]) &&
  263. IsDOSPathSep(path[1u]) &&
  264. !IsDOSPathSep(path[2u]);
  265. }
  266. // Under Unix-ish systems (basically everything except Windows but we can't
  267. // just test for non-__WIN32__ because Cygwin defines it, yet we want to use
  268. // lstat() under it, so test for all the rest explicitly) we may work either
  269. // with the file itself or its target if it's a symbolic link and we should
  270. // dereference it, as determined by wxFileName::ShouldFollowLink() and the
  271. // absence of the wxFILE_EXISTS_NO_FOLLOW flag. StatAny() can be used to stat
  272. // the appropriate file with an extra twist that it also works when there is no
  273. // wxFileName object at all, as is the case in static methods.
  274. #if defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__))
  275. #define wxHAVE_LSTAT
  276. #endif
  277. #ifdef wxHAVE_LSTAT
  278. // Private implementation, don't call directly, use one of the overloads below.
  279. bool DoStatAny(wxStructStat& st, wxString path, bool dereference)
  280. {
  281. // We need to remove any trailing slashes from the path because they could
  282. // interfere with the symlink following decision: even if we use lstat(),
  283. // it would still follow the symlink if we pass it a path with a slash at
  284. // the end because the symlink resolution would happen while following the
  285. // path and not for the last path element itself.
  286. while ( wxEndsWithPathSeparator(path) )
  287. {
  288. const size_t posLast = path.length() - 1;
  289. if ( !posLast )
  290. {
  291. // Don't turn "/" into empty string.
  292. break;
  293. }
  294. path.erase(posLast);
  295. }
  296. int ret = dereference ? wxStat(path, &st) : wxLstat(path, &st);
  297. return ret == 0;
  298. }
  299. // Overloads to use for a case when we don't have wxFileName object and when we
  300. // do have one.
  301. inline
  302. bool StatAny(wxStructStat& st, const wxString& path, int flags)
  303. {
  304. return DoStatAny(st, path, !(flags & wxFILE_EXISTS_NO_FOLLOW));
  305. }
  306. inline
  307. bool StatAny(wxStructStat& st, const wxFileName& fn)
  308. {
  309. return DoStatAny(st, fn.GetFullPath(), fn.ShouldFollowLink());
  310. }
  311. #endif // wxHAVE_LSTAT
  312. // ----------------------------------------------------------------------------
  313. // private constants
  314. // ----------------------------------------------------------------------------
  315. // length of \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ string
  316. static const size_t wxMSWUniqueVolumePrefixLength = 49;
  317. } // anonymous namespace
  318. // ============================================================================
  319. // implementation
  320. // ============================================================================
  321. // ----------------------------------------------------------------------------
  322. // wxFileName construction
  323. // ----------------------------------------------------------------------------
  324. void wxFileName::Assign( const wxFileName &filepath )
  325. {
  326. m_volume = filepath.GetVolume();
  327. m_dirs = filepath.GetDirs();
  328. m_name = filepath.GetName();
  329. m_ext = filepath.GetExt();
  330. m_relative = filepath.m_relative;
  331. m_hasExt = filepath.m_hasExt;
  332. m_dontFollowLinks = filepath.m_dontFollowLinks;
  333. }
  334. void wxFileName::Assign(const wxString& volume,
  335. const wxString& path,
  336. const wxString& name,
  337. const wxString& ext,
  338. bool hasExt,
  339. wxPathFormat format)
  340. {
  341. // we should ignore paths which look like UNC shares because we already
  342. // have the volume here and the UNC notation (\\server\path) is only valid
  343. // for paths which don't start with a volume, so prevent SetPath() from
  344. // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path
  345. //
  346. // note also that this is a rather ugly way to do what we want (passing
  347. // some kind of flag telling to ignore UNC paths to SetPath() would be
  348. // better) but this is the safest thing to do to avoid breaking backwards
  349. // compatibility in 2.8
  350. if ( IsUNCPath(path, format) )
  351. {
  352. // remove one of the 2 leading backslashes to ensure that it's not
  353. // recognized as an UNC path by SetPath()
  354. wxString pathNonUNC(path, 1, wxString::npos);
  355. SetPath(pathNonUNC, format);
  356. }
  357. else // no UNC complications
  358. {
  359. SetPath(path, format);
  360. }
  361. m_volume = volume;
  362. m_ext = ext;
  363. m_name = name;
  364. m_hasExt = hasExt;
  365. }
  366. void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format )
  367. {
  368. m_dirs.Clear();
  369. if ( pathOrig.empty() )
  370. {
  371. // no path at all
  372. m_relative = true;
  373. return;
  374. }
  375. format = GetFormat( format );
  376. // 0) deal with possible volume part first
  377. wxString volume,
  378. path;
  379. SplitVolume(pathOrig, &volume, &path, format);
  380. if ( !volume.empty() )
  381. {
  382. m_relative = false;
  383. SetVolume(volume);
  384. }
  385. // 1) Determine if the path is relative or absolute.
  386. if ( path.empty() )
  387. {
  388. // we had only the volume
  389. return;
  390. }
  391. wxChar leadingChar = path[0u];
  392. switch (format)
  393. {
  394. case wxPATH_MAC:
  395. m_relative = leadingChar == wxT(':');
  396. // We then remove a leading ":". The reason is in our
  397. // storage form for relative paths:
  398. // ":dir:file.txt" actually means "./dir/file.txt" in
  399. // DOS notation and should get stored as
  400. // (relative) (dir) (file.txt)
  401. // "::dir:file.txt" actually means "../dir/file.txt"
  402. // stored as (relative) (..) (dir) (file.txt)
  403. // This is important only for the Mac as an empty dir
  404. // actually means <UP>, whereas under DOS, double
  405. // slashes can be ignored: "\\\\" is the same as "\\".
  406. if (m_relative)
  407. path.erase( 0, 1 );
  408. break;
  409. case wxPATH_VMS:
  410. // TODO: what is the relative path format here?
  411. m_relative = false;
  412. break;
  413. default:
  414. wxFAIL_MSG( wxT("Unknown path format") );
  415. // !! Fall through !!
  416. case wxPATH_UNIX:
  417. m_relative = leadingChar != wxT('/');
  418. break;
  419. case wxPATH_DOS:
  420. m_relative = !IsPathSeparator(leadingChar, format);
  421. break;
  422. }
  423. // 2) Break up the path into its members. If the original path
  424. // was just "/" or "\\", m_dirs will be empty. We know from
  425. // the m_relative field, if this means "nothing" or "root dir".
  426. wxStringTokenizer tn( path, GetPathSeparators(format) );
  427. while ( tn.HasMoreTokens() )
  428. {
  429. wxString token = tn.GetNextToken();
  430. // Remove empty token under DOS and Unix, interpret them
  431. // as .. under Mac.
  432. if (token.empty())
  433. {
  434. if (format == wxPATH_MAC)
  435. m_dirs.Add( wxT("..") );
  436. // else ignore
  437. }
  438. else
  439. {
  440. m_dirs.Add( token );
  441. }
  442. }
  443. }
  444. void wxFileName::Assign(const wxString& fullpath,
  445. wxPathFormat format)
  446. {
  447. wxString volume, path, name, ext;
  448. bool hasExt;
  449. SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format);
  450. Assign(volume, path, name, ext, hasExt, format);
  451. }
  452. void wxFileName::Assign(const wxString& fullpathOrig,
  453. const wxString& fullname,
  454. wxPathFormat format)
  455. {
  456. // always recognize fullpath as directory, even if it doesn't end with a
  457. // slash
  458. wxString fullpath = fullpathOrig;
  459. if ( !fullpath.empty() && !wxEndsWithPathSeparator(fullpath) )
  460. {
  461. fullpath += GetPathSeparator(format);
  462. }
  463. wxString volume, path, name, ext;
  464. bool hasExt;
  465. // do some consistency checks: the name should be really just the filename
  466. // and the path should be really just a path
  467. wxString volDummy, pathDummy, nameDummy, extDummy;
  468. SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format);
  469. wxASSERT_MSG( volDummy.empty() && pathDummy.empty(),
  470. wxT("the file name shouldn't contain the path") );
  471. SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format);
  472. #ifndef __VMS
  473. // This test makes no sense on an OpenVMS system.
  474. wxASSERT_MSG( nameDummy.empty() && extDummy.empty(),
  475. wxT("the path shouldn't contain file name nor extension") );
  476. #endif
  477. Assign(volume, path, name, ext, hasExt, format);
  478. }
  479. void wxFileName::Assign(const wxString& pathOrig,
  480. const wxString& name,
  481. const wxString& ext,
  482. wxPathFormat format)
  483. {
  484. wxString volume,
  485. path;
  486. SplitVolume(pathOrig, &volume, &path, format);
  487. Assign(volume, path, name, ext, format);
  488. }
  489. void wxFileName::AssignDir(const wxString& dir, wxPathFormat format)
  490. {
  491. Assign(dir, wxEmptyString, format);
  492. }
  493. void wxFileName::Clear()
  494. {
  495. m_dirs.clear();
  496. m_volume.clear();
  497. m_name.clear();
  498. m_ext.clear();
  499. // we don't have any absolute path for now
  500. m_relative = true;
  501. // nor any extension
  502. m_hasExt = false;
  503. // follow symlinks by default
  504. m_dontFollowLinks = false;
  505. }
  506. /* static */
  507. wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format)
  508. {
  509. return wxFileName(file, format);
  510. }
  511. /* static */
  512. wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format)
  513. {
  514. wxFileName fn;
  515. fn.AssignDir(dir, format);
  516. return fn;
  517. }
  518. // ----------------------------------------------------------------------------
  519. // existence tests
  520. // ----------------------------------------------------------------------------
  521. namespace
  522. {
  523. #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
  524. void RemoveTrailingSeparatorsFromPath(wxString& strPath)
  525. {
  526. // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists,
  527. // so remove all trailing backslashes from the path - but don't do this for
  528. // the paths "d:\" (which are different from "d:"), for just "\" or for
  529. // windows unique volume names ("\\?\Volume{GUID}\")
  530. while ( wxEndsWithPathSeparator( strPath ) )
  531. {
  532. size_t len = strPath.length();
  533. if ( len == 1 || (len == 3 && strPath[len - 2] == wxT(':')) ||
  534. (len == wxMSWUniqueVolumePrefixLength &&
  535. wxFileName::IsMSWUniqueVolumeNamePath(strPath)))
  536. {
  537. break;
  538. }
  539. strPath.Truncate(len - 1);
  540. }
  541. }
  542. #endif // __WINDOWS__ || __OS2__
  543. bool
  544. wxFileSystemObjectExists(const wxString& path, int flags)
  545. {
  546. // Should the existence of file/directory with this name be accepted, i.e.
  547. // result in the true return value from this function?
  548. const bool acceptFile = (flags & wxFILE_EXISTS_REGULAR) != 0;
  549. const bool acceptDir = (flags & wxFILE_EXISTS_DIR) != 0;
  550. wxString strPath(path);
  551. #if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
  552. if ( acceptDir )
  553. {
  554. // Ensure that the path doesn't have any trailing separators when
  555. // checking for directories.
  556. RemoveTrailingSeparatorsFromPath(strPath);
  557. }
  558. // we must use GetFileAttributes() instead of the ANSI C functions because
  559. // it can cope with network (UNC) paths unlike them
  560. DWORD ret = ::GetFileAttributes(strPath.t_str());
  561. if ( ret == INVALID_FILE_ATTRIBUTES )
  562. return false;
  563. if ( ret & FILE_ATTRIBUTE_DIRECTORY )
  564. return acceptDir;
  565. // Anything else must be a file (perhaps we should check for
  566. // FILE_ATTRIBUTE_REPARSE_POINT?)
  567. return acceptFile;
  568. #elif defined(__OS2__)
  569. if ( acceptDir )
  570. {
  571. // OS/2 can't handle "d:", it wants either "d:\" or "d:."
  572. if (strPath.length() == 2 && strPath[1u] == wxT(':'))
  573. strPath << wxT('.');
  574. }
  575. FILESTATUS3 Info = {{0}};
  576. APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD,
  577. (void*) &Info, sizeof(FILESTATUS3));
  578. if ( rc == NO_ERROR )
  579. {
  580. if ( Info.attrFile & FILE_DIRECTORY )
  581. return acceptDir;
  582. else
  583. return acceptFile;
  584. }
  585. // We consider that the path must exist if we get a sharing violation for
  586. // it but we don't know what is it in this case.
  587. if ( rc == ERROR_SHARING_VIOLATION )
  588. return flags & wxFILE_EXISTS_ANY;
  589. // Any other error (usually ERROR_PATH_NOT_FOUND), means there is nothing
  590. // there.
  591. return false;
  592. #else // Non-MSW, non-OS/2
  593. wxStructStat st;
  594. if ( !StatAny(st, strPath, flags) )
  595. return false;
  596. if ( S_ISREG(st.st_mode) )
  597. return acceptFile;
  598. if ( S_ISDIR(st.st_mode) )
  599. return acceptDir;
  600. if ( S_ISLNK(st.st_mode) )
  601. {
  602. // Take care to not test for "!= 0" here as this would erroneously
  603. // return true if only wxFILE_EXISTS_NO_FOLLOW, which is part of
  604. // wxFILE_EXISTS_SYMLINK, is set too.
  605. return (flags & wxFILE_EXISTS_SYMLINK) == wxFILE_EXISTS_SYMLINK;
  606. }
  607. if ( S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) )
  608. return (flags & wxFILE_EXISTS_DEVICE) != 0;
  609. if ( S_ISFIFO(st.st_mode) )
  610. return (flags & wxFILE_EXISTS_FIFO) != 0;
  611. if ( S_ISSOCK(st.st_mode) )
  612. return (flags & wxFILE_EXISTS_SOCKET) != 0;
  613. return flags & wxFILE_EXISTS_ANY;
  614. #endif // Platforms
  615. }
  616. } // anonymous namespace
  617. bool wxFileName::FileExists() const
  618. {
  619. int flags = wxFILE_EXISTS_REGULAR;
  620. if ( !ShouldFollowLink() )
  621. flags |= wxFILE_EXISTS_NO_FOLLOW;
  622. return wxFileSystemObjectExists(GetFullPath(), flags);
  623. }
  624. /* static */
  625. bool wxFileName::FileExists( const wxString &filePath )
  626. {
  627. return wxFileSystemObjectExists(filePath, wxFILE_EXISTS_REGULAR);
  628. }
  629. bool wxFileName::DirExists() const
  630. {
  631. int flags = wxFILE_EXISTS_DIR;
  632. if ( !ShouldFollowLink() )
  633. flags |= wxFILE_EXISTS_NO_FOLLOW;
  634. return Exists(GetPath(), flags);
  635. }
  636. /* static */
  637. bool wxFileName::DirExists( const wxString &dirPath )
  638. {
  639. return wxFileSystemObjectExists(dirPath, wxFILE_EXISTS_DIR);
  640. }
  641. bool wxFileName::Exists(int flags) const
  642. {
  643. // Notice that wxFILE_EXISTS_NO_FOLLOW may be specified in the flags even
  644. // if our DontFollowLink() hadn't been called and we do honour it then. But
  645. // if the user took the care of calling DontFollowLink(), it is always
  646. // taken into account.
  647. if ( !ShouldFollowLink() )
  648. flags |= wxFILE_EXISTS_NO_FOLLOW;
  649. return wxFileSystemObjectExists(GetFullPath(), flags);
  650. }
  651. /* static */
  652. bool wxFileName::Exists(const wxString& path, int flags)
  653. {
  654. return wxFileSystemObjectExists(path, flags);
  655. }
  656. // ----------------------------------------------------------------------------
  657. // CWD and HOME stuff
  658. // ----------------------------------------------------------------------------
  659. void wxFileName::AssignCwd(const wxString& volume)
  660. {
  661. AssignDir(wxFileName::GetCwd(volume));
  662. }
  663. /* static */
  664. wxString wxFileName::GetCwd(const wxString& volume)
  665. {
  666. // if we have the volume, we must get the current directory on this drive
  667. // and to do this we have to chdir to this volume - at least under Windows,
  668. // I don't know how to get the current drive on another volume elsewhere
  669. // (TODO)
  670. wxString cwdOld;
  671. if ( !volume.empty() )
  672. {
  673. cwdOld = wxGetCwd();
  674. SetCwd(volume + GetVolumeSeparator());
  675. }
  676. wxString cwd = ::wxGetCwd();
  677. if ( !volume.empty() )
  678. {
  679. SetCwd(cwdOld);
  680. }
  681. return cwd;
  682. }
  683. bool wxFileName::SetCwd() const
  684. {
  685. return wxFileName::SetCwd( GetPath() );
  686. }
  687. bool wxFileName::SetCwd( const wxString &cwd )
  688. {
  689. return ::wxSetWorkingDirectory( cwd );
  690. }
  691. void wxFileName::AssignHomeDir()
  692. {
  693. AssignDir(wxFileName::GetHomeDir());
  694. }
  695. wxString wxFileName::GetHomeDir()
  696. {
  697. return ::wxGetHomeDir();
  698. }
  699. // ----------------------------------------------------------------------------
  700. // CreateTempFileName
  701. // ----------------------------------------------------------------------------
  702. #if wxUSE_FILE || wxUSE_FFILE
  703. #if !defined wx_fdopen && defined HAVE_FDOPEN
  704. #define wx_fdopen fdopen
  705. #endif
  706. // NB: GetTempFileName() under Windows creates the file, so using
  707. // O_EXCL there would fail
  708. #ifdef __WINDOWS__
  709. #define wxOPEN_EXCL 0
  710. #else
  711. #define wxOPEN_EXCL O_EXCL
  712. #endif
  713. #ifdef wxOpenOSFHandle
  714. #define WX_HAVE_DELETE_ON_CLOSE
  715. // On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags.
  716. //
  717. static int wxOpenWithDeleteOnClose(const wxString& filename)
  718. {
  719. DWORD access = GENERIC_READ | GENERIC_WRITE;
  720. DWORD disposition = OPEN_ALWAYS;
  721. DWORD attributes = FILE_ATTRIBUTE_TEMPORARY |
  722. FILE_FLAG_DELETE_ON_CLOSE;
  723. HANDLE h = ::CreateFile(filename.t_str(), access, 0, NULL,
  724. disposition, attributes, NULL);
  725. return wxOpenOSFHandle(h, wxO_BINARY);
  726. }
  727. #endif // wxOpenOSFHandle
  728. // Helper to open the file
  729. //
  730. static int wxTempOpen(const wxString& path, bool *deleteOnClose)
  731. {
  732. #ifdef WX_HAVE_DELETE_ON_CLOSE
  733. if (*deleteOnClose)
  734. return wxOpenWithDeleteOnClose(path);
  735. #endif
  736. *deleteOnClose = false;
  737. return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600);
  738. }
  739. #if wxUSE_FFILE
  740. // Helper to open the file and attach it to the wxFFile
  741. //
  742. static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose)
  743. {
  744. #ifndef wx_fdopen
  745. *deleteOnClose = false;
  746. return file->Open(path, wxT("w+b"));
  747. #else // wx_fdopen
  748. int fd = wxTempOpen(path, deleteOnClose);
  749. if (fd == -1)
  750. return false;
  751. file->Attach(wx_fdopen(fd, "w+b"), path);
  752. return file->IsOpened();
  753. #endif // wx_fdopen
  754. }
  755. #endif // wxUSE_FFILE
  756. #if !wxUSE_FILE
  757. #define WXFILEARGS(x, y) y
  758. #elif !wxUSE_FFILE
  759. #define WXFILEARGS(x, y) x
  760. #else
  761. #define WXFILEARGS(x, y) x, y
  762. #endif
  763. // Implementation of wxFileName::CreateTempFileName().
  764. //
  765. static wxString wxCreateTempImpl(
  766. const wxString& prefix,
  767. WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
  768. bool *deleteOnClose = NULL)
  769. {
  770. #if wxUSE_FILE && wxUSE_FFILE
  771. wxASSERT(fileTemp == NULL || ffileTemp == NULL);
  772. #endif
  773. wxString path, dir, name;
  774. bool wantDeleteOnClose = false;
  775. if (deleteOnClose)
  776. {
  777. // set the result to false initially
  778. wantDeleteOnClose = *deleteOnClose;
  779. *deleteOnClose = false;
  780. }
  781. else
  782. {
  783. // easier if it alwasys points to something
  784. deleteOnClose = &wantDeleteOnClose;
  785. }
  786. // use the directory specified by the prefix
  787. wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */);
  788. if (dir.empty())
  789. {
  790. dir = wxFileName::GetTempDir();
  791. }
  792. #if defined(__WXWINCE__)
  793. path = dir + wxT("\\") + name;
  794. int i = 1;
  795. while (wxFileName::FileExists(path))
  796. {
  797. path = dir + wxT("\\") + name ;
  798. path << i;
  799. i ++;
  800. }
  801. #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
  802. if (!::GetTempFileName(dir.t_str(), name.t_str(), 0,
  803. wxStringBuffer(path, MAX_PATH + 1)))
  804. {
  805. wxLogLastError(wxT("GetTempFileName"));
  806. path.clear();
  807. }
  808. #else // !Windows
  809. path = dir;
  810. if ( !wxEndsWithPathSeparator(dir) &&
  811. (name.empty() || !wxIsPathSeparator(name[0u])) )
  812. {
  813. path += wxFILE_SEP_PATH;
  814. }
  815. path += name;
  816. #if defined(HAVE_MKSTEMP)
  817. // scratch space for mkstemp()
  818. path += wxT("XXXXXX");
  819. // we need to copy the path to the buffer in which mkstemp() can modify it
  820. wxCharBuffer buf(path.fn_str());
  821. // cast is safe because the string length doesn't change
  822. int fdTemp = mkstemp( (char*)(const char*) buf );
  823. if ( fdTemp == -1 )
  824. {
  825. // this might be not necessary as mkstemp() on most systems should have
  826. // already done it but it doesn't hurt neither...
  827. path.clear();
  828. }
  829. else // mkstemp() succeeded
  830. {
  831. path = wxConvFile.cMB2WX( (const char*) buf );
  832. #if wxUSE_FILE
  833. // avoid leaking the fd
  834. if ( fileTemp )
  835. {
  836. fileTemp->Attach(fdTemp);
  837. }
  838. else
  839. #endif
  840. #if wxUSE_FFILE
  841. if ( ffileTemp )
  842. {
  843. #ifdef wx_fdopen
  844. ffileTemp->Attach(wx_fdopen(fdTemp, "r+b"), path);
  845. #else
  846. ffileTemp->Open(path, wxT("r+b"));
  847. close(fdTemp);
  848. #endif
  849. }
  850. else
  851. #endif
  852. {
  853. close(fdTemp);
  854. }
  855. }
  856. #else // !HAVE_MKSTEMP
  857. #ifdef HAVE_MKTEMP
  858. // same as above
  859. path += wxT("XXXXXX");
  860. wxCharBuffer buf = wxConvFile.cWX2MB( path );
  861. if ( !mktemp( (char*)(const char*) buf ) )
  862. {
  863. path.clear();
  864. }
  865. else
  866. {
  867. path = wxConvFile.cMB2WX( (const char*) buf );
  868. }
  869. #else // !HAVE_MKTEMP (includes __DOS__)
  870. // generate the unique file name ourselves
  871. #if !defined(__DOS__)
  872. path << (unsigned int)getpid();
  873. #endif
  874. wxString pathTry;
  875. static const size_t numTries = 1000;
  876. for ( size_t n = 0; n < numTries; n++ )
  877. {
  878. // 3 hex digits is enough for numTries == 1000 < 4096
  879. pathTry = path + wxString::Format(wxT("%.03x"), (unsigned int) n);
  880. if ( !wxFileName::FileExists(pathTry) )
  881. {
  882. break;
  883. }
  884. pathTry.clear();
  885. }
  886. path = pathTry;
  887. #endif // HAVE_MKTEMP/!HAVE_MKTEMP
  888. #endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
  889. #endif // Windows/!Windows
  890. if ( path.empty() )
  891. {
  892. wxLogSysError(_("Failed to create a temporary file name"));
  893. }
  894. else
  895. {
  896. bool ok = true;
  897. // open the file - of course, there is a race condition here, this is
  898. // why we always prefer using mkstemp()...
  899. #if wxUSE_FILE
  900. if ( fileTemp && !fileTemp->IsOpened() )
  901. {
  902. *deleteOnClose = wantDeleteOnClose;
  903. int fd = wxTempOpen(path, deleteOnClose);
  904. if (fd != -1)
  905. fileTemp->Attach(fd);
  906. else
  907. ok = false;
  908. }
  909. #endif
  910. #if wxUSE_FFILE
  911. if ( ffileTemp && !ffileTemp->IsOpened() )
  912. {
  913. *deleteOnClose = wantDeleteOnClose;
  914. ok = wxTempOpen(ffileTemp, path, deleteOnClose);
  915. }
  916. #endif
  917. if ( !ok )
  918. {
  919. // FIXME: If !ok here should we loop and try again with another
  920. // file name? That is the standard recourse if open(O_EXCL)
  921. // fails, though of course it should be protected against
  922. // possible infinite looping too.
  923. wxLogError(_("Failed to open temporary file."));
  924. path.clear();
  925. }
  926. }
  927. return path;
  928. }
  929. static bool wxCreateTempImpl(
  930. const wxString& prefix,
  931. WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
  932. wxString *name)
  933. {
  934. bool deleteOnClose = true;
  935. *name = wxCreateTempImpl(prefix,
  936. WXFILEARGS(fileTemp, ffileTemp),
  937. &deleteOnClose);
  938. bool ok = !name->empty();
  939. if (deleteOnClose)
  940. name->clear();
  941. #ifdef __UNIX__
  942. else if (ok && wxRemoveFile(*name))
  943. name->clear();
  944. #endif
  945. return ok;
  946. }
  947. static void wxAssignTempImpl(
  948. wxFileName *fn,
  949. const wxString& prefix,
  950. WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp))
  951. {
  952. wxString tempname;
  953. tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp));
  954. if ( tempname.empty() )
  955. {
  956. // error, failed to get temp file name
  957. fn->Clear();
  958. }
  959. else // ok
  960. {
  961. fn->Assign(tempname);
  962. }
  963. }
  964. void wxFileName::AssignTempFileName(const wxString& prefix)
  965. {
  966. wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL));
  967. }
  968. /* static */
  969. wxString wxFileName::CreateTempFileName(const wxString& prefix)
  970. {
  971. return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL));
  972. }
  973. #endif // wxUSE_FILE || wxUSE_FFILE
  974. #if wxUSE_FILE
  975. wxString wxCreateTempFileName(const wxString& prefix,
  976. wxFile *fileTemp,
  977. bool *deleteOnClose)
  978. {
  979. return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose);
  980. }
  981. bool wxCreateTempFile(const wxString& prefix,
  982. wxFile *fileTemp,
  983. wxString *name)
  984. {
  985. return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name);
  986. }
  987. void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp)
  988. {
  989. wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL));
  990. }
  991. /* static */
  992. wxString
  993. wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp)
  994. {
  995. return wxCreateTempFileName(prefix, fileTemp);
  996. }
  997. #endif // wxUSE_FILE
  998. #if wxUSE_FFILE
  999. wxString wxCreateTempFileName(const wxString& prefix,
  1000. wxFFile *fileTemp,
  1001. bool *deleteOnClose)
  1002. {
  1003. return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose);
  1004. }
  1005. bool wxCreateTempFile(const wxString& prefix,
  1006. wxFFile *fileTemp,
  1007. wxString *name)
  1008. {
  1009. return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name);
  1010. }
  1011. void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp)
  1012. {
  1013. wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp));
  1014. }
  1015. /* static */
  1016. wxString
  1017. wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp)
  1018. {
  1019. return wxCreateTempFileName(prefix, fileTemp);
  1020. }
  1021. #endif // wxUSE_FFILE
  1022. // ----------------------------------------------------------------------------
  1023. // directory operations
  1024. // ----------------------------------------------------------------------------
  1025. // helper of GetTempDir(): check if the given directory exists and return it if
  1026. // it does or an empty string otherwise
  1027. namespace
  1028. {
  1029. wxString CheckIfDirExists(const wxString& dir)
  1030. {
  1031. return wxFileName::DirExists(dir) ? dir : wxString();
  1032. }
  1033. } // anonymous namespace
  1034. wxString wxFileName::GetTempDir()
  1035. {
  1036. // first try getting it from environment: this allows overriding the values
  1037. // used by default if the user wants to create temporary files in another
  1038. // directory
  1039. wxString dir = CheckIfDirExists(wxGetenv("TMPDIR"));
  1040. if ( dir.empty() )
  1041. {
  1042. dir = CheckIfDirExists(wxGetenv("TMP"));
  1043. if ( dir.empty() )
  1044. dir = CheckIfDirExists(wxGetenv("TEMP"));
  1045. }
  1046. // if no environment variables are set, use the system default
  1047. if ( dir.empty() )
  1048. {
  1049. #if defined(__WXWINCE__)
  1050. dir = CheckIfDirExists(wxT("\\temp"));
  1051. #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
  1052. if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) )
  1053. {
  1054. wxLogLastError(wxT("GetTempPath"));
  1055. }
  1056. #elif defined(__WXMAC__) && wxOSX_USE_CARBON
  1057. dir = wxMacFindFolderNoSeparator(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder);
  1058. #endif // systems with native way
  1059. }
  1060. else // we got directory from an environment variable
  1061. {
  1062. // remove any trailing path separators, we don't want to ever return
  1063. // them from this function for consistency
  1064. const size_t lastNonSep = dir.find_last_not_of(GetPathSeparators());
  1065. if ( lastNonSep == wxString::npos )
  1066. {
  1067. // the string consists entirely of separators, leave only one
  1068. dir = GetPathSeparator();
  1069. }
  1070. else
  1071. {
  1072. dir.erase(lastNonSep + 1);
  1073. }
  1074. }
  1075. // fall back to hard coded value
  1076. if ( dir.empty() )
  1077. {
  1078. #ifdef __UNIX_LIKE__
  1079. dir = CheckIfDirExists("/tmp");
  1080. if ( dir.empty() )
  1081. #endif // __UNIX_LIKE__
  1082. dir = ".";
  1083. }
  1084. return dir;
  1085. }
  1086. bool wxFileName::Mkdir( int perm, int flags ) const
  1087. {
  1088. return wxFileName::Mkdir(GetPath(), perm, flags);
  1089. }
  1090. bool wxFileName::Mkdir( const wxString& dir, int perm, int flags )
  1091. {
  1092. if ( flags & wxPATH_MKDIR_FULL )
  1093. {
  1094. // split the path in components
  1095. wxFileName filename;
  1096. filename.AssignDir(dir);
  1097. wxString currPath;
  1098. if ( filename.HasVolume())
  1099. {
  1100. currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE);
  1101. }
  1102. wxArrayString dirs = filename.GetDirs();
  1103. size_t count = dirs.GetCount();
  1104. for ( size_t i = 0; i < count; i++ )
  1105. {
  1106. if ( i > 0 || filename.IsAbsolute() )
  1107. currPath += wxFILE_SEP_PATH;
  1108. currPath += dirs[i];
  1109. if (!DirExists(currPath))
  1110. {
  1111. if (!wxMkdir(currPath, perm))
  1112. {
  1113. // no need to try creating further directories
  1114. return false;
  1115. }
  1116. }
  1117. }
  1118. return true;
  1119. }
  1120. return ::wxMkdir( dir, perm );
  1121. }
  1122. bool wxFileName::Rmdir(int flags) const
  1123. {
  1124. return wxFileName::Rmdir( GetPath(), flags );
  1125. }
  1126. bool wxFileName::Rmdir(const wxString& dir, int flags)
  1127. {
  1128. #ifdef __WINDOWS__
  1129. if ( flags & wxPATH_RMDIR_RECURSIVE )
  1130. {
  1131. // SHFileOperation needs double null termination string
  1132. // but without separator at the end of the path
  1133. wxString path(dir);
  1134. if ( path.Last() == wxFILE_SEP_PATH )
  1135. path.RemoveLast();
  1136. path += wxT('\0');
  1137. SHFILEOPSTRUCT fileop;
  1138. wxZeroMemory(fileop);
  1139. fileop.wFunc = FO_DELETE;
  1140. fileop.pFrom = path.t_str();
  1141. fileop.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
  1142. #ifndef __WXWINCE__
  1143. // FOF_NOERRORUI is not defined in WinCE
  1144. fileop.fFlags |= FOF_NOERRORUI;
  1145. #endif
  1146. int ret = SHFileOperation(&fileop);
  1147. if ( ret != 0 )
  1148. {
  1149. // SHFileOperation may return non-Win32 error codes, so the error
  1150. // message can be incorrect
  1151. wxLogApiError(wxT("SHFileOperation"), ret);
  1152. return false;
  1153. }
  1154. return true;
  1155. }
  1156. else if ( flags & wxPATH_RMDIR_FULL )
  1157. #else // !__WINDOWS__
  1158. if ( flags != 0 ) // wxPATH_RMDIR_FULL or wxPATH_RMDIR_RECURSIVE
  1159. #endif // !__WINDOWS__
  1160. {
  1161. #ifndef __WINDOWS__
  1162. if ( flags & wxPATH_RMDIR_RECURSIVE )
  1163. {
  1164. // When deleting the tree recursively, we are supposed to delete
  1165. // this directory itself even when it is a symlink -- but without
  1166. // following it. Do it here as wxRmdir() would simply follow if
  1167. // called for a symlink.
  1168. if ( wxFileName::Exists(dir, wxFILE_EXISTS_SYMLINK) )
  1169. {
  1170. return wxRemoveFile(dir);
  1171. }
  1172. }
  1173. #endif // !__WINDOWS__
  1174. wxString path(dir);
  1175. if ( path.Last() != wxFILE_SEP_PATH )
  1176. path += wxFILE_SEP_PATH;
  1177. wxDir d(path);
  1178. if ( !d.IsOpened() )
  1179. return false;
  1180. wxString filename;
  1181. // First delete all subdirectories: notice that we don't follow
  1182. // symbolic links, potentially leading outside this directory, to avoid
  1183. // unpleasant surprises.
  1184. bool cont = d.GetFirst(&filename, wxString(),
  1185. wxDIR_DIRS | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
  1186. while ( cont )
  1187. {
  1188. wxFileName::Rmdir(path + filename, flags);
  1189. cont = d.GetNext(&filename);
  1190. }
  1191. #ifndef __WINDOWS__
  1192. if ( flags & wxPATH_RMDIR_RECURSIVE )
  1193. {
  1194. // Delete all files too and, for the same reasons as above, don't
  1195. // follow symlinks which could refer to the files outside of this
  1196. // directory and just delete the symlinks themselves.
  1197. cont = d.GetFirst(&filename, wxString(),
  1198. wxDIR_FILES | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
  1199. while ( cont )
  1200. {
  1201. ::wxRemoveFile(path + filename);
  1202. cont = d.GetNext(&filename);
  1203. }
  1204. }
  1205. #endif // !__WINDOWS__
  1206. }
  1207. return ::wxRmdir(dir);
  1208. }
  1209. // ----------------------------------------------------------------------------
  1210. // path normalization
  1211. // ----------------------------------------------------------------------------
  1212. bool wxFileName::Normalize(int flags,
  1213. const wxString& cwd,
  1214. wxPathFormat format)
  1215. {
  1216. // deal with env vars renaming first as this may seriously change the path
  1217. if ( flags & wxPATH_NORM_ENV_VARS )
  1218. {
  1219. wxString pathOrig = GetFullPath(format);
  1220. wxString path = wxExpandEnvVars(pathOrig);
  1221. if ( path != pathOrig )
  1222. {
  1223. Assign(path);
  1224. }
  1225. }
  1226. // the existing path components
  1227. wxArrayString dirs = GetDirs();
  1228. // the path to prepend in front to make the path absolute
  1229. wxFileName curDir;
  1230. format = GetFormat(format);
  1231. // set up the directory to use for making the path absolute later
  1232. if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) )
  1233. {
  1234. if ( cwd.empty() )
  1235. {
  1236. curDir.AssignCwd(GetVolume());
  1237. }
  1238. else // cwd provided
  1239. {
  1240. curDir.AssignDir(cwd);
  1241. }
  1242. }
  1243. // handle ~ stuff under Unix only
  1244. if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) && m_relative )
  1245. {
  1246. if ( !dirs.IsEmpty() )
  1247. {
  1248. wxString dir = dirs[0u];
  1249. if ( !dir.empty() && dir[0u] == wxT('~') )
  1250. {
  1251. // to make the path absolute use the home directory
  1252. curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
  1253. dirs.RemoveAt(0u);
  1254. }
  1255. }
  1256. }
  1257. // transform relative path into abs one
  1258. if ( curDir.IsOk() )
  1259. {
  1260. // this path may be relative because it doesn't have the volume name
  1261. // and still have m_relative=true; in this case we shouldn't modify
  1262. // our directory components but just set the current volume
  1263. if ( !HasVolume() && curDir.HasVolume() )
  1264. {
  1265. SetVolume(curDir.GetVolume());
  1266. if ( !m_relative )
  1267. {
  1268. // yes, it was the case - we don't need curDir then
  1269. curDir.Clear();
  1270. }
  1271. }
  1272. // finally, prepend curDir to the dirs array
  1273. wxArrayString dirsNew = curDir.GetDirs();
  1274. WX_PREPEND_ARRAY(dirs, dirsNew);
  1275. // if we used e.g. tilde expansion previously and wxGetUserHome didn't
  1276. // return for some reason an absolute path, then curDir maybe not be absolute!
  1277. if ( !curDir.m_relative )
  1278. {
  1279. // we have prepended an absolute path and thus we are now an absolute
  1280. // file name too
  1281. m_relative = false;
  1282. }
  1283. // else if (flags & wxPATH_NORM_ABSOLUTE):
  1284. // should we warn the user that we didn't manage to make the path absolute?
  1285. }
  1286. // now deal with ".", ".." and the rest
  1287. m_dirs.Empty();
  1288. size_t count = dirs.GetCount();
  1289. for ( size_t n = 0; n < count; n++ )
  1290. {
  1291. wxString dir = dirs[n];
  1292. if ( flags & wxPATH_NORM_DOTS )
  1293. {
  1294. if ( dir == wxT(".") )
  1295. {
  1296. // just ignore
  1297. continue;
  1298. }
  1299. if ( dir == wxT("..") )
  1300. {
  1301. if ( m_dirs.empty() )
  1302. {
  1303. // We have more ".." than directory components so far.
  1304. // Don't treat this as an error as the path could have been
  1305. // entered by user so try to handle it reasonably: if the
  1306. // path is absolute, just ignore the extra ".." because
  1307. // "/.." is the same as "/". Otherwise, i.e. for relative
  1308. // paths, keep ".." unchanged because removing it would
  1309. // modify the file a relative path refers to.
  1310. if ( !m_relative )
  1311. continue;
  1312. }
  1313. else // Normal case, go one step up.
  1314. {
  1315. m_dirs.pop_back();
  1316. continue;
  1317. }
  1318. }
  1319. }
  1320. m_dirs.Add(dir);
  1321. }
  1322. #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
  1323. if ( (flags & wxPATH_NORM_SHORTCUT) )
  1324. {
  1325. wxString filename;
  1326. if (GetShortcutTarget(GetFullPath(format), filename))
  1327. {
  1328. m_relative = false;
  1329. Assign(filename);
  1330. }
  1331. }
  1332. #endif
  1333. #if defined(__WIN32__)
  1334. if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) )
  1335. {
  1336. Assign(GetLongPath());
  1337. }
  1338. #endif // Win32
  1339. // Change case (this should be kept at the end of the function, to ensure
  1340. // that the path doesn't change any more after we normalize its case)
  1341. if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
  1342. {
  1343. m_volume.MakeLower();
  1344. m_name.MakeLower();
  1345. m_ext.MakeLower();
  1346. // directory entries must be made lower case as well
  1347. count = m_dirs.GetCount();
  1348. for ( size_t i = 0; i < count; i++ )
  1349. {
  1350. m_dirs[i].MakeLower();
  1351. }
  1352. }
  1353. return true;
  1354. }
  1355. #ifndef __WXWINCE__
  1356. bool wxFileName::ReplaceEnvVariable(const wxString& envname,
  1357. const wxString& replacementFmtString,
  1358. wxPathFormat format)
  1359. {
  1360. // look into stringForm for the contents of the given environment variable
  1361. wxString val;
  1362. if (envname.empty() ||
  1363. !wxGetEnv(envname, &val))
  1364. return false;
  1365. if (val.empty())
  1366. return false;
  1367. wxString stringForm = GetPath(wxPATH_GET_VOLUME, format);
  1368. // do not touch the file name and the extension
  1369. wxString replacement = wxString::Format(replacementFmtString, envname);
  1370. stringForm.Replace(val, replacement);
  1371. // Now assign ourselves the modified path:
  1372. Assign(stringForm, GetFullName(), format);
  1373. return true;
  1374. }
  1375. #endif
  1376. bool wxFileName::ReplaceHomeDir(wxPathFormat format)
  1377. {
  1378. wxString homedir = wxGetHomeDir();
  1379. if (homedir.empty())
  1380. return false;
  1381. wxString stringForm = GetPath(wxPATH_GET_VOLUME, format);
  1382. // do not touch the file name and the extension
  1383. stringForm.Replace(homedir, "~");
  1384. // Now assign ourselves the modified path:
  1385. Assign(stringForm, GetFullName(), format);
  1386. return true;
  1387. }
  1388. // ----------------------------------------------------------------------------
  1389. // get the shortcut target
  1390. // ----------------------------------------------------------------------------
  1391. // WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions.
  1392. // The .lnk file is a plain text file so it should be easy to
  1393. // make it work. Hint from Google Groups:
  1394. // "If you open up a lnk file, you'll see a
  1395. // number, followed by a pound sign (#), followed by more text. The
  1396. // number is the number of characters that follows the pound sign. The
  1397. // characters after the pound sign are the command line (which _can_
  1398. // include arguments) to be executed. Any path (e.g. \windows\program
  1399. // files\myapp.exe) that includes spaces needs to be enclosed in
  1400. // quotation marks."
  1401. #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
  1402. bool wxFileName::GetShortcutTarget(const wxString& shortcutPath,
  1403. wxString& targetFilename,
  1404. wxString* arguments) const
  1405. {
  1406. wxString path, file, ext;
  1407. wxFileName::SplitPath(shortcutPath, & path, & file, & ext);
  1408. HRESULT hres;
  1409. IShellLink* psl;
  1410. bool success = false;
  1411. // Assume it's not a shortcut if it doesn't end with lnk
  1412. if (ext.CmpNoCase(wxT("lnk"))!=0)
  1413. return false;
  1414. // create a ShellLink object
  1415. hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  1416. IID_IShellLink, (LPVOID*) &psl);
  1417. if (SUCCEEDED(hres))
  1418. {
  1419. IPersistFile* ppf;
  1420. hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
  1421. if (SUCCEEDED(hres))
  1422. {
  1423. WCHAR wsz[MAX_PATH];
  1424. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, shortcutPath.mb_str(), -1, wsz,
  1425. MAX_PATH);
  1426. hres = ppf->Load(wsz, 0);
  1427. ppf->Release();
  1428. if (SUCCEEDED(hres))
  1429. {
  1430. wxChar buf[2048];
  1431. // Wrong prototype in early versions
  1432. #if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2)
  1433. psl->GetPath((CHAR*) buf, 2048, NULL, SLGP_UNCPRIORITY);
  1434. #else
  1435. psl->GetPath(buf, 2048, NULL, SLGP_UNCPRIORITY);
  1436. #endif
  1437. targetFilename = wxString(buf);
  1438. success = (shortcutPath != targetFilename);
  1439. psl->GetArguments(buf, 2048);
  1440. wxString args(buf);
  1441. if (!args.empty() && arguments)
  1442. {
  1443. *arguments = args;
  1444. }
  1445. }
  1446. }
  1447. psl->Release();
  1448. }
  1449. return success;
  1450. }
  1451. #endif // __WIN32__ && !__WXWINCE__
  1452. // ----------------------------------------------------------------------------
  1453. // absolute/relative paths
  1454. // ----------------------------------------------------------------------------
  1455. bool wxFileName::IsAbsolute(wxPathFormat format) const
  1456. {
  1457. // unix paths beginning with ~ are reported as being absolute
  1458. if ( format == wxPATH_UNIX )
  1459. {
  1460. if ( !m_dirs.IsEmpty() )
  1461. {
  1462. wxString dir = m_dirs[0u];
  1463. if (!dir.empty() && dir[0u] == wxT('~'))
  1464. return true;
  1465. }
  1466. }
  1467. // if our path doesn't start with a path separator, it's not an absolute
  1468. // path
  1469. if ( m_relative )
  1470. return false;
  1471. if ( !GetVolumeSeparator(format).empty() )
  1472. {
  1473. // this format has volumes and an absolute path must have one, it's not
  1474. // enough to have the full path to be an absolute file under Windows
  1475. if ( GetVolume().empty() )
  1476. return false;
  1477. }
  1478. return true;
  1479. }
  1480. bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
  1481. {
  1482. wxFileName fnBase = wxFileName::DirName(pathBase, format);
  1483. // get cwd only once - small time saving
  1484. wxString cwd = wxGetCwd();
  1485. Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
  1486. fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
  1487. bool withCase = IsCaseSensitive(format);
  1488. // we can't do anything if the files live on different volumes
  1489. if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) )
  1490. {
  1491. // nothing done
  1492. return false;
  1493. }
  1494. // same drive, so we don't need our volume
  1495. m_volume.clear();
  1496. // remove common directories starting at the top
  1497. while ( !m_dirs.IsEmpty() && !fnBase.m_dirs.IsEmpty() &&
  1498. m_dirs[0u].IsSameAs(fnBase.m_dirs[0u], withCase) )
  1499. {
  1500. m_dirs.RemoveAt(0);
  1501. fnBase.m_dirs.RemoveAt(0);
  1502. }
  1503. // add as many ".." as needed
  1504. size_t count = fnBase.m_dirs.GetCount();
  1505. for ( size_t i = 0; i < count; i++ )
  1506. {
  1507. m_dirs.Insert(wxT(".."), 0u);
  1508. }
  1509. if ( format == wxPATH_UNIX || format == wxPATH_DOS )
  1510. {
  1511. // a directory made relative with respect to itself is '.' under Unix
  1512. // and DOS, by definition (but we don't have to insert "./" for the
  1513. // files)
  1514. if ( m_dirs.IsEmpty() && IsDir() )
  1515. {
  1516. m_dirs.Add(wxT('.'));
  1517. }
  1518. }
  1519. m_relative = true;
  1520. // we were modified
  1521. return true;
  1522. }
  1523. // ----------------------------------------------------------------------------
  1524. // filename kind tests
  1525. // ----------------------------------------------------------------------------
  1526. bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const
  1527. {
  1528. wxFileName fn1 = *this,
  1529. fn2 = filepath;
  1530. // get cwd only once - small time saving
  1531. wxString cwd = wxGetCwd();
  1532. fn1.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format);
  1533. fn2.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format);
  1534. if ( fn1.GetFullPath() == fn2.GetFullPath() )
  1535. return true;
  1536. #ifdef wxHAVE_LSTAT
  1537. wxStructStat st1, st2;
  1538. if ( StatAny(st1, fn1) && StatAny(st2, fn2) )
  1539. {
  1540. if ( st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev )
  1541. return true;
  1542. }
  1543. //else: It's not an error if one or both files don't exist.
  1544. #endif // wxHAVE_LSTAT
  1545. return false;
  1546. }
  1547. /* static */
  1548. bool wxFileName::IsCaseSensitive( wxPathFormat format )
  1549. {
  1550. // only Unix filenames are truly case-sensitive
  1551. return GetFormat(format) == wxPATH_UNIX;
  1552. }
  1553. /* static */
  1554. wxString wxFileName::GetForbiddenChars(wxPathFormat format)
  1555. {
  1556. // Inits to forbidden characters that are common to (almost) all platforms.
  1557. wxString strForbiddenChars = wxT("*?");
  1558. // If asserts, wxPathFormat has been changed. In case of a new path format
  1559. // addition, the following code might have to be updated.
  1560. wxCOMPILE_TIME_ASSERT(wxPATH_MAX == 5, wxPathFormatChanged);
  1561. switch ( GetFormat(format) )
  1562. {
  1563. default :
  1564. wxFAIL_MSG( wxT("Unknown path format") );
  1565. // !! Fall through !!
  1566. case wxPATH_UNIX:
  1567. break;
  1568. case wxPATH_MAC:
  1569. // On a Mac even names with * and ? are allowed (Tested with OS
  1570. // 9.2.1 and OS X 10.2.5)
  1571. strForbiddenChars.clear();
  1572. break;
  1573. case wxPATH_DOS:
  1574. strForbiddenChars += wxT("\\/:\"<>|");
  1575. break;
  1576. case wxPATH_VMS:
  1577. break;
  1578. }
  1579. return strForbiddenChars;
  1580. }
  1581. /* static */
  1582. wxString wxFileName::GetVolumeSeparator(wxPathFormat WXUNUSED_IN_WINCE(format))
  1583. {
  1584. #ifdef __WXWINCE__
  1585. return wxEmptyString;
  1586. #else
  1587. wxString sepVol;
  1588. if ( (GetFormat(format) == wxPATH_DOS) ||
  1589. (GetFormat(format) == wxPATH_VMS) )
  1590. {
  1591. sepVol = wxFILE_SEP_DSK;
  1592. }
  1593. //else: leave empty
  1594. return sepVol;
  1595. #endif
  1596. }
  1597. /* static */
  1598. wxString wxFileName::GetPathSeparators(wxPathFormat format)
  1599. {
  1600. wxString seps;
  1601. switch ( GetFormat(format) )
  1602. {
  1603. case wxPATH_DOS:
  1604. // accept both as native APIs do but put the native one first as
  1605. // this is the one we use in GetFullPath()
  1606. seps << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_UNIX;
  1607. break;
  1608. default:
  1609. wxFAIL_MSG( wxT("Unknown wxPATH_XXX style") );
  1610. // fall through
  1611. case wxPATH_UNIX:
  1612. seps = wxFILE_SEP_PATH_UNIX;
  1613. break;
  1614. case wxPATH_MAC:
  1615. seps = wxFILE_SEP_PATH_MAC;
  1616. break;
  1617. case wxPATH_VMS:
  1618. seps = wxFILE_SEP_PATH_VMS;
  1619. break;
  1620. }
  1621. return seps;
  1622. }
  1623. /* static */
  1624. wxString wxFileName::GetPathTerminators(wxPathFormat format)
  1625. {
  1626. format = GetFormat(format);
  1627. // under VMS the end of the path is ']', not the path separator used to
  1628. // separate the components
  1629. return format == wxPATH_VMS ? wxString(wxT(']')) : GetPathSeparators(format);
  1630. }
  1631. /* static */
  1632. bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
  1633. {
  1634. // wxString::Find() doesn't work as expected with NUL - it will always find
  1635. // it, so test for it separately
  1636. return ch != wxT('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
  1637. }
  1638. /* static */
  1639. bool
  1640. wxFileName::IsMSWUniqueVolumeNamePath(const wxString& path, wxPathFormat format)
  1641. {
  1642. // return true if the format used is the DOS/Windows one and the string begins
  1643. // with a Windows unique volume name ("\\?\Volume{guid}\")
  1644. return format == wxPATH_DOS &&
  1645. path.length() >= wxMSWUniqueVolumePrefixLength &&
  1646. path.StartsWith(wxS("\\\\?\\Volume{")) &&
  1647. path[wxMSWUniqueVolumePrefixLength - 1] == wxFILE_SEP_PATH_DOS;
  1648. }
  1649. // ----------------------------------------------------------------------------
  1650. // path components manipulation
  1651. // ----------------------------------------------------------------------------
  1652. /* static */ bool wxFileName::IsValidDirComponent(const wxString& dir)
  1653. {
  1654. if ( dir.empty() )
  1655. {
  1656. wxFAIL_MSG( wxT("empty directory passed to wxFileName::InsertDir()") );
  1657. return false;
  1658. }
  1659. const size_t len = dir.length();
  1660. for ( size_t n = 0; n < len; n++ )
  1661. {
  1662. if ( dir[n] == GetVolumeSeparator() || IsPathSeparator(dir[n]) )
  1663. {
  1664. wxFAIL_MSG( wxT("invalid directory component in wxFileName") );
  1665. return false;
  1666. }
  1667. }
  1668. return true;
  1669. }
  1670. bool wxFileName::AppendDir( const wxString& dir )
  1671. {
  1672. if (!IsValidDirComponent(dir))
  1673. return false;
  1674. m_dirs.Add(dir);
  1675. return true;
  1676. }
  1677. void wxFileName::PrependDir( const wxString& dir )
  1678. {
  1679. InsertDir(0, dir);
  1680. }
  1681. bool wxFileName::InsertDir(size_t before, const wxString& dir)
  1682. {
  1683. if (!IsValidDirComponent(dir))
  1684. return false;
  1685. m_dirs.Insert(dir, before);
  1686. return true;
  1687. }
  1688. void wxFileName::RemoveDir(size_t pos)
  1689. {
  1690. m_dirs.RemoveAt(pos);
  1691. }
  1692. // ----------------------------------------------------------------------------
  1693. // accessors
  1694. // ----------------------------------------------------------------------------
  1695. void wxFileName::SetFullName(const wxString& fullname)
  1696. {
  1697. SplitPath(fullname, NULL /* no volume */, NULL /* no path */,
  1698. &m_name, &m_ext, &m_hasExt);
  1699. }
  1700. wxString wxFileName::GetFullName() const
  1701. {
  1702. wxString fullname = m_name;
  1703. if ( m_hasExt )
  1704. {
  1705. fullname << wxFILE_SEP_EXT << m_ext;
  1706. }
  1707. return fullname;
  1708. }
  1709. wxString wxFileName::GetPath( int flags, wxPathFormat format ) const
  1710. {
  1711. format = GetFormat( format );
  1712. wxString fullpath;
  1713. // return the volume with the path as well if requested
  1714. if ( flags & wxPATH_GET_VOLUME )
  1715. {
  1716. fullpath += wxGetVolumeString(GetVolume(), format);
  1717. }
  1718. // the leading character
  1719. switch ( format )
  1720. {
  1721. case wxPATH_MAC:
  1722. if ( m_relative )
  1723. fullpath += wxFILE_SEP_PATH_MAC;
  1724. break;
  1725. case wxPATH_DOS:
  1726. if ( !m_relative )
  1727. fullpath += wxFILE_SEP_PATH_DOS;
  1728. break;
  1729. default:
  1730. wxFAIL_MSG( wxT("Unknown path format") );
  1731. // fall through
  1732. case wxPATH_UNIX:
  1733. if ( !m_relative )
  1734. {
  1735. fullpath += wxFILE_SEP_PATH_UNIX;
  1736. }
  1737. break;
  1738. case wxPATH_VMS:
  1739. // no leading character here but use this place to unset
  1740. // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense
  1741. // as, if I understand correctly, there should never be a dot
  1742. // before the closing bracket
  1743. flags &= ~wxPATH_GET_SEPARATOR;
  1744. }
  1745. if ( m_dirs.empty() )
  1746. {
  1747. // there is nothing more
  1748. return fullpath;
  1749. }
  1750. // then concatenate all the path components using the path separator
  1751. if ( format == wxPATH_VMS )
  1752. {
  1753. fullpath += wxT('[');
  1754. }
  1755. const size_t dirCount = m_dirs.GetCount();
  1756. for ( size_t i = 0; i < dirCount; i++ )
  1757. {
  1758. switch (format)
  1759. {
  1760. case wxPATH_MAC:
  1761. if ( m_dirs[i] == wxT(".") )
  1762. {
  1763. // skip appending ':', this shouldn't be done in this
  1764. // case as "::" is interpreted as ".." under Unix
  1765. continue;
  1766. }
  1767. // convert back from ".." to nothing
  1768. if ( !m_dirs[i].IsSameAs(wxT("..")) )
  1769. fullpath += m_dirs[i];
  1770. break;
  1771. default:
  1772. wxFAIL_MSG( wxT("Unexpected path format") );
  1773. // still fall through
  1774. case wxPATH_DOS:
  1775. case wxPATH_UNIX:
  1776. fullpath += m_dirs[i];
  1777. break;
  1778. case wxPATH_VMS:
  1779. // TODO: What to do with ".." under VMS
  1780. // convert back from ".." to nothing
  1781. if ( !m_dirs[i].IsSameAs(wxT("..")) )
  1782. fullpath += m_dirs[i];
  1783. break;
  1784. }
  1785. if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) )
  1786. fullpath += GetPathSeparator(format);
  1787. }
  1788. if ( format == wxPATH_VMS )
  1789. {
  1790. fullpath += wxT(']');
  1791. }
  1792. return fullpath;
  1793. }
  1794. wxString wxFileName::GetFullPath( wxPathFormat format ) const
  1795. {
  1796. // we already have a function to get the path
  1797. wxString fullpath = GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR,
  1798. format);
  1799. // now just add the file name and extension to it
  1800. fullpath += GetFullName();
  1801. return fullpath;
  1802. }
  1803. // Return the short form of the path (returns identity on non-Windows platforms)
  1804. wxString wxFileName::GetShortPath() const
  1805. {
  1806. wxString path(GetFullPath());
  1807. #if defined(__WINDOWS__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
  1808. DWORD sz = ::GetShortPathName(path.t_str(), NULL, 0);
  1809. if ( sz != 0 )
  1810. {
  1811. wxString pathOut;
  1812. if ( ::GetShortPathName
  1813. (
  1814. path.t_str(),
  1815. wxStringBuffer(pathOut, sz),
  1816. sz
  1817. ) != 0 )
  1818. {
  1819. return pathOut;
  1820. }
  1821. }
  1822. #endif // Windows
  1823. return path;
  1824. }
  1825. // Return the long form of the path (returns identity on non-Windows platforms)
  1826. wxString wxFileName::GetLongPath() const
  1827. {
  1828. wxString pathOut,
  1829. path = GetFullPath();
  1830. #if defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__)
  1831. #if wxUSE_DYNLIB_CLASS
  1832. typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD);
  1833. // this is MT-safe as in the worst case we're going to resolve the function
  1834. // twice -- but as the result is the same in both threads, it's ok
  1835. static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL;
  1836. if ( !s_pfnGetLongPathName )
  1837. {
  1838. static bool s_triedToLoad = false;
  1839. if ( !s_triedToLoad )
  1840. {
  1841. s_triedToLoad = true;
  1842. wxDynamicLibrary dllKernel(wxT("kernel32"));
  1843. const wxChar* GetLongPathName = wxT("GetLongPathName")
  1844. #if wxUSE_UNICODE
  1845. wxT("W");
  1846. #else // ANSI
  1847. wxT("A");
  1848. #endif // Unicode/ANSI
  1849. if ( dllKernel.HasSymbol(GetLongPathName) )
  1850. {
  1851. s_pfnGetLongPathName = (GET_LONG_PATH_NAME)
  1852. dllKernel.GetSymbol(GetLongPathName);
  1853. }
  1854. // note that kernel32.dll can be unloaded, it stays in memory
  1855. // anyhow as all Win32 programs link to it and so it's safe to call
  1856. // GetLongPathName() even after unloading it
  1857. }
  1858. }
  1859. if ( s_pfnGetLongPathName )
  1860. {
  1861. DWORD dwSize = (*s_pfnGetLongPathName)(path.t_str(), NULL, 0);
  1862. if ( dwSize > 0 )
  1863. {
  1864. if ( (*s_pfnGetLongPathName)
  1865. (
  1866. path.t_str(),
  1867. wxStringBuffer(pathOut, dwSize),
  1868. dwSize
  1869. ) != 0 )
  1870. {
  1871. return pathOut;
  1872. }
  1873. }
  1874. }
  1875. #endif // wxUSE_DYNLIB_CLASS
  1876. // The OS didn't support GetLongPathName, or some other error.
  1877. // We need to call FindFirstFile on each component in turn.
  1878. WIN32_FIND_DATA findFileData;
  1879. HANDLE hFind;
  1880. if ( HasVolume() )
  1881. pathOut = GetVolume() +
  1882. GetVolumeSeparator(wxPATH_DOS) +
  1883. GetPathSeparator(wxPATH_DOS);
  1884. else
  1885. pathOut.clear();
  1886. wxArrayString dirs = GetDirs();
  1887. dirs.Add(GetFullName());
  1888. wxString tmpPath;
  1889. size_t count = dirs.GetCount();
  1890. for ( size_t i = 0; i < count; i++ )
  1891. {
  1892. const wxString& dir = dirs[i];
  1893. // We're using pathOut to collect the long-name path, but using a
  1894. // temporary for appending the last path component which may be
  1895. // short-name
  1896. tmpPath = pathOut + dir;
  1897. // We must not process "." or ".." here as they would be (unexpectedly)
  1898. // replaced by the corresponding directory names so just leave them
  1899. // alone
  1900. //
  1901. // And we can't pass a drive and root dir to FindFirstFile (VZ: why?)
  1902. if ( tmpPath.empty() || dir == '.' || dir == ".." ||
  1903. tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) )
  1904. {
  1905. tmpPath += wxFILE_SEP_PATH;
  1906. pathOut = tmpPath;
  1907. continue;
  1908. }
  1909. hFind = ::FindFirstFile(tmpPath.t_str(), &findFileData);
  1910. if (hFind == INVALID_HANDLE_VALUE)
  1911. {
  1912. // Error: most likely reason is that path doesn't exist, so
  1913. // append any unprocessed parts and return
  1914. for ( i += 1; i < count; i++ )
  1915. tmpPath += wxFILE_SEP_PATH + dirs[i];
  1916. return tmpPath;
  1917. }
  1918. pathOut += findFileData.cFileName;
  1919. if ( (i < (count-1)) )
  1920. pathOut += wxFILE_SEP_PATH;
  1921. ::FindClose(hFind);
  1922. }
  1923. #else // !Win32
  1924. pathOut = path;
  1925. #endif // Win32/!Win32
  1926. return pathOut;
  1927. }
  1928. wxPathFormat wxFileName::GetFormat( wxPathFormat format )
  1929. {
  1930. if (format == wxPATH_NATIVE)
  1931. {
  1932. #if defined(__WINDOWS__) || defined(__OS2__) || defined(__DOS__)
  1933. format = wxPATH_DOS;
  1934. #elif defined(__VMS)
  1935. format = wxPATH_VMS;
  1936. #else
  1937. format = wxPATH_UNIX;
  1938. #endif
  1939. }
  1940. return format;
  1941. }
  1942. #ifdef wxHAS_FILESYSTEM_VOLUMES
  1943. /* static */
  1944. wxString wxFileName::GetVolumeString(char drive, int flags)
  1945. {
  1946. wxASSERT_MSG( !(flags & ~wxPATH_GET_SEPARATOR), "invalid flag specified" );
  1947. wxString vol(drive);
  1948. vol += wxFILE_SEP_DSK;
  1949. if ( flags & wxPATH_GET_SEPARATOR )
  1950. vol += wxFILE_SEP_PATH;
  1951. return vol;
  1952. }
  1953. #endif // wxHAS_FILESYSTEM_VOLUMES
  1954. // ----------------------------------------------------------------------------
  1955. // path splitting function
  1956. // ----------------------------------------------------------------------------
  1957. /* static */
  1958. void
  1959. wxFileName::SplitVolume(const wxString& fullpathWithVolume,
  1960. wxString *pstrVolume,
  1961. wxString *pstrPath,
  1962. wxPathFormat format)
  1963. {
  1964. format = GetFormat(format);
  1965. wxString fullpath = fullpathWithVolume;
  1966. if ( IsMSWUniqueVolumeNamePath(fullpath, format) )
  1967. {
  1968. // special Windows unique volume names hack: transform
  1969. // \\?\Volume{guid}\path into Volume{guid}:path
  1970. // note: this check must be done before the check for UNC path
  1971. // we know the last backslash from the unique volume name is located
  1972. // there from IsMSWUniqueVolumeNamePath
  1973. fullpath[wxMSWUniqueVolumePrefixLength - 1] = wxFILE_SEP_DSK;
  1974. // paths starting with a unique volume name should always be absolute
  1975. fullpath.insert(wxMSWUniqueVolumePrefixLength, 1, wxFILE_SEP_PATH_DOS);
  1976. // remove the leading "\\?\" part
  1977. fullpath.erase(0, 4);
  1978. }
  1979. else if ( IsUNCPath(fullpath, format) )
  1980. {
  1981. // special Windows UNC paths hack: transform \\share\path into share:path
  1982. fullpath.erase(0, 2);
  1983. size_t posFirstSlash =
  1984. fullpath.find_first_of(GetPathTerminators(format));
  1985. if ( posFirstSlash != wxString::npos )
  1986. {
  1987. fullpath[posFirstSlash] = wxFILE_SEP_DSK;
  1988. // UNC paths are always absolute, right? (FIXME)
  1989. fullpath.insert(posFirstSlash + 1, 1, wxFILE_SEP_PATH_DOS);
  1990. }
  1991. }
  1992. // We separate the volume here
  1993. if ( format == wxPATH_DOS || format == wxPATH_VMS )
  1994. {
  1995. wxString sepVol = GetVolumeSeparator(format);
  1996. // we have to exclude the case of a colon in the very beginning of the
  1997. // string as it can't be a volume separator (nor can this be a valid
  1998. // DOS file name at all but we'll leave dealing with this to our caller)
  1999. size_t posFirstColon = fullpath.find_first_of(sepVol);
  2000. if ( posFirstColon && posFirstColon != wxString::npos )
  2001. {
  2002. if ( pstrVolume )
  2003. {
  2004. *pstrVolume = fullpath.Left(posFirstColon);
  2005. }
  2006. // remove the volume name and the separator from the full path
  2007. fullpath.erase(0, posFirstColon + sepVol.length());
  2008. }
  2009. }
  2010. if ( pstrPath )
  2011. *pstrPath = fullpath;
  2012. }
  2013. /* static */
  2014. void wxFileName::SplitPath(const wxString& fullpathWithVolume,
  2015. wxString *pstrVolume,
  2016. wxString *pstrPath,
  2017. wxString *pstrName,
  2018. wxString *pstrExt,
  2019. bool *hasExt,
  2020. wxPathFormat format)
  2021. {
  2022. format = GetFormat(format);
  2023. wxString fullpath;
  2024. SplitVolume(fullpathWithVolume, pstrVolume, &fullpath, format);
  2025. // find the positions of the last dot and last path separator in the path
  2026. size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT);
  2027. size_t posLastSlash = fullpath.find_last_of(GetPathTerminators(format));
  2028. // check whether this dot occurs at the very beginning of a path component
  2029. if ( (posLastDot != wxString::npos) &&
  2030. (posLastDot == 0 ||
  2031. IsPathSeparator(fullpath[posLastDot - 1]) ||
  2032. (format == wxPATH_VMS && fullpath[posLastDot - 1] == wxT(']'))) )
  2033. {
  2034. // dot may be (and commonly -- at least under Unix -- is) the first
  2035. // character of the filename, don't treat the entire filename as
  2036. // extension in this case
  2037. posLastDot = wxString::npos;
  2038. }
  2039. // if we do have a dot and a slash, check that the dot is in the name part
  2040. if ( (posLastDot != wxString::npos) &&
  2041. (posLastSlash != wxString::npos) &&
  2042. (posLastDot < posLastSlash) )
  2043. {
  2044. // the dot is part of the path, not the start of the extension
  2045. posLastDot = wxString::npos;
  2046. }
  2047. // now fill in the variables provided by user
  2048. if ( pstrPath )
  2049. {
  2050. if ( posLastSlash == wxString::npos )
  2051. {
  2052. // no path at all
  2053. pstrPath->Empty();
  2054. }
  2055. else
  2056. {
  2057. // take everything up to the path separator but take care to make
  2058. // the path equal to something like '/', not empty, for the files
  2059. // immediately under root directory
  2060. size_t len = posLastSlash;
  2061. // this rule does not apply to mac since we do not start with colons (sep)
  2062. // except for relative paths
  2063. if ( !len && format != wxPATH_MAC)
  2064. len++;
  2065. *pstrPath = fullpath.Left(len);
  2066. // special VMS hack: remove the initial bracket
  2067. if ( format == wxPATH_VMS )
  2068. {
  2069. if ( (*pstrPath)[0u] == wxT('[') )
  2070. pstrPath->erase(0, 1);
  2071. }
  2072. }
  2073. }
  2074. if ( pstrName )
  2075. {
  2076. // take all characters starting from the one after the last slash and
  2077. // up to, but excluding, the last dot
  2078. size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1;
  2079. size_t count;
  2080. if ( posLastDot == wxString::npos )
  2081. {
  2082. // take all until the end
  2083. count = wxString::npos;
  2084. }
  2085. else if ( posLastSlash == wxString::npos )
  2086. {
  2087. count = posLastDot;
  2088. }
  2089. else // have both dot and slash
  2090. {
  2091. count = posLastDot - posLastSlash - 1;
  2092. }
  2093. *pstrName = fullpath.Mid(nStart, count);
  2094. }
  2095. // finally deal with the extension here: we have an added complication that
  2096. // extension may be empty (but present) as in "foo." where trailing dot
  2097. // indicates the empty extension at the end -- and hence we must remember
  2098. // that we have it independently of pstrExt
  2099. if ( posLastDot == wxString::npos )
  2100. {
  2101. // no extension
  2102. if ( pstrExt )
  2103. pstrExt->clear();
  2104. if ( hasExt )
  2105. *hasExt = false;
  2106. }
  2107. else
  2108. {
  2109. // take everything after the dot
  2110. if ( pstrExt )
  2111. *pstrExt = fullpath.Mid(posLastDot + 1);
  2112. if ( hasExt )
  2113. *hasExt = true;
  2114. }
  2115. }
  2116. /* static */
  2117. void wxFileName::SplitPath(const wxString& fullpath,
  2118. wxString *path,
  2119. wxString *name,
  2120. wxString *ext,
  2121. wxPathFormat format)
  2122. {
  2123. wxString volume;
  2124. SplitPath(fullpath, &volume, path, name, ext, format);
  2125. if ( path )
  2126. {
  2127. path->Prepend(wxGetVolumeString(volume, format));
  2128. }
  2129. }
  2130. /* static */
  2131. wxString wxFileName::StripExtension(const wxString& fullpath)
  2132. {
  2133. wxFileName fn(fullpath);
  2134. fn.SetExt("");
  2135. return fn.GetFullPath();
  2136. }
  2137. // ----------------------------------------------------------------------------
  2138. // file permissions functions
  2139. // ----------------------------------------------------------------------------
  2140. bool wxFileName::SetPermissions(int permissions)
  2141. {
  2142. // Don't do anything for a symlink but first make sure it is one.
  2143. if ( m_dontFollowLinks &&
  2144. Exists(wxFILE_EXISTS_SYMLINK|wxFILE_EXISTS_NO_FOLLOW) )
  2145. {
  2146. // Looks like changing permissions for a symlinc is only supported
  2147. // on BSD where lchmod is present and correctly implemented.
  2148. // http://lists.gnu.org/archive/html/bug-coreutils/2009-09/msg00268.html
  2149. return false;
  2150. }
  2151. #ifdef __WINDOWS__
  2152. int accMode = 0;
  2153. if ( permissions & (wxS_IRUSR|wxS_IRGRP|wxS_IROTH) )
  2154. accMode = _S_IREAD;
  2155. if ( permissions & (wxS_IWUSR|wxS_IWGRP|wxS_IWOTH) )
  2156. accMode |= _S_IWRITE;
  2157. permissions = accMode;
  2158. #endif // __WINDOWS__
  2159. return wxChmod(GetFullPath(), permissions) == 0;
  2160. }
  2161. // ----------------------------------------------------------------------------
  2162. // time functions
  2163. // ----------------------------------------------------------------------------
  2164. #if wxUSE_DATETIME
  2165. bool wxFileName::SetTimes(const wxDateTime *dtAccess,
  2166. const wxDateTime *dtMod,
  2167. const wxDateTime *dtCreate) const
  2168. {
  2169. #if defined(__WIN32__)
  2170. FILETIME ftAccess, ftCreate, ftWrite;
  2171. if ( dtCreate )
  2172. ConvertWxToFileTime(&ftCreate, *dtCreate);
  2173. if ( dtAccess )
  2174. ConvertWxToFileTime(&ftAccess, *dtAccess);
  2175. if ( dtMod )
  2176. ConvertWxToFileTime(&ftWrite, *dtMod);
  2177. wxString path;
  2178. int flags;
  2179. if ( IsDir() )
  2180. {
  2181. if ( wxGetOsVersion() == wxOS_WINDOWS_9X )
  2182. {
  2183. wxLogError(_("Setting directory access times is not supported "
  2184. "under this OS version"));
  2185. return false;
  2186. }
  2187. path = GetPath();
  2188. flags = FILE_FLAG_BACKUP_SEMANTICS;
  2189. }
  2190. else // file
  2191. {
  2192. path = GetFullPath();
  2193. flags = 0;
  2194. }
  2195. wxFileHandle fh(path, wxFileHandle::WriteAttr, flags);
  2196. if ( fh.IsOk() )
  2197. {
  2198. if ( ::SetFileTime(fh,
  2199. dtCreate ? &ftCreate : NULL,
  2200. dtAccess ? &ftAccess : NULL,
  2201. dtMod ? &ftWrite : NULL) )
  2202. {
  2203. return true;
  2204. }
  2205. }
  2206. #elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__))
  2207. wxUnusedVar(dtCreate);
  2208. if ( !dtAccess && !dtMod )
  2209. {
  2210. // can't modify the creation time anyhow, don't try
  2211. return true;
  2212. }
  2213. // if dtAccess or dtMod is not specified, use the other one (which must be
  2214. // non NULL because of the test above) for both times
  2215. utimbuf utm;
  2216. utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks();
  2217. utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks();
  2218. if ( utime(GetFullPath().fn_str(), &utm) == 0 )
  2219. {
  2220. return true;
  2221. }
  2222. #else // other platform
  2223. wxUnusedVar(dtAccess);
  2224. wxUnusedVar(dtMod);
  2225. wxUnusedVar(dtCreate);
  2226. #endif // platforms
  2227. wxLogSysError(_("Failed to modify file times for '%s'"),
  2228. GetFullPath().c_str());
  2229. return false;
  2230. }
  2231. bool wxFileName::Touch() const
  2232. {
  2233. #if defined(__UNIX_LIKE__)
  2234. // under Unix touching file is simple: just pass NULL to utime()
  2235. if ( utime(GetFullPath().fn_str(), NULL) == 0 )
  2236. {
  2237. return true;
  2238. }
  2239. wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str());
  2240. return false;
  2241. #else // other platform
  2242. wxDateTime dtNow = wxDateTime::Now();
  2243. return SetTimes(&dtNow, &dtNow, NULL /* don't change create time */);
  2244. #endif // platforms
  2245. }
  2246. bool wxFileName::GetTimes(wxDateTime *dtAccess,
  2247. wxDateTime *dtMod,
  2248. wxDateTime *dtCreate) const
  2249. {
  2250. #if defined(__WIN32__)
  2251. // we must use different methods for the files and directories under
  2252. // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and
  2253. // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and
  2254. // not 9x
  2255. bool ok;
  2256. FILETIME ftAccess, ftCreate, ftWrite;
  2257. if ( IsDir() )
  2258. {
  2259. // implemented in msw/dir.cpp
  2260. extern bool wxGetDirectoryTimes(const wxString& dirname,
  2261. FILETIME *, FILETIME *, FILETIME *);
  2262. // we should pass the path without the trailing separator to
  2263. // wxGetDirectoryTimes()
  2264. ok = wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME),
  2265. &ftAccess, &ftCreate, &ftWrite);
  2266. }
  2267. else // file
  2268. {
  2269. wxFileHandle fh(GetFullPath(), wxFileHandle::ReadAttr);
  2270. if ( fh.IsOk() )
  2271. {
  2272. ok = ::GetFileTime(fh,
  2273. dtCreate ? &ftCreate : NULL,
  2274. dtAccess ? &ftAccess : NULL,
  2275. dtMod ? &ftWrite : NULL) != 0;
  2276. }
  2277. else
  2278. {
  2279. ok = false;
  2280. }
  2281. }
  2282. if ( ok )
  2283. {
  2284. if ( dtCreate )
  2285. ConvertFileTimeToWx(dtCreate, ftCreate);
  2286. if ( dtAccess )
  2287. ConvertFileTimeToWx(dtAccess, ftAccess);
  2288. if ( dtMod )
  2289. ConvertFileTimeToWx(dtMod, ftWrite);
  2290. return true;
  2291. }
  2292. #elif defined(wxHAVE_LSTAT)
  2293. // no need to test for IsDir() here
  2294. wxStructStat stBuf;
  2295. if ( StatAny(stBuf, *this) )
  2296. {
  2297. // Android defines st_*time fields as unsigned long, but time_t as long,
  2298. // hence the static_casts.
  2299. if ( dtAccess )
  2300. dtAccess->Set(static_cast<time_t>(stBuf.st_atime));
  2301. if ( dtMod )
  2302. dtMod->Set(static_cast<time_t>(stBuf.st_mtime));
  2303. if ( dtCreate )
  2304. dtCreate->Set(static_cast<time_t>(stBuf.st_ctime));
  2305. return true;
  2306. }
  2307. #else // other platform
  2308. wxUnusedVar(dtAccess);
  2309. wxUnusedVar(dtMod);
  2310. wxUnusedVar(dtCreate);
  2311. #endif // platforms
  2312. wxLogSysError(_("Failed to retrieve file times for '%s'"),
  2313. GetFullPath().c_str());
  2314. return false;
  2315. }
  2316. #endif // wxUSE_DATETIME
  2317. // ----------------------------------------------------------------------------
  2318. // file size functions
  2319. // ----------------------------------------------------------------------------
  2320. #if wxUSE_LONGLONG
  2321. /* static */
  2322. wxULongLong wxFileName::GetSize(const wxString &filename)
  2323. {
  2324. if (!wxFileExists(filename))
  2325. return wxInvalidSize;
  2326. #if defined(__WIN32__)
  2327. wxFileHandle f(filename, wxFileHandle::ReadAttr);
  2328. if (!f.IsOk())
  2329. return wxInvalidSize;
  2330. DWORD lpFileSizeHigh;
  2331. DWORD ret = GetFileSize(f, &lpFileSizeHigh);
  2332. if ( ret == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR )
  2333. return wxInvalidSize;
  2334. return wxULongLong(lpFileSizeHigh, ret);
  2335. #else // ! __WIN32__
  2336. wxStructStat st;
  2337. if (wxStat( filename, &st) != 0)
  2338. return wxInvalidSize;
  2339. return wxULongLong(st.st_size);
  2340. #endif
  2341. }
  2342. /* static */
  2343. wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs,
  2344. const wxString &nullsize,
  2345. int precision,
  2346. wxSizeConvention conv)
  2347. {
  2348. // deal with trivial case first
  2349. if ( bs == 0 || bs == wxInvalidSize )
  2350. return nullsize;
  2351. // depending on the convention used the multiplier may be either 1000 or
  2352. // 1024 and the binary infix may be empty (for "KB") or "i" (for "KiB")
  2353. double multiplier = 1024.;
  2354. wxString biInfix;
  2355. switch ( conv )
  2356. {
  2357. case wxSIZE_CONV_TRADITIONAL:
  2358. // nothing to do, this corresponds to the default values of both
  2359. // the multiplier and infix string
  2360. break;
  2361. case wxSIZE_CONV_IEC:
  2362. biInfix = "i";
  2363. break;
  2364. case wxSIZE_CONV_SI:
  2365. multiplier = 1000;
  2366. break;
  2367. }
  2368. const double kiloByteSize = multiplier;
  2369. const double megaByteSize = multiplier * kiloByteSize;
  2370. const double gigaByteSize = multiplier * megaByteSize;
  2371. const double teraByteSize = multiplier * gigaByteSize;
  2372. const double bytesize = bs.ToDouble();
  2373. wxString result;
  2374. if ( bytesize < kiloByteSize )
  2375. result.Printf("%s B", bs.ToString());
  2376. else if ( bytesize < megaByteSize )
  2377. result.Printf("%.*f K%sB", precision, bytesize/kiloByteSize, biInfix);
  2378. else if (bytesize < gigaByteSize)
  2379. result.Printf("%.*f M%sB", precision, bytesize/megaByteSize, biInfix);
  2380. else if (bytesize < teraByteSize)
  2381. result.Printf("%.*f G%sB", precision, bytesize/gigaByteSize, biInfix);
  2382. else
  2383. result.Printf("%.*f T%sB", precision, bytesize/teraByteSize, biInfix);
  2384. return result;
  2385. }
  2386. wxULongLong wxFileName::GetSize() const
  2387. {
  2388. return GetSize(GetFullPath());
  2389. }
  2390. wxString wxFileName::GetHumanReadableSize(const wxString& failmsg,
  2391. int precision,
  2392. wxSizeConvention conv) const
  2393. {
  2394. return GetHumanReadableSize(GetSize(), failmsg, precision, conv);
  2395. }
  2396. #endif // wxUSE_LONGLONG
  2397. // ----------------------------------------------------------------------------
  2398. // Mac-specific functions
  2399. // ----------------------------------------------------------------------------
  2400. #if defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON
  2401. namespace
  2402. {
  2403. class MacDefaultExtensionRecord
  2404. {
  2405. public:
  2406. MacDefaultExtensionRecord()
  2407. {
  2408. m_type =
  2409. m_creator = 0 ;
  2410. }
  2411. // default copy ctor, assignment operator and dtor are ok
  2412. MacDefaultExtensionRecord(const wxString& ext, OSType type, OSType creator)
  2413. : m_ext(ext)
  2414. {
  2415. m_type = type;
  2416. m_creator = creator;
  2417. }
  2418. wxString m_ext;
  2419. OSType m_type;
  2420. OSType m_creator;
  2421. };
  2422. WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray);
  2423. bool gMacDefaultExtensionsInited = false;
  2424. #include "wx/arrimpl.cpp"
  2425. WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray);
  2426. MacDefaultExtensionArray gMacDefaultExtensions;
  2427. // load the default extensions
  2428. const MacDefaultExtensionRecord gDefaults[] =
  2429. {
  2430. MacDefaultExtensionRecord( "txt", 'TEXT', 'ttxt' ),
  2431. MacDefaultExtensionRecord( "tif", 'TIFF', '****' ),
  2432. MacDefaultExtensionRecord( "jpg", 'JPEG', '****' ),
  2433. };
  2434. void MacEnsureDefaultExtensionsLoaded()
  2435. {
  2436. if ( !gMacDefaultExtensionsInited )
  2437. {
  2438. // we could load the pc exchange prefs here too
  2439. for ( size_t i = 0 ; i < WXSIZEOF( gDefaults ) ; ++i )
  2440. {
  2441. gMacDefaultExtensions.Add( gDefaults[i] ) ;
  2442. }
  2443. gMacDefaultExtensionsInited = true;
  2444. }
  2445. }
  2446. } // anonymous namespace
  2447. bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator )
  2448. {
  2449. FSRef fsRef ;
  2450. FSCatalogInfo catInfo;
  2451. FileInfo *finfo ;
  2452. if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr )
  2453. {
  2454. if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
  2455. {
  2456. finfo = (FileInfo*)&catInfo.finderInfo;
  2457. finfo->fileType = type ;
  2458. finfo->fileCreator = creator ;
  2459. FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ;
  2460. return true ;
  2461. }
  2462. }
  2463. return false ;
  2464. }
  2465. bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator ) const
  2466. {
  2467. FSRef fsRef ;
  2468. FSCatalogInfo catInfo;
  2469. FileInfo *finfo ;
  2470. if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr )
  2471. {
  2472. if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
  2473. {
  2474. finfo = (FileInfo*)&catInfo.finderInfo;
  2475. *type = finfo->fileType ;
  2476. *creator = finfo->fileCreator ;
  2477. return true ;
  2478. }
  2479. }
  2480. return false ;
  2481. }
  2482. bool wxFileName::MacSetDefaultTypeAndCreator()
  2483. {
  2484. wxUint32 type , creator ;
  2485. if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type ,
  2486. &creator ) )
  2487. {
  2488. return MacSetTypeAndCreator( type , creator ) ;
  2489. }
  2490. return false;
  2491. }
  2492. bool wxFileName::MacFindDefaultTypeAndCreator( const wxString& ext , wxUint32 *type , wxUint32 *creator )
  2493. {
  2494. MacEnsureDefaultExtensionsLoaded() ;
  2495. wxString extl = ext.Lower() ;
  2496. for( int i = gMacDefaultExtensions.Count() - 1 ; i >= 0 ; --i )
  2497. {
  2498. if ( gMacDefaultExtensions.Item(i).m_ext == extl )
  2499. {
  2500. *type = gMacDefaultExtensions.Item(i).m_type ;
  2501. *creator = gMacDefaultExtensions.Item(i).m_creator ;
  2502. return true ;
  2503. }
  2504. }
  2505. return false ;
  2506. }
  2507. void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator )
  2508. {
  2509. MacEnsureDefaultExtensionsLoaded();
  2510. MacDefaultExtensionRecord rec(ext.Lower(), type, creator);
  2511. gMacDefaultExtensions.Add( rec );
  2512. }
  2513. #endif // defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON