PageRenderTime 254ms CodeModel.GetById 86ms RepoModel.GetById 1ms app.codeStats 0ms

/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

Large files files are truncated, but you can click here to view the full file

  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];

Large files files are truncated, but you can click here to view the full file