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 and Mac OS X under CodeWarrior 7 format, 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/types.h> 
 125 #include <sys/stat.h> 
 136 #include <sys/utime.h> 
 137 #include <sys/stat.h> 
 148 #define MAX_PATH _MAX_PATH 
 153 extern const wxULongLong wxInvalidSize 
= (unsigned)-1; 
 154 #endif // wxUSE_LONGLONG 
 157     // this define is missing from VC6 headers 
 158     #ifndef INVALID_FILE_ATTRIBUTES 
 159         #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) 
 166 // ---------------------------------------------------------------------------- 
 168 // ---------------------------------------------------------------------------- 
 170 // small helper class which opens and closes the file - we use it just to get 
 171 // a file handle for the given file name to pass it to some Win32 API function 
 172 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
 183     wxFileHandle(const wxString
& filename
, OpenMode mode
, int flags 
= 0) 
 185         // be careful and use FILE_{READ,WRITE}_ATTRIBUTES here instead of the 
 186         // usual GENERIC_{READ,WRITE} as we don't want the file access time to 
 187         // be changed when we open it because this class is used for setting 
 188         // access time (see #10567) 
 189         m_hFile 
= ::CreateFile
 
 191                      filename
.fn_str(),             // name 
 192                      mode 
== ReadAttr 
? FILE_READ_ATTRIBUTES    
// access mask 
 193                                       : FILE_WRITE_ATTRIBUTES
, 
 194                      FILE_SHARE_READ 
|              // sharing mode 
 195                      FILE_SHARE_WRITE
,              // (allow everything) 
 196                      NULL
,                          // no secutity attr 
 197                      OPEN_EXISTING
,                 // creation disposition 
 199                      NULL                           
// no template file 
 202         if ( m_hFile 
== INVALID_HANDLE_VALUE 
) 
 204             if ( mode 
== ReadAttr 
) 
 206                 wxLogSysError(_("Failed to open '%s' for reading"), 
 211                 wxLogSysError(_("Failed to open '%s' for writing"), 
 219         if ( m_hFile 
!= INVALID_HANDLE_VALUE 
) 
 221             if ( !::CloseHandle(m_hFile
) ) 
 223                 wxLogSysError(_("Failed to close file handle")); 
 228     // return true only if the file could be opened successfully 
 229     bool IsOk() const { return m_hFile 
!= INVALID_HANDLE_VALUE
; } 
 232     operator HANDLE() const { return m_hFile
; } 
 240 // ---------------------------------------------------------------------------- 
 242 // ---------------------------------------------------------------------------- 
 244 #if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__) 
 246 // convert between wxDateTime and FILETIME which is a 64-bit value representing 
 247 // the number of 100-nanosecond intervals since January 1, 1601. 
 249 static void ConvertFileTimeToWx(wxDateTime 
*dt
, const FILETIME 
&ft
) 
 251     FILETIME ftcopy 
= ft
; 
 253     if ( !::FileTimeToLocalFileTime(&ftcopy
, &ftLocal
) ) 
 255         wxLogLastError(wxT("FileTimeToLocalFileTime")); 
 259     if ( !::FileTimeToSystemTime(&ftLocal
, &st
) ) 
 261         wxLogLastError(wxT("FileTimeToSystemTime")); 
 264     dt
->Set(st
.wDay
, wxDateTime::Month(st
.wMonth 
- 1), st
.wYear
, 
 265             st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
); 
 268 static void ConvertWxToFileTime(FILETIME 
*ft
, const wxDateTime
& dt
) 
 271     st
.wDay 
= dt
.GetDay(); 
 272     st
.wMonth 
= (WORD
)(dt
.GetMonth() + 1); 
 273     st
.wYear 
= (WORD
)dt
.GetYear(); 
 274     st
.wHour 
= dt
.GetHour(); 
 275     st
.wMinute 
= dt
.GetMinute(); 
 276     st
.wSecond 
= dt
.GetSecond(); 
 277     st
.wMilliseconds 
= dt
.GetMillisecond(); 
 280     if ( !::SystemTimeToFileTime(&st
, &ftLocal
) ) 
 282         wxLogLastError(wxT("SystemTimeToFileTime")); 
 285     if ( !::LocalFileTimeToFileTime(&ftLocal
, ft
) ) 
 287         wxLogLastError(wxT("LocalFileTimeToFileTime")); 
 291 #endif // wxUSE_DATETIME && __WIN32__ 
 293 // return a string with the volume par 
 294 static wxString 
wxGetVolumeString(const wxString
& volume
, wxPathFormat format
) 
 298     if ( !volume
.empty() ) 
 300         format 
= wxFileName::GetFormat(format
); 
 302         // Special Windows UNC paths hack, part 2: undo what we did in 
 303         // SplitPath() and make an UNC path if we have a drive which is not a 
 304         // single letter (hopefully the network shares can't be one letter only 
 305         // although I didn't find any authoritative docs on this) 
 306         if ( format 
== wxPATH_DOS 
&& volume
.length() > 1 ) 
 308             // We also have to check for Windows unique volume names here and 
 309             // return it with '\\?\' prepended to it 
 310             if ( wxFileName::IsMSWUniqueVolumeNamePath("\\\\?\\" + volume 
+ "\\", 
 313                 path 
<< "\\\\?\\" << volume
; 
 317                 // it must be a UNC path 
 318                 path 
<< wxFILE_SEP_PATH_DOS 
<< wxFILE_SEP_PATH_DOS 
<< volume
; 
 321         else if  ( format 
== wxPATH_DOS 
|| format 
== wxPATH_VMS 
) 
 323             path 
<< volume 
<< wxFileName::GetVolumeSeparator(format
); 
 331 // return true if the character is a DOS path separator i.e. either a slash or 
 333 inline bool IsDOSPathSep(wxUniChar ch
) 
 335     return ch 
== wxFILE_SEP_PATH_DOS 
|| ch 
== wxFILE_SEP_PATH_UNIX
; 
 338 // return true if the format used is the DOS/Windows one and the string looks 
 340 static bool IsUNCPath(const wxString
& path
, wxPathFormat format
) 
 342     return format 
== wxPATH_DOS 
&& 
 343                 path
.length() >= 4 && // "\\a" can't be a UNC path 
 344                     IsDOSPathSep(path
[0u]) && 
 345                         IsDOSPathSep(path
[1u]) && 
 346                             !IsDOSPathSep(path
[2u]); 
 349 // ---------------------------------------------------------------------------- 
 351 // ---------------------------------------------------------------------------- 
 353 // length of \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ string 
 354 static const size_t wxMSWUniqueVolumePrefixLength 
= 49; 
 356 } // anonymous namespace 
 358 // ============================================================================ 
 360 // ============================================================================ 
 362 // ---------------------------------------------------------------------------- 
 363 // wxFileName construction 
 364 // ---------------------------------------------------------------------------- 
 366 void wxFileName::Assign( const wxFileName 
&filepath 
) 
 368     m_volume 
= filepath
.GetVolume(); 
 369     m_dirs 
= filepath
.GetDirs(); 
 370     m_name 
= filepath
.GetName(); 
 371     m_ext 
= filepath
.GetExt(); 
 372     m_relative 
= filepath
.m_relative
; 
 373     m_hasExt 
= filepath
.m_hasExt
; 
 376 void wxFileName::Assign(const wxString
& volume
, 
 377                         const wxString
& path
, 
 378                         const wxString
& name
, 
 383     // we should ignore paths which look like UNC shares because we already 
 384     // have the volume here and the UNC notation (\\server\path) is only valid 
 385     // for paths which don't start with a volume, so prevent SetPath() from 
 386     // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path 
 388     // note also that this is a rather ugly way to do what we want (passing 
 389     // some kind of flag telling to ignore UNC paths to SetPath() would be 
 390     // better) but this is the safest thing to do to avoid breaking backwards 
 391     // compatibility in 2.8 
 392     if ( IsUNCPath(path
, format
) ) 
 394         // remove one of the 2 leading backslashes to ensure that it's not 
 395         // recognized as an UNC path by SetPath() 
 396         wxString 
pathNonUNC(path
, 1, wxString::npos
); 
 397         SetPath(pathNonUNC
, format
); 
 399     else // no UNC complications 
 401         SetPath(path
, format
); 
 411 void wxFileName::SetPath( const wxString
& pathOrig
, wxPathFormat format 
) 
 415     if ( pathOrig
.empty() ) 
 423     format 
= GetFormat( format 
); 
 425     // 0) deal with possible volume part first 
 428     SplitVolume(pathOrig
, &volume
, &path
, format
); 
 429     if ( !volume
.empty() ) 
 436     // 1) Determine if the path is relative or absolute. 
 440         // we had only the volume 
 444     wxChar leadingChar 
= path
[0u]; 
 449             m_relative 
= leadingChar 
== wxT(':'); 
 451             // We then remove a leading ":". The reason is in our 
 452             // storage form for relative paths: 
 453             // ":dir:file.txt" actually means "./dir/file.txt" in 
 454             // DOS notation and should get stored as 
 455             // (relative) (dir) (file.txt) 
 456             // "::dir:file.txt" actually means "../dir/file.txt" 
 457             // stored as (relative) (..) (dir) (file.txt) 
 458             // This is important only for the Mac as an empty dir 
 459             // actually means <UP>, whereas under DOS, double 
 460             // slashes can be ignored: "\\\\" is the same as "\\". 
 466             // TODO: what is the relative path format here? 
 471             wxFAIL_MSG( wxT("Unknown path format") ); 
 472             // !! Fall through !! 
 475             m_relative 
= leadingChar 
!= wxT('/'); 
 479             m_relative 
= !IsPathSeparator(leadingChar
, format
); 
 484     // 2) Break up the path into its members. If the original path 
 485     //    was just "/" or "\\", m_dirs will be empty. We know from 
 486     //    the m_relative field, if this means "nothing" or "root dir". 
 488     wxStringTokenizer 
tn( path
, GetPathSeparators(format
) ); 
 490     while ( tn
.HasMoreTokens() ) 
 492         wxString token 
= tn
.GetNextToken(); 
 494         // Remove empty token under DOS and Unix, interpret them 
 498             if (format 
== wxPATH_MAC
) 
 499                 m_dirs
.Add( wxT("..") ); 
 509 void wxFileName::Assign(const wxString
& fullpath
, 
 512     wxString volume
, path
, name
, ext
; 
 514     SplitPath(fullpath
, &volume
, &path
, &name
, &ext
, &hasExt
, format
); 
 516     Assign(volume
, path
, name
, ext
, hasExt
, format
); 
 519 void wxFileName::Assign(const wxString
& fullpathOrig
, 
 520                         const wxString
& fullname
, 
 523     // always recognize fullpath as directory, even if it doesn't end with a 
 525     wxString fullpath 
= fullpathOrig
; 
 526     if ( !fullpath
.empty() && !wxEndsWithPathSeparator(fullpath
) ) 
 528         fullpath 
+= GetPathSeparator(format
); 
 531     wxString volume
, path
, name
, ext
; 
 534     // do some consistency checks: the name should be really just the filename 
 535     // and the path should be really just a path 
 536     wxString volDummy
, pathDummy
, nameDummy
, extDummy
; 
 538     SplitPath(fullname
, &volDummy
, &pathDummy
, &name
, &ext
, &hasExt
, format
); 
 540     wxASSERT_MSG( volDummy
.empty() && pathDummy
.empty(), 
 541                   wxT("the file name shouldn't contain the path") ); 
 543     SplitPath(fullpath
, &volume
, &path
, &nameDummy
, &extDummy
, format
); 
 546    // This test makes no sense on an OpenVMS system. 
 547    wxASSERT_MSG( nameDummy
.empty() && extDummy
.empty(), 
 548                   wxT("the path shouldn't contain file name nor extension") ); 
 550     Assign(volume
, path
, name
, ext
, hasExt
, format
); 
 553 void wxFileName::Assign(const wxString
& pathOrig
, 
 554                         const wxString
& name
, 
 560     SplitVolume(pathOrig
, &volume
, &path
, format
); 
 562     Assign(volume
, path
, name
, ext
, format
); 
 565 void wxFileName::AssignDir(const wxString
& dir
, wxPathFormat format
) 
 567     Assign(dir
, wxEmptyString
, format
); 
 570 void wxFileName::Clear() 
 576     m_ext 
= wxEmptyString
; 
 578     // we don't have any absolute path for now 
 586 wxFileName 
wxFileName::FileName(const wxString
& file
, wxPathFormat format
) 
 588     return wxFileName(file
, format
); 
 592 wxFileName 
wxFileName::DirName(const wxString
& dir
, wxPathFormat format
) 
 595     fn
.AssignDir(dir
, format
); 
 599 // ---------------------------------------------------------------------------- 
 601 // ---------------------------------------------------------------------------- 
 603 bool wxFileName::FileExists() const 
 605     return wxFileName::FileExists( GetFullPath() ); 
 609 bool wxFileName::FileExists( const wxString 
&filePath 
) 
 611 #if defined(__WXPALMOS__) 
 613 #elif defined(__WIN32__) && !defined(__WXMICROWIN__) 
 614     // we must use GetFileAttributes() instead of the ANSI C functions because 
 615     // it can cope with network (UNC) paths unlike them 
 616     DWORD ret 
= ::GetFileAttributes(filePath
.fn_str()); 
 618     return (ret 
!= INVALID_FILE_ATTRIBUTES
) && !(ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
 621         #define S_ISREG(mode) ((mode) & S_IFREG) 
 624 #ifndef wxNEED_WX_UNISTD_H 
 625     return (wxStat( filePath
.fn_str() , &st
) == 0 && S_ISREG(st
.st_mode
)) 
 627       || (errno 
== EACCES
) // if access is denied something with that name 
 628                             // exists and is opened in exclusive mode. 
 632     return wxStat( filePath 
, &st
) == 0 && S_ISREG(st
.st_mode
); 
 634 #endif // __WIN32__/!__WIN32__ 
 637 bool wxFileName::DirExists() const 
 639     return wxFileName::DirExists( GetPath() ); 
 643 bool wxFileName::DirExists( const wxString 
&dirPath 
) 
 645     wxString 
strPath(dirPath
); 
 647 #if defined(__WINDOWS__) || defined(__OS2__) 
 648     // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, 
 649     // so remove all trailing backslashes from the path - but don't do this for 
 650     // the paths "d:\" (which are different from "d:"), for just "\" or for 
 651     // windows unique volume names ("\\?\Volume{GUID}\") 
 652     while ( wxEndsWithPathSeparator(strPath
) ) 
 654         size_t len 
= strPath
.length(); 
 655         if ( len 
== 1 || (len 
== 3 && strPath
[len 
- 2] == wxT(':')) || 
 656             (len 
== wxMSWUniqueVolumePrefixLength 
&& 
 657              wxFileName::IsMSWUniqueVolumeNamePath(strPath
))) 
 662         strPath
.Truncate(len 
- 1); 
 664 #endif // __WINDOWS__ 
 667     // OS/2 can't handle "d:", it wants either "d:\" or "d:." 
 668     if (strPath
.length() == 2 && strPath
[1u] == wxT(':')) 
 672 #if defined(__WXPALMOS__) 
 674 #elif defined(__WIN32__) && !defined(__WXMICROWIN__) 
 675     // stat() can't cope with network paths 
 676     DWORD ret 
= ::GetFileAttributes(strPath
.fn_str()); 
 678     return (ret 
!= INVALID_FILE_ATTRIBUTES
) && (ret 
& FILE_ATTRIBUTE_DIRECTORY
); 
 679 #elif defined(__OS2__) 
 680     FILESTATUS3 Info 
= {{0}}; 
 681     APIRET rc 
= ::DosQueryPathInfo((PSZ
)(WXSTRINGCAST strPath
), FIL_STANDARD
, 
 682                                    (void*) &Info
, sizeof(FILESTATUS3
)); 
 684     return ((rc 
== NO_ERROR
) && (Info
.attrFile 
& FILE_DIRECTORY
)) || 
 685       (rc 
== ERROR_SHARING_VIOLATION
); 
 686     // If we got a sharing violation, there must be something with this name. 
 690 #ifndef __VISAGECPP__ 
 691     return wxStat(strPath
.c_str(), &st
) == 0 && ((st
.st_mode 
& S_IFMT
) == S_IFDIR
); 
 693     // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only 
 694     return wxStat(strPath
.c_str(), &st
) == 0 && (st
.st_mode 
== S_IFDIR
); 
 697 #endif // __WIN32__/!__WIN32__ 
 700 // ---------------------------------------------------------------------------- 
 701 // CWD and HOME stuff 
 702 // ---------------------------------------------------------------------------- 
 704 void wxFileName::AssignCwd(const wxString
& volume
) 
 706     AssignDir(wxFileName::GetCwd(volume
)); 
 710 wxString 
wxFileName::GetCwd(const wxString
& volume
) 
 712     // if we have the volume, we must get the current directory on this drive 
 713     // and to do this we have to chdir to this volume - at least under Windows, 
 714     // I don't know how to get the current drive on another volume elsewhere 
 717     if ( !volume
.empty() ) 
 720         SetCwd(volume 
+ GetVolumeSeparator()); 
 723     wxString cwd 
= ::wxGetCwd(); 
 725     if ( !volume
.empty() ) 
 733 bool wxFileName::SetCwd() const 
 735     return wxFileName::SetCwd( GetPath() ); 
 738 bool wxFileName::SetCwd( const wxString 
&cwd 
) 
 740     return ::wxSetWorkingDirectory( cwd 
); 
 743 void wxFileName::AssignHomeDir() 
 745     AssignDir(wxFileName::GetHomeDir()); 
 748 wxString 
wxFileName::GetHomeDir() 
 750     return ::wxGetHomeDir(); 
 754 // ---------------------------------------------------------------------------- 
 755 // CreateTempFileName 
 756 // ---------------------------------------------------------------------------- 
 758 #if wxUSE_FILE || wxUSE_FFILE 
 761 #if !defined wx_fdopen && defined HAVE_FDOPEN 
 762     #define wx_fdopen fdopen 
 765 // NB: GetTempFileName() under Windows creates the file, so using 
 766 //     O_EXCL there would fail 
 768     #define wxOPEN_EXCL 0 
 770     #define wxOPEN_EXCL O_EXCL 
 774 #ifdef wxOpenOSFHandle 
 775 #define WX_HAVE_DELETE_ON_CLOSE 
 776 // On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags. 
 778 static int wxOpenWithDeleteOnClose(const wxString
& filename
) 
 780     DWORD access 
= GENERIC_READ 
| GENERIC_WRITE
; 
 782     DWORD disposition 
= OPEN_ALWAYS
; 
 784     DWORD attributes 
= FILE_ATTRIBUTE_TEMPORARY 
| 
 785                        FILE_FLAG_DELETE_ON_CLOSE
; 
 787     HANDLE h 
= ::CreateFile(filename
.fn_str(), access
, 0, NULL
, 
 788                             disposition
, attributes
, NULL
); 
 790     return wxOpenOSFHandle(h
, wxO_BINARY
); 
 792 #endif // wxOpenOSFHandle 
 795 // Helper to open the file 
 797 static int wxTempOpen(const wxString
& path
, bool *deleteOnClose
) 
 799 #ifdef WX_HAVE_DELETE_ON_CLOSE 
 801         return wxOpenWithDeleteOnClose(path
); 
 804     *deleteOnClose 
= false; 
 806     return wxOpen(path
, wxO_BINARY 
| O_RDWR 
| O_CREAT 
| wxOPEN_EXCL
, 0600); 
 811 // Helper to open the file and attach it to the wxFFile 
 813 static bool wxTempOpen(wxFFile 
*file
, const wxString
& path
, bool *deleteOnClose
) 
 816     *deleteOnClose 
= false; 
 817     return file
->Open(path
, wxT("w+b")); 
 819     int fd 
= wxTempOpen(path
, deleteOnClose
); 
 822     file
->Attach(wx_fdopen(fd
, "w+b")); 
 823     return file
->IsOpened(); 
 826 #endif // wxUSE_FFILE 
 830     #define WXFILEARGS(x, y) y 
 832     #define WXFILEARGS(x, y) x 
 834     #define WXFILEARGS(x, y) x, y 
 838 // Implementation of wxFileName::CreateTempFileName(). 
 840 static wxString 
wxCreateTempImpl( 
 841         const wxString
& prefix
, 
 842         WXFILEARGS(wxFile 
*fileTemp
, wxFFile 
*ffileTemp
), 
 843         bool *deleteOnClose 
= NULL
) 
 845 #if wxUSE_FILE && wxUSE_FFILE 
 846     wxASSERT(fileTemp 
== NULL 
|| ffileTemp 
== NULL
); 
 848     wxString path
, dir
, name
; 
 849     bool wantDeleteOnClose 
= false; 
 853         // set the result to false initially 
 854         wantDeleteOnClose 
= *deleteOnClose
; 
 855         *deleteOnClose 
= false; 
 859         // easier if it alwasys points to something 
 860         deleteOnClose 
= &wantDeleteOnClose
; 
 863     // use the directory specified by the prefix 
 864     wxFileName::SplitPath(prefix
, &dir
, &name
, NULL 
/* extension */); 
 868         dir 
= wxFileName::GetTempDir(); 
 871 #if defined(__WXWINCE__) 
 872     path 
= dir 
+ wxT("\\") + name
; 
 874     while (wxFileName::FileExists(path
)) 
 876         path 
= dir 
+ wxT("\\") + name 
; 
 881 #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 882     if ( !::GetTempFileName(dir
.fn_str(), name
.fn_str(), 0, 
 883                             wxStringBuffer(path
, MAX_PATH 
+ 1)) ) 
 885         wxLogLastError(wxT("GetTempFileName")); 
 893     if ( !wxEndsWithPathSeparator(dir
) && 
 894             (name
.empty() || !wxIsPathSeparator(name
[0u])) ) 
 896         path 
+= wxFILE_SEP_PATH
; 
 901 #if defined(HAVE_MKSTEMP) 
 902     // scratch space for mkstemp() 
 903     path 
+= wxT("XXXXXX"); 
 905     // we need to copy the path to the buffer in which mkstemp() can modify it 
 906     wxCharBuffer 
buf(path
.fn_str()); 
 908     // cast is safe because the string length doesn't change 
 909     int fdTemp 
= mkstemp( (char*)(const char*) buf 
); 
 912         // this might be not necessary as mkstemp() on most systems should have 
 913         // already done it but it doesn't hurt neither... 
 916     else // mkstemp() succeeded 
 918         path 
= wxConvFile
.cMB2WX( (const char*) buf 
); 
 921         // avoid leaking the fd 
 924             fileTemp
->Attach(fdTemp
); 
 933             ffileTemp
->Attach(wx_fdopen(fdTemp
, "r+b")); 
 935             ffileTemp
->Open(path
, wxT("r+b")); 
 946 #else // !HAVE_MKSTEMP 
 950     path 
+= wxT("XXXXXX"); 
 952     wxCharBuffer buf 
= wxConvFile
.cWX2MB( path 
); 
 953     if ( !mktemp( (char*)(const char*) buf 
) ) 
 959         path 
= wxConvFile
.cMB2WX( (const char*) buf 
); 
 961 #else // !HAVE_MKTEMP (includes __DOS__) 
 962     // generate the unique file name ourselves 
 963     #if !defined(__DOS__) && !defined(__PALMOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) ) 
 964     path 
<< (unsigned int)getpid(); 
 969     static const size_t numTries 
= 1000; 
 970     for ( size_t n 
= 0; n 
< numTries
; n
++ ) 
 972         // 3 hex digits is enough for numTries == 1000 < 4096 
 973         pathTry 
= path 
+ wxString::Format(wxT("%.03x"), (unsigned int) n
); 
 974         if ( !wxFileName::FileExists(pathTry
) ) 
 983 #endif // HAVE_MKTEMP/!HAVE_MKTEMP 
 985 #endif // HAVE_MKSTEMP/!HAVE_MKSTEMP 
 987 #endif // Windows/!Windows 
 991         wxLogSysError(_("Failed to create a temporary file name")); 
 997         // open the file - of course, there is a race condition here, this is 
 998         // why we always prefer using mkstemp()... 
1000         if ( fileTemp 
&& !fileTemp
->IsOpened() ) 
1002             *deleteOnClose 
= wantDeleteOnClose
; 
1003             int fd 
= wxTempOpen(path
, deleteOnClose
); 
1005                 fileTemp
->Attach(fd
); 
1012         if ( ffileTemp 
&& !ffileTemp
->IsOpened() ) 
1014             *deleteOnClose 
= wantDeleteOnClose
; 
1015             ok 
= wxTempOpen(ffileTemp
, path
, deleteOnClose
); 
1021             // FIXME: If !ok here should we loop and try again with another 
1022             //        file name?  That is the standard recourse if open(O_EXCL) 
1023             //        fails, though of course it should be protected against 
1024             //        possible infinite looping too. 
1026             wxLogError(_("Failed to open temporary file.")); 
1036 static bool wxCreateTempImpl( 
1037         const wxString
& prefix
, 
1038         WXFILEARGS(wxFile 
*fileTemp
, wxFFile 
*ffileTemp
), 
1041     bool deleteOnClose 
= true; 
1043     *name 
= wxCreateTempImpl(prefix
, 
1044                              WXFILEARGS(fileTemp
, ffileTemp
), 
1047     bool ok 
= !name
->empty(); 
1052     else if (ok 
&& wxRemoveFile(*name
)) 
1060 static void wxAssignTempImpl( 
1062         const wxString
& prefix
, 
1063         WXFILEARGS(wxFile 
*fileTemp
, wxFFile 
*ffileTemp
)) 
1066     tempname 
= wxCreateTempImpl(prefix
, WXFILEARGS(fileTemp
, ffileTemp
)); 
1068     if ( tempname
.empty() ) 
1070         // error, failed to get temp file name 
1075         fn
->Assign(tempname
); 
1080 void wxFileName::AssignTempFileName(const wxString
& prefix
) 
1082     wxAssignTempImpl(this, prefix
, WXFILEARGS(NULL
, NULL
)); 
1086 wxString 
wxFileName::CreateTempFileName(const wxString
& prefix
) 
1088     return wxCreateTempImpl(prefix
, WXFILEARGS(NULL
, NULL
)); 
1091 #endif // wxUSE_FILE || wxUSE_FFILE 
1096 wxString 
wxCreateTempFileName(const wxString
& prefix
, 
1098                               bool *deleteOnClose
) 
1100     return wxCreateTempImpl(prefix
, WXFILEARGS(fileTemp
, NULL
), deleteOnClose
); 
1103 bool wxCreateTempFile(const wxString
& prefix
, 
1107     return wxCreateTempImpl(prefix
, WXFILEARGS(fileTemp
, NULL
), name
); 
1110 void wxFileName::AssignTempFileName(const wxString
& prefix
, wxFile 
*fileTemp
) 
1112     wxAssignTempImpl(this, prefix
, WXFILEARGS(fileTemp
, NULL
)); 
1117 wxFileName::CreateTempFileName(const wxString
& prefix
, wxFile 
*fileTemp
) 
1119     return wxCreateTempFileName(prefix
, fileTemp
); 
1122 #endif // wxUSE_FILE 
1127 wxString 
wxCreateTempFileName(const wxString
& prefix
, 
1129                               bool *deleteOnClose
) 
1131     return wxCreateTempImpl(prefix
, WXFILEARGS(NULL
, fileTemp
), deleteOnClose
); 
1134 bool wxCreateTempFile(const wxString
& prefix
, 
1138     return wxCreateTempImpl(prefix
, WXFILEARGS(NULL
, fileTemp
), name
); 
1142 void wxFileName::AssignTempFileName(const wxString
& prefix
, wxFFile 
*fileTemp
) 
1144     wxAssignTempImpl(this, prefix
, WXFILEARGS(NULL
, fileTemp
)); 
1149 wxFileName::CreateTempFileName(const wxString
& prefix
, wxFFile 
*fileTemp
) 
1151     return wxCreateTempFileName(prefix
, fileTemp
); 
1154 #endif // wxUSE_FFILE 
1157 // ---------------------------------------------------------------------------- 
1158 // directory operations 
1159 // ---------------------------------------------------------------------------- 
1161 // helper of GetTempDir(): check if the given directory exists and return it if 
1162 // it does or an empty string otherwise 
1166 wxString 
CheckIfDirExists(const wxString
& dir
) 
1168     return wxFileName::DirExists(dir
) ? dir 
: wxString(); 
1171 } // anonymous namespace 
1173 wxString 
wxFileName::GetTempDir() 
1175     // first try getting it from environment: this allows overriding the values 
1176     // used by default if the user wants to create temporary files in another 
1178     wxString dir 
= CheckIfDirExists(wxGetenv("TMPDIR")); 
1181         dir 
= CheckIfDirExists(wxGetenv("TMP")); 
1183             dir 
= CheckIfDirExists(wxGetenv("TEMP")); 
1186     // if no environment variables are set, use the system default 
1189 #if defined(__WXWINCE__) 
1190         dir 
= CheckIfDirExists(wxT("\\temp")); 
1191 #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
1192         if ( !::GetTempPath(MAX_PATH
, wxStringBuffer(dir
, MAX_PATH 
+ 1)) ) 
1194             wxLogLastError(wxT("GetTempPath")); 
1196 #elif defined(__WXMAC__) && wxOSX_USE_CARBON 
1197         dir 
= wxMacFindFolder(short(kOnSystemDisk
), kTemporaryFolderType
, kCreateFolder
); 
1198 #endif // systems with native way 
1201     // fall back to hard coded value 
1204 #ifdef __UNIX_LIKE__ 
1205         dir 
= CheckIfDirExists("/tmp"); 
1207 #endif // __UNIX_LIKE__ 
1214 bool wxFileName::Mkdir( int perm
, int flags 
) const 
1216     return wxFileName::Mkdir(GetPath(), perm
, flags
); 
1219 bool wxFileName::Mkdir( const wxString
& dir
, int perm
, int flags 
) 
1221     if ( flags 
& wxPATH_MKDIR_FULL 
) 
1223         // split the path in components 
1224         wxFileName filename
; 
1225         filename
.AssignDir(dir
); 
1228         if ( filename
.HasVolume()) 
1230             currPath 
<< wxGetVolumeString(filename
.GetVolume(), wxPATH_NATIVE
); 
1233         wxArrayString dirs 
= filename
.GetDirs(); 
1234         size_t count 
= dirs
.GetCount(); 
1235         for ( size_t i 
= 0; i 
< count
; i
++ ) 
1237             if ( i 
> 0 || filename
.IsAbsolute() ) 
1238                 currPath 
+= wxFILE_SEP_PATH
; 
1239             currPath 
+= dirs
[i
]; 
1241             if (!DirExists(currPath
)) 
1243                 if (!wxMkdir(currPath
, perm
)) 
1245                     // no need to try creating further directories 
1255     return ::wxMkdir( dir
, perm 
); 
1258 bool wxFileName::Rmdir(int flags
) const 
1260     return wxFileName::Rmdir( GetPath(), flags 
); 
1263 bool wxFileName::Rmdir(const wxString
& dir
, int flags
) 
1266     if ( flags 
& wxPATH_RMDIR_RECURSIVE 
) 
1268         // SHFileOperation needs double null termination string 
1269         // but without separator at the end of the path 
1271         if ( path
.Last() == wxFILE_SEP_PATH 
) 
1275         SHFILEOPSTRUCT fileop
; 
1276         wxZeroMemory(fileop
); 
1277         fileop
.wFunc 
= FO_DELETE
; 
1278         fileop
.pFrom 
= path
.fn_str(); 
1279         fileop
.fFlags 
= FOF_SILENT 
| FOF_NOCONFIRMATION
; 
1281         // FOF_NOERRORUI is not defined in WinCE 
1282         fileop
.fFlags 
|= FOF_NOERRORUI
; 
1285         int ret 
= SHFileOperation(&fileop
); 
1288             // SHFileOperation may return non-Win32 error codes, so the error 
1289             // message can be incorrect 
1290             wxLogApiError(wxT("SHFileOperation"), ret
); 
1296     else if ( flags 
& wxPATH_RMDIR_FULL 
) 
1298     if ( flags 
!= 0 )   // wxPATH_RMDIR_FULL or wxPATH_RMDIR_RECURSIVE 
1299 #endif // !__WXMSW__ 
1302         if ( path
.Last() != wxFILE_SEP_PATH 
) 
1303             path 
+= wxFILE_SEP_PATH
; 
1307         if ( !d
.IsOpened() ) 
1312         // first delete all subdirectories 
1313         bool cont 
= d
.GetFirst(&filename
, "", wxDIR_DIRS 
| wxDIR_HIDDEN
); 
1316             wxFileName::Rmdir(path 
+ filename
, flags
); 
1317             cont 
= d
.GetNext(&filename
); 
1321         if ( flags 
& wxPATH_RMDIR_RECURSIVE 
) 
1323             // delete all files too 
1324             cont 
= d
.GetFirst(&filename
, "", wxDIR_FILES 
| wxDIR_HIDDEN
); 
1327                 ::wxRemoveFile(path 
+ filename
); 
1328                 cont 
= d
.GetNext(&filename
); 
1331 #endif // !__WXMSW__ 
1334     return ::wxRmdir(dir
); 
1337 // ---------------------------------------------------------------------------- 
1338 // path normalization 
1339 // ---------------------------------------------------------------------------- 
1341 bool wxFileName::Normalize(int flags
, 
1342                            const wxString
& cwd
, 
1343                            wxPathFormat format
) 
1345     // deal with env vars renaming first as this may seriously change the path 
1346     if ( flags 
& wxPATH_NORM_ENV_VARS 
) 
1348         wxString pathOrig 
= GetFullPath(format
); 
1349         wxString path 
= wxExpandEnvVars(pathOrig
); 
1350         if ( path 
!= pathOrig 
) 
1356     // the existing path components 
1357     wxArrayString dirs 
= GetDirs(); 
1359     // the path to prepend in front to make the path absolute 
1362     format 
= GetFormat(format
); 
1364     // set up the directory to use for making the path absolute later 
1365     if ( (flags 
& wxPATH_NORM_ABSOLUTE
) && !IsAbsolute(format
) ) 
1369             curDir
.AssignCwd(GetVolume()); 
1371         else // cwd provided 
1373             curDir
.AssignDir(cwd
); 
1377     // handle ~ stuff under Unix only 
1378     if ( (format 
== wxPATH_UNIX
) && (flags 
& wxPATH_NORM_TILDE
) && m_relative 
) 
1380         if ( !dirs
.IsEmpty() ) 
1382             wxString dir 
= dirs
[0u]; 
1383             if ( !dir
.empty() && dir
[0u] == wxT('~') ) 
1385                 // to make the path absolute use the home directory 
1386                 curDir
.AssignDir(wxGetUserHome(dir
.c_str() + 1)); 
1392     // transform relative path into abs one 
1393     if ( curDir
.IsOk() ) 
1395         // this path may be relative because it doesn't have the volume name 
1396         // and still have m_relative=true; in this case we shouldn't modify 
1397         // our directory components but just set the current volume 
1398         if ( !HasVolume() && curDir
.HasVolume() ) 
1400             SetVolume(curDir
.GetVolume()); 
1404                 // yes, it was the case - we don't need curDir then 
1409         // finally, prepend curDir to the dirs array 
1410         wxArrayString dirsNew 
= curDir
.GetDirs(); 
1411         WX_PREPEND_ARRAY(dirs
, dirsNew
); 
1413         // if we used e.g. tilde expansion previously and wxGetUserHome didn't 
1414         // return for some reason an absolute path, then curDir maybe not be absolute! 
1415         if ( !curDir
.m_relative 
) 
1417             // we have prepended an absolute path and thus we are now an absolute 
1421         // else if (flags & wxPATH_NORM_ABSOLUTE): 
1422         //   should we warn the user that we didn't manage to make the path absolute? 
1425     // now deal with ".", ".." and the rest 
1427     size_t count 
= dirs
.GetCount(); 
1428     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1430         wxString dir 
= dirs
[n
]; 
1432         if ( flags 
& wxPATH_NORM_DOTS 
) 
1434             if ( dir 
== wxT(".") ) 
1440             if ( dir 
== wxT("..") ) 
1442                 if ( m_dirs
.IsEmpty() ) 
1444                     wxLogError(_("The path '%s' contains too many \"..\"!"), 
1445                                GetFullPath().c_str()); 
1449                 m_dirs
.RemoveAt(m_dirs
.GetCount() - 1); 
1457 #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE 
1458     if ( (flags 
& wxPATH_NORM_SHORTCUT
) ) 
1461         if (GetShortcutTarget(GetFullPath(format
), filename
)) 
1469 #if defined(__WIN32__) 
1470     if ( (flags 
& wxPATH_NORM_LONG
) && (format 
== wxPATH_DOS
) ) 
1472         Assign(GetLongPath()); 
1476     // Change case  (this should be kept at the end of the function, to ensure 
1477     // that the path doesn't change any more after we normalize its case) 
1478     if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
1480         m_volume
.MakeLower(); 
1484         // directory entries must be made lower case as well 
1485         count 
= m_dirs
.GetCount(); 
1486         for ( size_t i 
= 0; i 
< count
; i
++ ) 
1488             m_dirs
[i
].MakeLower(); 
1496 bool wxFileName::ReplaceEnvVariable(const wxString
& envname
, 
1497                                     const wxString
& replacementFmtString
, 
1498                                     wxPathFormat format
) 
1500     // look into stringForm for the contents of the given environment variable 
1502     if (envname
.empty() || 
1503         !wxGetEnv(envname
, &val
)) 
1508     wxString stringForm 
= GetPath(wxPATH_GET_VOLUME
, format
); 
1509         // do not touch the file name and the extension 
1511     wxString replacement 
= wxString::Format(replacementFmtString
, envname
); 
1512     stringForm
.Replace(val
, replacement
); 
1514     // Now assign ourselves the modified path: 
1515     Assign(stringForm
, GetFullName(), format
); 
1521 bool wxFileName::ReplaceHomeDir(wxPathFormat format
) 
1523     wxString homedir 
= wxGetHomeDir(); 
1524     if (homedir
.empty()) 
1527     wxString stringForm 
= GetPath(wxPATH_GET_VOLUME
, format
); 
1528         // do not touch the file name and the extension 
1530     stringForm
.Replace(homedir
, "~"); 
1532     // Now assign ourselves the modified path: 
1533     Assign(stringForm
, GetFullName(), format
); 
1538 // ---------------------------------------------------------------------------- 
1539 // get the shortcut target 
1540 // ---------------------------------------------------------------------------- 
1542 // WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions. 
1543 // The .lnk file is a plain text file so it should be easy to 
1544 // make it work. Hint from Google Groups: 
1545 // "If you open up a lnk file, you'll see a 
1546 // number, followed by a pound sign (#), followed by more text. The 
1547 // number is the number of characters that follows the pound sign. The 
1548 // characters after the pound sign are the command line (which _can_ 
1549 // include arguments) to be executed. Any path (e.g. \windows\program 
1550 // files\myapp.exe) that includes spaces needs to be enclosed in 
1551 // quotation marks." 
1553 #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE 
1554 // The following lines are necessary under WinCE 
1555 // #include "wx/msw/private.h" 
1556 // #include <ole2.h> 
1558 #if defined(__WXWINCE__) 
1559 #include <shlguid.h> 
1562 bool wxFileName::GetShortcutTarget(const wxString
& shortcutPath
, 
1563                                    wxString
& targetFilename
, 
1564                                    wxString
* arguments
) const 
1566     wxString path
, file
, ext
; 
1567     wxFileName::SplitPath(shortcutPath
, & path
, & file
, & ext
); 
1571     bool success 
= false; 
1573     // Assume it's not a shortcut if it doesn't end with lnk 
1574     if (ext
.CmpNoCase(wxT("lnk"))!=0) 
1577     // create a ShellLink object 
1578     hres 
= CoCreateInstance(CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, 
1579                             IID_IShellLink
, (LPVOID
*) &psl
); 
1581     if (SUCCEEDED(hres
)) 
1584         hres 
= psl
->QueryInterface( IID_IPersistFile
, (LPVOID 
*) &ppf
); 
1585         if (SUCCEEDED(hres
)) 
1587             WCHAR wsz
[MAX_PATH
]; 
1589             MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, shortcutPath
.mb_str(), -1, wsz
, 
1592             hres 
= ppf
->Load(wsz
, 0); 
1595             if (SUCCEEDED(hres
)) 
1598                 // Wrong prototype in early versions 
1599 #if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2) 
1600                 psl
->GetPath((CHAR
*) buf
, 2048, NULL
, SLGP_UNCPRIORITY
); 
1602                 psl
->GetPath(buf
, 2048, NULL
, SLGP_UNCPRIORITY
); 
1604                 targetFilename 
= wxString(buf
); 
1605                 success 
= (shortcutPath 
!= targetFilename
); 
1607                 psl
->GetArguments(buf
, 2048); 
1609                 if (!args
.empty() && arguments
) 
1621 #endif // __WIN32__ && !__WXWINCE__ 
1624 // ---------------------------------------------------------------------------- 
1625 // absolute/relative paths 
1626 // ---------------------------------------------------------------------------- 
1628 bool wxFileName::IsAbsolute(wxPathFormat format
) const 
1630     // unix paths beginning with ~ are reported as being absolute 
1631     if ( format 
== wxPATH_UNIX 
) 
1633         if ( !m_dirs
.IsEmpty() ) 
1635             wxString dir 
= m_dirs
[0u]; 
1637             if (!dir
.empty() && dir
[0u] == wxT('~')) 
1642     // if our path doesn't start with a path separator, it's not an absolute 
1647     if ( !GetVolumeSeparator(format
).empty() ) 
1649         // this format has volumes and an absolute path must have one, it's not 
1650         // enough to have the full path to be an absolute file under Windows 
1651         if ( GetVolume().empty() ) 
1658 bool wxFileName::MakeRelativeTo(const wxString
& pathBase
, wxPathFormat format
) 
1660     wxFileName fnBase 
= wxFileName::DirName(pathBase
, format
); 
1662     // get cwd only once - small time saving 
1663     wxString cwd 
= wxGetCwd(); 
1664     Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1665     fnBase
.Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1667     bool withCase 
= IsCaseSensitive(format
); 
1669     // we can't do anything if the files live on different volumes 
1670     if ( !GetVolume().IsSameAs(fnBase
.GetVolume(), withCase
) ) 
1676     // same drive, so we don't need our volume 
1679     // remove common directories starting at the top 
1680     while ( !m_dirs
.IsEmpty() && !fnBase
.m_dirs
.IsEmpty() && 
1681                 m_dirs
[0u].IsSameAs(fnBase
.m_dirs
[0u], withCase
) ) 
1684         fnBase
.m_dirs
.RemoveAt(0); 
1687     // add as many ".." as needed 
1688     size_t count 
= fnBase
.m_dirs
.GetCount(); 
1689     for ( size_t i 
= 0; i 
< count
; i
++ ) 
1691         m_dirs
.Insert(wxT(".."), 0u); 
1694     if ( format 
== wxPATH_UNIX 
|| format 
== wxPATH_DOS 
) 
1696         // a directory made relative with respect to itself is '.' under Unix 
1697         // and DOS, by definition (but we don't have to insert "./" for the 
1699         if ( m_dirs
.IsEmpty() && IsDir() ) 
1701             m_dirs
.Add(wxT('.')); 
1711 // ---------------------------------------------------------------------------- 
1712 // filename kind tests 
1713 // ---------------------------------------------------------------------------- 
1715 bool wxFileName::SameAs(const wxFileName
& filepath
, wxPathFormat format
) const 
1717     wxFileName fn1 
= *this, 
1720     // get cwd only once - small time saving 
1721     wxString cwd 
= wxGetCwd(); 
1722     fn1
.Normalize(wxPATH_NORM_ALL 
| wxPATH_NORM_CASE
, cwd
, format
); 
1723     fn2
.Normalize(wxPATH_NORM_ALL 
| wxPATH_NORM_CASE
, cwd
, format
); 
1725     if ( fn1
.GetFullPath() == fn2
.GetFullPath() ) 
1728     // TODO: compare inodes for Unix, this works even when filenames are 
1729     //       different but files are the same (symlinks) (VZ) 
1735 bool wxFileName::IsCaseSensitive( wxPathFormat format 
) 
1737     // only Unix filenames are truely case-sensitive 
1738     return GetFormat(format
) == wxPATH_UNIX
; 
1742 wxString 
wxFileName::GetForbiddenChars(wxPathFormat format
) 
1744     // Inits to forbidden characters that are common to (almost) all platforms. 
1745     wxString strForbiddenChars 
= wxT("*?"); 
1747     // If asserts, wxPathFormat has been changed. In case of a new path format 
1748     // addition, the following code might have to be updated. 
1749     wxCOMPILE_TIME_ASSERT(wxPATH_MAX 
== 5, wxPathFormatChanged
); 
1750     switch ( GetFormat(format
) ) 
1753             wxFAIL_MSG( wxT("Unknown path format") ); 
1754             // !! Fall through !! 
1760             // On a Mac even names with * and ? are allowed (Tested with OS 
1761             // 9.2.1 and OS X 10.2.5) 
1762             strForbiddenChars 
= wxEmptyString
; 
1766             strForbiddenChars 
+= wxT("\\/:\"<>|"); 
1773     return strForbiddenChars
; 
1777 wxString 
wxFileName::GetVolumeSeparator(wxPathFormat 
WXUNUSED_IN_WINCE(format
)) 
1780     return wxEmptyString
; 
1784     if ( (GetFormat(format
) == wxPATH_DOS
) || 
1785          (GetFormat(format
) == wxPATH_VMS
) ) 
1787         sepVol 
= wxFILE_SEP_DSK
; 
1796 wxString 
wxFileName::GetPathSeparators(wxPathFormat format
) 
1799     switch ( GetFormat(format
) ) 
1802             // accept both as native APIs do but put the native one first as 
1803             // this is the one we use in GetFullPath() 
1804             seps 
<< wxFILE_SEP_PATH_DOS 
<< wxFILE_SEP_PATH_UNIX
; 
1808             wxFAIL_MSG( wxT("Unknown wxPATH_XXX style") ); 
1812             seps 
= wxFILE_SEP_PATH_UNIX
; 
1816             seps 
= wxFILE_SEP_PATH_MAC
; 
1820             seps 
= wxFILE_SEP_PATH_VMS
; 
1828 wxString 
wxFileName::GetPathTerminators(wxPathFormat format
) 
1830     format 
= GetFormat(format
); 
1832     // under VMS the end of the path is ']', not the path separator used to 
1833     // separate the components 
1834     return format 
== wxPATH_VMS 
? wxString(wxT(']')) : GetPathSeparators(format
); 
1838 bool wxFileName::IsPathSeparator(wxChar ch
, wxPathFormat format
) 
1840     // wxString::Find() doesn't work as expected with NUL - it will always find 
1841     // it, so test for it separately 
1842     return ch 
!= wxT('\0') && GetPathSeparators(format
).Find(ch
) != wxNOT_FOUND
; 
1847 wxFileName::IsMSWUniqueVolumeNamePath(const wxString
& path
, wxPathFormat format
) 
1849     // return true if the format used is the DOS/Windows one and the string begins 
1850     // with a Windows unique volume name ("\\?\Volume{guid}\") 
1851     return format 
== wxPATH_DOS 
&& 
1852             path
.length() >= wxMSWUniqueVolumePrefixLength 
&& 
1853              path
.StartsWith(wxS("\\\\?\\Volume{")) && 
1854               path
[wxMSWUniqueVolumePrefixLength 
- 1] == wxFILE_SEP_PATH_DOS
; 
1857 // ---------------------------------------------------------------------------- 
1858 // path components manipulation 
1859 // ---------------------------------------------------------------------------- 
1861 /* static */ bool wxFileName::IsValidDirComponent(const wxString
& dir
) 
1865         wxFAIL_MSG( wxT("empty directory passed to wxFileName::InsertDir()") ); 
1870     const size_t len 
= dir
.length(); 
1871     for ( size_t n 
= 0; n 
< len
; n
++ ) 
1873         if ( dir
[n
] == GetVolumeSeparator() || IsPathSeparator(dir
[n
]) ) 
1875             wxFAIL_MSG( wxT("invalid directory component in wxFileName") ); 
1884 void wxFileName::AppendDir( const wxString
& dir 
) 
1886     if ( IsValidDirComponent(dir
) ) 
1890 void wxFileName::PrependDir( const wxString
& dir 
) 
1895 void wxFileName::InsertDir(size_t before
, const wxString
& dir
) 
1897     if ( IsValidDirComponent(dir
) ) 
1898         m_dirs
.Insert(dir
, before
); 
1901 void wxFileName::RemoveDir(size_t pos
) 
1903     m_dirs
.RemoveAt(pos
); 
1906 // ---------------------------------------------------------------------------- 
1908 // ---------------------------------------------------------------------------- 
1910 void wxFileName::SetFullName(const wxString
& fullname
) 
1912     SplitPath(fullname
, NULL 
/* no volume */, NULL 
/* no path */, 
1913                         &m_name
, &m_ext
, &m_hasExt
); 
1916 wxString 
wxFileName::GetFullName() const 
1918     wxString fullname 
= m_name
; 
1921         fullname 
<< wxFILE_SEP_EXT 
<< m_ext
; 
1927 wxString 
wxFileName::GetPath( int flags
, wxPathFormat format 
) const 
1929     format 
= GetFormat( format 
); 
1933     // return the volume with the path as well if requested 
1934     if ( flags 
& wxPATH_GET_VOLUME 
) 
1936         fullpath 
+= wxGetVolumeString(GetVolume(), format
); 
1939     // the leading character 
1944                 fullpath 
+= wxFILE_SEP_PATH_MAC
; 
1949                 fullpath 
+= wxFILE_SEP_PATH_DOS
; 
1953             wxFAIL_MSG( wxT("Unknown path format") ); 
1959                 fullpath 
+= wxFILE_SEP_PATH_UNIX
; 
1964             // no leading character here but use this place to unset 
1965             // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense 
1966             // as, if I understand correctly, there should never be a dot 
1967             // before the closing bracket 
1968             flags 
&= ~wxPATH_GET_SEPARATOR
; 
1971     if ( m_dirs
.empty() ) 
1973         // there is nothing more 
1977     // then concatenate all the path components using the path separator 
1978     if ( format 
== wxPATH_VMS 
) 
1980         fullpath 
+= wxT('['); 
1983     const size_t dirCount 
= m_dirs
.GetCount(); 
1984     for ( size_t i 
= 0; i 
< dirCount
; i
++ ) 
1989                 if ( m_dirs
[i
] == wxT(".") ) 
1991                     // skip appending ':', this shouldn't be done in this 
1992                     // case as "::" is interpreted as ".." under Unix 
1996                 // convert back from ".." to nothing 
1997                 if ( !m_dirs
[i
].IsSameAs(wxT("..")) ) 
1998                      fullpath 
+= m_dirs
[i
]; 
2002                 wxFAIL_MSG( wxT("Unexpected path format") ); 
2003                 // still fall through 
2007                 fullpath 
+= m_dirs
[i
]; 
2011                 // TODO: What to do with ".." under VMS 
2013                 // convert back from ".." to nothing 
2014                 if ( !m_dirs
[i
].IsSameAs(wxT("..")) ) 
2015                     fullpath 
+= m_dirs
[i
]; 
2019         if ( (flags 
& wxPATH_GET_SEPARATOR
) || (i 
!= dirCount 
- 1) ) 
2020             fullpath 
+= GetPathSeparator(format
); 
2023     if ( format 
== wxPATH_VMS 
) 
2025         fullpath 
+= wxT(']'); 
2031 wxString 
wxFileName::GetFullPath( wxPathFormat format 
) const 
2033     // we already have a function to get the path 
2034     wxString fullpath 
= GetPath(wxPATH_GET_VOLUME 
| wxPATH_GET_SEPARATOR
, 
2037     // now just add the file name and extension to it 
2038     fullpath 
+= GetFullName(); 
2043 // Return the short form of the path (returns identity on non-Windows platforms) 
2044 wxString 
wxFileName::GetShortPath() const 
2046     wxString 
path(GetFullPath()); 
2048 #if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
2049     DWORD sz 
= ::GetShortPathName(path
.fn_str(), NULL
, 0); 
2053         if ( ::GetShortPathName
 
2056                 wxStringBuffer(pathOut
, sz
), 
2068 // Return the long form of the path (returns identity on non-Windows platforms) 
2069 wxString 
wxFileName::GetLongPath() const 
2072              path 
= GetFullPath(); 
2074 #if defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__) 
2076 #if wxUSE_DYNLIB_CLASS 
2077     typedef DWORD (WINAPI 
*GET_LONG_PATH_NAME
)(const wxChar 
*, wxChar 
*, DWORD
); 
2079     // this is MT-safe as in the worst case we're going to resolve the function 
2080     // twice -- but as the result is the same in both threads, it's ok 
2081     static GET_LONG_PATH_NAME s_pfnGetLongPathName 
= NULL
; 
2082     if ( !s_pfnGetLongPathName 
) 
2084         static bool s_triedToLoad 
= false; 
2086         if ( !s_triedToLoad 
) 
2088             s_triedToLoad 
= true; 
2090             wxDynamicLibrary 
dllKernel(wxT("kernel32")); 
2092             const wxChar
* GetLongPathName 
= wxT("GetLongPathName") 
2097 #endif // Unicode/ANSI 
2099             if ( dllKernel
.HasSymbol(GetLongPathName
) ) 
2101                 s_pfnGetLongPathName 
= (GET_LONG_PATH_NAME
) 
2102                     dllKernel
.GetSymbol(GetLongPathName
); 
2105             // note that kernel32.dll can be unloaded, it stays in memory 
2106             // anyhow as all Win32 programs link to it and so it's safe to call 
2107             // GetLongPathName() even after unloading it 
2111     if ( s_pfnGetLongPathName 
) 
2113         DWORD dwSize 
= (*s_pfnGetLongPathName
)(path
.fn_str(), NULL
, 0); 
2116             if ( (*s_pfnGetLongPathName
) 
2119                   wxStringBuffer(pathOut
, dwSize
), 
2127 #endif // wxUSE_DYNLIB_CLASS 
2129     // The OS didn't support GetLongPathName, or some other error. 
2130     // We need to call FindFirstFile on each component in turn. 
2132     WIN32_FIND_DATA findFileData
; 
2136         pathOut 
= GetVolume() + 
2137                   GetVolumeSeparator(wxPATH_DOS
) + 
2138                   GetPathSeparator(wxPATH_DOS
); 
2140         pathOut 
= wxEmptyString
; 
2142     wxArrayString dirs 
= GetDirs(); 
2143     dirs
.Add(GetFullName()); 
2147     size_t count 
= dirs
.GetCount(); 
2148     for ( size_t i 
= 0; i 
< count
; i
++ ) 
2150         const wxString
& dir 
= dirs
[i
]; 
2152         // We're using pathOut to collect the long-name path, but using a 
2153         // temporary for appending the last path component which may be 
2155         tmpPath 
= pathOut 
+ dir
; 
2157         // We must not process "." or ".." here as they would be (unexpectedly) 
2158         // replaced by the corresponding directory names so just leave them 
2161         // And we can't pass a drive and root dir to FindFirstFile (VZ: why?) 
2162         if ( tmpPath
.empty() || dir 
== '.' || dir 
== ".." || 
2163                 tmpPath
.Last() == GetVolumeSeparator(wxPATH_DOS
) ) 
2165             tmpPath 
+= wxFILE_SEP_PATH
; 
2170         hFind 
= ::FindFirstFile(tmpPath
.fn_str(), &findFileData
); 
2171         if (hFind 
== INVALID_HANDLE_VALUE
) 
2173             // Error: most likely reason is that path doesn't exist, so 
2174             // append any unprocessed parts and return 
2175             for ( i 
+= 1; i 
< count
; i
++ ) 
2176                 tmpPath 
+= wxFILE_SEP_PATH 
+ dirs
[i
]; 
2181         pathOut 
+= findFileData
.cFileName
; 
2182         if ( (i 
< (count
-1)) ) 
2183             pathOut 
+= wxFILE_SEP_PATH
; 
2189 #endif // Win32/!Win32 
2194 wxPathFormat 
wxFileName::GetFormat( wxPathFormat format 
) 
2196     if (format 
== wxPATH_NATIVE
) 
2198 #if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__) 
2199         format 
= wxPATH_DOS
; 
2200 #elif defined(__VMS) 
2201         format 
= wxPATH_VMS
; 
2203         format 
= wxPATH_UNIX
; 
2209 #ifdef wxHAS_FILESYSTEM_VOLUMES 
2212 wxString 
wxFileName::GetVolumeString(char drive
, int flags
) 
2214     wxASSERT_MSG( !(flags 
& ~wxPATH_GET_SEPARATOR
), "invalid flag specified" ); 
2216     wxString 
vol(drive
); 
2217     vol 
+= wxFILE_SEP_DSK
; 
2218     if ( flags 
& wxPATH_GET_SEPARATOR 
) 
2219         vol 
+= wxFILE_SEP_PATH
; 
2224 #endif // wxHAS_FILESYSTEM_VOLUMES 
2226 // ---------------------------------------------------------------------------- 
2227 // path splitting function 
2228 // ---------------------------------------------------------------------------- 
2232 wxFileName::SplitVolume(const wxString
& fullpathWithVolume
, 
2233                         wxString 
*pstrVolume
, 
2235                         wxPathFormat format
) 
2237     format 
= GetFormat(format
); 
2239     wxString fullpath 
= fullpathWithVolume
; 
2241     if ( IsMSWUniqueVolumeNamePath(fullpath
, format
) ) 
2243         // special Windows unique volume names hack: transform 
2244         // \\?\Volume{guid}\path into Volume{guid}:path 
2245         // note: this check must be done before the check for UNC path 
2247         // we know the last backslash from the unique volume name is located 
2248         // there from IsMSWUniqueVolumeNamePath 
2249         fullpath
[wxMSWUniqueVolumePrefixLength 
- 1] = wxFILE_SEP_DSK
; 
2251         // paths starting with a unique volume name should always be absolute 
2252         fullpath
.insert(wxMSWUniqueVolumePrefixLength
, 1, wxFILE_SEP_PATH_DOS
); 
2254         // remove the leading "\\?\" part 
2255         fullpath
.erase(0, 4); 
2257     else if ( IsUNCPath(fullpath
, format
) ) 
2259         // special Windows UNC paths hack: transform \\share\path into share:path 
2261         fullpath
.erase(0, 2); 
2263         size_t posFirstSlash 
= 
2264             fullpath
.find_first_of(GetPathTerminators(format
)); 
2265         if ( posFirstSlash 
!= wxString::npos 
) 
2267             fullpath
[posFirstSlash
] = wxFILE_SEP_DSK
; 
2269             // UNC paths are always absolute, right? (FIXME) 
2270             fullpath
.insert(posFirstSlash 
+ 1, 1, wxFILE_SEP_PATH_DOS
); 
2274     // We separate the volume here 
2275     if ( format 
== wxPATH_DOS 
|| format 
== wxPATH_VMS 
) 
2277         wxString sepVol 
= GetVolumeSeparator(format
); 
2279         // we have to exclude the case of a colon in the very beginning of the 
2280         // string as it can't be a volume separator (nor can this be a valid 
2281         // DOS file name at all but we'll leave dealing with this to our caller) 
2282         size_t posFirstColon 
= fullpath
.find_first_of(sepVol
); 
2283         if ( posFirstColon 
&& posFirstColon 
!= wxString::npos 
) 
2287                 *pstrVolume 
= fullpath
.Left(posFirstColon
); 
2290             // remove the volume name and the separator from the full path 
2291             fullpath
.erase(0, posFirstColon 
+ sepVol
.length()); 
2296         *pstrPath 
= fullpath
; 
2300 void wxFileName::SplitPath(const wxString
& fullpathWithVolume
, 
2301                            wxString 
*pstrVolume
, 
2306                            wxPathFormat format
) 
2308     format 
= GetFormat(format
); 
2311     SplitVolume(fullpathWithVolume
, pstrVolume
, &fullpath
, format
); 
2313     // find the positions of the last dot and last path separator in the path 
2314     size_t posLastDot 
= fullpath
.find_last_of(wxFILE_SEP_EXT
); 
2315     size_t posLastSlash 
= fullpath
.find_last_of(GetPathTerminators(format
)); 
2317     // check whether this dot occurs at the very beginning of a path component 
2318     if ( (posLastDot 
!= wxString::npos
) && 
2320             IsPathSeparator(fullpath
[posLastDot 
- 1]) || 
2321             (format 
== wxPATH_VMS 
&& fullpath
[posLastDot 
- 1] == wxT(']'))) ) 
2323         // dot may be (and commonly -- at least under Unix -- is) the first 
2324         // character of the filename, don't treat the entire filename as 
2325         // extension in this case 
2326         posLastDot 
= wxString::npos
; 
2329     // if we do have a dot and a slash, check that the dot is in the name part 
2330     if ( (posLastDot 
!= wxString::npos
) && 
2331          (posLastSlash 
!= wxString::npos
) && 
2332          (posLastDot 
< posLastSlash
) ) 
2334         // the dot is part of the path, not the start of the extension 
2335         posLastDot 
= wxString::npos
; 
2338     // now fill in the variables provided by user 
2341         if ( posLastSlash 
== wxString::npos 
) 
2348             // take everything up to the path separator but take care to make 
2349             // the path equal to something like '/', not empty, for the files 
2350             // immediately under root directory 
2351             size_t len 
= posLastSlash
; 
2353             // this rule does not apply to mac since we do not start with colons (sep) 
2354             // except for relative paths 
2355             if ( !len 
&& format 
!= wxPATH_MAC
) 
2358             *pstrPath 
= fullpath
.Left(len
); 
2360             // special VMS hack: remove the initial bracket 
2361             if ( format 
== wxPATH_VMS 
) 
2363                 if ( (*pstrPath
)[0u] == wxT('[') ) 
2364                     pstrPath
->erase(0, 1); 
2371         // take all characters starting from the one after the last slash and 
2372         // up to, but excluding, the last dot 
2373         size_t nStart 
= posLastSlash 
== wxString::npos 
? 0 : posLastSlash 
+ 1; 
2375         if ( posLastDot 
== wxString::npos 
) 
2377             // take all until the end 
2378             count 
= wxString::npos
; 
2380         else if ( posLastSlash 
== wxString::npos 
) 
2384         else // have both dot and slash 
2386             count 
= posLastDot 
- posLastSlash 
- 1; 
2389         *pstrName 
= fullpath
.Mid(nStart
, count
); 
2392     // finally deal with the extension here: we have an added complication that 
2393     // extension may be empty (but present) as in "foo." where trailing dot 
2394     // indicates the empty extension at the end -- and hence we must remember 
2395     // that we have it independently of pstrExt 
2396     if ( posLastDot 
== wxString::npos 
) 
2406         // take everything after the dot 
2408             *pstrExt 
= fullpath
.Mid(posLastDot 
+ 1); 
2415 void wxFileName::SplitPath(const wxString
& fullpath
, 
2419                            wxPathFormat format
) 
2422     SplitPath(fullpath
, &volume
, path
, name
, ext
, format
); 
2426         path
->Prepend(wxGetVolumeString(volume
, format
)); 
2431 wxString 
wxFileName::StripExtension(const wxString
& fullpath
) 
2433     wxFileName 
fn(fullpath
); 
2435     return fn
.GetFullPath(); 
2438 // ---------------------------------------------------------------------------- 
2440 // ---------------------------------------------------------------------------- 
2444 bool wxFileName::SetTimes(const wxDateTime 
*dtAccess
, 
2445                           const wxDateTime 
*dtMod
, 
2446                           const wxDateTime 
*dtCreate
) const 
2448 #if defined(__WIN32__) 
2449     FILETIME ftAccess
, ftCreate
, ftWrite
; 
2452         ConvertWxToFileTime(&ftCreate
, *dtCreate
); 
2454         ConvertWxToFileTime(&ftAccess
, *dtAccess
); 
2456         ConvertWxToFileTime(&ftWrite
, *dtMod
); 
2462         if ( wxGetOsVersion() == wxOS_WINDOWS_9X 
) 
2464             wxLogError(_("Setting directory access times is not supported " 
2465                          "under this OS version")); 
2470         flags 
= FILE_FLAG_BACKUP_SEMANTICS
; 
2474         path 
= GetFullPath(); 
2478     wxFileHandle 
fh(path
, wxFileHandle::WriteAttr
, flags
); 
2481         if ( ::SetFileTime(fh
, 
2482                            dtCreate 
? &ftCreate 
: NULL
, 
2483                            dtAccess 
? &ftAccess 
: NULL
, 
2484                            dtMod 
? &ftWrite 
: NULL
) ) 
2489 #elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) 
2490     wxUnusedVar(dtCreate
); 
2492     if ( !dtAccess 
&& !dtMod 
) 
2494         // can't modify the creation time anyhow, don't try 
2498     // if dtAccess or dtMod is not specified, use the other one (which must be 
2499     // non NULL because of the test above) for both times 
2501     utm
.actime 
= dtAccess 
? dtAccess
->GetTicks() : dtMod
->GetTicks(); 
2502     utm
.modtime 
= dtMod 
? dtMod
->GetTicks() : dtAccess
->GetTicks(); 
2503     if ( utime(GetFullPath().fn_str(), &utm
) == 0 ) 
2507 #else // other platform 
2508     wxUnusedVar(dtAccess
); 
2510     wxUnusedVar(dtCreate
); 
2513     wxLogSysError(_("Failed to modify file times for '%s'"), 
2514                   GetFullPath().c_str()); 
2519 bool wxFileName::Touch() const 
2521 #if defined(__UNIX_LIKE__) 
2522     // under Unix touching file is simple: just pass NULL to utime() 
2523     if ( utime(GetFullPath().fn_str(), NULL
) == 0 ) 
2528     wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); 
2531 #else // other platform 
2532     wxDateTime dtNow 
= wxDateTime::Now(); 
2534     return SetTimes(&dtNow
, &dtNow
, NULL 
/* don't change create time */); 
2538 bool wxFileName::GetTimes(wxDateTime 
*dtAccess
, 
2540                           wxDateTime 
*dtCreate
) const 
2542 #if defined(__WIN32__) 
2543     // we must use different methods for the files and directories under 
2544     // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and 
2545     // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and 
2548     FILETIME ftAccess
, ftCreate
, ftWrite
; 
2551         // implemented in msw/dir.cpp 
2552         extern bool wxGetDirectoryTimes(const wxString
& dirname
, 
2553                                         FILETIME 
*, FILETIME 
*, FILETIME 
*); 
2555         // we should pass the path without the trailing separator to 
2556         // wxGetDirectoryTimes() 
2557         ok 
= wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME
), 
2558                                  &ftAccess
, &ftCreate
, &ftWrite
); 
2562         wxFileHandle 
fh(GetFullPath(), wxFileHandle::ReadAttr
); 
2565             ok 
= ::GetFileTime(fh
, 
2566                                dtCreate 
? &ftCreate 
: NULL
, 
2567                                dtAccess 
? &ftAccess 
: NULL
, 
2568                                dtMod 
? &ftWrite 
: NULL
) != 0; 
2579             ConvertFileTimeToWx(dtCreate
, ftCreate
); 
2581             ConvertFileTimeToWx(dtAccess
, ftAccess
); 
2583             ConvertFileTimeToWx(dtMod
, ftWrite
); 
2587 #elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__)) 
2588     // no need to test for IsDir() here 
2590     if ( wxStat( GetFullPath().c_str(), &stBuf
) == 0 ) 
2593             dtAccess
->Set(stBuf
.st_atime
); 
2595             dtMod
->Set(stBuf
.st_mtime
); 
2597             dtCreate
->Set(stBuf
.st_ctime
); 
2601 #else // other platform 
2602     wxUnusedVar(dtAccess
); 
2604     wxUnusedVar(dtCreate
); 
2607     wxLogSysError(_("Failed to retrieve file times for '%s'"), 
2608                   GetFullPath().c_str()); 
2613 #endif // wxUSE_DATETIME 
2616 // ---------------------------------------------------------------------------- 
2617 // file size functions 
2618 // ---------------------------------------------------------------------------- 
2623 wxULongLong 
wxFileName::GetSize(const wxString 
&filename
) 
2625     if (!wxFileExists(filename
)) 
2626         return wxInvalidSize
; 
2628 #if defined(__WXPALMOS__) 
2630     return wxInvalidSize
; 
2631 #elif defined(__WIN32__) 
2632     wxFileHandle 
f(filename
, wxFileHandle::ReadAttr
); 
2634         return wxInvalidSize
; 
2636     DWORD lpFileSizeHigh
; 
2637     DWORD ret 
= GetFileSize(f
, &lpFileSizeHigh
); 
2638     if ( ret 
== INVALID_FILE_SIZE 
&& ::GetLastError() != NO_ERROR 
) 
2639         return wxInvalidSize
; 
2641     return wxULongLong(lpFileSizeHigh
, ret
); 
2642 #else // ! __WIN32__ 
2644 #ifndef wxNEED_WX_UNISTD_H 
2645     if (wxStat( filename
.fn_str() , &st
) != 0) 
2647     if (wxStat( filename
, &st
) != 0) 
2649         return wxInvalidSize
; 
2650     return wxULongLong(st
.st_size
); 
2655 wxString 
wxFileName::GetHumanReadableSize(const wxULongLong 
&bs
, 
2656                                           const wxString 
&nullsize
, 
2659     static const double KILOBYTESIZE 
= 1024.0; 
2660     static const double MEGABYTESIZE 
= 1024.0*KILOBYTESIZE
; 
2661     static const double GIGABYTESIZE 
= 1024.0*MEGABYTESIZE
; 
2662     static const double TERABYTESIZE 
= 1024.0*GIGABYTESIZE
; 
2664     if (bs 
== 0 || bs 
== wxInvalidSize
) 
2667     double bytesize 
= bs
.ToDouble(); 
2668     if (bytesize 
< KILOBYTESIZE
) 
2669         return wxString::Format(_("%s B"), bs
.ToString().c_str()); 
2670     if (bytesize 
< MEGABYTESIZE
) 
2671         return wxString::Format(_("%.*f kB"), precision
, bytesize
/KILOBYTESIZE
); 
2672     if (bytesize 
< GIGABYTESIZE
) 
2673         return wxString::Format(_("%.*f MB"), precision
, bytesize
/MEGABYTESIZE
); 
2674     if (bytesize 
< TERABYTESIZE
) 
2675         return wxString::Format(_("%.*f GB"), precision
, bytesize
/GIGABYTESIZE
); 
2677     return wxString::Format(_("%.*f TB"), precision
, bytesize
/TERABYTESIZE
); 
2680 wxULongLong 
wxFileName::GetSize() const 
2682     return GetSize(GetFullPath()); 
2685 wxString 
wxFileName::GetHumanReadableSize(const wxString 
&failmsg
, int precision
) const 
2687     return GetHumanReadableSize(GetSize(), failmsg
, precision
); 
2690 #endif // wxUSE_LONGLONG 
2692 // ---------------------------------------------------------------------------- 
2693 // Mac-specific functions 
2694 // ---------------------------------------------------------------------------- 
2696 #if defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON 
2701 class MacDefaultExtensionRecord
 
2704     MacDefaultExtensionRecord() 
2710     // default copy ctor, assignment operator and dtor are ok 
2712     MacDefaultExtensionRecord(const wxString
& ext
, OSType type
, OSType creator
) 
2716         m_creator 
= creator
; 
2724 WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord
, MacDefaultExtensionArray
); 
2726 bool gMacDefaultExtensionsInited 
= false; 
2728 #include "wx/arrimpl.cpp" 
2730 WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray
); 
2732 MacDefaultExtensionArray gMacDefaultExtensions
; 
2734 // load the default extensions 
2735 const MacDefaultExtensionRecord gDefaults
[] = 
2737     MacDefaultExtensionRecord( "txt", 'TEXT', 'ttxt' ), 
2738     MacDefaultExtensionRecord( "tif", 'TIFF', '****' ), 
2739     MacDefaultExtensionRecord( "jpg", 'JPEG', '****' ), 
2742 void MacEnsureDefaultExtensionsLoaded() 
2744     if ( !gMacDefaultExtensionsInited 
) 
2746         // we could load the pc exchange prefs here too 
2747         for ( size_t i 
= 0 ; i 
< WXSIZEOF( gDefaults 
) ; ++i 
) 
2749             gMacDefaultExtensions
.Add( gDefaults
[i
] ) ; 
2751         gMacDefaultExtensionsInited 
= true; 
2755 } // anonymous namespace 
2757 bool wxFileName::MacSetTypeAndCreator( wxUint32 type 
, wxUint32 creator 
) 
2760     FSCatalogInfo catInfo
; 
2763     if ( wxMacPathToFSRef( GetFullPath() , &fsRef 
) == noErr 
) 
2765         if ( FSGetCatalogInfo (&fsRef
, kFSCatInfoFinderInfo
, &catInfo
, NULL
, NULL
, NULL
) == noErr 
) 
2767             finfo 
= (FileInfo
*)&catInfo
.finderInfo
; 
2768             finfo
->fileType 
= type 
; 
2769             finfo
->fileCreator 
= creator 
; 
2770             FSSetCatalogInfo( &fsRef
, kFSCatInfoFinderInfo
, &catInfo 
) ; 
2777 bool wxFileName::MacGetTypeAndCreator( wxUint32 
*type 
, wxUint32 
*creator 
) const 
2780     FSCatalogInfo catInfo
; 
2783     if ( wxMacPathToFSRef( GetFullPath() , &fsRef 
) == noErr 
) 
2785         if ( FSGetCatalogInfo (&fsRef
, kFSCatInfoFinderInfo
, &catInfo
, NULL
, NULL
, NULL
) == noErr 
) 
2787             finfo 
= (FileInfo
*)&catInfo
.finderInfo
; 
2788             *type 
= finfo
->fileType 
; 
2789             *creator 
= finfo
->fileCreator 
; 
2796 bool wxFileName::MacSetDefaultTypeAndCreator() 
2798     wxUint32 type 
, creator 
; 
2799     if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type 
, 
2802         return MacSetTypeAndCreator( type 
, creator 
) ; 
2807 bool wxFileName::MacFindDefaultTypeAndCreator( const wxString
& ext 
, wxUint32 
*type 
, wxUint32 
*creator 
) 
2809   MacEnsureDefaultExtensionsLoaded() ; 
2810   wxString extl 
= ext
.Lower() ; 
2811   for( int i 
= gMacDefaultExtensions
.Count() - 1 ; i 
>= 0 ; --i 
) 
2813     if ( gMacDefaultExtensions
.Item(i
).m_ext 
== extl 
) 
2815       *type 
= gMacDefaultExtensions
.Item(i
).m_type 
; 
2816       *creator 
= gMacDefaultExtensions
.Item(i
).m_creator 
; 
2823 void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString
& ext 
, wxUint32 type 
, wxUint32 creator 
) 
2825   MacEnsureDefaultExtensionsLoaded(); 
2826   MacDefaultExtensionRecord 
rec(ext
.Lower(), type
, creator
); 
2827   gMacDefaultExtensions
.Add( rec 
); 
2830 #endif // defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON