1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/filename.cpp 
   3 // Purpose:     wxFileName - encapsulates a file path 
   4 // Author:      Robert Roebling, Vadim Zeitlin 
   8 // Copyright:   (c) 2000 Robert Roebling 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13    Here are brief descriptions of the filename formats supported by this class: 
  15    wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file 
  17                 /dir1/dir2/.../dirN/filename, "." and ".." stand for the 
  18                 current and parent directory respectively, "~" is parsed as the 
  19                 user HOME and "~username" as the HOME of that user 
  21    wxPATH_DOS:  DOS/Windows format, absolute file names have the form: 
  22                 drive:\dir1\dir2\...\dirN\filename.ext where drive is a single 
  23                 letter. "." and ".." as for Unix but no "~". 
  25                 There are also UNC names of the form \\share\fullpath and 
  26                 MSW unique volume names of the form \\?\Volume{GUID}\fullpath. 
  28                 The latter provide a uniform way to access a volume regardless of 
  29                 its current mount point, i.e. you can change a volume's mount 
  30                 point from D: to E:, or even remove it, and still be able to 
  31                 access it through its unique volume name. More on the subject can 
  32                 be found in MSDN's article "Naming a Volume" that is currently at 
  33                 http://msdn.microsoft.com/en-us/library/aa365248(VS.85).aspx. 
  36    wxPATH_MAC:  Mac OS 8/9 only, not used any longer, absolute file 
  38                     volume:dir1:...:dirN:filename 
  39                 and the relative file names are either 
  40                     :dir1:...:dirN:filename 
  43                 (although :filename works as well). 
  44                 Since the volume is just part of the file path, it is not 
  45                 treated like a separate entity as it is done under DOS and 
  46                 VMS, it is just treated as another dir. 
  48    wxPATH_VMS:  VMS native format, absolute file names have the form 
  49                     <device>:[dir1.dir2.dir3]file.txt 
  51                     <device>:[000000.dir1.dir2.dir3]file.txt 
  53                 the <device> is the physical device (i.e. disk). 000000 is the 
  54                 root directory on the device which can be omitted. 
  56                 Note that VMS uses different separators unlike Unix: 
  57                  : always after the device. If the path does not contain : than 
  58                    the default (the device of the current directory) is assumed. 
  59                  [ start of directory specification 
  60                  . separator between directory and subdirectory 
  61                  ] between directory and file 
  64 // ============================================================================ 
  66 // ============================================================================ 
  68 // ---------------------------------------------------------------------------- 
  70 // ---------------------------------------------------------------------------- 
  72 // For compilers that support precompilation, includes "wx.h". 
  73 #include "wx/wxprec.h" 
  81         #include "wx/msw/wrapwin.h" // For GetShort/LongPathName 
  83     #include "wx/dynarray.h" 
  90 #include "wx/filename.h" 
  91 #include "wx/private/filename.h" 
  92 #include "wx/tokenzr.h" 
  93 #include "wx/config.h"          // for wxExpandEnvVars 
  94 #include "wx/dynlib.h" 
  97 #if defined(__WIN32__) && defined(__MINGW32__) 
  98     #include "wx/msw/gccpriv.h" 
 102 #include "wx/msw/private.h" 
 105 #if defined(__WXMAC__) 
 106   #include  "wx/osx/private.h"  // includes mac headers 
 109 // utime() is POSIX so should normally be available on all Unices 
 111 #include <sys/types.h> 
 113 #include <sys/stat.h> 
 123 #include <sys/utime.h> 
 124 #include <sys/stat.h> 
 135 #define MAX_PATH _MAX_PATH 
 139     #define S_ISREG(mode) ((mode) & S_IFREG) 
 142     #define S_ISDIR(mode) ((mode) & S_IFDIR) 
 146 extern const wxULongLong wxInvalidSize 
= (unsigned)-1; 
 147 #endif // wxUSE_LONGLONG 
 152 // ---------------------------------------------------------------------------- 
 154 // ---------------------------------------------------------------------------- 
 156 // small helper class which opens and closes the file - we use it just to get 
 157 // a file handle for the given file name to pass it to some Win32 API function 
 158 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
 169     wxFileHandle(const wxString
& filename
, OpenMode mode
, int flags 
= 0) 
 171         // be careful and use FILE_{READ,WRITE}_ATTRIBUTES here instead of the 
 172         // usual GENERIC_{READ,WRITE} as we don't want the file access time to 
 173         // be changed when we open it because this class is used for setting 
 174         // access time (see #10567) 
 175         m_hFile 
= ::CreateFile
 
 177                      filename
.t_str(),             // name 
 178                      mode 
== ReadAttr 
? FILE_READ_ATTRIBUTES    
// access mask 
 179                                       : FILE_WRITE_ATTRIBUTES
, 
 180                      FILE_SHARE_READ 
|              // sharing mode 
 181                      FILE_SHARE_WRITE
,              // (allow everything) 
 182                      NULL
,                          // no secutity attr 
 183                      OPEN_EXISTING
,                 // creation disposition 
 185                      NULL                           
// no template file 
 188         if ( m_hFile 
== INVALID_HANDLE_VALUE 
) 
 190             if ( mode 
== ReadAttr 
) 
 192                 wxLogSysError(_("Failed to open '%s' for reading"), 
 197                 wxLogSysError(_("Failed to open '%s' for writing"), 
 205         if ( m_hFile 
!= INVALID_HANDLE_VALUE 
) 
 207             if ( !::CloseHandle(m_hFile
) ) 
 209                 wxLogSysError(_("Failed to close file handle")); 
 214     // return true only if the file could be opened successfully 
 215     bool IsOk() const { return m_hFile 
!= INVALID_HANDLE_VALUE
; } 
 218     operator HANDLE() const { return m_hFile
; } 
 226 // ---------------------------------------------------------------------------- 
 228 // ---------------------------------------------------------------------------- 
 230 #if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__) 
 232 // convert between wxDateTime and FILETIME which is a 64-bit value representing 
 233 // the number of 100-nanosecond intervals since January 1, 1601. 
 235 static void ConvertFileTimeToWx(wxDateTime 
*dt
, const FILETIME 
&ft
) 
 237     FILETIME ftcopy 
= ft
; 
 239     if ( !::FileTimeToLocalFileTime(&ftcopy
, &ftLocal
) ) 
 241         wxLogLastError(wxT("FileTimeToLocalFileTime")); 
 245     if ( !::FileTimeToSystemTime(&ftLocal
, &st
) ) 
 247         wxLogLastError(wxT("FileTimeToSystemTime")); 
 250     dt
->Set(st
.wDay
, wxDateTime::Month(st
.wMonth 
- 1), st
.wYear
, 
 251             st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
); 
 254 static void ConvertWxToFileTime(FILETIME 
*ft
, const wxDateTime
& dt
) 
 257     st
.wDay 
= dt
.GetDay(); 
 258     st
.wMonth 
= (WORD
)(dt
.GetMonth() + 1); 
 259     st
.wYear 
= (WORD
)dt
.GetYear(); 
 260     st
.wHour 
= dt
.GetHour(); 
 261     st
.wMinute 
= dt
.GetMinute(); 
 262     st
.wSecond 
= dt
.GetSecond(); 
 263     st
.wMilliseconds 
= dt
.GetMillisecond(); 
 266     if ( !::SystemTimeToFileTime(&st
, &ftLocal
) ) 
 268         wxLogLastError(wxT("SystemTimeToFileTime")); 
 271     if ( !::LocalFileTimeToFileTime(&ftLocal
, ft
) ) 
 273         wxLogLastError(wxT("LocalFileTimeToFileTime")); 
 277 #endif // wxUSE_DATETIME && __WIN32__ 
 279 // return a string with the volume par 
 280 static wxString 
wxGetVolumeString(const wxString
& volume
, wxPathFormat format
) 
 284     if ( !volume
.empty() ) 
 286         format 
= wxFileName::GetFormat(format
); 
 288         // Special Windows UNC paths hack, part 2: undo what we did in 
 289         // SplitPath() and make an UNC path if we have a drive which is not a 
 290         // single letter (hopefully the network shares can't be one letter only 
 291         // although I didn't find any authoritative docs on this) 
 292         if ( format 
== wxPATH_DOS 
&& volume
.length() > 1 ) 
 294             // We also have to check for Windows unique volume names here and 
 295             // return it with '\\?\' prepended to it 
 296             if ( wxFileName::IsMSWUniqueVolumeNamePath("\\\\?\\" + volume 
+ "\\", 
 299                 path 
<< "\\\\?\\" << volume
; 
 303                 // it must be a UNC path 
 304                 path 
<< wxFILE_SEP_PATH_DOS 
<< wxFILE_SEP_PATH_DOS 
<< volume
; 
 307         else if  ( format 
== wxPATH_DOS 
|| format 
== wxPATH_VMS 
) 
 309             path 
<< volume 
<< wxFileName::GetVolumeSeparator(format
); 
 317 // return true if the character is a DOS path separator i.e. either a slash or 
 319 inline bool IsDOSPathSep(wxUniChar ch
) 
 321     return ch 
== wxFILE_SEP_PATH_DOS 
|| ch 
== wxFILE_SEP_PATH_UNIX
; 
 324 // return true if the format used is the DOS/Windows one and the string looks 
 326 static bool IsUNCPath(const wxString
& path
, wxPathFormat format
) 
 328     return format 
== wxPATH_DOS 
&& 
 329                 path
.length() >= 4 && // "\\a" can't be a UNC path 
 330                     IsDOSPathSep(path
[0u]) && 
 331                         IsDOSPathSep(path
[1u]) && 
 332                             !IsDOSPathSep(path
[2u]); 
 335 // ---------------------------------------------------------------------------- 
 337 // ---------------------------------------------------------------------------- 
 339 // length of \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ string 
 340 static const size_t wxMSWUniqueVolumePrefixLength 
= 49; 
 342 } // anonymous namespace 
 344 // ============================================================================ 
 346 // ============================================================================ 
 348 // ---------------------------------------------------------------------------- 
 349 // wxFileName construction 
 350 // ---------------------------------------------------------------------------- 
 352 void wxFileName::Assign( const wxFileName 
&filepath 
) 
 354     m_volume 
= filepath
.GetVolume(); 
 355     m_dirs 
= filepath
.GetDirs(); 
 356     m_name 
= filepath
.GetName(); 
 357     m_ext 
= filepath
.GetExt(); 
 358     m_relative 
= filepath
.m_relative
; 
 359     m_hasExt 
= filepath
.m_hasExt
; 
 362 void wxFileName::Assign(const wxString
& volume
, 
 363                         const wxString
& path
, 
 364                         const wxString
& name
, 
 369     // we should ignore paths which look like UNC shares because we already 
 370     // have the volume here and the UNC notation (\\server\path) is only valid 
 371     // for paths which don't start with a volume, so prevent SetPath() from 
 372     // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path 
 374     // note also that this is a rather ugly way to do what we want (passing 
 375     // some kind of flag telling to ignore UNC paths to SetPath() would be 
 376     // better) but this is the safest thing to do to avoid breaking backwards 
 377     // compatibility in 2.8 
 378     if ( IsUNCPath(path
, format
) ) 
 380         // remove one of the 2 leading backslashes to ensure that it's not 
 381         // recognized as an UNC path by SetPath() 
 382         wxString 
pathNonUNC(path
, 1, wxString::npos
); 
 383         SetPath(pathNonUNC
, format
); 
 385     else // no UNC complications 
 387         SetPath(path
, format
); 
 397 void wxFileName::SetPath( const wxString
& pathOrig
, wxPathFormat format 
) 
 401     if ( pathOrig
.empty() ) 
 409     format 
= GetFormat( format 
); 
 411     // 0) deal with possible volume part first 
 414     SplitVolume(pathOrig
, &volume
, &path
, format
); 
 415     if ( !volume
.empty() ) 
 422     // 1) Determine if the path is relative or absolute. 
 426         // we had only the volume 
 430     wxChar leadingChar 
= path
[0u]; 
 435             m_relative 
= leadingChar 
== wxT(':'); 
 437             // We then remove a leading ":". The reason is in our 
 438             // storage form for relative paths: 
 439             // ":dir:file.txt" actually means "./dir/file.txt" in 
 440             // DOS notation and should get stored as 
 441             // (relative) (dir) (file.txt) 
 442             // "::dir:file.txt" actually means "../dir/file.txt" 
 443             // stored as (relative) (..) (dir) (file.txt) 
 444             // This is important only for the Mac as an empty dir 
 445             // actually means <UP>, whereas under DOS, double 
 446             // slashes can be ignored: "\\\\" is the same as "\\". 
 452             // TODO: what is the relative path format here? 
 457             wxFAIL_MSG( wxT("Unknown path format") ); 
 458             // !! Fall through !! 
 461             m_relative 
= leadingChar 
!= wxT('/'); 
 465             m_relative 
= !IsPathSeparator(leadingChar
, format
); 
 470     // 2) Break up the path into its members. If the original path 
 471     //    was just "/" or "\\", m_dirs will be empty. We know from 
 472     //    the m_relative field, if this means "nothing" or "root dir". 
 474     wxStringTokenizer 
tn( path
, GetPathSeparators(format
) ); 
 476     while ( tn
.HasMoreTokens() ) 
 478         wxString token 
= tn
.GetNextToken(); 
 480         // Remove empty token under DOS and Unix, interpret them 
 484             if (format 
== wxPATH_MAC
) 
 485                 m_dirs
.Add( wxT("..") ); 
 495 void wxFileName::Assign(const wxString
& fullpath
, 
 498     wxString volume
, path
, name
, ext
; 
 500     SplitPath(fullpath
, &volume
, &path
, &name
, &ext
, &hasExt
, format
); 
 502     Assign(volume
, path
, name
, ext
, hasExt
, format
); 
 505 void wxFileName::Assign(const wxString
& fullpathOrig
, 
 506                         const wxString
& fullname
, 
 509     // always recognize fullpath as directory, even if it doesn't end with a 
 511     wxString fullpath 
= fullpathOrig
; 
 512     if ( !fullpath
.empty() && !wxEndsWithPathSeparator(fullpath
) ) 
 514         fullpath 
+= GetPathSeparator(format
); 
 517     wxString volume
, path
, name
, ext
; 
 520     // do some consistency checks: the name should be really just the filename 
 521     // and the path should be really just a path 
 522     wxString volDummy
, pathDummy
, nameDummy
, extDummy
; 
 524     SplitPath(fullname
, &volDummy
, &pathDummy
, &name
, &ext
, &hasExt
, format
); 
 526     wxASSERT_MSG( volDummy
.empty() && pathDummy
.empty(), 
 527                   wxT("the file name shouldn't contain the path") ); 
 529     SplitPath(fullpath
, &volume
, &path
, &nameDummy
, &extDummy
, format
); 
 532    // This test makes no sense on an OpenVMS system. 
 533    wxASSERT_MSG( nameDummy
.empty() && extDummy
.empty(), 
 534                   wxT("the path shouldn't contain file name nor extension") ); 
 536     Assign(volume
, path
, name
, ext
, hasExt
, format
); 
 539 void wxFileName::Assign(const wxString
& pathOrig
, 
 540                         const wxString
& name
, 
 546     SplitVolume(pathOrig
, &volume
, &path
, format
); 
 548     Assign(volume
, path
, name
, ext
, format
); 
 551 void wxFileName::AssignDir(const wxString
& dir
, wxPathFormat format
) 
 553     Assign(dir
, wxEmptyString
, format
); 
 556 void wxFileName::Clear() 
 562     m_ext 
= wxEmptyString
; 
 564     // we don't have any absolute path for now 
 572 wxFileName 
wxFileName::FileName(const wxString
& file
, wxPathFormat format
) 
 574     return wxFileName(file
, format
); 
 578 wxFileName 
wxFileName::DirName(const wxString
& dir
, wxPathFormat format
) 
 581     fn
.AssignDir(dir
, format
); 
 585 // ---------------------------------------------------------------------------- 
 587 // ---------------------------------------------------------------------------- 
 592 // Flags for wxFileSystemObjectExists() asking it to check for: 
 595     wxFileSystemObject_File  
= 1,   // file existence 
 596     wxFileSystemObject_Dir   
= 2,   // directory existence 
 597     wxFileSystemObject_Other 
= 4,   // existence of something else, e.g. 
 598                                     // device, socket, FIFO under Unix 
 599     wxFileSystemObject_Any   
= 7    // existence of anything at all 
 602 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 604 void RemoveTrailingSeparatorsFromPath(wxString
& strPath
) 
 606     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, 
 607     // so remove all trailing backslashes from the path - but don't do this for 
 608     // the paths "d:\" (which are different from "d:"), for just "\" or for 
 609     // windows unique volume names ("\\?\Volume{GUID}\") 
 610     while ( wxEndsWithPathSeparator( strPath 
) ) 
 612         size_t len 
= strPath
.length(); 
 613         if ( len 
== 1 || (len 
== 3 && strPath
[len 
- 2] == wxT(':')) || 
 614                 (len 
== wxMSWUniqueVolumePrefixLength 
&& 
 615                  wxFileName::IsMSWUniqueVolumeNamePath(strPath
))) 
 620         strPath
.Truncate(len 
- 1); 
 624 #endif // __WINDOWS__ || __OS2__ 
 626 bool wxFileSystemObjectExists(const wxString
& path
, int flags
) 
 628     // Should the existence of file/directory with this name be accepted, i.e. 
 629     // result in the true return value from this function? 
 630     const bool acceptFile 
= (flags 
& wxFileSystemObject_File
) != 0; 
 631     const bool acceptDir  
= (flags 
& wxFileSystemObject_Dir
) != 0; 
 633     wxString 
strPath(path
); 
 635 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 638         // Ensure that the path doesn't have any trailing separators when 
 639         // checking for directories. 
 640         RemoveTrailingSeparatorsFromPath(strPath
); 
 643     // we must use GetFileAttributes() instead of the ANSI C functions because 
 644     // it can cope with network (UNC) paths unlike them 
 645     DWORD ret 
= ::GetFileAttributes(strPath
.t_str()); 
 647     if ( ret 
== INVALID_FILE_ATTRIBUTES 
) 
 650     if ( ret 
& FILE_ATTRIBUTE_DIRECTORY 
) 
 653     // Anything else must be a file (perhaps we should check for 
 654     // FILE_ATTRIBUTE_REPARSE_POINT?) 
 656 #elif defined(__OS2__) 
 659         // OS/2 can't handle "d:", it wants either "d:\" or "d:." 
 660         if (strPath
.length() == 2 && strPath
[1u] == wxT(':')) 
 664     FILESTATUS3 Info 
= {{0}}; 
 665     APIRET rc 
= ::DosQueryPathInfo((PSZ
)(WXSTRINGCAST strPath
), FIL_STANDARD
, 
 666             (void*) &Info
, sizeof(FILESTATUS3
)); 
 668     if ( rc 
== NO_ERROR 
) 
 670         if ( Info
.attrFile 
& FILE_DIRECTORY 
) 
 676     // We consider that the path must exist if we get a sharing violation for 
 677     // it but we don't know what is it in this case. 
 678     if ( rc 
== ERROR_SHARING_VIOLATION 
) 
 679         return flags 
& wxFileSystemObject_Other
; 
 681     // Any other error (usually ERROR_PATH_NOT_FOUND), means there is nothing 
 684 #else // Non-MSW, non-OS/2 
 686     if ( wxStat(strPath
, &st
) != 0 ) 
 689     if ( S_ISREG(st
.st_mode
) ) 
 691     if ( S_ISDIR(st
.st_mode
) ) 
 694     return flags 
& wxFileSystemObject_Other
; 
 698 } // anonymous namespace 
 700 bool wxFileName::FileExists() const 
 702     return wxFileName::FileExists( GetFullPath() ); 
 706 bool wxFileName::FileExists( const wxString 
&filePath 
) 
 708     return wxFileSystemObjectExists(filePath
, wxFileSystemObject_File
); 
 711 bool wxFileName::DirExists() const 
 713     return wxFileName::DirExists( GetPath() ); 
 717 bool wxFileName::DirExists( const wxString 
&dirPath 
) 
 719     return wxFileSystemObjectExists(dirPath
, wxFileSystemObject_Dir
); 
 723 bool wxFileName::Exists(const wxString
& path
) 
 725     return wxFileSystemObjectExists(path
, wxFileSystemObject_Any
); 
 728 // ---------------------------------------------------------------------------- 
 729 // CWD and HOME stuff 
 730 // ---------------------------------------------------------------------------- 
 732 void wxFileName::AssignCwd(const wxString
& volume
) 
 734     AssignDir(wxFileName::GetCwd(volume
)); 
 738 wxString 
wxFileName::GetCwd(const wxString
& volume
) 
 740     // if we have the volume, we must get the current directory on this drive 
 741     // and to do this we have to chdir to this volume - at least under Windows, 
 742     // I don't know how to get the current drive on another volume elsewhere 
 745     if ( !volume
.empty() ) 
 748         SetCwd(volume 
+ GetVolumeSeparator()); 
 751     wxString cwd 
= ::wxGetCwd(); 
 753     if ( !volume
.empty() ) 
 761 bool wxFileName::SetCwd() const 
 763     return wxFileName::SetCwd( GetPath() ); 
 766 bool wxFileName::SetCwd( const wxString 
&cwd 
) 
 768     return ::wxSetWorkingDirectory( cwd 
); 
 771 void wxFileName::AssignHomeDir() 
 773     AssignDir(wxFileName::GetHomeDir()); 
 776 wxString 
wxFileName::GetHomeDir() 
 778     return ::wxGetHomeDir(); 
 782 // ---------------------------------------------------------------------------- 
 783 // CreateTempFileName 
 784 // ---------------------------------------------------------------------------- 
 786 #if wxUSE_FILE || wxUSE_FFILE 
 789 #if !defined wx_fdopen && defined HAVE_FDOPEN 
 790     #define wx_fdopen fdopen 
 793 // NB: GetTempFileName() under Windows creates the file, so using 
 794 //     O_EXCL there would fail 
 796     #define wxOPEN_EXCL 0 
 798     #define wxOPEN_EXCL O_EXCL 
 802 #ifdef wxOpenOSFHandle 
 803 #define WX_HAVE_DELETE_ON_CLOSE 
 804 // On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags. 
 806 static int wxOpenWithDeleteOnClose(const wxString
& filename
) 
 808     DWORD access 
= GENERIC_READ 
| GENERIC_WRITE
; 
 810     DWORD disposition 
= OPEN_ALWAYS
; 
 812     DWORD attributes 
= FILE_ATTRIBUTE_TEMPORARY 
| 
 813                        FILE_FLAG_DELETE_ON_CLOSE
; 
 815     HANDLE h 
= ::CreateFile(filename
.t_str(), access
, 0, NULL
, 
 816                             disposition
, attributes
, NULL
); 
 818     return wxOpenOSFHandle(h
, wxO_BINARY
); 
 820 #endif // wxOpenOSFHandle 
 823 // Helper to open the file 
 825 static int wxTempOpen(const wxString
& path
, bool *deleteOnClose
) 
 827 #ifdef WX_HAVE_DELETE_ON_CLOSE 
 829         return wxOpenWithDeleteOnClose(path
); 
 832     *deleteOnClose 
= false; 
 834     return wxOpen(path
, wxO_BINARY 
| O_RDWR 
| O_CREAT 
| wxOPEN_EXCL
, 0600); 
 839 // Helper to open the file and attach it to the wxFFile 
 841 static bool wxTempOpen(wxFFile 
*file
, const wxString
& path
, bool *deleteOnClose
) 
 844     *deleteOnClose 
= false; 
 845     return file
->Open(path
, wxT("w+b")); 
 847     int fd 
= wxTempOpen(path
, deleteOnClose
); 
 850     file
->Attach(wx_fdopen(fd
, "w+b"), path
); 
 851     return file
->IsOpened(); 
 854 #endif // wxUSE_FFILE 
 858     #define WXFILEARGS(x, y) y 
 860     #define WXFILEARGS(x, y) x 
 862     #define WXFILEARGS(x, y) x, y 
 866 // Implementation of wxFileName::CreateTempFileName(). 
 868 static wxString 
wxCreateTempImpl( 
 869         const wxString
& prefix
, 
 870         WXFILEARGS(wxFile 
*fileTemp
, wxFFile 
*ffileTemp
), 
 871         bool *deleteOnClose 
= NULL
) 
 873 #if wxUSE_FILE && wxUSE_FFILE 
 874     wxASSERT(fileTemp 
== NULL 
|| ffileTemp 
== NULL
); 
 876     wxString path
, dir
, name
; 
 877     bool wantDeleteOnClose 
= false; 
 881         // set the result to false initially 
 882         wantDeleteOnClose 
= *deleteOnClose
; 
 883         *deleteOnClose 
= false; 
 887         // easier if it alwasys points to something 
 888         deleteOnClose 
= &wantDeleteOnClose
; 
 891     // use the directory specified by the prefix 
 892     wxFileName::SplitPath(prefix
, &dir
, &name
, NULL 
/* extension */); 
 896         dir 
= wxFileName::GetTempDir(); 
 899 #if defined(__WXWINCE__) 
 900     path 
= dir 
+ wxT("\\") + name
; 
 902     while (wxFileName::FileExists(path
)) 
 904         path 
= dir 
+ wxT("\\") + name 
; 
 909 #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 910     if (!::GetTempFileName(dir
.t_str(), name
.t_str(), 0, 
 911                            wxStringBuffer(path
, MAX_PATH 
+ 1))) 
 913         wxLogLastError(wxT("GetTempFileName")); 
 921     if ( !wxEndsWithPathSeparator(dir
) && 
 922             (name
.empty() || !wxIsPathSeparator(name
[0u])) ) 
 924         path 
+= wxFILE_SEP_PATH
; 
 929 #if defined(HAVE_MKSTEMP) 
 930     // scratch space for mkstemp() 
 931     path 
+= wxT("XXXXXX"); 
 933     // we need to copy the path to the buffer in which mkstemp() can modify it 
 934     wxCharBuffer 
buf(path
.fn_str()); 
 936     // cast is safe because the string length doesn't change 
 937     int fdTemp 
= mkstemp( (char*)(const char*) buf 
); 
 940         // this might be not necessary as mkstemp() on most systems should have 
 941         // already done it but it doesn't hurt neither... 
 944     else // mkstemp() succeeded 
 946         path 
= wxConvFile
.cMB2WX( (const char*) buf 
); 
 949         // avoid leaking the fd 
 952             fileTemp
->Attach(fdTemp
); 
 961             ffileTemp
->Attach(wx_fdopen(fdTemp
, "r+b"), path
); 
 963             ffileTemp
->Open(path
, wxT("r+b")); 
 974 #else // !HAVE_MKSTEMP 
 978     path 
+= wxT("XXXXXX"); 
 980     wxCharBuffer buf 
= wxConvFile
.cWX2MB( path 
); 
 981     if ( !mktemp( (char*)(const char*) buf 
) ) 
 987         path 
= wxConvFile
.cMB2WX( (const char*) buf 
); 
 989 #else // !HAVE_MKTEMP (includes __DOS__) 
 990     // generate the unique file name ourselves 
 991     #if !defined(__DOS__) 
 992     path 
<< (unsigned int)getpid(); 
 997     static const size_t numTries 
= 1000; 
 998     for ( size_t n 
= 0; n 
< numTries
; n
++ ) 
1000         // 3 hex digits is enough for numTries == 1000 < 4096 
1001         pathTry 
= path 
+ wxString::Format(wxT("%.03x"), (unsigned int) n
); 
1002         if ( !wxFileName::FileExists(pathTry
) ) 
1011 #endif // HAVE_MKTEMP/!HAVE_MKTEMP 
1013 #endif // HAVE_MKSTEMP/!HAVE_MKSTEMP 
1015 #endif // Windows/!Windows 
1019         wxLogSysError(_("Failed to create a temporary file name")); 
1025         // open the file - of course, there is a race condition here, this is 
1026         // why we always prefer using mkstemp()... 
1028         if ( fileTemp 
&& !fileTemp
->IsOpened() ) 
1030             *deleteOnClose 
= wantDeleteOnClose
; 
1031             int fd 
= wxTempOpen(path
, deleteOnClose
); 
1033                 fileTemp
->Attach(fd
); 
1040         if ( ffileTemp 
&& !ffileTemp
->IsOpened() ) 
1042             *deleteOnClose 
= wantDeleteOnClose
; 
1043             ok 
= wxTempOpen(ffileTemp
, path
, deleteOnClose
); 
1049             // FIXME: If !ok here should we loop and try again with another 
1050             //        file name?  That is the standard recourse if open(O_EXCL) 
1051             //        fails, though of course it should be protected against 
1052             //        possible infinite looping too. 
1054             wxLogError(_("Failed to open temporary file.")); 
1064 static bool wxCreateTempImpl( 
1065         const wxString
& prefix
, 
1066         WXFILEARGS(wxFile 
*fileTemp
, wxFFile 
*ffileTemp
), 
1069     bool deleteOnClose 
= true; 
1071     *name 
= wxCreateTempImpl(prefix
, 
1072                              WXFILEARGS(fileTemp
, ffileTemp
), 
1075     bool ok 
= !name
->empty(); 
1080     else if (ok 
&& wxRemoveFile(*name
)) 
1088 static void wxAssignTempImpl( 
1090         const wxString
& prefix
, 
1091         WXFILEARGS(wxFile 
*fileTemp
, wxFFile 
*ffileTemp
)) 
1094     tempname 
= wxCreateTempImpl(prefix
, WXFILEARGS(fileTemp
, ffileTemp
)); 
1096     if ( tempname
.empty() ) 
1098         // error, failed to get temp file name 
1103         fn
->Assign(tempname
); 
1108 void wxFileName::AssignTempFileName(const wxString
& prefix
) 
1110     wxAssignTempImpl(this, prefix
, WXFILEARGS(NULL
, NULL
)); 
1114 wxString 
wxFileName::CreateTempFileName(const wxString
& prefix
) 
1116     return wxCreateTempImpl(prefix
, WXFILEARGS(NULL
, NULL
)); 
1119 #endif // wxUSE_FILE || wxUSE_FFILE 
1124 wxString 
wxCreateTempFileName(const wxString
& prefix
, 
1126                               bool *deleteOnClose
) 
1128     return wxCreateTempImpl(prefix
, WXFILEARGS(fileTemp
, NULL
), deleteOnClose
); 
1131 bool wxCreateTempFile(const wxString
& prefix
, 
1135     return wxCreateTempImpl(prefix
, WXFILEARGS(fileTemp
, NULL
), name
); 
1138 void wxFileName::AssignTempFileName(const wxString
& prefix
, wxFile 
*fileTemp
) 
1140     wxAssignTempImpl(this, prefix
, WXFILEARGS(fileTemp
, NULL
)); 
1145 wxFileName::CreateTempFileName(const wxString
& prefix
, wxFile 
*fileTemp
) 
1147     return wxCreateTempFileName(prefix
, fileTemp
); 
1150 #endif // wxUSE_FILE 
1155 wxString 
wxCreateTempFileName(const wxString
& prefix
, 
1157                               bool *deleteOnClose
) 
1159     return wxCreateTempImpl(prefix
, WXFILEARGS(NULL
, fileTemp
), deleteOnClose
); 
1162 bool wxCreateTempFile(const wxString
& prefix
, 
1166     return wxCreateTempImpl(prefix
, WXFILEARGS(NULL
, fileTemp
), name
); 
1170 void wxFileName::AssignTempFileName(const wxString
& prefix
, wxFFile 
*fileTemp
) 
1172     wxAssignTempImpl(this, prefix
, WXFILEARGS(NULL
, fileTemp
)); 
1177 wxFileName::CreateTempFileName(const wxString
& prefix
, wxFFile 
*fileTemp
) 
1179     return wxCreateTempFileName(prefix
, fileTemp
); 
1182 #endif // wxUSE_FFILE 
1185 // ---------------------------------------------------------------------------- 
1186 // directory operations 
1187 // ---------------------------------------------------------------------------- 
1189 // helper of GetTempDir(): check if the given directory exists and return it if 
1190 // it does or an empty string otherwise 
1194 wxString 
CheckIfDirExists(const wxString
& dir
) 
1196     return wxFileName::DirExists(dir
) ? dir 
: wxString(); 
1199 } // anonymous namespace 
1201 wxString 
wxFileName::GetTempDir() 
1203     // first try getting it from environment: this allows overriding the values 
1204     // used by default if the user wants to create temporary files in another 
1206     wxString dir 
= CheckIfDirExists(wxGetenv("TMPDIR")); 
1209         dir 
= CheckIfDirExists(wxGetenv("TMP")); 
1211             dir 
= CheckIfDirExists(wxGetenv("TEMP")); 
1214     // if no environment variables are set, use the system default 
1217 #if defined(__WXWINCE__) 
1218         dir 
= CheckIfDirExists(wxT("\\temp")); 
1219 #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
1220         if ( !::GetTempPath(MAX_PATH
, wxStringBuffer(dir
, MAX_PATH 
+ 1)) ) 
1222             wxLogLastError(wxT("GetTempPath")); 
1224 #elif defined(__WXMAC__) && wxOSX_USE_CARBON 
1225         dir 
= wxMacFindFolderNoSeparator(short(kOnSystemDisk
), kTemporaryFolderType
, kCreateFolder
); 
1226 #endif // systems with native way 
1228     else // we got directory from an environment variable 
1230         // remove any trailing path separators, we don't want to ever return 
1231         // them from this function for consistency 
1232         const size_t lastNonSep 
= dir
.find_last_not_of(GetPathSeparators()); 
1233         if ( lastNonSep 
== wxString::npos 
) 
1235             // the string consists entirely of separators, leave only one 
1236             dir 
= GetPathSeparator(); 
1240             dir
.erase(lastNonSep 
+ 1); 
1244     // fall back to hard coded value 
1247 #ifdef __UNIX_LIKE__ 
1248         dir 
= CheckIfDirExists("/tmp"); 
1250 #endif // __UNIX_LIKE__ 
1257 bool wxFileName::Mkdir( int perm
, int flags 
) const 
1259     return wxFileName::Mkdir(GetPath(), perm
, flags
); 
1262 bool wxFileName::Mkdir( const wxString
& dir
, int perm
, int flags 
) 
1264     if ( flags 
& wxPATH_MKDIR_FULL 
) 
1266         // split the path in components 
1267         wxFileName filename
; 
1268         filename
.AssignDir(dir
); 
1271         if ( filename
.HasVolume()) 
1273             currPath 
<< wxGetVolumeString(filename
.GetVolume(), wxPATH_NATIVE
); 
1276         wxArrayString dirs 
= filename
.GetDirs(); 
1277         size_t count 
= dirs
.GetCount(); 
1278         for ( size_t i 
= 0; i 
< count
; i
++ ) 
1280             if ( i 
> 0 || filename
.IsAbsolute() ) 
1281                 currPath 
+= wxFILE_SEP_PATH
; 
1282             currPath 
+= dirs
[i
]; 
1284             if (!DirExists(currPath
)) 
1286                 if (!wxMkdir(currPath
, perm
)) 
1288                     // no need to try creating further directories 
1298     return ::wxMkdir( dir
, perm 
); 
1301 bool wxFileName::Rmdir(int flags
) const 
1303     return wxFileName::Rmdir( GetPath(), flags 
); 
1306 bool wxFileName::Rmdir(const wxString
& dir
, int flags
) 
1309     if ( flags 
& wxPATH_RMDIR_RECURSIVE 
) 
1311         // SHFileOperation needs double null termination string 
1312         // but without separator at the end of the path 
1314         if ( path
.Last() == wxFILE_SEP_PATH 
) 
1318         SHFILEOPSTRUCT fileop
; 
1319         wxZeroMemory(fileop
); 
1320         fileop
.wFunc 
= FO_DELETE
; 
1321         fileop
.pFrom 
= path
.t_str(); 
1322         fileop
.fFlags 
= FOF_SILENT 
| FOF_NOCONFIRMATION
; 
1324         // FOF_NOERRORUI is not defined in WinCE 
1325         fileop
.fFlags 
|= FOF_NOERRORUI
; 
1328         int ret 
= SHFileOperation(&fileop
); 
1331             // SHFileOperation may return non-Win32 error codes, so the error 
1332             // message can be incorrect 
1333             wxLogApiError(wxT("SHFileOperation"), ret
); 
1339     else if ( flags 
& wxPATH_RMDIR_FULL 
) 
1340 #else // !__WINDOWS__ 
1341     if ( flags 
!= 0 )   // wxPATH_RMDIR_FULL or wxPATH_RMDIR_RECURSIVE 
1342 #endif // !__WINDOWS__ 
1345         if ( path
.Last() != wxFILE_SEP_PATH 
) 
1346             path 
+= wxFILE_SEP_PATH
; 
1350         if ( !d
.IsOpened() ) 
1355         // first delete all subdirectories 
1356         bool cont 
= d
.GetFirst(&filename
, "", wxDIR_DIRS 
| wxDIR_HIDDEN
); 
1359             wxFileName::Rmdir(path 
+ filename
, flags
); 
1360             cont 
= d
.GetNext(&filename
); 
1364         if ( flags 
& wxPATH_RMDIR_RECURSIVE 
) 
1366             // delete all files too 
1367             cont 
= d
.GetFirst(&filename
, "", wxDIR_FILES 
| wxDIR_HIDDEN
); 
1370                 ::wxRemoveFile(path 
+ filename
); 
1371                 cont 
= d
.GetNext(&filename
); 
1374 #endif // !__WINDOWS__ 
1377     return ::wxRmdir(dir
); 
1380 // ---------------------------------------------------------------------------- 
1381 // path normalization 
1382 // ---------------------------------------------------------------------------- 
1384 bool wxFileName::Normalize(int flags
, 
1385                            const wxString
& cwd
, 
1386                            wxPathFormat format
) 
1388     // deal with env vars renaming first as this may seriously change the path 
1389     if ( flags 
& wxPATH_NORM_ENV_VARS 
) 
1391         wxString pathOrig 
= GetFullPath(format
); 
1392         wxString path 
= wxExpandEnvVars(pathOrig
); 
1393         if ( path 
!= pathOrig 
) 
1399     // the existing path components 
1400     wxArrayString dirs 
= GetDirs(); 
1402     // the path to prepend in front to make the path absolute 
1405     format 
= GetFormat(format
); 
1407     // set up the directory to use for making the path absolute later 
1408     if ( (flags 
& wxPATH_NORM_ABSOLUTE
) && !IsAbsolute(format
) ) 
1412             curDir
.AssignCwd(GetVolume()); 
1414         else // cwd provided 
1416             curDir
.AssignDir(cwd
); 
1420     // handle ~ stuff under Unix only 
1421     if ( (format 
== wxPATH_UNIX
) && (flags 
& wxPATH_NORM_TILDE
) && m_relative 
) 
1423         if ( !dirs
.IsEmpty() ) 
1425             wxString dir 
= dirs
[0u]; 
1426             if ( !dir
.empty() && dir
[0u] == wxT('~') ) 
1428                 // to make the path absolute use the home directory 
1429                 curDir
.AssignDir(wxGetUserHome(dir
.c_str() + 1)); 
1435     // transform relative path into abs one 
1436     if ( curDir
.IsOk() ) 
1438         // this path may be relative because it doesn't have the volume name 
1439         // and still have m_relative=true; in this case we shouldn't modify 
1440         // our directory components but just set the current volume 
1441         if ( !HasVolume() && curDir
.HasVolume() ) 
1443             SetVolume(curDir
.GetVolume()); 
1447                 // yes, it was the case - we don't need curDir then 
1452         // finally, prepend curDir to the dirs array 
1453         wxArrayString dirsNew 
= curDir
.GetDirs(); 
1454         WX_PREPEND_ARRAY(dirs
, dirsNew
); 
1456         // if we used e.g. tilde expansion previously and wxGetUserHome didn't 
1457         // return for some reason an absolute path, then curDir maybe not be absolute! 
1458         if ( !curDir
.m_relative 
) 
1460             // we have prepended an absolute path and thus we are now an absolute 
1464         // else if (flags & wxPATH_NORM_ABSOLUTE): 
1465         //   should we warn the user that we didn't manage to make the path absolute? 
1468     // now deal with ".", ".." and the rest 
1470     size_t count 
= dirs
.GetCount(); 
1471     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1473         wxString dir 
= dirs
[n
]; 
1475         if ( flags 
& wxPATH_NORM_DOTS 
) 
1477             if ( dir 
== wxT(".") ) 
1483             if ( dir 
== wxT("..") ) 
1485                 if ( m_dirs
.empty() ) 
1487                     // We have more ".." than directory components so far. 
1488                     // Don't treat this as an error as the path could have been 
1489                     // entered by user so try to handle it reasonably: if the 
1490                     // path is absolute, just ignore the extra ".." because 
1491                     // "/.." is the same as "/". Otherwise, i.e. for relative 
1492                     // paths, keep ".." unchanged because removing it would 
1493                     // modify the file a relative path refers to. 
1498                 else // Normal case, go one step up. 
1509 #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE 
1510     if ( (flags 
& wxPATH_NORM_SHORTCUT
) ) 
1513         if (GetShortcutTarget(GetFullPath(format
), filename
)) 
1521 #if defined(__WIN32__) 
1522     if ( (flags 
& wxPATH_NORM_LONG
) && (format 
== wxPATH_DOS
) ) 
1524         Assign(GetLongPath()); 
1528     // Change case  (this should be kept at the end of the function, to ensure 
1529     // that the path doesn't change any more after we normalize its case) 
1530     if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
1532         m_volume
.MakeLower(); 
1536         // directory entries must be made lower case as well 
1537         count 
= m_dirs
.GetCount(); 
1538         for ( size_t i 
= 0; i 
< count
; i
++ ) 
1540             m_dirs
[i
].MakeLower(); 
1548 bool wxFileName::ReplaceEnvVariable(const wxString
& envname
, 
1549                                     const wxString
& replacementFmtString
, 
1550                                     wxPathFormat format
) 
1552     // look into stringForm for the contents of the given environment variable 
1554     if (envname
.empty() || 
1555         !wxGetEnv(envname
, &val
)) 
1560     wxString stringForm 
= GetPath(wxPATH_GET_VOLUME
, format
); 
1561         // do not touch the file name and the extension 
1563     wxString replacement 
= wxString::Format(replacementFmtString
, envname
); 
1564     stringForm
.Replace(val
, replacement
); 
1566     // Now assign ourselves the modified path: 
1567     Assign(stringForm
, GetFullName(), format
); 
1573 bool wxFileName::ReplaceHomeDir(wxPathFormat format
) 
1575     wxString homedir 
= wxGetHomeDir(); 
1576     if (homedir
.empty()) 
1579     wxString stringForm 
= GetPath(wxPATH_GET_VOLUME
, format
); 
1580         // do not touch the file name and the extension 
1582     stringForm
.Replace(homedir
, "~"); 
1584     // Now assign ourselves the modified path: 
1585     Assign(stringForm
, GetFullName(), format
); 
1590 // ---------------------------------------------------------------------------- 
1591 // get the shortcut target 
1592 // ---------------------------------------------------------------------------- 
1594 // WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions. 
1595 // The .lnk file is a plain text file so it should be easy to 
1596 // make it work. Hint from Google Groups: 
1597 // "If you open up a lnk file, you'll see a 
1598 // number, followed by a pound sign (#), followed by more text. The 
1599 // number is the number of characters that follows the pound sign. The 
1600 // characters after the pound sign are the command line (which _can_ 
1601 // include arguments) to be executed. Any path (e.g. \windows\program 
1602 // files\myapp.exe) that includes spaces needs to be enclosed in 
1603 // quotation marks." 
1605 #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE 
1606 // The following lines are necessary under WinCE 
1607 // #include "wx/msw/private.h" 
1608 // #include <ole2.h> 
1610 #if defined(__WXWINCE__) 
1611 #include <shlguid.h> 
1614 bool wxFileName::GetShortcutTarget(const wxString
& shortcutPath
, 
1615                                    wxString
& targetFilename
, 
1616                                    wxString
* arguments
) const 
1618     wxString path
, file
, ext
; 
1619     wxFileName::SplitPath(shortcutPath
, & path
, & file
, & ext
); 
1623     bool success 
= false; 
1625     // Assume it's not a shortcut if it doesn't end with lnk 
1626     if (ext
.CmpNoCase(wxT("lnk"))!=0) 
1629     // create a ShellLink object 
1630     hres 
= CoCreateInstance(CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, 
1631                             IID_IShellLink
, (LPVOID
*) &psl
); 
1633     if (SUCCEEDED(hres
)) 
1636         hres 
= psl
->QueryInterface( IID_IPersistFile
, (LPVOID 
*) &ppf
); 
1637         if (SUCCEEDED(hres
)) 
1639             WCHAR wsz
[MAX_PATH
]; 
1641             MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, shortcutPath
.mb_str(), -1, wsz
, 
1644             hres 
= ppf
->Load(wsz
, 0); 
1647             if (SUCCEEDED(hres
)) 
1650                 // Wrong prototype in early versions 
1651 #if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2) 
1652                 psl
->GetPath((CHAR
*) buf
, 2048, NULL
, SLGP_UNCPRIORITY
); 
1654                 psl
->GetPath(buf
, 2048, NULL
, SLGP_UNCPRIORITY
); 
1656                 targetFilename 
= wxString(buf
); 
1657                 success 
= (shortcutPath 
!= targetFilename
); 
1659                 psl
->GetArguments(buf
, 2048); 
1661                 if (!args
.empty() && arguments
) 
1673 #endif // __WIN32__ && !__WXWINCE__ 
1676 // ---------------------------------------------------------------------------- 
1677 // absolute/relative paths 
1678 // ---------------------------------------------------------------------------- 
1680 bool wxFileName::IsAbsolute(wxPathFormat format
) const 
1682     // unix paths beginning with ~ are reported as being absolute 
1683     if ( format 
== wxPATH_UNIX 
) 
1685         if ( !m_dirs
.IsEmpty() ) 
1687             wxString dir 
= m_dirs
[0u]; 
1689             if (!dir
.empty() && dir
[0u] == wxT('~')) 
1694     // if our path doesn't start with a path separator, it's not an absolute 
1699     if ( !GetVolumeSeparator(format
).empty() ) 
1701         // this format has volumes and an absolute path must have one, it's not 
1702         // enough to have the full path to be an absolute file under Windows 
1703         if ( GetVolume().empty() ) 
1710 bool wxFileName::MakeRelativeTo(const wxString
& pathBase
, wxPathFormat format
) 
1712     wxFileName fnBase 
= wxFileName::DirName(pathBase
, format
); 
1714     // get cwd only once - small time saving 
1715     wxString cwd 
= wxGetCwd(); 
1716     Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1717     fnBase
.Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1719     bool withCase 
= IsCaseSensitive(format
); 
1721     // we can't do anything if the files live on different volumes 
1722     if ( !GetVolume().IsSameAs(fnBase
.GetVolume(), withCase
) ) 
1728     // same drive, so we don't need our volume 
1731     // remove common directories starting at the top 
1732     while ( !m_dirs
.IsEmpty() && !fnBase
.m_dirs
.IsEmpty() && 
1733                 m_dirs
[0u].IsSameAs(fnBase
.m_dirs
[0u], withCase
) ) 
1736         fnBase
.m_dirs
.RemoveAt(0); 
1739     // add as many ".." as needed 
1740     size_t count 
= fnBase
.m_dirs
.GetCount(); 
1741     for ( size_t i 
= 0; i 
< count
; i
++ ) 
1743         m_dirs
.Insert(wxT(".."), 0u); 
1746     if ( format 
== wxPATH_UNIX 
|| format 
== wxPATH_DOS 
) 
1748         // a directory made relative with respect to itself is '.' under Unix 
1749         // and DOS, by definition (but we don't have to insert "./" for the 
1751         if ( m_dirs
.IsEmpty() && IsDir() ) 
1753             m_dirs
.Add(wxT('.')); 
1763 // ---------------------------------------------------------------------------- 
1764 // filename kind tests 
1765 // ---------------------------------------------------------------------------- 
1767 bool wxFileName::SameAs(const wxFileName
& filepath
, wxPathFormat format
) const 
1769     wxFileName fn1 
= *this, 
1772     // get cwd only once - small time saving 
1773     wxString cwd 
= wxGetCwd(); 
1774     fn1
.Normalize(wxPATH_NORM_ALL 
| wxPATH_NORM_CASE
, cwd
, format
); 
1775     fn2
.Normalize(wxPATH_NORM_ALL 
| wxPATH_NORM_CASE
, cwd
, format
); 
1777     if ( fn1
.GetFullPath() == fn2
.GetFullPath() ) 
1780 #if defined(__UNIX__) 
1781     wxStructStat st1
, st2
; 
1782     if ( wxStat(fn1
.GetFullPath(), &st1
) == 0 && 
1783             wxStat(fn2
.GetFullPath(), &st2
) == 0 ) 
1785         if ( st1
.st_ino 
== st2
.st_ino 
&& st1
.st_dev 
== st2
.st_dev 
) 
1788     //else: It's not an error if one or both files don't exist. 
1789 #endif // defined __UNIX__ 
1795 bool wxFileName::IsCaseSensitive( wxPathFormat format 
) 
1797     // only Unix filenames are truly case-sensitive 
1798     return GetFormat(format
) == wxPATH_UNIX
; 
1802 wxString 
wxFileName::GetForbiddenChars(wxPathFormat format
) 
1804     // Inits to forbidden characters that are common to (almost) all platforms. 
1805     wxString strForbiddenChars 
= wxT("*?"); 
1807     // If asserts, wxPathFormat has been changed. In case of a new path format 
1808     // addition, the following code might have to be updated. 
1809     wxCOMPILE_TIME_ASSERT(wxPATH_MAX 
== 5, wxPathFormatChanged
); 
1810     switch ( GetFormat(format
) ) 
1813             wxFAIL_MSG( wxT("Unknown path format") ); 
1814             // !! Fall through !! 
1820             // On a Mac even names with * and ? are allowed (Tested with OS 
1821             // 9.2.1 and OS X 10.2.5) 
1822             strForbiddenChars 
= wxEmptyString
; 
1826             strForbiddenChars 
+= wxT("\\/:\"<>|"); 
1833     return strForbiddenChars
; 
1837 wxString 
wxFileName::GetVolumeSeparator(wxPathFormat 
WXUNUSED_IN_WINCE(format
)) 
1840     return wxEmptyString
; 
1844     if ( (GetFormat(format
) == wxPATH_DOS
) || 
1845          (GetFormat(format
) == wxPATH_VMS
) ) 
1847         sepVol 
= wxFILE_SEP_DSK
; 
1856 wxString 
wxFileName::GetPathSeparators(wxPathFormat format
) 
1859     switch ( GetFormat(format
) ) 
1862             // accept both as native APIs do but put the native one first as 
1863             // this is the one we use in GetFullPath() 
1864             seps 
<< wxFILE_SEP_PATH_DOS 
<< wxFILE_SEP_PATH_UNIX
; 
1868             wxFAIL_MSG( wxT("Unknown wxPATH_XXX style") ); 
1872             seps 
= wxFILE_SEP_PATH_UNIX
; 
1876             seps 
= wxFILE_SEP_PATH_MAC
; 
1880             seps 
= wxFILE_SEP_PATH_VMS
; 
1888 wxString 
wxFileName::GetPathTerminators(wxPathFormat format
) 
1890     format 
= GetFormat(format
); 
1892     // under VMS the end of the path is ']', not the path separator used to 
1893     // separate the components 
1894     return format 
== wxPATH_VMS 
? wxString(wxT(']')) : GetPathSeparators(format
); 
1898 bool wxFileName::IsPathSeparator(wxChar ch
, wxPathFormat format
) 
1900     // wxString::Find() doesn't work as expected with NUL - it will always find 
1901     // it, so test for it separately 
1902     return ch 
!= wxT('\0') && GetPathSeparators(format
).Find(ch
) != wxNOT_FOUND
; 
1907 wxFileName::IsMSWUniqueVolumeNamePath(const wxString
& path
, wxPathFormat format
) 
1909     // return true if the format used is the DOS/Windows one and the string begins 
1910     // with a Windows unique volume name ("\\?\Volume{guid}\") 
1911     return format 
== wxPATH_DOS 
&& 
1912             path
.length() >= wxMSWUniqueVolumePrefixLength 
&& 
1913              path
.StartsWith(wxS("\\\\?\\Volume{")) && 
1914               path
[wxMSWUniqueVolumePrefixLength 
- 1] == wxFILE_SEP_PATH_DOS
; 
1917 // ---------------------------------------------------------------------------- 
1918 // path components manipulation 
1919 // ---------------------------------------------------------------------------- 
1921 /* static */ bool wxFileName::IsValidDirComponent(const wxString
& dir
) 
1925         wxFAIL_MSG( wxT("empty directory passed to wxFileName::InsertDir()") ); 
1930     const size_t len 
= dir
.length(); 
1931     for ( size_t n 
= 0; n 
< len
; n
++ ) 
1933         if ( dir
[n
] == GetVolumeSeparator() || IsPathSeparator(dir
[n
]) ) 
1935             wxFAIL_MSG( wxT("invalid directory component in wxFileName") ); 
1944 void wxFileName::AppendDir( const wxString
& dir 
) 
1946     if ( IsValidDirComponent(dir
) ) 
1950 void wxFileName::PrependDir( const wxString
& dir 
) 
1955 void wxFileName::InsertDir(size_t before
, const wxString
& dir
) 
1957     if ( IsValidDirComponent(dir
) ) 
1958         m_dirs
.Insert(dir
, before
); 
1961 void wxFileName::RemoveDir(size_t pos
) 
1963     m_dirs
.RemoveAt(pos
); 
1966 // ---------------------------------------------------------------------------- 
1968 // ---------------------------------------------------------------------------- 
1970 void wxFileName::SetFullName(const wxString
& fullname
) 
1972     SplitPath(fullname
, NULL 
/* no volume */, NULL 
/* no path */, 
1973                         &m_name
, &m_ext
, &m_hasExt
); 
1976 wxString 
wxFileName::GetFullName() const 
1978     wxString fullname 
= m_name
; 
1981         fullname 
<< wxFILE_SEP_EXT 
<< m_ext
; 
1987 wxString 
wxFileName::GetPath( int flags
, wxPathFormat format 
) const 
1989     format 
= GetFormat( format 
); 
1993     // return the volume with the path as well if requested 
1994     if ( flags 
& wxPATH_GET_VOLUME 
) 
1996         fullpath 
+= wxGetVolumeString(GetVolume(), format
); 
1999     // the leading character 
2004                 fullpath 
+= wxFILE_SEP_PATH_MAC
; 
2009                 fullpath 
+= wxFILE_SEP_PATH_DOS
; 
2013             wxFAIL_MSG( wxT("Unknown path format") ); 
2019                 fullpath 
+= wxFILE_SEP_PATH_UNIX
; 
2024             // no leading character here but use this place to unset 
2025             // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense 
2026             // as, if I understand correctly, there should never be a dot 
2027             // before the closing bracket 
2028             flags 
&= ~wxPATH_GET_SEPARATOR
; 
2031     if ( m_dirs
.empty() ) 
2033         // there is nothing more 
2037     // then concatenate all the path components using the path separator 
2038     if ( format 
== wxPATH_VMS 
) 
2040         fullpath 
+= wxT('['); 
2043     const size_t dirCount 
= m_dirs
.GetCount(); 
2044     for ( size_t i 
= 0; i 
< dirCount
; i
++ ) 
2049                 if ( m_dirs
[i
] == wxT(".") ) 
2051                     // skip appending ':', this shouldn't be done in this 
2052                     // case as "::" is interpreted as ".." under Unix 
2056                 // convert back from ".." to nothing 
2057                 if ( !m_dirs
[i
].IsSameAs(wxT("..")) ) 
2058                      fullpath 
+= m_dirs
[i
]; 
2062                 wxFAIL_MSG( wxT("Unexpected path format") ); 
2063                 // still fall through 
2067                 fullpath 
+= m_dirs
[i
]; 
2071                 // TODO: What to do with ".." under VMS 
2073                 // convert back from ".." to nothing 
2074                 if ( !m_dirs
[i
].IsSameAs(wxT("..")) ) 
2075                     fullpath 
+= m_dirs
[i
]; 
2079         if ( (flags 
& wxPATH_GET_SEPARATOR
) || (i 
!= dirCount 
- 1) ) 
2080             fullpath 
+= GetPathSeparator(format
); 
2083     if ( format 
== wxPATH_VMS 
) 
2085         fullpath 
+= wxT(']'); 
2091 wxString 
wxFileName::GetFullPath( wxPathFormat format 
) const 
2093     // we already have a function to get the path 
2094     wxString fullpath 
= GetPath(wxPATH_GET_VOLUME 
| wxPATH_GET_SEPARATOR
, 
2097     // now just add the file name and extension to it 
2098     fullpath 
+= GetFullName(); 
2103 // Return the short form of the path (returns identity on non-Windows platforms) 
2104 wxString 
wxFileName::GetShortPath() const 
2106     wxString 
path(GetFullPath()); 
2108 #if defined(__WINDOWS__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
2109     DWORD sz 
= ::GetShortPathName(path
.t_str(), NULL
, 0); 
2113         if ( ::GetShortPathName
 
2116                 wxStringBuffer(pathOut
, sz
), 
2128 // Return the long form of the path (returns identity on non-Windows platforms) 
2129 wxString 
wxFileName::GetLongPath() const 
2132              path 
= GetFullPath(); 
2134 #if defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__) 
2136 #if wxUSE_DYNLIB_CLASS 
2137     typedef DWORD (WINAPI 
*GET_LONG_PATH_NAME
)(const wxChar 
*, wxChar 
*, DWORD
); 
2139     // this is MT-safe as in the worst case we're going to resolve the function 
2140     // twice -- but as the result is the same in both threads, it's ok 
2141     static GET_LONG_PATH_NAME s_pfnGetLongPathName 
= NULL
; 
2142     if ( !s_pfnGetLongPathName 
) 
2144         static bool s_triedToLoad 
= false; 
2146         if ( !s_triedToLoad 
) 
2148             s_triedToLoad 
= true; 
2150             wxDynamicLibrary 
dllKernel(wxT("kernel32")); 
2152             const wxChar
* GetLongPathName 
= wxT("GetLongPathName") 
2157 #endif // Unicode/ANSI 
2159             if ( dllKernel
.HasSymbol(GetLongPathName
) ) 
2161                 s_pfnGetLongPathName 
= (GET_LONG_PATH_NAME
) 
2162                     dllKernel
.GetSymbol(GetLongPathName
); 
2165             // note that kernel32.dll can be unloaded, it stays in memory 
2166             // anyhow as all Win32 programs link to it and so it's safe to call 
2167             // GetLongPathName() even after unloading it 
2171     if ( s_pfnGetLongPathName 
) 
2173         DWORD dwSize 
= (*s_pfnGetLongPathName
)(path
.t_str(), NULL
, 0); 
2176             if ( (*s_pfnGetLongPathName
) 
2179                   wxStringBuffer(pathOut
, dwSize
), 
2187 #endif // wxUSE_DYNLIB_CLASS 
2189     // The OS didn't support GetLongPathName, or some other error. 
2190     // We need to call FindFirstFile on each component in turn. 
2192     WIN32_FIND_DATA findFileData
; 
2196         pathOut 
= GetVolume() + 
2197                   GetVolumeSeparator(wxPATH_DOS
) + 
2198                   GetPathSeparator(wxPATH_DOS
); 
2200         pathOut 
= wxEmptyString
; 
2202     wxArrayString dirs 
= GetDirs(); 
2203     dirs
.Add(GetFullName()); 
2207     size_t count 
= dirs
.GetCount(); 
2208     for ( size_t i 
= 0; i 
< count
; i
++ ) 
2210         const wxString
& dir 
= dirs
[i
]; 
2212         // We're using pathOut to collect the long-name path, but using a 
2213         // temporary for appending the last path component which may be 
2215         tmpPath 
= pathOut 
+ dir
; 
2217         // We must not process "." or ".." here as they would be (unexpectedly) 
2218         // replaced by the corresponding directory names so just leave them 
2221         // And we can't pass a drive and root dir to FindFirstFile (VZ: why?) 
2222         if ( tmpPath
.empty() || dir 
== '.' || dir 
== ".." || 
2223                 tmpPath
.Last() == GetVolumeSeparator(wxPATH_DOS
) ) 
2225             tmpPath 
+= wxFILE_SEP_PATH
; 
2230         hFind 
= ::FindFirstFile(tmpPath
.t_str(), &findFileData
); 
2231         if (hFind 
== INVALID_HANDLE_VALUE
) 
2233             // Error: most likely reason is that path doesn't exist, so 
2234             // append any unprocessed parts and return 
2235             for ( i 
+= 1; i 
< count
; i
++ ) 
2236                 tmpPath 
+= wxFILE_SEP_PATH 
+ dirs
[i
]; 
2241         pathOut 
+= findFileData
.cFileName
; 
2242         if ( (i 
< (count
-1)) ) 
2243             pathOut 
+= wxFILE_SEP_PATH
; 
2249 #endif // Win32/!Win32 
2254 wxPathFormat 
wxFileName::GetFormat( wxPathFormat format 
) 
2256     if (format 
== wxPATH_NATIVE
) 
2258 #if defined(__WINDOWS__) || defined(__OS2__) || defined(__DOS__) 
2259         format 
= wxPATH_DOS
; 
2260 #elif defined(__VMS) 
2261         format 
= wxPATH_VMS
; 
2263         format 
= wxPATH_UNIX
; 
2269 #ifdef wxHAS_FILESYSTEM_VOLUMES 
2272 wxString 
wxFileName::GetVolumeString(char drive
, int flags
) 
2274     wxASSERT_MSG( !(flags 
& ~wxPATH_GET_SEPARATOR
), "invalid flag specified" ); 
2276     wxString 
vol(drive
); 
2277     vol 
+= wxFILE_SEP_DSK
; 
2278     if ( flags 
& wxPATH_GET_SEPARATOR 
) 
2279         vol 
+= wxFILE_SEP_PATH
; 
2284 #endif // wxHAS_FILESYSTEM_VOLUMES 
2286 // ---------------------------------------------------------------------------- 
2287 // path splitting function 
2288 // ---------------------------------------------------------------------------- 
2292 wxFileName::SplitVolume(const wxString
& fullpathWithVolume
, 
2293                         wxString 
*pstrVolume
, 
2295                         wxPathFormat format
) 
2297     format 
= GetFormat(format
); 
2299     wxString fullpath 
= fullpathWithVolume
; 
2301     if ( IsMSWUniqueVolumeNamePath(fullpath
, format
) ) 
2303         // special Windows unique volume names hack: transform 
2304         // \\?\Volume{guid}\path into Volume{guid}:path 
2305         // note: this check must be done before the check for UNC path 
2307         // we know the last backslash from the unique volume name is located 
2308         // there from IsMSWUniqueVolumeNamePath 
2309         fullpath
[wxMSWUniqueVolumePrefixLength 
- 1] = wxFILE_SEP_DSK
; 
2311         // paths starting with a unique volume name should always be absolute 
2312         fullpath
.insert(wxMSWUniqueVolumePrefixLength
, 1, wxFILE_SEP_PATH_DOS
); 
2314         // remove the leading "\\?\" part 
2315         fullpath
.erase(0, 4); 
2317     else if ( IsUNCPath(fullpath
, format
) ) 
2319         // special Windows UNC paths hack: transform \\share\path into share:path 
2321         fullpath
.erase(0, 2); 
2323         size_t posFirstSlash 
= 
2324             fullpath
.find_first_of(GetPathTerminators(format
)); 
2325         if ( posFirstSlash 
!= wxString::npos 
) 
2327             fullpath
[posFirstSlash
] = wxFILE_SEP_DSK
; 
2329             // UNC paths are always absolute, right? (FIXME) 
2330             fullpath
.insert(posFirstSlash 
+ 1, 1, wxFILE_SEP_PATH_DOS
); 
2334     // We separate the volume here 
2335     if ( format 
== wxPATH_DOS 
|| format 
== wxPATH_VMS 
) 
2337         wxString sepVol 
= GetVolumeSeparator(format
); 
2339         // we have to exclude the case of a colon in the very beginning of the 
2340         // string as it can't be a volume separator (nor can this be a valid 
2341         // DOS file name at all but we'll leave dealing with this to our caller) 
2342         size_t posFirstColon 
= fullpath
.find_first_of(sepVol
); 
2343         if ( posFirstColon 
&& posFirstColon 
!= wxString::npos 
) 
2347                 *pstrVolume 
= fullpath
.Left(posFirstColon
); 
2350             // remove the volume name and the separator from the full path 
2351             fullpath
.erase(0, posFirstColon 
+ sepVol
.length()); 
2356         *pstrPath 
= fullpath
; 
2360 void wxFileName::SplitPath(const wxString
& fullpathWithVolume
, 
2361                            wxString 
*pstrVolume
, 
2366                            wxPathFormat format
) 
2368     format 
= GetFormat(format
); 
2371     SplitVolume(fullpathWithVolume
, pstrVolume
, &fullpath
, format
); 
2373     // find the positions of the last dot and last path separator in the path 
2374     size_t posLastDot 
= fullpath
.find_last_of(wxFILE_SEP_EXT
); 
2375     size_t posLastSlash 
= fullpath
.find_last_of(GetPathTerminators(format
)); 
2377     // check whether this dot occurs at the very beginning of a path component 
2378     if ( (posLastDot 
!= wxString::npos
) && 
2380             IsPathSeparator(fullpath
[posLastDot 
- 1]) || 
2381             (format 
== wxPATH_VMS 
&& fullpath
[posLastDot 
- 1] == wxT(']'))) ) 
2383         // dot may be (and commonly -- at least under Unix -- is) the first 
2384         // character of the filename, don't treat the entire filename as 
2385         // extension in this case 
2386         posLastDot 
= wxString::npos
; 
2389     // if we do have a dot and a slash, check that the dot is in the name part 
2390     if ( (posLastDot 
!= wxString::npos
) && 
2391          (posLastSlash 
!= wxString::npos
) && 
2392          (posLastDot 
< posLastSlash
) ) 
2394         // the dot is part of the path, not the start of the extension 
2395         posLastDot 
= wxString::npos
; 
2398     // now fill in the variables provided by user 
2401         if ( posLastSlash 
== wxString::npos 
) 
2408             // take everything up to the path separator but take care to make 
2409             // the path equal to something like '/', not empty, for the files 
2410             // immediately under root directory 
2411             size_t len 
= posLastSlash
; 
2413             // this rule does not apply to mac since we do not start with colons (sep) 
2414             // except for relative paths 
2415             if ( !len 
&& format 
!= wxPATH_MAC
) 
2418             *pstrPath 
= fullpath
.Left(len
); 
2420             // special VMS hack: remove the initial bracket 
2421             if ( format 
== wxPATH_VMS 
) 
2423                 if ( (*pstrPath
)[0u] == wxT('[') ) 
2424                     pstrPath
->erase(0, 1); 
2431         // take all characters starting from the one after the last slash and 
2432         // up to, but excluding, the last dot 
2433         size_t nStart 
= posLastSlash 
== wxString::npos 
? 0 : posLastSlash 
+ 1; 
2435         if ( posLastDot 
== wxString::npos 
) 
2437             // take all until the end 
2438             count 
= wxString::npos
; 
2440         else if ( posLastSlash 
== wxString::npos 
) 
2444         else // have both dot and slash 
2446             count 
= posLastDot 
- posLastSlash 
- 1; 
2449         *pstrName 
= fullpath
.Mid(nStart
, count
); 
2452     // finally deal with the extension here: we have an added complication that 
2453     // extension may be empty (but present) as in "foo." where trailing dot 
2454     // indicates the empty extension at the end -- and hence we must remember 
2455     // that we have it independently of pstrExt 
2456     if ( posLastDot 
== wxString::npos 
) 
2466         // take everything after the dot 
2468             *pstrExt 
= fullpath
.Mid(posLastDot 
+ 1); 
2475 void wxFileName::SplitPath(const wxString
& fullpath
, 
2479                            wxPathFormat format
) 
2482     SplitPath(fullpath
, &volume
, path
, name
, ext
, format
); 
2486         path
->Prepend(wxGetVolumeString(volume
, format
)); 
2491 wxString 
wxFileName::StripExtension(const wxString
& fullpath
) 
2493     wxFileName 
fn(fullpath
); 
2495     return fn
.GetFullPath(); 
2498 // ---------------------------------------------------------------------------- 
2500 // ---------------------------------------------------------------------------- 
2504 bool wxFileName::SetTimes(const wxDateTime 
*dtAccess
, 
2505                           const wxDateTime 
*dtMod
, 
2506                           const wxDateTime 
*dtCreate
) const 
2508 #if defined(__WIN32__) 
2509     FILETIME ftAccess
, ftCreate
, ftWrite
; 
2512         ConvertWxToFileTime(&ftCreate
, *dtCreate
); 
2514         ConvertWxToFileTime(&ftAccess
, *dtAccess
); 
2516         ConvertWxToFileTime(&ftWrite
, *dtMod
); 
2522         if ( wxGetOsVersion() == wxOS_WINDOWS_9X 
) 
2524             wxLogError(_("Setting directory access times is not supported " 
2525                          "under this OS version")); 
2530         flags 
= FILE_FLAG_BACKUP_SEMANTICS
; 
2534         path 
= GetFullPath(); 
2538     wxFileHandle 
fh(path
, wxFileHandle::WriteAttr
, flags
); 
2541         if ( ::SetFileTime(fh
, 
2542                            dtCreate 
? &ftCreate 
: NULL
, 
2543                            dtAccess 
? &ftAccess 
: NULL
, 
2544                            dtMod 
? &ftWrite 
: NULL
) ) 
2549 #elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) 
2550     wxUnusedVar(dtCreate
); 
2552     if ( !dtAccess 
&& !dtMod 
) 
2554         // can't modify the creation time anyhow, don't try 
2558     // if dtAccess or dtMod is not specified, use the other one (which must be 
2559     // non NULL because of the test above) for both times 
2561     utm
.actime 
= dtAccess 
? dtAccess
->GetTicks() : dtMod
->GetTicks(); 
2562     utm
.modtime 
= dtMod 
? dtMod
->GetTicks() : dtAccess
->GetTicks(); 
2563     if ( utime(GetFullPath().fn_str(), &utm
) == 0 ) 
2567 #else // other platform 
2568     wxUnusedVar(dtAccess
); 
2570     wxUnusedVar(dtCreate
); 
2573     wxLogSysError(_("Failed to modify file times for '%s'"), 
2574                   GetFullPath().c_str()); 
2579 bool wxFileName::Touch() const 
2581 #if defined(__UNIX_LIKE__) 
2582     // under Unix touching file is simple: just pass NULL to utime() 
2583     if ( utime(GetFullPath().fn_str(), NULL
) == 0 ) 
2588     wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); 
2591 #else // other platform 
2592     wxDateTime dtNow 
= wxDateTime::Now(); 
2594     return SetTimes(&dtNow
, &dtNow
, NULL 
/* don't change create time */); 
2598 bool wxFileName::GetTimes(wxDateTime 
*dtAccess
, 
2600                           wxDateTime 
*dtCreate
) const 
2602 #if defined(__WIN32__) 
2603     // we must use different methods for the files and directories under 
2604     // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and 
2605     // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and 
2608     FILETIME ftAccess
, ftCreate
, ftWrite
; 
2611         // implemented in msw/dir.cpp 
2612         extern bool wxGetDirectoryTimes(const wxString
& dirname
, 
2613                                         FILETIME 
*, FILETIME 
*, FILETIME 
*); 
2615         // we should pass the path without the trailing separator to 
2616         // wxGetDirectoryTimes() 
2617         ok 
= wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME
), 
2618                                  &ftAccess
, &ftCreate
, &ftWrite
); 
2622         wxFileHandle 
fh(GetFullPath(), wxFileHandle::ReadAttr
); 
2625             ok 
= ::GetFileTime(fh
, 
2626                                dtCreate 
? &ftCreate 
: NULL
, 
2627                                dtAccess 
? &ftAccess 
: NULL
, 
2628                                dtMod 
? &ftWrite 
: NULL
) != 0; 
2639             ConvertFileTimeToWx(dtCreate
, ftCreate
); 
2641             ConvertFileTimeToWx(dtAccess
, ftAccess
); 
2643             ConvertFileTimeToWx(dtMod
, ftWrite
); 
2647 #elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__)) 
2648     // no need to test for IsDir() here 
2650     if ( wxStat( GetFullPath(), &stBuf
) == 0 ) 
2652         // Android defines st_*time fields as unsigned long, but time_t as long, 
2653         // hence the static_casts. 
2655             dtAccess
->Set(static_cast<time_t>(stBuf
.st_atime
)); 
2657             dtMod
->Set(static_cast<time_t>(stBuf
.st_mtime
)); 
2659             dtCreate
->Set(static_cast<time_t>(stBuf
.st_ctime
)); 
2663 #else // other platform 
2664     wxUnusedVar(dtAccess
); 
2666     wxUnusedVar(dtCreate
); 
2669     wxLogSysError(_("Failed to retrieve file times for '%s'"), 
2670                   GetFullPath().c_str()); 
2675 #endif // wxUSE_DATETIME 
2678 // ---------------------------------------------------------------------------- 
2679 // file size functions 
2680 // ---------------------------------------------------------------------------- 
2685 wxULongLong 
wxFileName::GetSize(const wxString 
&filename
) 
2687     if (!wxFileExists(filename
)) 
2688         return wxInvalidSize
; 
2690 #if defined(__WIN32__) 
2691     wxFileHandle 
f(filename
, wxFileHandle::ReadAttr
); 
2693         return wxInvalidSize
; 
2695     DWORD lpFileSizeHigh
; 
2696     DWORD ret 
= GetFileSize(f
, &lpFileSizeHigh
); 
2697     if ( ret 
== INVALID_FILE_SIZE 
&& ::GetLastError() != NO_ERROR 
) 
2698         return wxInvalidSize
; 
2700     return wxULongLong(lpFileSizeHigh
, ret
); 
2701 #else // ! __WIN32__ 
2703     if (wxStat( filename
, &st
) != 0) 
2704         return wxInvalidSize
; 
2705     return wxULongLong(st
.st_size
); 
2710 wxString 
wxFileName::GetHumanReadableSize(const wxULongLong 
&bs
, 
2711                                           const wxString 
&nullsize
, 
2713                                           wxSizeConvention conv
) 
2715     // deal with trivial case first 
2716     if ( bs 
== 0 || bs 
== wxInvalidSize 
) 
2719     // depending on the convention used the multiplier may be either 1000 or 
2720     // 1024 and the binary infix may be empty (for "KB") or "i" (for "KiB") 
2721     double multiplier 
= 1024.; 
2726         case wxSIZE_CONV_TRADITIONAL
: 
2727             // nothing to do, this corresponds to the default values of both 
2728             // the multiplier and infix string 
2731         case wxSIZE_CONV_IEC
: 
2735         case wxSIZE_CONV_SI
: 
2740     const double kiloByteSize 
= multiplier
; 
2741     const double megaByteSize 
= multiplier 
* kiloByteSize
; 
2742     const double gigaByteSize 
= multiplier 
* megaByteSize
; 
2743     const double teraByteSize 
= multiplier 
* gigaByteSize
; 
2745     const double bytesize 
= bs
.ToDouble(); 
2748     if ( bytesize 
< kiloByteSize 
) 
2749         result
.Printf("%s B", bs
.ToString()); 
2750     else if ( bytesize 
< megaByteSize 
) 
2751         result
.Printf("%.*f K%sB", precision
, bytesize
/kiloByteSize
, biInfix
); 
2752     else if (bytesize 
< gigaByteSize
) 
2753         result
.Printf("%.*f M%sB", precision
, bytesize
/megaByteSize
, biInfix
); 
2754     else if (bytesize 
< teraByteSize
) 
2755         result
.Printf("%.*f G%sB", precision
, bytesize
/gigaByteSize
, biInfix
); 
2757         result
.Printf("%.*f T%sB", precision
, bytesize
/teraByteSize
, biInfix
); 
2762 wxULongLong 
wxFileName::GetSize() const 
2764     return GetSize(GetFullPath()); 
2767 wxString 
wxFileName::GetHumanReadableSize(const wxString
& failmsg
, 
2769                                           wxSizeConvention conv
) const 
2771     return GetHumanReadableSize(GetSize(), failmsg
, precision
, conv
); 
2774 #endif // wxUSE_LONGLONG 
2776 // ---------------------------------------------------------------------------- 
2777 // Mac-specific functions 
2778 // ---------------------------------------------------------------------------- 
2780 #if defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON 
2785 class MacDefaultExtensionRecord
 
2788     MacDefaultExtensionRecord() 
2794     // default copy ctor, assignment operator and dtor are ok 
2796     MacDefaultExtensionRecord(const wxString
& ext
, OSType type
, OSType creator
) 
2800         m_creator 
= creator
; 
2808 WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord
, MacDefaultExtensionArray
); 
2810 bool gMacDefaultExtensionsInited 
= false; 
2812 #include "wx/arrimpl.cpp" 
2814 WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray
); 
2816 MacDefaultExtensionArray gMacDefaultExtensions
; 
2818 // load the default extensions 
2819 const MacDefaultExtensionRecord gDefaults
[] = 
2821     MacDefaultExtensionRecord( "txt", 'TEXT', 'ttxt' ), 
2822     MacDefaultExtensionRecord( "tif", 'TIFF', '****' ), 
2823     MacDefaultExtensionRecord( "jpg", 'JPEG', '****' ), 
2826 void MacEnsureDefaultExtensionsLoaded() 
2828     if ( !gMacDefaultExtensionsInited 
) 
2830         // we could load the pc exchange prefs here too 
2831         for ( size_t i 
= 0 ; i 
< WXSIZEOF( gDefaults 
) ; ++i 
) 
2833             gMacDefaultExtensions
.Add( gDefaults
[i
] ) ; 
2835         gMacDefaultExtensionsInited 
= true; 
2839 } // anonymous namespace 
2841 bool wxFileName::MacSetTypeAndCreator( wxUint32 type 
, wxUint32 creator 
) 
2844     FSCatalogInfo catInfo
; 
2847     if ( wxMacPathToFSRef( GetFullPath() , &fsRef 
) == noErr 
) 
2849         if ( FSGetCatalogInfo (&fsRef
, kFSCatInfoFinderInfo
, &catInfo
, NULL
, NULL
, NULL
) == noErr 
) 
2851             finfo 
= (FileInfo
*)&catInfo
.finderInfo
; 
2852             finfo
->fileType 
= type 
; 
2853             finfo
->fileCreator 
= creator 
; 
2854             FSSetCatalogInfo( &fsRef
, kFSCatInfoFinderInfo
, &catInfo 
) ; 
2861 bool wxFileName::MacGetTypeAndCreator( wxUint32 
*type 
, wxUint32 
*creator 
) const 
2864     FSCatalogInfo catInfo
; 
2867     if ( wxMacPathToFSRef( GetFullPath() , &fsRef 
) == noErr 
) 
2869         if ( FSGetCatalogInfo (&fsRef
, kFSCatInfoFinderInfo
, &catInfo
, NULL
, NULL
, NULL
) == noErr 
) 
2871             finfo 
= (FileInfo
*)&catInfo
.finderInfo
; 
2872             *type 
= finfo
->fileType 
; 
2873             *creator 
= finfo
->fileCreator 
; 
2880 bool wxFileName::MacSetDefaultTypeAndCreator() 
2882     wxUint32 type 
, creator 
; 
2883     if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type 
, 
2886         return MacSetTypeAndCreator( type 
, creator 
) ; 
2891 bool wxFileName::MacFindDefaultTypeAndCreator( const wxString
& ext 
, wxUint32 
*type 
, wxUint32 
*creator 
) 
2893   MacEnsureDefaultExtensionsLoaded() ; 
2894   wxString extl 
= ext
.Lower() ; 
2895   for( int i 
= gMacDefaultExtensions
.Count() - 1 ; i 
>= 0 ; --i 
) 
2897     if ( gMacDefaultExtensions
.Item(i
).m_ext 
== extl 
) 
2899       *type 
= gMacDefaultExtensions
.Item(i
).m_type 
; 
2900       *creator 
= gMacDefaultExtensions
.Item(i
).m_creator 
; 
2907 void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString
& ext 
, wxUint32 type 
, wxUint32 creator 
) 
2909   MacEnsureDefaultExtensionsLoaded(); 
2910   MacDefaultExtensionRecord 
rec(ext
.Lower(), type
, creator
); 
2911   gMacDefaultExtensions
.Add( rec 
); 
2914 #endif // defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON