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 
  27    wxPATH_MAC:  Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file 
  29                     volume:dir1:...:dirN:filename 
  30                 and the relative file names are either 
  31                     :dir1:...:dirN:filename 
  34                 (although :filename works as well). 
  35                 Since the volume is just part of the file path, it is not 
  36                 treated like a separate entity as it is done under DOS and 
  37                 VMS, it is just treated as another dir. 
  39    wxPATH_VMS:  VMS native format, absolute file names have the form 
  40                     <device>:[dir1.dir2.dir3]file.txt 
  42                     <device>:[000000.dir1.dir2.dir3]file.txt 
  44                 the <device> is the physical device (i.e. disk). 000000 is the 
  45                 root directory on the device which can be omitted. 
  47                 Note that VMS uses different separators unlike Unix: 
  48                  : always after the device. If the path does not contain : than 
  49                    the default (the device of the current directory) is assumed. 
  50                  [ start of directory specyfication 
  51                  . separator between directory and subdirectory 
  52                  ] between directory and file 
  55 // ============================================================================ 
  57 // ============================================================================ 
  59 // ---------------------------------------------------------------------------- 
  61 // ---------------------------------------------------------------------------- 
  63 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  64 #pragma implementation "filename.h" 
  67 // For compilers that support precompilation, includes "wx.h". 
  68 #include "wx/wxprec.h" 
  80 #include "wx/filename.h" 
  81 #include "wx/tokenzr.h" 
  82 #include "wx/config.h"          // for wxExpandEnvVars 
  85 #include "wx/dynlib.h" 
  87 // For GetShort/LongPathName 
  89 #include "wx/msw/wrapwin.h" 
  93 #include "wx/msw/private.h" 
  96 #if defined(__WXMAC__) 
  97   #include  "wx/mac/private.h"  // includes mac headers 
 100 // utime() is POSIX so should normally be available on all Unices 
 102 #include <sys/types.h> 
 104 #include <sys/stat.h> 
 114 #include <sys/types.h> 
 116 #include <sys/stat.h> 
 127 #include <sys/utime.h> 
 128 #include <sys/stat.h> 
 139 #define MAX_PATH _MAX_PATH 
 142 // ---------------------------------------------------------------------------- 
 144 // ---------------------------------------------------------------------------- 
 146 // small helper class which opens and closes the file - we use it just to get 
 147 // a file handle for the given file name to pass it to some Win32 API function 
 148 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
 159     wxFileHandle(const wxString
& filename
, OpenMode mode
) 
 161         m_hFile 
= ::CreateFile
 
 164                      mode 
== Read 
? GENERIC_READ    
// access mask 
 167                      NULL
,                          // no secutity attr 
 168                      OPEN_EXISTING
,                 // creation disposition 
 170                      NULL                           
// no template file 
 173         if ( m_hFile 
== INVALID_HANDLE_VALUE 
) 
 175             wxLogSysError(_("Failed to open '%s' for %s"), 
 177                           mode 
== Read 
? _("reading") : _("writing")); 
 183         if ( m_hFile 
!= INVALID_HANDLE_VALUE 
) 
 185             if ( !::CloseHandle(m_hFile
) ) 
 187                 wxLogSysError(_("Failed to close file handle")); 
 192     // return true only if the file could be opened successfully 
 193     bool IsOk() const { return m_hFile 
!= INVALID_HANDLE_VALUE
; } 
 196     operator HANDLE() const { return m_hFile
; } 
 204 // ---------------------------------------------------------------------------- 
 206 // ---------------------------------------------------------------------------- 
 208 #if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__) 
 210 // convert between wxDateTime and FILETIME which is a 64-bit value representing 
 211 // the number of 100-nanosecond intervals since January 1, 1601. 
 213 static void ConvertFileTimeToWx(wxDateTime 
*dt
, const FILETIME 
&ft
) 
 215     FILETIME ftcopy 
= ft
; 
 217     if ( !::FileTimeToLocalFileTime(&ftcopy
, &ftLocal
) ) 
 219         wxLogLastError(_T("FileTimeToLocalFileTime")); 
 223     if ( !::FileTimeToSystemTime(&ftLocal
, &st
) ) 
 225         wxLogLastError(_T("FileTimeToSystemTime")); 
 228     dt
->Set(st
.wDay
, wxDateTime::Month(st
.wMonth 
- 1), st
.wYear
, 
 229             st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
); 
 232 static void ConvertWxToFileTime(FILETIME 
*ft
, const wxDateTime
& dt
) 
 235     st
.wDay 
= dt
.GetDay(); 
 236     st
.wMonth 
= dt
.GetMonth() + 1; 
 237     st
.wYear 
= dt
.GetYear(); 
 238     st
.wHour 
= dt
.GetHour(); 
 239     st
.wMinute 
= dt
.GetMinute(); 
 240     st
.wSecond 
= dt
.GetSecond(); 
 241     st
.wMilliseconds 
= dt
.GetMillisecond(); 
 244     if ( !::SystemTimeToFileTime(&st
, &ftLocal
) ) 
 246         wxLogLastError(_T("SystemTimeToFileTime")); 
 249     if ( !::LocalFileTimeToFileTime(&ftLocal
, ft
) ) 
 251         wxLogLastError(_T("LocalFileTimeToFileTime")); 
 255 #endif // wxUSE_DATETIME && __WIN32__ 
 257 // return a string with the volume par 
 258 static wxString 
wxGetVolumeString(const wxString
& volume
, wxPathFormat format
) 
 262     if ( !volume
.empty() ) 
 264         format 
= wxFileName::GetFormat(format
); 
 266         // Special Windows UNC paths hack, part 2: undo what we did in 
 267         // SplitPath() and make an UNC path if we have a drive which is not a 
 268         // single letter (hopefully the network shares can't be one letter only 
 269         // although I didn't find any authoritative docs on this) 
 270         if ( format 
== wxPATH_DOS 
&& volume
.length() > 1 ) 
 272             path 
<< wxFILE_SEP_PATH_DOS 
<< wxFILE_SEP_PATH_DOS 
<< volume
; 
 274         else if  ( format 
== wxPATH_DOS 
|| format 
== wxPATH_VMS 
) 
 276             path 
<< volume 
<< wxFileName::GetVolumeSeparator(format
); 
 284 // ============================================================================ 
 286 // ============================================================================ 
 288 // ---------------------------------------------------------------------------- 
 289 // wxFileName construction 
 290 // ---------------------------------------------------------------------------- 
 292 void wxFileName::Assign( const wxFileName 
&filepath 
) 
 294     m_volume 
= filepath
.GetVolume(); 
 295     m_dirs 
= filepath
.GetDirs(); 
 296     m_name 
= filepath
.GetName(); 
 297     m_ext 
= filepath
.GetExt(); 
 298     m_relative 
= filepath
.m_relative
; 
 301 void wxFileName::Assign(const wxString
& volume
, 
 302                         const wxString
& path
, 
 303                         const wxString
& name
, 
 305                         wxPathFormat format 
) 
 307     SetPath( path
, format 
); 
 314 void wxFileName::SetPath( const wxString 
&path
, wxPathFormat format 
) 
 320         wxPathFormat my_format 
= GetFormat( format 
); 
 321         wxString my_path 
= path
; 
 323         // 1) Determine if the path is relative or absolute. 
 324         wxChar leadingChar 
= my_path
[0u]; 
 329                 m_relative 
= leadingChar 
== wxT(':'); 
 331                 // We then remove a leading ":". The reason is in our 
 332                 // storage form for relative paths: 
 333                 // ":dir:file.txt" actually means "./dir/file.txt" in 
 334                 // DOS notation and should get stored as 
 335                 // (relative) (dir) (file.txt) 
 336                 // "::dir:file.txt" actually means "../dir/file.txt" 
 337                 // stored as (relative) (..) (dir) (file.txt) 
 338                 // This is important only for the Mac as an empty dir 
 339                 // actually means <UP>, whereas under DOS, double 
 340                 // slashes can be ignored: "\\\\" is the same as "\\". 
 342                     my_path
.erase( 0, 1 ); 
 346                 // TODO: what is the relative path format here? 
 351                 wxFAIL_MSG( _T("Unknown path format") ); 
 352                 // !! Fall through !! 
 355                 // the paths of the form "~" or "~username" are absolute 
 356                 m_relative 
= leadingChar 
!= wxT('/') && leadingChar 
!= _T('~'); 
 360                 m_relative 
= !IsPathSeparator(leadingChar
, my_format
); 
 365         // 2) Break up the path into its members. If the original path 
 366         //    was just "/" or "\\", m_dirs will be empty. We know from 
 367         //    the m_relative field, if this means "nothing" or "root dir". 
 369         wxStringTokenizer 
tn( my_path
, GetPathSeparators(my_format
) ); 
 371         while ( tn
.HasMoreTokens() ) 
 373             wxString token 
= tn
.GetNextToken(); 
 375             // Remove empty token under DOS and Unix, interpret them 
 379                 if (my_format 
== wxPATH_MAC
) 
 380                     m_dirs
.Add( wxT("..") ); 
 389     else // no path at all 
 395 void wxFileName::Assign(const wxString
& fullpath
, 
 398     wxString volume
, path
, name
, ext
; 
 399     SplitPath(fullpath
, &volume
, &path
, &name
, &ext
, format
); 
 401     Assign(volume
, path
, name
, ext
, format
); 
 404 void wxFileName::Assign(const wxString
& fullpathOrig
, 
 405                         const wxString
& fullname
, 
 408     // always recognize fullpath as directory, even if it doesn't end with a 
 410     wxString fullpath 
= fullpathOrig
; 
 411     if ( !wxEndsWithPathSeparator(fullpath
) ) 
 413         fullpath 
+= GetPathSeparator(format
); 
 416     wxString volume
, path
, name
, ext
; 
 418     // do some consistency checks in debug mode: the name should be really just 
 419     // the filename and the path should be really just a path 
 421     wxString pathDummy
, nameDummy
, extDummy
; 
 423     SplitPath(fullname
, &pathDummy
, &name
, &ext
, format
); 
 425     wxASSERT_MSG( pathDummy
.empty(), 
 426                   _T("the file name shouldn't contain the path") ); 
 428     SplitPath(fullpath
, &volume
, &path
, &nameDummy
, &extDummy
, format
); 
 430     wxASSERT_MSG( nameDummy
.empty() && extDummy
.empty(), 
 431                   _T("the path shouldn't contain file name nor extension") ); 
 433 #else // !__WXDEBUG__ 
 434     SplitPath(fullname
, NULL 
/* no path */, &name
, &ext
, format
); 
 435     SplitPath(fullpath
, &volume
, &path
, NULL
, NULL
, format
); 
 436 #endif // __WXDEBUG__/!__WXDEBUG__ 
 438     Assign(volume
, path
, name
, ext
, format
); 
 441 void wxFileName::AssignDir(const wxString
& dir
, wxPathFormat format
) 
 443     Assign(dir
, _T(""), format
); 
 446 void wxFileName::Clear() 
 452     m_ext 
= wxEmptyString
; 
 454     // we don't have any absolute path for now 
 459 wxFileName 
wxFileName::FileName(const wxString
& file
, wxPathFormat format
) 
 461     return wxFileName(file
, format
); 
 465 wxFileName 
wxFileName::DirName(const wxString
& dir
, wxPathFormat format
) 
 468     fn
.AssignDir(dir
, format
); 
 472 // ---------------------------------------------------------------------------- 
 474 // ---------------------------------------------------------------------------- 
 476 bool wxFileName::FileExists() const 
 478     return wxFileName::FileExists( GetFullPath() ); 
 481 bool wxFileName::FileExists( const wxString 
&file 
) 
 483     return ::wxFileExists( file 
); 
 486 bool wxFileName::DirExists() const 
 488     return wxFileName::DirExists( GetFullPath() ); 
 491 bool wxFileName::DirExists( const wxString 
&dir 
) 
 493     return ::wxDirExists( dir 
); 
 496 // ---------------------------------------------------------------------------- 
 497 // CWD and HOME stuff 
 498 // ---------------------------------------------------------------------------- 
 500 void wxFileName::AssignCwd(const wxString
& volume
) 
 502     AssignDir(wxFileName::GetCwd(volume
)); 
 506 wxString 
wxFileName::GetCwd(const wxString
& volume
) 
 508     // if we have the volume, we must get the current directory on this drive 
 509     // and to do this we have to chdir to this volume - at least under Windows, 
 510     // I don't know how to get the current drive on another volume elsewhere 
 513     if ( !volume
.empty() ) 
 516         SetCwd(volume 
+ GetVolumeSeparator()); 
 519     wxString cwd 
= ::wxGetCwd(); 
 521     if ( !volume
.empty() ) 
 529 bool wxFileName::SetCwd() 
 531     return wxFileName::SetCwd( GetFullPath() ); 
 534 bool wxFileName::SetCwd( const wxString 
&cwd 
) 
 536     return ::wxSetWorkingDirectory( cwd 
); 
 539 void wxFileName::AssignHomeDir() 
 541     AssignDir(wxFileName::GetHomeDir()); 
 544 wxString 
wxFileName::GetHomeDir() 
 546     return ::wxGetHomeDir(); 
 549 void wxFileName::AssignTempFileName(const wxString
& prefix
, wxFile 
*fileTemp
) 
 551     wxString tempname 
= CreateTempFileName(prefix
, fileTemp
); 
 552     if ( tempname
.empty() ) 
 554         // error, failed to get temp file name 
 565 wxFileName::CreateTempFileName(const wxString
& prefix
, wxFile 
*fileTemp
) 
 567     wxString path
, dir
, name
; 
 569     // use the directory specified by the prefix 
 570     SplitPath(prefix
, &dir
, &name
, NULL 
/* extension */); 
 572 #if defined(__WXWINCE__) 
 575         // FIXME. Create \temp dir? 
 578     path 
= dir 
+ wxT("\\") + prefix
; 
 580     while (wxFileExists(path
)) 
 582         path 
= dir 
+ wxT("\\") + prefix 
; 
 587 #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 591         if ( !::GetTempPath(MAX_PATH
, wxStringBuffer(dir
, MAX_PATH 
+ 1)) ) 
 593             wxLogLastError(_T("GetTempPath")); 
 598             // GetTempFileName() fails if we pass it an empty string 
 602     else // we have a dir to create the file in 
 604         // ensure we use only the back slashes as GetTempFileName(), unlike all 
 605         // the other APIs, is picky and doesn't accept the forward ones 
 606         dir
.Replace(_T("/"), _T("\\")); 
 609     if ( !::GetTempFileName(dir
, name
, 0, wxStringBuffer(path
, MAX_PATH 
+ 1)) ) 
 611         wxLogLastError(_T("GetTempFileName")); 
 616     if ( !::GetTempFileName(NULL
, prefix
, 0, wxStringBuffer(path
, 1025)) ) 
 625 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 626         dir 
= wxMacFindFolder(  (short) kOnSystemDisk
, kTemporaryFolderType
, kCreateFolder 
) ; 
 628         dir 
= wxGetenv(_T("TMP")); 
 631             dir 
= wxGetenv(_T("TEMP")); 
 637             #if defined(__DOS__) || defined(__OS2__) 
 648     if ( !wxEndsWithPathSeparator(dir
) && 
 649             (name
.empty() || !wxIsPathSeparator(name
[0u])) ) 
 651         path 
+= wxFILE_SEP_PATH
; 
 656 #if defined(HAVE_MKSTEMP) 
 657     // scratch space for mkstemp() 
 658     path 
+= _T("XXXXXX"); 
 660     // we need to copy the path to the buffer in which mkstemp() can modify it 
 661     wxCharBuffer 
buf( wxConvFile
.cWX2MB( path 
) ); 
 663     // cast is safe because the string length doesn't change 
 664     int fdTemp 
= mkstemp( (char*)(const char*) buf 
); 
 667         // this might be not necessary as mkstemp() on most systems should have 
 668         // already done it but it doesn't hurt neither... 
 671     else // mkstemp() succeeded 
 673         path 
= wxConvFile
.cMB2WX( (const char*) buf 
); 
 675         // avoid leaking the fd 
 678             fileTemp
->Attach(fdTemp
); 
 685 #else // !HAVE_MKSTEMP 
 689     path 
+= _T("XXXXXX"); 
 691     wxCharBuffer buf 
= wxConvFile
.cWX2MB( path 
); 
 692     if ( !mktemp( (const char*) buf 
) ) 
 698         path 
= wxConvFile
.cMB2WX( (const char*) buf 
); 
 700 #else // !HAVE_MKTEMP (includes __DOS__) 
 701     // generate the unique file name ourselves 
 702     #if !defined(__DOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) ) 
 703     path 
<< (unsigned int)getpid(); 
 708     static const size_t numTries 
= 1000; 
 709     for ( size_t n 
= 0; n 
< numTries
; n
++ ) 
 711         // 3 hex digits is enough for numTries == 1000 < 4096 
 712         pathTry 
= path 
+ wxString::Format(_T("%.03x"), (unsigned int) n
); 
 713         if ( !wxFile::Exists(pathTry
) ) 
 722 #endif // HAVE_MKTEMP/!HAVE_MKTEMP 
 727 #endif // HAVE_MKSTEMP/!HAVE_MKSTEMP 
 729 #endif // Windows/!Windows 
 733         wxLogSysError(_("Failed to create a temporary file name")); 
 735     else if ( fileTemp 
&& !fileTemp
->IsOpened() ) 
 737         // open the file - of course, there is a race condition here, this is 
 738         // why we always prefer using mkstemp()... 
 740         // NB: GetTempFileName() under Windows creates the file, so using 
 741         //     write_excl there would fail 
 742         if ( !fileTemp
->Open(path
, 
 743 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 748                              wxS_IRUSR 
| wxS_IWUSR
) ) 
 750             // FIXME: If !ok here should we loop and try again with another 
 751             //        file name?  That is the standard recourse if open(O_EXCL) 
 752             //        fails, though of course it should be protected against 
 753             //        possible infinite looping too. 
 755             wxLogError(_("Failed to open temporary file.")); 
 764 // ---------------------------------------------------------------------------- 
 765 // directory operations 
 766 // ---------------------------------------------------------------------------- 
 768 bool wxFileName::Mkdir( int perm
, int flags 
) 
 770     return wxFileName::Mkdir( GetFullPath(), perm
, flags 
); 
 773 bool wxFileName::Mkdir( const wxString
& dir
, int perm
, int flags 
) 
 775     if ( flags 
& wxPATH_MKDIR_FULL 
) 
 777         // split the path in components 
 779         filename
.AssignDir(dir
); 
 782         if ( filename
.HasVolume()) 
 784             currPath 
<< wxGetVolumeString(filename
.GetVolume(), wxPATH_NATIVE
); 
 787         wxArrayString dirs 
= filename
.GetDirs(); 
 788         size_t count 
= dirs
.GetCount(); 
 789         for ( size_t i 
= 0; i 
< count
; i
++ ) 
 792 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 793                         // relative pathnames are exactely the other way round under mac... 
 794                 !filename
.IsAbsolute()  
 796                 filename
.IsAbsolute()  
 799                 currPath 
+= wxFILE_SEP_PATH
; 
 802             if (!DirExists(currPath
)) 
 804                 if (!wxMkdir(currPath
, perm
)) 
 806                     // no need to try creating further directories 
 816     return ::wxMkdir( dir
, perm 
); 
 819 bool wxFileName::Rmdir() 
 821     return wxFileName::Rmdir( GetFullPath() ); 
 824 bool wxFileName::Rmdir( const wxString 
&dir 
) 
 826     return ::wxRmdir( dir 
); 
 829 // ---------------------------------------------------------------------------- 
 830 // path normalization 
 831 // ---------------------------------------------------------------------------- 
 833 bool wxFileName::Normalize(int flags
, 
 837     // deal with env vars renaming first as this may seriously change the path 
 838     if ( flags 
& wxPATH_NORM_ENV_VARS 
) 
 840         wxString pathOrig 
= GetFullPath(format
); 
 841         wxString path 
= wxExpandEnvVars(pathOrig
); 
 842         if ( path 
!= pathOrig 
) 
 849     // the existing path components 
 850     wxArrayString dirs 
= GetDirs(); 
 852     // the path to prepend in front to make the path absolute 
 855     format 
= GetFormat(format
); 
 857     // make the path absolute 
 858     if ( (flags 
& wxPATH_NORM_ABSOLUTE
) && !IsAbsolute(format
) ) 
 862             curDir
.AssignCwd(GetVolume()); 
 866             curDir
.AssignDir(cwd
); 
 869         // the path may be not absolute because it doesn't have the volume name 
 870         // but in this case we shouldn't modify the directory components of it 
 871         // but just set the current volume 
 872         if ( !HasVolume() && curDir
.HasVolume() ) 
 874             SetVolume(curDir
.GetVolume()); 
 878                 // yes, it was the case - we don't need curDir then 
 884     // handle ~ stuff under Unix only 
 885     if ( (format 
== wxPATH_UNIX
) && (flags 
& wxPATH_NORM_TILDE
) ) 
 887         if ( !dirs
.IsEmpty() ) 
 889             wxString dir 
= dirs
[0u]; 
 890             if ( !dir
.empty() && dir
[0u] == _T('~') ) 
 892                 curDir
.AssignDir(wxGetUserHome(dir
.c_str() + 1)); 
 899     // transform relative path into abs one 
 902         wxArrayString dirsNew 
= curDir
.GetDirs(); 
 903         size_t count 
= dirs
.GetCount(); 
 904         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 906             dirsNew
.Add(dirs
[n
]); 
 912     // now deal with ".", ".." and the rest 
 914     size_t count 
= dirs
.GetCount(); 
 915     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 917         wxString dir 
= dirs
[n
]; 
 919         if ( flags 
& wxPATH_NORM_DOTS 
) 
 921             if ( dir 
== wxT(".") ) 
 927             if ( dir 
== wxT("..") ) 
 929                 if ( m_dirs
.IsEmpty() ) 
 931                     wxLogError(_("The path '%s' contains too many \"..\"!"), 
 932                                GetFullPath().c_str()); 
 936                 m_dirs
.RemoveAt(m_dirs
.GetCount() - 1); 
 941         if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
 949 #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE 
 950     if ( (flags 
& wxPATH_NORM_SHORTCUT
) ) 
 953         if (GetShortcutTarget(GetFullPath(format
), filename
)) 
 955             // Repeat this since we may now have a new path 
 956             if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
 958                 filename
.MakeLower(); 
 966     if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
 968         // VZ: expand env vars here too? 
 974     // we do have the path now 
 976     // NB: need to do this before (maybe) calling Assign() below 
 979 #if defined(__WIN32__) 
 980     if ( (flags 
& wxPATH_NORM_LONG
) && (format 
== wxPATH_DOS
) ) 
 982         Assign(GetLongPath()); 
 989 // ---------------------------------------------------------------------------- 
 990 // get the shortcut target 
 991 // ---------------------------------------------------------------------------- 
 993 // WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions. 
 994 // The .lnk file is a plain text file so it should be easy to 
 995 // make it work. Hint from Google Groups: 
 996 // "If you open up a lnk file, you'll see a 
 997 // number, followed by a pound sign (#), followed by more text. The 
 998 // number is the number of characters that follows the pound sign. The 
 999 // characters after the pound sign are the command line (which _can_ 
1000 // include arguments) to be executed. Any path (e.g. \windows\program 
1001 // files\myapp.exe) that includes spaces needs to be enclosed in 
1002 // quotation marks." 
1004 #if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE 
1005 // The following lines are necessary under WinCE 
1006 // #include "wx/msw/private.h" 
1007 // #include <ole2.h> 
1009 #if defined(__WXWINCE__) 
1010 #include <shlguid.h> 
1013 bool wxFileName::GetShortcutTarget(const wxString
& shortcutPath
, wxString
& targetFilename
, wxString
* arguments
) 
1015     wxString path
, file
, ext
; 
1016     wxSplitPath(shortcutPath
, & path
, & file
, & ext
); 
1020     bool success 
= FALSE
; 
1022     // Assume it's not a shortcut if it doesn't end with lnk 
1023     if (ext
.Lower() != wxT("lnk")) 
1026         // create a ShellLink object 
1027         hres 
= CoCreateInstance(CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, 
1028                                 IID_IShellLink
, (LPVOID
*) &psl
); 
1030         if (SUCCEEDED(hres
)) 
1033                 hres 
= psl
->QueryInterface( IID_IPersistFile
, (LPVOID 
*) &ppf
); 
1034                 if (SUCCEEDED(hres
)) 
1036                         WCHAR wsz
[MAX_PATH
]; 
1038                         MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, shortcutPath
.mb_str(), -1, wsz
, 
1041                         hres 
= ppf
->Load(wsz
, 0);                        
1042                         if (SUCCEEDED(hres
)) 
1045                                 psl
->GetPath(buf
, 2048, NULL
, SLGP_UNCPRIORITY
); 
1046                                 targetFilename 
= wxString(buf
); 
1047                 success 
= (shortcutPath 
!= targetFilename
); 
1049                                 psl
->GetArguments(buf
, 2048); 
1051                 if (!args
.IsEmpty() && arguments
) 
1064 // ---------------------------------------------------------------------------- 
1065 // absolute/relative paths 
1066 // ---------------------------------------------------------------------------- 
1068 bool wxFileName::IsAbsolute(wxPathFormat format
) const 
1070     // if our path doesn't start with a path separator, it's not an absolute 
1075     if ( !GetVolumeSeparator(format
).empty() ) 
1077         // this format has volumes and an absolute path must have one, it's not 
1078         // enough to have the full path to bean absolute file under Windows 
1079         if ( GetVolume().empty() ) 
1086 bool wxFileName::MakeRelativeTo(const wxString
& pathBase
, wxPathFormat format
) 
1088     wxFileName fnBase 
= wxFileName::DirName(pathBase
, format
); 
1090     // get cwd only once - small time saving 
1091     wxString cwd 
= wxGetCwd(); 
1092     Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1093     fnBase
.Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1095     bool withCase 
= IsCaseSensitive(format
); 
1097     // we can't do anything if the files live on different volumes 
1098     if ( !GetVolume().IsSameAs(fnBase
.GetVolume(), withCase
) ) 
1104     // same drive, so we don't need our volume 
1107     // remove common directories starting at the top 
1108     while ( !m_dirs
.IsEmpty() && !fnBase
.m_dirs
.IsEmpty() && 
1109                 m_dirs
[0u].IsSameAs(fnBase
.m_dirs
[0u], withCase
) ) 
1112         fnBase
.m_dirs
.RemoveAt(0); 
1115     // add as many ".." as needed 
1116     size_t count 
= fnBase
.m_dirs
.GetCount(); 
1117     for ( size_t i 
= 0; i 
< count
; i
++ ) 
1119         m_dirs
.Insert(wxT(".."), 0u); 
1122     if ( format 
== wxPATH_UNIX 
|| format 
== wxPATH_DOS 
) 
1124         // a directory made relative with respect to itself is '.' under Unix 
1125         // and DOS, by definition (but we don't have to insert "./" for the 
1127         if ( m_dirs
.IsEmpty() && IsDir() ) 
1129             m_dirs
.Add(_T('.')); 
1139 // ---------------------------------------------------------------------------- 
1140 // filename kind tests 
1141 // ---------------------------------------------------------------------------- 
1143 bool wxFileName::SameAs(const wxFileName
& filepath
, wxPathFormat format
) const 
1145     wxFileName fn1 
= *this, 
1148     // get cwd only once - small time saving 
1149     wxString cwd 
= wxGetCwd(); 
1150     fn1
.Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1151     fn2
.Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1153     if ( fn1
.GetFullPath() == fn2
.GetFullPath() ) 
1156     // TODO: compare inodes for Unix, this works even when filenames are 
1157     //       different but files are the same (symlinks) (VZ) 
1163 bool wxFileName::IsCaseSensitive( wxPathFormat format 
) 
1165     // only Unix filenames are truely case-sensitive 
1166     return GetFormat(format
) == wxPATH_UNIX
; 
1170 wxString 
wxFileName::GetForbiddenChars(wxPathFormat format
) 
1172     // Inits to forbidden characters that are common to (almost) all platforms. 
1173     wxString strForbiddenChars 
= wxT("*?"); 
1175     // If asserts, wxPathFormat has been changed. In case of a new path format 
1176     // addition, the following code might have to be updated. 
1177     wxCOMPILE_TIME_ASSERT(wxPATH_MAX 
== 5, wxPathFormatChanged
); 
1178     switch ( GetFormat(format
) ) 
1181             wxFAIL_MSG( wxT("Unknown path format") ); 
1182             // !! Fall through !! 
1188             // On a Mac even names with * and ? are allowed (Tested with OS 
1189             // 9.2.1 and OS X 10.2.5) 
1190             strForbiddenChars 
= wxEmptyString
; 
1194             strForbiddenChars 
+= wxT("\\/:\"<>|"); 
1201     return strForbiddenChars
; 
1205 wxString 
wxFileName::GetVolumeSeparator(wxPathFormat format
) 
1209     if ( (GetFormat(format
) == wxPATH_DOS
) || 
1210          (GetFormat(format
) == wxPATH_VMS
) ) 
1212         sepVol 
= wxFILE_SEP_DSK
; 
1220 wxString 
wxFileName::GetPathSeparators(wxPathFormat format
) 
1223     switch ( GetFormat(format
) ) 
1226             // accept both as native APIs do but put the native one first as 
1227             // this is the one we use in GetFullPath() 
1228             seps 
<< wxFILE_SEP_PATH_DOS 
<< wxFILE_SEP_PATH_UNIX
; 
1232             wxFAIL_MSG( _T("Unknown wxPATH_XXX style") ); 
1236             seps 
= wxFILE_SEP_PATH_UNIX
; 
1240             seps 
= wxFILE_SEP_PATH_MAC
; 
1244             seps 
= wxFILE_SEP_PATH_VMS
; 
1252 bool wxFileName::IsPathSeparator(wxChar ch
, wxPathFormat format
) 
1254     // wxString::Find() doesn't work as expected with NUL - it will always find 
1255     // it, so it is almost surely a bug if this function is called with NUL arg 
1256     wxASSERT_MSG( ch 
!= _T('\0'), _T("shouldn't be called with NUL") ); 
1258     return GetPathSeparators(format
).Find(ch
) != wxNOT_FOUND
; 
1261 // ---------------------------------------------------------------------------- 
1262 // path components manipulation 
1263 // ---------------------------------------------------------------------------- 
1265 /* static */ bool wxFileName::IsValidDirComponent(const wxString
& dir
) 
1269         wxFAIL_MSG( _T("empty directory passed to wxFileName::InsertDir()") ); 
1274     const size_t len 
= dir
.length(); 
1275     for ( size_t n 
= 0; n 
< len
; n
++ ) 
1277         if ( dir
[n
] == GetVolumeSeparator() || IsPathSeparator(dir
[n
]) ) 
1279             wxFAIL_MSG( _T("invalid directory component in wxFileName") ); 
1288 void wxFileName::AppendDir( const wxString 
&dir 
) 
1290     if ( IsValidDirComponent(dir
) ) 
1294 void wxFileName::PrependDir( const wxString 
&dir 
) 
1299 void wxFileName::InsertDir( int before
, const wxString 
&dir 
) 
1301     if ( IsValidDirComponent(dir
) ) 
1302         m_dirs
.Insert( dir
, before 
); 
1305 void wxFileName::RemoveDir( int pos 
) 
1307     m_dirs
.RemoveAt( (size_t)pos 
); 
1310 // ---------------------------------------------------------------------------- 
1312 // ---------------------------------------------------------------------------- 
1314 void wxFileName::SetFullName(const wxString
& fullname
) 
1316     SplitPath(fullname
, NULL 
/* no path */, &m_name
, &m_ext
); 
1319 wxString 
wxFileName::GetFullName() const 
1321     wxString fullname 
= m_name
; 
1322     if ( !m_ext
.empty() ) 
1324         fullname 
<< wxFILE_SEP_EXT 
<< m_ext
; 
1330 wxString 
wxFileName::GetPath( int flags
, wxPathFormat format 
) const 
1332     format 
= GetFormat( format 
); 
1336     // return the volume with the path as well if requested 
1337     if ( flags 
& wxPATH_GET_VOLUME 
) 
1339         fullpath 
+= wxGetVolumeString(GetVolume(), format
); 
1342     // the leading character 
1347                 fullpath 
+= wxFILE_SEP_PATH_MAC
; 
1352                 fullpath 
+= wxFILE_SEP_PATH_DOS
; 
1356             wxFAIL_MSG( wxT("Unknown path format") ); 
1362                 // normally the absolute file names start with a slash 
1363                 // with one exception: the ones like "~/foo.bar" don't 
1365                 if ( m_dirs
.IsEmpty() || m_dirs
[0u] != _T('~') ) 
1367                     fullpath 
+= wxFILE_SEP_PATH_UNIX
; 
1373             // no leading character here but use this place to unset 
1374             // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense 
1375             // as, if I understand correctly, there should never be a dot 
1376             // before the closing bracket 
1377             flags 
&= ~wxPATH_GET_SEPARATOR
; 
1380     if ( m_dirs
.empty() ) 
1382         // there is nothing more 
1386     // then concatenate all the path components using the path separator 
1387     if ( format 
== wxPATH_VMS 
) 
1389         fullpath 
+= wxT('['); 
1392     const size_t dirCount 
= m_dirs
.GetCount(); 
1393     for ( size_t i 
= 0; i 
< dirCount
; i
++ ) 
1398                 if ( m_dirs
[i
] == wxT(".") ) 
1400                     // skip appending ':', this shouldn't be done in this 
1401                     // case as "::" is interpreted as ".." under Unix 
1405                 // convert back from ".." to nothing 
1406                 if ( m_dirs
[i
] != wxT("..") ) 
1407                      fullpath 
+= m_dirs
[i
]; 
1411                 wxFAIL_MSG( wxT("Unexpected path format") ); 
1412                 // still fall through 
1416                 fullpath 
+= m_dirs
[i
]; 
1420                 // TODO: What to do with ".." under VMS 
1422                 // convert back from ".." to nothing 
1423                 if ( m_dirs
[i
] != wxT("..") ) 
1424                     fullpath 
+= m_dirs
[i
]; 
1428         if ( (flags 
& wxPATH_GET_SEPARATOR
) || (i 
!= dirCount 
- 1) ) 
1429             fullpath 
+= GetPathSeparator(format
); 
1432     if ( format 
== wxPATH_VMS 
) 
1434         fullpath 
+= wxT(']'); 
1440 wxString 
wxFileName::GetFullPath( wxPathFormat format 
) const 
1442     // we already have a function to get the path 
1443     wxString fullpath 
= GetPath(wxPATH_GET_VOLUME 
| wxPATH_GET_SEPARATOR
, 
1446     // now just add the file name and extension to it 
1447     fullpath 
+= GetFullName(); 
1452 // Return the short form of the path (returns identity on non-Windows platforms) 
1453 wxString 
wxFileName::GetShortPath() const 
1455 #if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
1456     wxString 
path(GetFullPath()); 
1458     DWORD sz 
= ::GetShortPathName(path
, NULL
, 0); 
1462         ok 
= ::GetShortPathName
 
1465                 wxStringBuffer(pathOut
, sz
), 
1474     return GetFullPath(); 
1478 // Return the long form of the path (returns identity on non-Windows platforms) 
1479 wxString 
wxFileName::GetLongPath() const 
1482              path 
= GetFullPath(); 
1484 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
1485     bool success 
= false; 
1487 #if wxUSE_DYNAMIC_LOADER 
1488     typedef DWORD (WINAPI 
*GET_LONG_PATH_NAME
)(const wxChar 
*, wxChar 
*, DWORD
); 
1490     static bool s_triedToLoad 
= false; 
1492     if ( !s_triedToLoad 
) 
1494         // suppress the errors about missing GetLongPathName[AW] 
1497         s_triedToLoad 
= true; 
1498         wxDynamicLibrary 
dllKernel(_T("kernel32")); 
1499         if ( dllKernel
.IsLoaded() ) 
1501             // may succeed or fail depending on the Windows version 
1502             static GET_LONG_PATH_NAME s_pfnGetLongPathName 
= NULL
; 
1504             s_pfnGetLongPathName 
= (GET_LONG_PATH_NAME
) dllKernel
.GetSymbol(_T("GetLongPathNameW")); 
1506             s_pfnGetLongPathName 
= (GET_LONG_PATH_NAME
) dllKernel
.GetSymbol(_T("GetLongPathNameA")); 
1509             if ( s_pfnGetLongPathName 
) 
1511                 DWORD dwSize 
= (*s_pfnGetLongPathName
)(path
, NULL
, 0); 
1512                 bool ok 
= dwSize 
> 0; 
1516                     DWORD sz 
= (*s_pfnGetLongPathName
)(path
, NULL
, 0); 
1520                         ok 
= (*s_pfnGetLongPathName
) 
1523                                 wxStringBuffer(pathOut
, sz
), 
1535 #endif // wxUSE_DYNAMIC_LOADER 
1539         // The OS didn't support GetLongPathName, or some other error. 
1540         // We need to call FindFirstFile on each component in turn. 
1542         WIN32_FIND_DATA findFileData
; 
1546             pathOut 
= GetVolume() + 
1547                       GetVolumeSeparator(wxPATH_DOS
) + 
1548                       GetPathSeparator(wxPATH_DOS
); 
1550             pathOut 
= wxEmptyString
; 
1552         wxArrayString dirs 
= GetDirs(); 
1553         dirs
.Add(GetFullName()); 
1557         size_t count 
= dirs
.GetCount(); 
1558         for ( size_t i 
= 0; i 
< count
; i
++ ) 
1560             // We're using pathOut to collect the long-name path, but using a 
1561             // temporary for appending the last path component which may be 
1563             tmpPath 
= pathOut 
+ dirs
[i
]; 
1565             if ( tmpPath
.empty() ) 
1568             // can't see this being necessary? MF 
1569             if ( tmpPath
.Last() == GetVolumeSeparator(wxPATH_DOS
) ) 
1571                 // Can't pass a drive and root dir to FindFirstFile, 
1572                 // so continue to next dir 
1573                 tmpPath 
+= wxFILE_SEP_PATH
; 
1578             hFind 
= ::FindFirstFile(tmpPath
, &findFileData
); 
1579             if (hFind 
== INVALID_HANDLE_VALUE
) 
1581                 // Error: most likely reason is that path doesn't exist, so 
1582                 // append any unprocessed parts and return 
1583                 for ( i 
+= 1; i 
< count
; i
++ ) 
1584                     tmpPath 
+= wxFILE_SEP_PATH 
+ dirs
[i
]; 
1589             pathOut 
+= findFileData
.cFileName
; 
1590             if ( (i 
< (count
-1)) ) 
1591                 pathOut 
+= wxFILE_SEP_PATH
; 
1598 #endif // Win32/!Win32 
1603 wxPathFormat 
wxFileName::GetFormat( wxPathFormat format 
) 
1605     if (format 
== wxPATH_NATIVE
) 
1607 #if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__) 
1608         format 
= wxPATH_DOS
; 
1609 #elif defined(__WXMAC__) && !defined(__DARWIN__) 
1610         format 
= wxPATH_MAC
; 
1611 #elif defined(__VMS) 
1612         format 
= wxPATH_VMS
; 
1614         format 
= wxPATH_UNIX
; 
1620 // ---------------------------------------------------------------------------- 
1621 // path splitting function 
1622 // ---------------------------------------------------------------------------- 
1625 void wxFileName::SplitPath(const wxString
& fullpathWithVolume
, 
1626                            wxString 
*pstrVolume
, 
1630                            wxPathFormat format
) 
1632     format 
= GetFormat(format
); 
1634     wxString fullpath 
= fullpathWithVolume
; 
1636     // under VMS the end of the path is ']', not the path separator used to 
1637     // separate the components 
1638     wxString sepPath 
= format 
== wxPATH_VMS 
? wxString(_T(']')) 
1639                                             : GetPathSeparators(format
); 
1641     // special Windows UNC paths hack: transform \\share\path into share:path 
1642     if ( format 
== wxPATH_DOS 
) 
1644         if ( fullpath
.length() >= 4 && 
1645                 fullpath
[0u] == wxFILE_SEP_PATH_DOS 
&& 
1646                     fullpath
[1u] == wxFILE_SEP_PATH_DOS 
) 
1648             fullpath
.erase(0, 2); 
1650             size_t posFirstSlash 
= fullpath
.find_first_of(sepPath
); 
1651             if ( posFirstSlash 
!= wxString::npos 
) 
1653                 fullpath
[posFirstSlash
] = wxFILE_SEP_DSK
; 
1655                 // UNC paths are always absolute, right? (FIXME) 
1656                 fullpath
.insert(posFirstSlash 
+ 1, 1, wxFILE_SEP_PATH_DOS
); 
1661     // We separate the volume here 
1662     if ( format 
== wxPATH_DOS 
|| format 
== wxPATH_VMS 
) 
1664         wxString sepVol 
= GetVolumeSeparator(format
); 
1666         size_t posFirstColon 
= fullpath
.find_first_of(sepVol
); 
1667         if ( posFirstColon 
!= wxString::npos 
) 
1671                 *pstrVolume 
= fullpath
.Left(posFirstColon
); 
1674             // remove the volume name and the separator from the full path 
1675             fullpath
.erase(0, posFirstColon 
+ sepVol
.length()); 
1679     // find the positions of the last dot and last path separator in the path 
1680     size_t posLastDot 
= fullpath
.find_last_of(wxFILE_SEP_EXT
); 
1681     size_t posLastSlash 
= fullpath
.find_last_of(sepPath
); 
1683     if ( (posLastDot 
!= wxString::npos
) && 
1684             ((format 
== wxPATH_UNIX
) || (format 
== wxPATH_VMS
)) ) 
1686         if ( (posLastDot 
== 0) || 
1687              (fullpath
[posLastDot 
- 1] == sepPath
[0u] ) ) 
1689             // under Unix and VMS, dot may be (and commonly is) the first 
1690             // character of the filename, don't treat the entire filename as 
1691             // extension in this case 
1692             posLastDot 
= wxString::npos
; 
1696     // if we do have a dot and a slash, check that the dot is in the name part 
1697     if ( (posLastDot 
!= wxString::npos
) && 
1698          (posLastSlash 
!= wxString::npos
) && 
1699          (posLastDot 
< posLastSlash
) ) 
1701         // the dot is part of the path, not the start of the extension 
1702         posLastDot 
= wxString::npos
; 
1705     // now fill in the variables provided by user 
1708         if ( posLastSlash 
== wxString::npos 
) 
1715             // take everything up to the path separator but take care to make 
1716             // the path equal to something like '/', not empty, for the files 
1717             // immediately under root directory 
1718             size_t len 
= posLastSlash
; 
1720             // this rule does not apply to mac since we do not start with colons (sep) 
1721             // except for relative paths 
1722             if ( !len 
&& format 
!= wxPATH_MAC
) 
1725             *pstrPath 
= fullpath
.Left(len
); 
1727             // special VMS hack: remove the initial bracket 
1728             if ( format 
== wxPATH_VMS 
) 
1730                 if ( (*pstrPath
)[0u] == _T('[') ) 
1731                     pstrPath
->erase(0, 1); 
1738         // take all characters starting from the one after the last slash and 
1739         // up to, but excluding, the last dot 
1740         size_t nStart 
= posLastSlash 
== wxString::npos 
? 0 : posLastSlash 
+ 1; 
1742         if ( posLastDot 
== wxString::npos 
) 
1744             // take all until the end 
1745             count 
= wxString::npos
; 
1747         else if ( posLastSlash 
== wxString::npos 
) 
1751         else // have both dot and slash 
1753             count 
= posLastDot 
- posLastSlash 
- 1; 
1756         *pstrName 
= fullpath
.Mid(nStart
, count
); 
1761         if ( posLastDot 
== wxString::npos 
) 
1768             // take everything after the dot 
1769             *pstrExt 
= fullpath
.Mid(posLastDot 
+ 1); 
1775 void wxFileName::SplitPath(const wxString
& fullpath
, 
1779                            wxPathFormat format
) 
1782     SplitPath(fullpath
, &volume
, path
, name
, ext
, format
); 
1786         path
->Prepend(wxGetVolumeString(volume
, format
)); 
1790 // ---------------------------------------------------------------------------- 
1792 // ---------------------------------------------------------------------------- 
1796 bool wxFileName::SetTimes(const wxDateTime 
*dtAccess
, 
1797                           const wxDateTime 
*dtMod
, 
1798                           const wxDateTime 
*dtCreate
) 
1800 #if defined(__WIN32__) 
1803         // VZ: please let me know how to do this if you can 
1804         wxFAIL_MSG( _T("SetTimes() not implemented for the directories") ); 
1808         wxFileHandle 
fh(GetFullPath(), wxFileHandle::Write
); 
1811             FILETIME ftAccess
, ftCreate
, ftWrite
; 
1814                 ConvertWxToFileTime(&ftCreate
, *dtCreate
); 
1816                 ConvertWxToFileTime(&ftAccess
, *dtAccess
); 
1818                 ConvertWxToFileTime(&ftWrite
, *dtMod
); 
1820             if ( ::SetFileTime(fh
, 
1821                                dtCreate 
? &ftCreate 
: NULL
, 
1822                                dtAccess 
? &ftAccess 
: NULL
, 
1823                                dtMod 
? &ftWrite 
: NULL
) ) 
1829 #elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) 
1830     if ( !dtAccess 
&& !dtMod 
) 
1832         // can't modify the creation time anyhow, don't try 
1836     // if dtAccess or dtMod is not specified, use the other one (which must be 
1837     // non NULL because of the test above) for both times 
1839     utm
.actime 
= dtAccess 
? dtAccess
->GetTicks() : dtMod
->GetTicks(); 
1840     utm
.modtime 
= dtMod 
? dtMod
->GetTicks() : dtAccess
->GetTicks(); 
1841     if ( utime(GetFullPath().fn_str(), &utm
) == 0 ) 
1845 #else // other platform 
1848     wxLogSysError(_("Failed to modify file times for '%s'"), 
1849                   GetFullPath().c_str()); 
1854 bool wxFileName::Touch() 
1856 #if defined(__UNIX_LIKE__) 
1857     // under Unix touching file is simple: just pass NULL to utime() 
1858     if ( utime(GetFullPath().fn_str(), NULL
) == 0 ) 
1863     wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); 
1866 #else // other platform 
1867     wxDateTime dtNow 
= wxDateTime::Now(); 
1869     return SetTimes(&dtNow
, &dtNow
, NULL 
/* don't change create time */); 
1873 bool wxFileName::GetTimes(wxDateTime 
*dtAccess
, 
1875                           wxDateTime 
*dtCreate
) const 
1877 #if defined(__WIN32__) 
1878     // we must use different methods for the files and directories under 
1879     // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and 
1880     // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and 
1883     FILETIME ftAccess
, ftCreate
, ftWrite
; 
1886         // implemented in msw/dir.cpp 
1887         extern bool wxGetDirectoryTimes(const wxString
& dirname
, 
1888                                         FILETIME 
*, FILETIME 
*, FILETIME 
*); 
1890         // we should pass the path without the trailing separator to 
1891         // wxGetDirectoryTimes() 
1892         ok 
= wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME
), 
1893                                  &ftAccess
, &ftCreate
, &ftWrite
); 
1897         wxFileHandle 
fh(GetFullPath(), wxFileHandle::Read
); 
1900             ok 
= ::GetFileTime(fh
, 
1901                                dtCreate 
? &ftCreate 
: NULL
, 
1902                                dtAccess 
? &ftAccess 
: NULL
, 
1903                                dtMod 
? &ftWrite 
: NULL
) != 0; 
1914             ConvertFileTimeToWx(dtCreate
, ftCreate
); 
1916             ConvertFileTimeToWx(dtAccess
, ftAccess
); 
1918             ConvertFileTimeToWx(dtMod
, ftWrite
); 
1922 #elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || (defined(__DOS__) && defined(__WATCOMC__)) 
1924     if ( wxStat( GetFullPath().c_str(), &stBuf
) == 0 ) 
1927             dtAccess
->Set(stBuf
.st_atime
); 
1929             dtMod
->Set(stBuf
.st_mtime
); 
1931             dtCreate
->Set(stBuf
.st_ctime
); 
1935 #else // other platform 
1938     wxLogSysError(_("Failed to retrieve file times for '%s'"), 
1939                   GetFullPath().c_str()); 
1944 #endif // wxUSE_DATETIME 
1948 const short kMacExtensionMaxLength 
= 16 ; 
1949 class MacDefaultExtensionRecord
 
1952   MacDefaultExtensionRecord() 
1955     m_type 
= m_creator 
= NULL 
; 
1957   MacDefaultExtensionRecord( const MacDefaultExtensionRecord
& from 
) 
1959     wxStrcpy( m_ext 
, from
.m_ext 
) ; 
1960     m_type 
= from
.m_type 
; 
1961     m_creator 
= from
.m_creator 
; 
1963   MacDefaultExtensionRecord( const wxChar 
* extension 
, OSType type 
, OSType creator 
) 
1965     wxStrncpy( m_ext 
, extension 
, kMacExtensionMaxLength 
) ; 
1966     m_ext
[kMacExtensionMaxLength
] = 0 ; 
1968     m_creator 
= creator 
; 
1970   wxChar m_ext
[kMacExtensionMaxLength
] ; 
1975 #include "wx/dynarray.h" 
1976 WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord
, MacDefaultExtensionArray
) ; 
1978 bool gMacDefaultExtensionsInited 
= false ; 
1980 #include "wx/arrimpl.cpp" 
1982 WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray
) ; 
1984 MacDefaultExtensionArray gMacDefaultExtensions 
; 
1986 // load the default extensions 
1987 MacDefaultExtensionRecord gDefaults
[] = 
1989     MacDefaultExtensionRecord( wxT("txt") , 'TEXT' , 'ttxt' ) , 
1990     MacDefaultExtensionRecord( wxT("tif") , 'TIFF' , '****' ) , 
1991     MacDefaultExtensionRecord( wxT("jpg") , 'JPEG' , '****' ) , 
1994 static void MacEnsureDefaultExtensionsLoaded() 
1996     if ( !gMacDefaultExtensionsInited 
) 
1998         // we could load the pc exchange prefs here too 
1999         for ( size_t i 
= 0 ; i 
< WXSIZEOF( gDefaults 
) ; ++i 
) 
2001             gMacDefaultExtensions
.Add( gDefaults
[i
] ) ; 
2003         gMacDefaultExtensionsInited 
= true ; 
2006 bool wxFileName::MacSetTypeAndCreator( wxUint32 type 
, wxUint32 creator 
) 
2010   wxMacFilename2FSSpec(GetFullPath(),&spec
) ; 
2011   OSErr err 
= FSpGetFInfo( &spec 
, &fndrInfo 
) ; 
2012   wxCHECK( err 
== noErr 
, false ) ; 
2014   fndrInfo
.fdType 
= type 
; 
2015   fndrInfo
.fdCreator 
= creator 
; 
2016   FSpSetFInfo( &spec 
, &fndrInfo 
) ; 
2020 bool wxFileName::MacGetTypeAndCreator( wxUint32 
*type 
, wxUint32 
*creator 
) 
2024   wxMacFilename2FSSpec(GetFullPath(),&spec
) ; 
2025   OSErr err 
= FSpGetFInfo( &spec 
, &fndrInfo 
) ; 
2026   wxCHECK( err 
== noErr 
, false ) ; 
2028   *type 
= fndrInfo
.fdType 
; 
2029   *creator 
= fndrInfo
.fdCreator 
; 
2033 bool wxFileName::MacSetDefaultTypeAndCreator() 
2035     wxUint32 type 
, creator 
; 
2036     if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type 
, 
2039         return MacSetTypeAndCreator( type 
, creator 
) ; 
2044 bool wxFileName::MacFindDefaultTypeAndCreator( const wxString
& ext 
, wxUint32 
*type 
, wxUint32 
*creator 
) 
2046   MacEnsureDefaultExtensionsLoaded() ; 
2047   wxString extl 
= ext
.Lower() ; 
2048   for( int i 
= gMacDefaultExtensions
.Count() - 1 ; i 
>= 0 ; --i 
) 
2050     if ( gMacDefaultExtensions
.Item(i
).m_ext 
== extl 
) 
2052       *type 
= gMacDefaultExtensions
.Item(i
).m_type 
; 
2053       *creator 
= gMacDefaultExtensions
.Item(i
).m_creator 
; 
2060 void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString
& ext 
, wxUint32 type 
, wxUint32 creator 
) 
2062   MacEnsureDefaultExtensionsLoaded() ; 
2063   MacDefaultExtensionRecord rec 
; 
2065   rec
.m_creator 
= creator 
; 
2066   wxStrncpy( rec
.m_ext 
, ext
.Lower().c_str() , kMacExtensionMaxLength 
) ; 
2067   gMacDefaultExtensions
.Add( rec 
) ;