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 license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "filename.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  36 #include "wx/filename.h" 
  37 #include "wx/tokenzr.h" 
  38 #include "wx/config.h"          // for wxExpandEnvVars 
  41 #if wxUSE_DYNLIB_CLASS 
  42     #include "wx/dynlib.h" 
  45 // For GetShort/LongPathName 
  49     #include "wx/msw/winundef.h" 
  52 // utime() is POSIX so should normally be available on all Unices 
  54     #include <sys/types.h> 
  66 // ---------------------------------------------------------------------------- 
  68 // ---------------------------------------------------------------------------- 
  70 // small helper class which opens and closes the file - we use it just to get 
  71 // a file handle for the given file name to pass it to some Win32 API function 
  77     wxFileHandle(const wxString
& filename
) 
  79         m_hFile 
= ::CreateFile
 
  82                      GENERIC_READ
,      // access mask 
  84                      NULL
,              // no secutity attr 
  85                      OPEN_EXISTING
,     // creation disposition 
  87                      NULL               
// no template file 
  90         if ( m_hFile 
== INVALID_HANDLE_VALUE 
) 
  92             wxLogSysError(_("Failed to open '%s' for reading"), 
  99         if ( m_hFile 
!= INVALID_HANDLE_VALUE 
) 
 101             if ( !::CloseHandle(m_hFile
) ) 
 103                 wxLogSysError(_("Failed to close file handle")); 
 108     // return TRUE only if the file could be opened successfully 
 109     bool IsOk() const { return m_hFile 
!= INVALID_HANDLE_VALUE
; } 
 112     operator HANDLE() const { return m_hFile
; } 
 120 // ---------------------------------------------------------------------------- 
 122 // ---------------------------------------------------------------------------- 
 126 // convert between wxDateTime and FILETIME which is a 64-bit value representing 
 127 // the number of 100-nanosecond intervals since January 1, 1601. 
 129 // the number of milliseconds between the Unix Epoch (January 1, 1970) and the 
 130 // FILETIME reference point (January 1, 1601) 
 131 static const wxLongLong FILETIME_EPOCH_OFFSET 
= wxLongLong(0xa97, 0x30b66800); 
 133 static void ConvertFileTimeToWx(wxDateTime 
*dt
, const FILETIME 
&ft
) 
 135     wxLongLong 
ll(ft
.dwHighDateTime
, ft
.dwLowDateTime
); 
 137     // convert 100ns to ms 
 140     // move it to our Epoch 
 141     ll 
-= FILETIME_EPOCH_OFFSET
; 
 143     *dt 
= wxDateTime(ll
); 
 146 static void ConvertWxToFileTime(FILETIME 
*ft
, const wxDateTime
& dt
) 
 148     // do the reverse of ConvertFileTimeToWx() 
 149     wxLongLong ll 
= dt
.GetValue(); 
 151     ll 
+= FILETIME_EPOCH_OFFSET
; 
 153     ft
->dwHighDateTime 
= ll
.GetHi(); 
 154     ft
->dwLowDateTime 
= ll
.GetLo(); 
 159 // ============================================================================ 
 161 // ============================================================================ 
 163 // ---------------------------------------------------------------------------- 
 164 // wxFileName construction 
 165 // ---------------------------------------------------------------------------- 
 167 void wxFileName::Assign( const wxFileName 
&filepath 
) 
 169     m_ext 
= filepath
.GetExt(); 
 170     m_name 
= filepath
.GetName(); 
 171     m_dirs 
= filepath
.GetDirs(); 
 174 void wxFileName::Assign( const wxString
& path
, 
 175                          const wxString
& name
, 
 177                          wxPathFormat format 
) 
 179     wxStringTokenizer 
tn(path
, GetPathSeparators(format
), 
 180                          wxTOKEN_RET_EMPTY_ALL
); 
 183     while ( tn
.HasMoreTokens() ) 
 185         wxString token 
= tn
.GetNextToken(); 
 187         // If the path starts with a slash (or two for a network path), 
 188         // we need the first dir entry to be an empty for later reassembly. 
 189         if ((i 
< 2) || !token
.IsEmpty()) 
 199 void wxFileName::Assign(const wxString
& fullpath
, 
 202     wxString path
, name
, ext
; 
 203     SplitPath(fullpath
, &path
, &name
, &ext
, format
); 
 205     Assign(path
, name
, ext
, format
); 
 208 void wxFileName::Assign(const wxString
& path
, 
 209                         const wxString
& fullname
, 
 213     SplitPath(fullname
, NULL 
/* no path */, &name
, &ext
, format
); 
 215     Assign(path
, name
, ext
, format
); 
 218 void wxFileName::Clear() 
 222     m_ext 
= wxEmptyString
; 
 226 wxFileName 
wxFileName::FileName(const wxString
& file
) 
 228     return wxFileName(file
); 
 232 wxFileName 
wxFileName::DirName(const wxString
& dir
) 
 239 // ---------------------------------------------------------------------------- 
 241 // ---------------------------------------------------------------------------- 
 243 bool wxFileName::FileExists() 
 245     return wxFileName::FileExists( GetFullPath() ); 
 248 bool wxFileName::FileExists( const wxString 
&file 
) 
 250     return ::wxFileExists( file 
); 
 253 bool wxFileName::DirExists() 
 255     return wxFileName::DirExists( GetFullPath() ); 
 258 bool wxFileName::DirExists( const wxString 
&dir 
) 
 260     return ::wxDirExists( dir 
); 
 263 // ---------------------------------------------------------------------------- 
 264 // CWD and HOME stuff 
 265 // ---------------------------------------------------------------------------- 
 267 void wxFileName::AssignCwd() 
 269     AssignDir(wxFileName::GetCwd()); 
 273 wxString 
wxFileName::GetCwd() 
 278 bool wxFileName::SetCwd() 
 280     return wxFileName::SetCwd( GetFullPath() ); 
 283 bool wxFileName::SetCwd( const wxString 
&cwd 
) 
 285     return ::wxSetWorkingDirectory( cwd 
); 
 288 void wxFileName::AssignHomeDir() 
 290     AssignDir(wxFileName::GetHomeDir()); 
 293 wxString 
wxFileName::GetHomeDir() 
 295     return ::wxGetHomeDir(); 
 298 void wxFileName::AssignTempFileName( const wxString 
&prefix 
) 
 301     if ( wxGetTempFileName(prefix
, fullname
) ) 
 311 // ---------------------------------------------------------------------------- 
 312 // directory operations 
 313 // ---------------------------------------------------------------------------- 
 315 bool wxFileName::Mkdir( int perm
, bool full 
) 
 317     return wxFileName::Mkdir( GetFullPath(), perm
, full 
); 
 320 bool wxFileName::Mkdir( const wxString 
&dir
, int perm
, bool full 
) 
 324         wxFileName 
filename(dir
); 
 325         wxArrayString dirs 
= filename
.GetDirs(); 
 326         dirs
.Add(filename
.GetName()); 
 328         size_t count 
= dirs
.GetCount(); 
 332         for ( i 
= 0; i 
< count
; i
++ ) 
 336             if (currPath
.Last() == wxT(':')) 
 338                 // Can't create a root directory so continue to next dir 
 339                 currPath 
+= wxFILE_SEP_PATH
; 
 343             if (!DirExists(currPath
)) 
 344                 if (!wxMkdir(currPath
, perm
)) 
 347             if ( (i 
< (count
-1)) ) 
 348                 currPath 
+= wxFILE_SEP_PATH
; 
 351         return (noErrors 
== 0); 
 355         return ::wxMkdir( dir
, perm 
); 
 358 bool wxFileName::Rmdir() 
 360     return wxFileName::Rmdir( GetFullPath() ); 
 363 bool wxFileName::Rmdir( const wxString 
&dir 
) 
 365     return ::wxRmdir( dir 
); 
 368 // ---------------------------------------------------------------------------- 
 369 // path normalization 
 370 // ---------------------------------------------------------------------------- 
 372 bool wxFileName::Normalize(wxPathNormalize flags
, 
 376     // the existing path components 
 377     wxArrayString dirs 
= GetDirs(); 
 379     // the path to prepend in front to make the path absolute 
 382     format 
= GetFormat(format
); 
 384     // make the path absolute 
 385     if ( (flags 
& wxPATH_NORM_ABSOLUTE
) && !IsAbsolute() ) 
 390             curDir
.AssignDir(cwd
); 
 393     // handle ~ stuff under Unix only 
 394     if ( (format 
== wxPATH_UNIX
) && (flags 
& wxPATH_NORM_TILDE
) ) 
 396         if ( !dirs
.IsEmpty() ) 
 398             wxString dir 
= dirs
[0u]; 
 399             if ( !dir
.empty() && dir
[0u] == _T('~') ) 
 401                 curDir
.AssignDir(wxGetUserHome(dir
.c_str() + 1)); 
 410         wxArrayString dirsNew 
= curDir
.GetDirs(); 
 411         size_t count 
= dirs
.GetCount(); 
 412         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 414             dirsNew
.Add(dirs
[n
]); 
 420     // now deal with ".", ".." and the rest 
 422     size_t count 
= dirs
.GetCount(); 
 423     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 425         wxString dir 
= dirs
[n
]; 
 427         if ( flags 
&& wxPATH_NORM_DOTS 
) 
 429             if ( dir 
== wxT(".") ) 
 435             if ( dir 
== wxT("..") ) 
 437                 if ( m_dirs
.IsEmpty() ) 
 439                     wxLogError(_("The path '%s' contains too many \"..\"!"), 
 440                                GetFullPath().c_str()); 
 444                 m_dirs
.Remove(m_dirs
.GetCount() - 1); 
 449         if ( flags 
& wxPATH_NORM_ENV_VARS 
) 
 451             dir 
= wxExpandEnvVars(dir
); 
 454         if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
 462     if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
 464         // VZ: expand env vars here too? 
 470 #if defined(__WXMSW__) && defined(__WIN32__) 
 471     if (flags 
& wxPATH_NORM_LONG
) 
 473         Assign(GetLongPath()); 
 480 // ---------------------------------------------------------------------------- 
 481 // filename kind tests 
 482 // ---------------------------------------------------------------------------- 
 484 bool wxFileName::SameAs( const wxFileName 
&filepath
, wxPathFormat format
) 
 486     wxFileName fn1 
= *this, 
 489     // get cwd only once - small time saving 
 490     wxString cwd 
= wxGetCwd(); 
 491     fn1
.Normalize(wxPATH_NORM_ALL
, cwd
, format
); 
 492     fn2
.Normalize(wxPATH_NORM_ALL
, cwd
, format
); 
 494     if ( fn1
.GetFullPath() == fn2
.GetFullPath() ) 
 497     // TODO: compare inodes for Unix, this works even when filenames are 
 498     //       different but files are the same (symlinks) (VZ) 
 504 bool wxFileName::IsCaseSensitive( wxPathFormat format 
) 
 506     // only DOS and OpenVMS filenames are case-sensitive 
 507     return ( GetFormat(format
) != wxPATH_DOS 
& 
 508              GetFormat(format
) != wxPATH_VMS 
); 
 511 bool wxFileName::IsRelative( wxPathFormat format 
) 
 513     return !IsAbsolute(format
); 
 516 bool wxFileName::IsAbsolute( wxPathFormat format 
) 
 518     wxChar ch 
= m_dirs
.IsEmpty() ? _T('\0') : m_dirs
[0u][0u]; 
 520     // Hack to cope with e.g. c:\thing - need something better 
 521     wxChar driveSep 
= _T('\0'); 
 522     if (!m_dirs
.IsEmpty() && m_dirs
[0].Length() > 1) 
 523         driveSep 
= m_dirs
[0u][1u]; 
 525     // the path is absolute if it starts with a path separator or, only for 
 526     // Unix filenames, with "~" or "~user" 
 527     return IsPathSeparator(ch
, format
) || 
 528            driveSep 
== _T(':') || 
 529            (GetFormat(format
) == wxPATH_UNIX 
&& ch 
== _T('~') ); 
 533 wxString 
wxFileName::GetPathSeparators(wxPathFormat format
) 
 536     switch ( GetFormat(format
) ) 
 539             // accept both as native APIs do 
 540             seps 
<< wxFILE_SEP_PATH_UNIX 
<< wxFILE_SEP_PATH_DOS
; 
 544             wxFAIL_MSG( _T("unknown wxPATH_XXX style") ); 
 548             seps 
= wxFILE_SEP_PATH_UNIX
; 
 552             seps 
= wxFILE_SEP_PATH_MAC
; 
 556             seps 
= wxFILE_SEP_PATH_VMS
; 
 564 bool wxFileName::IsPathSeparator(wxChar ch
, wxPathFormat format
) 
 566     return GetPathSeparators(format
).Find(ch
) != wxNOT_FOUND
; 
 569 bool wxFileName::IsWild( wxPathFormat format 
) 
 571     // FIXME: this is probably false for Mac and this is surely wrong for most 
 572     //        of Unix shells (think about "[...]") 
 574     return m_name
.find_first_of(_T("*?")) != wxString::npos
; 
 577 // ---------------------------------------------------------------------------- 
 578 // path components manipulation 
 579 // ---------------------------------------------------------------------------- 
 581 void wxFileName::AppendDir( const wxString 
&dir 
) 
 586 void wxFileName::PrependDir( const wxString 
&dir 
) 
 588     m_dirs
.Insert( dir
, 0 ); 
 591 void wxFileName::InsertDir( int before
, const wxString 
&dir 
) 
 593     m_dirs
.Insert( dir
, before 
); 
 596 void wxFileName::RemoveDir( int pos 
) 
 598     m_dirs
.Remove( (size_t)pos 
); 
 601 // ---------------------------------------------------------------------------- 
 603 // ---------------------------------------------------------------------------- 
 605 void wxFileName::SetFullName(const wxString
& fullname
) 
 607     SplitPath(fullname
, NULL 
/* no path */, &m_name
, &m_ext
); 
 610 wxString 
wxFileName::GetFullName() const 
 612     wxString fullname 
= m_name
; 
 613     if ( !m_ext
.empty() ) 
 615         fullname 
<< wxFILE_SEP_EXT 
<< m_ext
; 
 621 wxString 
wxFileName::GetPath( bool add_separator
, wxPathFormat format 
) const 
 623     format 
= GetFormat( format 
); 
 626     size_t count 
= m_dirs
.GetCount(); 
 627     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 630         if ( add_separator 
|| (i 
< count
) ) 
 631             ret 
+= wxFILE_SEP_PATH
; 
 637 wxString 
wxFileName::GetFullPath( wxPathFormat format 
) const 
 639     format 
= GetFormat( format 
); 
 642     if (format 
== wxPATH_DOS
) 
 644         for (size_t i 
= 0; i 
< m_dirs
.GetCount(); i
++) 
 651     if (format 
== wxPATH_UNIX
) 
 653         for (size_t i 
= 0; i 
< m_dirs
.GetCount(); i
++) 
 660     if (format 
== wxPATH_VMS
) 
 663         for (size_t i 
= 0; i 
< m_dirs
.GetCount(); i
++) 
 672         for (size_t i 
= 0; i 
< m_dirs
.GetCount(); i
++) 
 681     if (!m_ext
.IsEmpty()) 
 690 // Return the short form of the path (returns identity on non-Windows platforms) 
 691 wxString 
wxFileName::GetShortPath() const 
 693 #if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) 
 694     wxString 
path(GetFullPath()); 
 696     DWORD sz 
= ::GetShortPathName(path
, NULL
, 0); 
 700         ok 
= ::GetShortPathName
 
 703                 pathOut
.GetWriteBuf(sz
), 
 706         pathOut
.UngetWriteBuf(); 
 713     return GetFullPath(); 
 717 // Return the long form of the path (returns identity on non-Windows platforms) 
 718 wxString 
wxFileName::GetLongPath() const 
 720 #if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) 
 721     wxString 
path(GetFullPath()); 
 723     bool success 
= FALSE
; 
 725     // VZ: this code was disabled, why? 
 726 #if 0 // wxUSE_DYNLIB_CLASS 
 727     typedef DWORD (*GET_LONG_PATH_NAME
)(const wxChar 
*, wxChar 
*, DWORD
); 
 729     static bool s_triedToLoad 
= FALSE
; 
 731     if ( !s_triedToLoad 
) 
 733         s_triedToLoad 
= TRUE
; 
 734         wxDllType dllKernel 
= wxDllLoader::LoadLibrary(_T("kernel32")); 
 737             // may succeed or fail depending on the Windows version 
 738                         static GET_LONG_PATH_NAME s_pfnGetLongPathName 
= NULL
; 
 740             s_pfnGetLongPathName 
= (GET_LONG_PATH_NAME
) wxDllLoader::GetSymbol(dllKernel
, _T("GetLongPathNameW")); 
 742             s_pfnGetLongPathName 
= (GET_LONG_PATH_NAME
) wxDllLoader::GetSymbol(dllKernel
, _T("GetLongPathNameA")); 
 745             wxDllLoader::UnloadLibrary(dllKernel
); 
 747             if ( s_pfnGetLongPathName 
) 
 749                 DWORD dwSize 
= (*s_pfnGetLongPathName
)(path
, NULL
, 0); 
 750                 bool ok 
= dwSize 
> 0; 
 754                     DWORD sz 
= (*s_pfnGetLongPathName
)(path
, NULL
, 0); 
 758                         ok 
= (*s_pfnGetLongPathName
) 
 761                                 pathOut
.GetWriteBuf(sz
), 
 764                         pathOut
.UngetWriteBuf(); 
 774 #endif // wxUSE_DYNLIB_CLASS 
 778         // The OS didn't support GetLongPathName, or some other error. 
 779         // We need to call FindFirstFile on each component in turn. 
 781         WIN32_FIND_DATA findFileData
; 
 783         pathOut 
= wxEmptyString
; 
 785         wxArrayString dirs 
= GetDirs(); 
 786         dirs
.Add(GetFullName()); 
 788         size_t count 
= dirs
.GetCount(); 
 792         for ( i 
= 0; i 
< count
; i
++ ) 
 794             // We're using pathOut to collect the long-name path, 
 795             // but using a temporary for appending the last path component which may be short-name 
 796             tmpPath 
= pathOut 
+ dirs
[i
]; 
 798             if (tmpPath
.Last() == wxT(':')) 
 800                 // Can't pass a drive and root dir to FindFirstFile, 
 801                 // so continue to next dir 
 802                 tmpPath 
+= wxFILE_SEP_PATH
; 
 807             hFind 
= ::FindFirstFile(tmpPath
, &findFileData
); 
 808             if (hFind 
== INVALID_HANDLE_VALUE
) 
 810                 // Error: return immediately with the original path 
 815                 pathOut 
+= findFileData
.cFileName
; 
 816                 if ( (i 
< (count
-1)) ) 
 817                     pathOut 
+= wxFILE_SEP_PATH
; 
 826     return GetFullPath(); 
 830 wxPathFormat 
wxFileName::GetFormat( wxPathFormat format 
) 
 832     if (format 
== wxPATH_NATIVE
) 
 834 #if defined(__WXMSW__) || defined(__WXPM__) 
 836 #elif defined(__WXMAC__) && !defined(__DARWIN__) 
 841         format 
= wxPATH_UNIX
; 
 847 // ---------------------------------------------------------------------------- 
 848 // path splitting function 
 849 // ---------------------------------------------------------------------------- 
 851 void wxFileName::SplitPath(const wxString
& fullpath
, 
 857     format 
= GetFormat(format
); 
 859     // find the positions of the last dot and last path separator in the path 
 860     size_t posLastDot 
= fullpath
.find_last_of(wxFILE_SEP_EXT
); 
 861     size_t posLastSlash 
= fullpath
.find_last_of(GetPathSeparators(format
)); 
 863     if ( (posLastDot 
!= wxString::npos
) && (format 
== wxPATH_UNIX
) ) 
 865         if ( (posLastDot 
== 0) || 
 866              (fullpath
[posLastDot 
- 1] == wxFILE_SEP_PATH_UNIX
) ) 
 868             // under Unix, dot may be (and commonly is) the first character of 
 869             // the filename, don't treat the entire filename as extension in 
 871             posLastDot 
= wxString::npos
; 
 875      if ( (posLastDot 
!= wxString::npos
) && (format 
== wxPATH_VMS
) ) 
 877         if ( (posLastDot 
== 0) || 
 878              (fullpath
[posLastDot 
- 1] == ']' ) ) 
 880             // under OpenVMS, dot may be (and commonly is) the first character of 
 881             // the filename, don't treat the entire filename as extension in 
 883             posLastDot 
= wxString::npos
; 
 887     // if we do have a dot and a slash, check that the dot is in the name part 
 888     if ( (posLastDot 
!= wxString::npos
) && 
 889          (posLastSlash 
!= wxString::npos
) && 
 890          (posLastDot 
< posLastSlash
) ) 
 892         // the dot is part of the path, not the start of the extension 
 893         posLastDot 
= wxString::npos
; 
 896     // now fill in the variables provided by user 
 899         if ( posLastSlash 
== wxString::npos 
) 
 906             // take all until the separator 
 907             *pstrPath 
= fullpath
.Left(posLastSlash
); 
 913         // take all characters starting from the one after the last slash and 
 914         // up to, but excluding, the last dot 
 915         size_t nStart 
= posLastSlash 
== wxString::npos 
? 0 : posLastSlash 
+ 1; 
 917         if ( posLastDot 
== wxString::npos 
) 
 919             // take all until the end 
 920             count 
= wxString::npos
; 
 922         else if ( posLastSlash 
== wxString::npos 
) 
 926         else // have both dot and slash 
 928             count 
= posLastDot 
- posLastSlash 
- 1; 
 931         *pstrName 
= fullpath
.Mid(nStart
, count
); 
 936         if ( posLastDot 
== wxString::npos 
) 
 943             // take everything after the dot 
 944             *pstrExt 
= fullpath
.Mid(posLastDot 
+ 1); 
 949 // ---------------------------------------------------------------------------- 
 951 // ---------------------------------------------------------------------------- 
 953 bool wxFileName::SetTimes(const wxDateTime 
*dtCreate
, 
 954                           const wxDateTime 
*dtAccess
, 
 955                           const wxDateTime 
*dtMod
) 
 957 #if defined(__UNIX_LIKE__) 
 958     if ( !dtAccess 
&& !dtMod 
) 
 960         // can't modify the creation time anyhow, don't try 
 964     // if dtAccess or dtMod is not specified, use the other one (which must be 
 965     // non NULL because of the test above) for both times 
 967     utm
.actime 
= dtAccess 
? dtAccess
->GetTicks() : dtMod
->GetTicks(); 
 968     utm
.modtime 
= dtMod 
? dtMod
->GetTicks() : dtAccess
->GetTicks(); 
 969     if ( utime(GetFullPath(), &utm
) == 0 ) 
 973 #elif defined(__WIN32__) 
 974     wxFileHandle 
fh(GetFullPath()); 
 977         FILETIME ftAccess
, ftCreate
, ftWrite
; 
 980             ConvertWxToFileTime(&ftCreate
, *dtCreate
); 
 982             ConvertWxToFileTime(&ftAccess
, *dtAccess
); 
 984             ConvertWxToFileTime(&ftWrite
, *dtMod
); 
 986         if ( ::SetFileTime(fh
, 
 987                            dtCreate 
? &ftCreate 
: NULL
, 
 988                            dtAccess 
? &ftAccess 
: NULL
, 
 989                            dtMod 
? &ftWrite 
: NULL
) ) 
 994 #else // other platform 
 997     wxLogSysError(_("Failed to modify file times for '%s'"), 
 998                   GetFullPath().c_str()); 
1003 bool wxFileName::Touch() 
1005 #if defined(__UNIX_LIKE__) 
1006     // under Unix touching file is simple: just pass NULL to utime() 
1007     if ( utime(GetFullPath(), NULL
) == 0 ) 
1012     wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); 
1015 #else // other platform 
1016     wxDateTime dtNow 
= wxDateTime::Now(); 
1018     return SetTimes(NULL 
/* don't change create time */, &dtNow
, &dtNow
); 
1022 bool wxFileName::GetTimes(wxDateTime 
*dtAccess
, 
1024                           wxDateTime 
*dtChange
) const 
1026 #if defined(__UNIX_LIKE__)  
1028     if ( wxStat(GetFullPath(), &stBuf
) == 0 ) 
1031             dtAccess
->Set(stBuf
.st_atime
); 
1033             dtMod
->Set(stBuf
.st_mtime
); 
1035             dtChange
->Set(stBuf
.st_ctime
); 
1039 #elif defined(__WXMAC__) 
1041     if ( wxStat(GetFullPath(), &stBuf
) == 0 ) 
1044             dtAccess
->Set(stBuf
.st_atime
); 
1046             dtMod
->Set(stBuf
.st_mtime
); 
1048             dtChange
->Set(stBuf
.st_ctime
); 
1052 #elif defined(__WIN32__) 
1053     wxFileHandle 
fh(GetFullPath()); 
1056         FILETIME ftAccess
, ftCreate
, ftWrite
; 
1058         if ( ::GetFileTime(fh
, 
1059                            dtMod 
? &ftCreate 
: NULL
, 
1060                            dtAccess 
? &ftAccess 
: NULL
, 
1061                            dtChange 
? &ftWrite 
: NULL
) ) 
1064                 ConvertFileTimeToWx(dtMod
, ftCreate
); 
1066                 ConvertFileTimeToWx(dtAccess
, ftAccess
); 
1068                 ConvertFileTimeToWx(dtChange
, ftWrite
); 
1073 #else // other platform 
1076     wxLogSysError(_("Failed to retrieve file times for '%s'"), 
1077                   GetFullPath().c_str());