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 // ---------------------------------------------------------------------------- 
  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 
  90 #include "wx/msw/winundef.h" 
  93 #if defined(__WXMAC__) 
  94   #include  "wx/mac/private.h"  // includes mac headers 
  97 // utime() is POSIX so should normally be available on all Unices 
  99 #include <sys/types.h> 
 101 #include <sys/stat.h> 
 117 #include <sys/utime.h> 
 118 #include <sys/stat.h> 
 128 #define MAX_PATH _MAX_PATH 
 131 // ---------------------------------------------------------------------------- 
 133 // ---------------------------------------------------------------------------- 
 135 // small helper class which opens and closes the file - we use it just to get 
 136 // a file handle for the given file name to pass it to some Win32 API function 
 137 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
 148     wxFileHandle(const wxString
& filename
, OpenMode mode
) 
 150         m_hFile 
= ::CreateFile
 
 153                      mode 
== Read 
? GENERIC_READ    
// access mask 
 156                      NULL
,                          // no secutity attr 
 157                      OPEN_EXISTING
,                 // creation disposition 
 159                      NULL                           
// no template file 
 162         if ( m_hFile 
== INVALID_HANDLE_VALUE 
) 
 164             wxLogSysError(_("Failed to open '%s' for %s"), 
 166                           mode 
== Read 
? _("reading") : _("writing")); 
 172         if ( m_hFile 
!= INVALID_HANDLE_VALUE 
) 
 174             if ( !::CloseHandle(m_hFile
) ) 
 176                 wxLogSysError(_("Failed to close file handle")); 
 181     // return TRUE only if the file could be opened successfully 
 182     bool IsOk() const { return m_hFile 
!= INVALID_HANDLE_VALUE
; } 
 185     operator HANDLE() const { return m_hFile
; } 
 193 // ---------------------------------------------------------------------------- 
 195 // ---------------------------------------------------------------------------- 
 197 #if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__) 
 199 // convert between wxDateTime and FILETIME which is a 64-bit value representing 
 200 // the number of 100-nanosecond intervals since January 1, 1601. 
 202 static void ConvertFileTimeToWx(wxDateTime 
*dt
, const FILETIME 
&ft
) 
 204     FILETIME ftcopy 
= ft
; 
 206     if ( !::FileTimeToLocalFileTime(&ftcopy
, &ftLocal
) ) 
 208         wxLogLastError(_T("FileTimeToLocalFileTime")); 
 212     if ( !::FileTimeToSystemTime(&ftLocal
, &st
) ) 
 214         wxLogLastError(_T("FileTimeToSystemTime")); 
 217     dt
->Set(st
.wDay
, wxDateTime::Month(st
.wMonth 
- 1), st
.wYear
, 
 218             st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
); 
 221 static void ConvertWxToFileTime(FILETIME 
*ft
, const wxDateTime
& dt
) 
 224     st
.wDay 
= dt
.GetDay(); 
 225     st
.wMonth 
= dt
.GetMonth() + 1; 
 226     st
.wYear 
= dt
.GetYear(); 
 227     st
.wHour 
= dt
.GetHour(); 
 228     st
.wMinute 
= dt
.GetMinute(); 
 229     st
.wSecond 
= dt
.GetSecond(); 
 230     st
.wMilliseconds 
= dt
.GetMillisecond(); 
 233     if ( !::SystemTimeToFileTime(&st
, &ftLocal
) ) 
 235         wxLogLastError(_T("SystemTimeToFileTime")); 
 238     if ( !::LocalFileTimeToFileTime(&ftLocal
, ft
) ) 
 240         wxLogLastError(_T("LocalFileTimeToFileTime")); 
 244 #endif // wxUSE_DATETIME && __WIN32__ 
 246 // return a string with the volume par 
 247 static wxString 
wxGetVolumeString(const wxString
& volume
, wxPathFormat format
) 
 251     if ( !volume
.empty() ) 
 253         format 
= wxFileName::GetFormat(format
); 
 255         // Special Windows UNC paths hack, part 2: undo what we did in 
 256         // SplitPath() and make an UNC path if we have a drive which is not a 
 257         // single letter (hopefully the network shares can't be one letter only 
 258         // although I didn't find any authoritative docs on this) 
 259         if ( format 
== wxPATH_DOS 
&& volume
.length() > 1 ) 
 261             path 
<< wxFILE_SEP_PATH_DOS 
<< wxFILE_SEP_PATH_DOS 
<< volume
; 
 263         else if  ( format 
== wxPATH_DOS 
|| format 
== wxPATH_VMS 
) 
 265             path 
<< volume 
<< wxFileName::GetVolumeSeparator(format
); 
 273 // ============================================================================ 
 275 // ============================================================================ 
 277 // ---------------------------------------------------------------------------- 
 278 // wxFileName construction 
 279 // ---------------------------------------------------------------------------- 
 281 void wxFileName::Assign( const wxFileName 
&filepath 
) 
 283     m_volume 
= filepath
.GetVolume(); 
 284     m_dirs 
= filepath
.GetDirs(); 
 285     m_name 
= filepath
.GetName(); 
 286     m_ext 
= filepath
.GetExt(); 
 287     m_relative 
= filepath
.m_relative
; 
 290 void wxFileName::Assign(const wxString
& volume
, 
 291                         const wxString
& path
, 
 292                         const wxString
& name
, 
 294                         wxPathFormat format 
) 
 296     SetPath( path
, format 
); 
 303 void wxFileName::SetPath( const wxString 
&path
, wxPathFormat format 
) 
 309         wxPathFormat my_format 
= GetFormat( format 
); 
 310         wxString my_path 
= path
; 
 312         // 1) Determine if the path is relative or absolute. 
 313         wxChar leadingChar 
= my_path
[0u]; 
 318                 m_relative 
= leadingChar 
== wxT(':'); 
 320                 // We then remove a leading ":". The reason is in our 
 321                 // storage form for relative paths: 
 322                 // ":dir:file.txt" actually means "./dir/file.txt" in 
 323                 // DOS notation and should get stored as 
 324                 // (relative) (dir) (file.txt) 
 325                 // "::dir:file.txt" actually means "../dir/file.txt" 
 326                 // stored as (relative) (..) (dir) (file.txt) 
 327                 // This is important only for the Mac as an empty dir 
 328                 // actually means <UP>, whereas under DOS, double 
 329                 // slashes can be ignored: "\\\\" is the same as "\\". 
 331                     my_path
.erase( 0, 1 ); 
 335                 // TODO: what is the relative path format here? 
 340                 // the paths of the form "~" or "~username" are absolute 
 341                 m_relative 
= leadingChar 
!= wxT('/') && leadingChar 
!= _T('~'); 
 345                 m_relative 
= !IsPathSeparator(leadingChar
, my_format
); 
 349                 wxFAIL_MSG( wxT("error") ); 
 353         // 2) Break up the path into its members. If the original path 
 354         //    was just "/" or "\\", m_dirs will be empty. We know from 
 355         //    the m_relative field, if this means "nothing" or "root dir". 
 357         wxStringTokenizer 
tn( my_path
, GetPathSeparators(my_format
) ); 
 359         while ( tn
.HasMoreTokens() ) 
 361             wxString token 
= tn
.GetNextToken(); 
 363             // Remove empty token under DOS and Unix, interpret them 
 367                 if (my_format 
== wxPATH_MAC
) 
 368                     m_dirs
.Add( wxT("..") ); 
 377     else // no path at all 
 383 void wxFileName::Assign(const wxString
& fullpath
, 
 386     wxString volume
, path
, name
, ext
; 
 387     SplitPath(fullpath
, &volume
, &path
, &name
, &ext
, format
); 
 389     Assign(volume
, path
, name
, ext
, format
); 
 392 void wxFileName::Assign(const wxString
& fullpathOrig
, 
 393                         const wxString
& fullname
, 
 396     // always recognize fullpath as directory, even if it doesn't end with a 
 398     wxString fullpath 
= fullpathOrig
; 
 399     if ( !wxEndsWithPathSeparator(fullpath
) ) 
 401         fullpath 
+= GetPathSeparator(format
); 
 404     wxString volume
, path
, name
, ext
; 
 406     // do some consistency checks in debug mode: the name should be really just 
 407     // the filename and the path should be really just a path 
 409     wxString pathDummy
, nameDummy
, extDummy
; 
 411     SplitPath(fullname
, &pathDummy
, &name
, &ext
, format
); 
 413     wxASSERT_MSG( pathDummy
.empty(), 
 414                   _T("the file name shouldn't contain the path") ); 
 416     SplitPath(fullpath
, &volume
, &path
, &nameDummy
, &extDummy
, format
); 
 418     wxASSERT_MSG( nameDummy
.empty() && extDummy
.empty(), 
 419                   _T("the path shouldn't contain file name nor extension") ); 
 421 #else // !__WXDEBUG__ 
 422     SplitPath(fullname
, NULL 
/* no path */, &name
, &ext
, format
); 
 423     SplitPath(fullpath
, &volume
, &path
, NULL
, NULL
, format
); 
 424 #endif // __WXDEBUG__/!__WXDEBUG__ 
 426     Assign(volume
, path
, name
, ext
, format
); 
 429 void wxFileName::AssignDir(const wxString
& dir
, wxPathFormat format
) 
 431     Assign(dir
, _T(""), format
); 
 434 void wxFileName::Clear() 
 440     m_ext 
= wxEmptyString
; 
 442     // we don't have any absolute path for now 
 447 wxFileName 
wxFileName::FileName(const wxString
& file
) 
 449     return wxFileName(file
); 
 453 wxFileName 
wxFileName::DirName(const wxString
& dir
) 
 460 // ---------------------------------------------------------------------------- 
 462 // ---------------------------------------------------------------------------- 
 464 bool wxFileName::FileExists() const 
 466     return wxFileName::FileExists( GetFullPath() ); 
 469 bool wxFileName::FileExists( const wxString 
&file 
) 
 471     return ::wxFileExists( file 
); 
 474 bool wxFileName::DirExists() const 
 476     return wxFileName::DirExists( GetFullPath() ); 
 479 bool wxFileName::DirExists( const wxString 
&dir 
) 
 481     return ::wxDirExists( dir 
); 
 484 // ---------------------------------------------------------------------------- 
 485 // CWD and HOME stuff 
 486 // ---------------------------------------------------------------------------- 
 488 void wxFileName::AssignCwd(const wxString
& volume
) 
 490     AssignDir(wxFileName::GetCwd(volume
)); 
 494 wxString 
wxFileName::GetCwd(const wxString
& volume
) 
 496     // if we have the volume, we must get the current directory on this drive 
 497     // and to do this we have to chdir to this volume - at least under Windows, 
 498     // I don't know how to get the current drive on another volume elsewhere 
 501     if ( !volume
.empty() ) 
 504         SetCwd(volume 
+ GetVolumeSeparator()); 
 507     wxString cwd 
= ::wxGetCwd(); 
 509     if ( !volume
.empty() ) 
 517 bool wxFileName::SetCwd() 
 519     return wxFileName::SetCwd( GetFullPath() ); 
 522 bool wxFileName::SetCwd( const wxString 
&cwd 
) 
 524     return ::wxSetWorkingDirectory( cwd 
); 
 527 void wxFileName::AssignHomeDir() 
 529     AssignDir(wxFileName::GetHomeDir()); 
 532 wxString 
wxFileName::GetHomeDir() 
 534     return ::wxGetHomeDir(); 
 537 void wxFileName::AssignTempFileName(const wxString
& prefix
, wxFile 
*fileTemp
) 
 539     wxString tempname 
= CreateTempFileName(prefix
, fileTemp
); 
 540     if ( tempname
.empty() ) 
 542         // error, failed to get temp file name 
 553 wxFileName::CreateTempFileName(const wxString
& prefix
, wxFile 
*fileTemp
) 
 555     wxString path
, dir
, name
; 
 557     // use the directory specified by the prefix 
 558     SplitPath(prefix
, &dir
, &name
, NULL 
/* extension */); 
 560 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 565         if ( !::GetTempPath(MAX_PATH
, wxStringBuffer(dir
, MAX_PATH 
+ 1)) ) 
 567             wxLogLastError(_T("GetTempPath")); 
 572             // GetTempFileName() fails if we pass it an empty string 
 576     else // we have a dir to create the file in 
 578         // ensure we use only the back slashes as GetTempFileName(), unlike all 
 579         // the other APIs, is picky and doesn't accept the forward ones 
 580         dir
.Replace(_T("/"), _T("\\")); 
 583     if ( !::GetTempFileName(dir
, name
, 0, wxStringBuffer(path
, MAX_PATH 
+ 1)) ) 
 585         wxLogLastError(_T("GetTempFileName")); 
 590     if ( !::GetTempFileName(NULL
, prefix
, 0, wxStringBuffer(path
, 1025)) ) 
 596 #elif defined(__WXPM__) 
 597     // for now just create a file 
 599     // future enhancements can be to set some extended attributes for file 
 600     // systems OS/2 supports that have them (HPFS, FAT32) and security 
 602     static const wxChar 
*szMktempSuffix 
= wxT("XXX"); 
 603     path 
<< dir 
<< _T('/') << name 
<< szMktempSuffix
; 
 605     // Temporarily remove - MN 
 607         ::DosCreateDir(wxStringBuffer(path
, MAX_PATH
), NULL
); 
 610 #else // !Windows, !OS/2 
 613 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 614         dir 
= wxMacFindFolder(  (short) kOnSystemDisk
, kTemporaryFolderType
, kCreateFolder 
) ; 
 616         dir 
= wxGetenv(_T("TMP")); 
 619             dir 
= wxGetenv(_T("TEMP")); 
 636     if ( !wxEndsWithPathSeparator(dir
) && 
 637             (name
.empty() || !wxIsPathSeparator(name
[0u])) ) 
 639         path 
+= wxFILE_SEP_PATH
; 
 644 #if defined(HAVE_MKSTEMP) 
 645     // scratch space for mkstemp() 
 646     path 
+= _T("XXXXXX"); 
 648     // we need to copy the path to the buffer in which mkstemp() can modify it 
 649     wxCharBuffer 
buf( wxConvFile
.cWX2MB( path 
) ); 
 651     // cast is safe because the string length doesn't change 
 652     int fdTemp 
= mkstemp( (char*)(const char*) buf 
); 
 655         // this might be not necessary as mkstemp() on most systems should have 
 656         // already done it but it doesn't hurt neither... 
 659     else // mkstemp() succeeded 
 661         path 
= wxConvFile
.cMB2WX( (const char*) buf 
); 
 663         // avoid leaking the fd 
 666             fileTemp
->Attach(fdTemp
); 
 673 #else // !HAVE_MKSTEMP 
 677     path 
+= _T("XXXXXX"); 
 679     wxCharBuffer buf 
= wxConvFile
.cWX2MB( path 
); 
 680     if ( !mktemp( (const char*) buf 
) ) 
 686         path 
= wxConvFile
.cMB2WX( (const char*) buf 
); 
 688 #else // !HAVE_MKTEMP (includes __DOS__) 
 689     // generate the unique file name ourselves 
 691     path 
<< (unsigned int)getpid(); 
 696     static const size_t numTries 
= 1000; 
 697     for ( size_t n 
= 0; n 
< numTries
; n
++ ) 
 699         // 3 hex digits is enough for numTries == 1000 < 4096 
 700         pathTry 
= path 
+ wxString::Format(_T("%.03x"), n
); 
 701         if ( !wxFile::Exists(pathTry
) ) 
 710 #endif // HAVE_MKTEMP/!HAVE_MKTEMP 
 715 #endif // HAVE_MKSTEMP/!HAVE_MKSTEMP 
 717 #endif // Windows/!Windows 
 721         wxLogSysError(_("Failed to create a temporary file name")); 
 723     else if ( fileTemp 
&& !fileTemp
->IsOpened() ) 
 725         // open the file - of course, there is a race condition here, this is 
 726         // why we always prefer using mkstemp()... 
 728         // NB: GetTempFileName() under Windows creates the file, so using 
 729         //     write_excl there would fail 
 730         if ( !fileTemp
->Open(path
, 
 731 #if defined(__WINDOWS__) && !defined(__WXMICROWIN__) 
 736                              wxS_IRUSR 
| wxS_IWUSR
) ) 
 738             // FIXME: If !ok here should we loop and try again with another 
 739             //        file name?  That is the standard recourse if open(O_EXCL) 
 740             //        fails, though of course it should be protected against 
 741             //        possible infinite looping too. 
 743             wxLogError(_("Failed to open temporary file.")); 
 752 // ---------------------------------------------------------------------------- 
 753 // directory operations 
 754 // ---------------------------------------------------------------------------- 
 756 bool wxFileName::Mkdir( int perm
, int flags 
) 
 758     return wxFileName::Mkdir( GetFullPath(), perm
, flags 
); 
 761 bool wxFileName::Mkdir( const wxString
& dir
, int perm
, int flags 
) 
 763     if ( flags 
& wxPATH_MKDIR_FULL 
) 
 765         // split the path in components 
 767         filename
.AssignDir(dir
); 
 770         if ( filename
.HasVolume()) 
 772             currPath 
<< wxGetVolumeString(filename
.GetVolume(), wxPATH_NATIVE
); 
 775         wxArrayString dirs 
= filename
.GetDirs(); 
 776         size_t count 
= dirs
.GetCount(); 
 777         for ( size_t i 
= 0; i 
< count
; i
++ ) 
 780 #if defined(__WXMAC__) && !defined(__DARWIN__) 
 781                         // relative pathnames are exactely the other way round under mac... 
 782                 !filename
.IsAbsolute()  
 784                 filename
.IsAbsolute()  
 787                 currPath 
+= wxFILE_SEP_PATH
; 
 790             if (!DirExists(currPath
)) 
 792                 if (!wxMkdir(currPath
, perm
)) 
 794                     // no need to try creating further directories 
 804     return ::wxMkdir( dir
, perm 
); 
 807 bool wxFileName::Rmdir() 
 809     return wxFileName::Rmdir( GetFullPath() ); 
 812 bool wxFileName::Rmdir( const wxString 
&dir 
) 
 814     return ::wxRmdir( dir 
); 
 817 // ---------------------------------------------------------------------------- 
 818 // path normalization 
 819 // ---------------------------------------------------------------------------- 
 821 bool wxFileName::Normalize(int flags
, 
 825     // the existing path components 
 826     wxArrayString dirs 
= GetDirs(); 
 828     // the path to prepend in front to make the path absolute 
 831     format 
= GetFormat(format
); 
 833     // make the path absolute 
 834     if ( (flags 
& wxPATH_NORM_ABSOLUTE
) && !IsAbsolute(format
) ) 
 838             curDir
.AssignCwd(GetVolume()); 
 842             curDir
.AssignDir(cwd
); 
 845         // the path may be not absolute because it doesn't have the volume name 
 846         // but in this case we shouldn't modify the directory components of it 
 847         // but just set the current volume 
 848         if ( !HasVolume() && curDir
.HasVolume() ) 
 850             SetVolume(curDir
.GetVolume()); 
 854                 // yes, it was the case - we don't need curDir then 
 860     // handle ~ stuff under Unix only 
 861     if ( (format 
== wxPATH_UNIX
) && (flags 
& wxPATH_NORM_TILDE
) ) 
 863         if ( !dirs
.IsEmpty() ) 
 865             wxString dir 
= dirs
[0u]; 
 866             if ( !dir
.empty() && dir
[0u] == _T('~') ) 
 868                 curDir
.AssignDir(wxGetUserHome(dir
.c_str() + 1)); 
 875     // transform relative path into abs one 
 878         wxArrayString dirsNew 
= curDir
.GetDirs(); 
 879         size_t count 
= dirs
.GetCount(); 
 880         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 882             dirsNew
.Add(dirs
[n
]); 
 888     // now deal with ".", ".." and the rest 
 890     size_t count 
= dirs
.GetCount(); 
 891     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 893         wxString dir 
= dirs
[n
]; 
 895         if ( flags 
& wxPATH_NORM_DOTS 
) 
 897             if ( dir 
== wxT(".") ) 
 903             if ( dir 
== wxT("..") ) 
 905                 if ( m_dirs
.IsEmpty() ) 
 907                     wxLogError(_("The path '%s' contains too many \"..\"!"), 
 908                                GetFullPath().c_str()); 
 912                 m_dirs
.RemoveAt(m_dirs
.GetCount() - 1); 
 917         if ( flags 
& wxPATH_NORM_ENV_VARS 
) 
 919             dir 
= wxExpandEnvVars(dir
); 
 922         if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
 930     if ( (flags 
& wxPATH_NORM_CASE
) && !IsCaseSensitive(format
) ) 
 932         // VZ: expand env vars here too? 
 938     // we do have the path now 
 940     // NB: need to do this before (maybe) calling Assign() below 
 943 #if defined(__WIN32__) 
 944     if ( (flags 
& wxPATH_NORM_LONG
) && (format 
== wxPATH_DOS
) ) 
 946         Assign(GetLongPath()); 
 953 // ---------------------------------------------------------------------------- 
 954 // absolute/relative paths 
 955 // ---------------------------------------------------------------------------- 
 957 bool wxFileName::IsAbsolute(wxPathFormat format
) const 
 959     // if our path doesn't start with a path separator, it's not an absolute 
 964     if ( !GetVolumeSeparator(format
).empty() ) 
 966         // this format has volumes and an absolute path must have one, it's not 
 967         // enough to have the full path to bean absolute file under Windows 
 968         if ( GetVolume().empty() ) 
 975 bool wxFileName::MakeRelativeTo(const wxString
& pathBase
, wxPathFormat format
) 
 977     wxFileName 
fnBase(pathBase
, format
); 
 979     // get cwd only once - small time saving 
 980     wxString cwd 
= wxGetCwd(); 
 981     Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
 982     fnBase
.Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
 984     bool withCase 
= IsCaseSensitive(format
); 
 986     // we can't do anything if the files live on different volumes 
 987     if ( !GetVolume().IsSameAs(fnBase
.GetVolume(), withCase
) ) 
 993     // same drive, so we don't need our volume 
 996     // remove common directories starting at the top 
 997     while ( !m_dirs
.IsEmpty() && !fnBase
.m_dirs
.IsEmpty() && 
 998                 m_dirs
[0u].IsSameAs(fnBase
.m_dirs
[0u], withCase
) ) 
1001         fnBase
.m_dirs
.RemoveAt(0); 
1004     // add as many ".." as needed 
1005     size_t count 
= fnBase
.m_dirs
.GetCount(); 
1006     for ( size_t i 
= 0; i 
< count
; i
++ ) 
1008         m_dirs
.Insert(wxT(".."), 0u); 
1011     if ( format 
== wxPATH_UNIX 
|| format 
== wxPATH_DOS 
) 
1013         // a directory made relative with respect to itself is '.' under Unix 
1014         // and DOS, by definition (but we don't have to insert "./" for the 
1016         if ( m_dirs
.IsEmpty() && IsDir() ) 
1018             m_dirs
.Add(_T('.')); 
1028 // ---------------------------------------------------------------------------- 
1029 // filename kind tests 
1030 // ---------------------------------------------------------------------------- 
1032 bool wxFileName::SameAs(const wxFileName
& filepath
, wxPathFormat format
) const 
1034     wxFileName fn1 
= *this, 
1037     // get cwd only once - small time saving 
1038     wxString cwd 
= wxGetCwd(); 
1039     fn1
.Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1040     fn2
.Normalize(wxPATH_NORM_ALL 
& ~wxPATH_NORM_CASE
, cwd
, format
); 
1042     if ( fn1
.GetFullPath() == fn2
.GetFullPath() ) 
1045     // TODO: compare inodes for Unix, this works even when filenames are 
1046     //       different but files are the same (symlinks) (VZ) 
1052 bool wxFileName::IsCaseSensitive( wxPathFormat format 
) 
1054     // only Unix filenames are truely case-sensitive 
1055     return GetFormat(format
) == wxPATH_UNIX
; 
1059 wxString 
wxFileName::GetVolumeSeparator(wxPathFormat format
) 
1063     if ( (GetFormat(format
) == wxPATH_DOS
) || 
1064          (GetFormat(format
) == wxPATH_VMS
) ) 
1066         sepVol 
= wxFILE_SEP_DSK
; 
1074 wxString 
wxFileName::GetPathSeparators(wxPathFormat format
) 
1077     switch ( GetFormat(format
) ) 
1080             // accept both as native APIs do but put the native one first as 
1081             // this is the one we use in GetFullPath() 
1082             seps 
<< wxFILE_SEP_PATH_DOS 
<< wxFILE_SEP_PATH_UNIX
; 
1086             wxFAIL_MSG( _T("unknown wxPATH_XXX style") ); 
1090             seps 
= wxFILE_SEP_PATH_UNIX
; 
1094             seps 
= wxFILE_SEP_PATH_MAC
; 
1098             seps 
= wxFILE_SEP_PATH_VMS
; 
1106 bool wxFileName::IsPathSeparator(wxChar ch
, wxPathFormat format
) 
1108     // wxString::Find() doesn't work as expected with NUL - it will always find 
1109     // it, so it is almost surely a bug if this function is called with NUL arg 
1110     wxASSERT_MSG( ch 
!= _T('\0'), _T("shouldn't be called with NUL") ); 
1112     return GetPathSeparators(format
).Find(ch
) != wxNOT_FOUND
; 
1115 // ---------------------------------------------------------------------------- 
1116 // path components manipulation 
1117 // ---------------------------------------------------------------------------- 
1119 void wxFileName::AppendDir( const wxString 
&dir 
) 
1124 void wxFileName::PrependDir( const wxString 
&dir 
) 
1126     m_dirs
.Insert( dir
, 0 ); 
1129 void wxFileName::InsertDir( int before
, const wxString 
&dir 
) 
1131     m_dirs
.Insert( dir
, before 
); 
1134 void wxFileName::RemoveDir( int pos 
) 
1136     m_dirs
.Remove( (size_t)pos 
); 
1139 // ---------------------------------------------------------------------------- 
1141 // ---------------------------------------------------------------------------- 
1143 void wxFileName::SetFullName(const wxString
& fullname
) 
1145     SplitPath(fullname
, NULL 
/* no path */, &m_name
, &m_ext
); 
1148 wxString 
wxFileName::GetFullName() const 
1150     wxString fullname 
= m_name
; 
1151     if ( !m_ext
.empty() ) 
1153         fullname 
<< wxFILE_SEP_EXT 
<< m_ext
; 
1159 wxString 
wxFileName::GetPath( int flags
, wxPathFormat format 
) const 
1161     format 
= GetFormat( format 
); 
1165     // return the volume with the path as well if requested 
1166     if ( flags 
& wxPATH_GET_VOLUME 
) 
1168         fullpath 
+= wxGetVolumeString(GetVolume(), format
); 
1171     // the leading character 
1176                 fullpath 
+= wxFILE_SEP_PATH_MAC
; 
1181                 fullpath 
+= wxFILE_SEP_PATH_DOS
; 
1185             wxFAIL_MSG( _T("unknown path format") ); 
1191                 // normally the absolute file names starts with a slash with 
1192                 // one exception: file names like "~/foo.bar" don't have it 
1193                 if ( m_dirs
.IsEmpty() || m_dirs
[0u] != _T('~') ) 
1195                     fullpath 
+= wxFILE_SEP_PATH_UNIX
; 
1201             // no leading character here but use this place to unset 
1202             // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense as, 
1203             // if I understand correctly, there should never be a dot before 
1204             // the closing bracket 
1205             flags 
&= ~wxPATH_GET_SEPARATOR
; 
1208     // then concatenate all the path components using the path separator 
1209     size_t dirCount 
= m_dirs
.GetCount(); 
1212         if ( format 
== wxPATH_VMS 
) 
1214             fullpath 
+= wxT('['); 
1217         for ( size_t i 
= 0; i 
< dirCount
; i
++ ) 
1222                     if ( m_dirs
[i
] == wxT(".") ) 
1224                         // skip appending ':', this shouldn't be done in this 
1225                         // case as "::" is interpreted as ".." under Unix 
1229                     // convert back from ".." to nothing 
1230                     if ( m_dirs
[i
] != wxT("..") ) 
1231                          fullpath 
+= m_dirs
[i
]; 
1235                     wxFAIL_MSG( wxT("unexpected path format") ); 
1236                     // still fall through 
1240                     fullpath 
+= m_dirs
[i
]; 
1244                     // TODO: What to do with ".." under VMS 
1246                     // convert back from ".." to nothing 
1247                     if ( m_dirs
[i
] != wxT("..") ) 
1248                         fullpath 
+= m_dirs
[i
]; 
1252             if ( (flags 
& wxPATH_GET_SEPARATOR
) || (i 
!= dirCount 
- 1) ) 
1253                 fullpath 
+= GetPathSeparator(format
); 
1256         if ( format 
== wxPATH_VMS 
) 
1258             fullpath 
+= wxT(']'); 
1265 wxString 
wxFileName::GetFullPath( wxPathFormat format 
) const 
1267     // we already have a function to get the path 
1268     wxString fullpath 
= GetPath(wxPATH_GET_VOLUME 
| wxPATH_GET_SEPARATOR
, 
1271     // now just add the file name and extension to it 
1272     fullpath 
+= GetFullName(); 
1277 // Return the short form of the path (returns identity on non-Windows platforms) 
1278 wxString 
wxFileName::GetShortPath() const 
1280 #if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) 
1281     wxString 
path(GetFullPath()); 
1283     DWORD sz 
= ::GetShortPathName(path
, NULL
, 0); 
1287         ok 
= ::GetShortPathName
 
1290                 pathOut
.GetWriteBuf(sz
), 
1293         pathOut
.UngetWriteBuf(); 
1300     return GetFullPath(); 
1304 // Return the long form of the path (returns identity on non-Windows platforms) 
1305 wxString 
wxFileName::GetLongPath() const 
1308              path 
= GetFullPath(); 
1310 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
1311     bool success 
= FALSE
; 
1313 #if wxUSE_DYNAMIC_LOADER 
1314     typedef DWORD (WINAPI 
*GET_LONG_PATH_NAME
)(const wxChar 
*, wxChar 
*, DWORD
); 
1316     static bool s_triedToLoad 
= FALSE
; 
1318     if ( !s_triedToLoad 
) 
1320         // suppress the errors about missing GetLongPathName[AW] 
1323         s_triedToLoad 
= TRUE
; 
1324         wxDynamicLibrary 
dllKernel(_T("kernel32")); 
1325         if ( dllKernel
.IsLoaded() ) 
1327             // may succeed or fail depending on the Windows version 
1328             static GET_LONG_PATH_NAME s_pfnGetLongPathName 
= NULL
; 
1330             s_pfnGetLongPathName 
= (GET_LONG_PATH_NAME
) dllKernel
.GetSymbol(_T("GetLongPathNameW")); 
1332             s_pfnGetLongPathName 
= (GET_LONG_PATH_NAME
) dllKernel
.GetSymbol(_T("GetLongPathNameA")); 
1335             if ( s_pfnGetLongPathName 
) 
1337                 DWORD dwSize 
= (*s_pfnGetLongPathName
)(path
, NULL
, 0); 
1338                 bool ok 
= dwSize 
> 0; 
1342                     DWORD sz 
= (*s_pfnGetLongPathName
)(path
, NULL
, 0); 
1346                         ok 
= (*s_pfnGetLongPathName
) 
1349                                 pathOut
.GetWriteBuf(sz
), 
1352                         pathOut
.UngetWriteBuf(); 
1363 #endif // wxUSE_DYNAMIC_LOADER 
1367         // The OS didn't support GetLongPathName, or some other error. 
1368         // We need to call FindFirstFile on each component in turn. 
1370         WIN32_FIND_DATA findFileData
; 
1374             pathOut 
= GetVolume() + 
1375                       GetVolumeSeparator(wxPATH_DOS
) + 
1376                       GetPathSeparator(wxPATH_DOS
); 
1378             pathOut 
= wxEmptyString
; 
1380         wxArrayString dirs 
= GetDirs(); 
1381         dirs
.Add(GetFullName()); 
1385         size_t count 
= dirs
.GetCount(); 
1386         for ( size_t i 
= 0; i 
< count
; i
++ ) 
1388             // We're using pathOut to collect the long-name path, but using a 
1389             // temporary for appending the last path component which may be 
1391             tmpPath 
= pathOut 
+ dirs
[i
]; 
1393             if ( tmpPath
.empty() ) 
1396             // can't see this being necessary? MF 
1397             if ( tmpPath
.Last() == GetVolumeSeparator(wxPATH_DOS
) ) 
1399                 // Can't pass a drive and root dir to FindFirstFile, 
1400                 // so continue to next dir 
1401                 tmpPath 
+= wxFILE_SEP_PATH
; 
1406             hFind 
= ::FindFirstFile(tmpPath
, &findFileData
); 
1407             if (hFind 
== INVALID_HANDLE_VALUE
) 
1409                 // Error: most likely reason is that path doesn't exist, so 
1410                 // append any unprocessed parts and return 
1411                 for ( i 
+= 1; i 
< count
; i
++ ) 
1412                     tmpPath 
+= wxFILE_SEP_PATH 
+ dirs
[i
]; 
1417             pathOut 
+= findFileData
.cFileName
; 
1418             if ( (i 
< (count
-1)) ) 
1419                 pathOut 
+= wxFILE_SEP_PATH
; 
1426 #endif // Win32/!Win32 
1431 wxPathFormat 
wxFileName::GetFormat( wxPathFormat format 
) 
1433     if (format 
== wxPATH_NATIVE
) 
1435 #if defined(__WXMSW__) || defined(__WXPM__) || defined(__DOS__) 
1436         format 
= wxPATH_DOS
; 
1437 #elif defined(__WXMAC__) && !defined(__DARWIN__) 
1438         format 
= wxPATH_MAC
; 
1439 #elif defined(__VMS) 
1440         format 
= wxPATH_VMS
; 
1442         format 
= wxPATH_UNIX
; 
1448 // ---------------------------------------------------------------------------- 
1449 // path splitting function 
1450 // ---------------------------------------------------------------------------- 
1453 void wxFileName::SplitPath(const wxString
& fullpathWithVolume
, 
1454                            wxString 
*pstrVolume
, 
1458                            wxPathFormat format
) 
1460     format 
= GetFormat(format
); 
1462     wxString fullpath 
= fullpathWithVolume
; 
1464     // under VMS the end of the path is ']', not the path separator used to 
1465     // separate the components 
1466     wxString sepPath 
= format 
== wxPATH_VMS 
? wxString(_T(']')) 
1467                                             : GetPathSeparators(format
); 
1469     // special Windows UNC paths hack: transform \\share\path into share:path 
1470     if ( format 
== wxPATH_DOS 
) 
1472         if ( fullpath
.length() >= 4 && 
1473                 fullpath
[0u] == wxFILE_SEP_PATH_DOS 
&& 
1474                     fullpath
[1u] == wxFILE_SEP_PATH_DOS 
) 
1476             fullpath
.erase(0, 2); 
1478             size_t posFirstSlash 
= fullpath
.find_first_of(sepPath
); 
1479             if ( posFirstSlash 
!= wxString::npos 
) 
1481                 fullpath
[posFirstSlash
] = wxFILE_SEP_DSK
; 
1483                 // UNC paths are always absolute, right? (FIXME) 
1484                 fullpath
.insert(posFirstSlash 
+ 1, wxFILE_SEP_PATH_DOS
); 
1489     // We separate the volume here 
1490     if ( format 
== wxPATH_DOS 
|| format 
== wxPATH_VMS 
) 
1492         wxString sepVol 
= GetVolumeSeparator(format
); 
1494         size_t posFirstColon 
= fullpath
.find_first_of(sepVol
); 
1495         if ( posFirstColon 
!= wxString::npos 
) 
1499                 *pstrVolume 
= fullpath
.Left(posFirstColon
); 
1502             // remove the volume name and the separator from the full path 
1503             fullpath
.erase(0, posFirstColon 
+ sepVol
.length()); 
1507     // find the positions of the last dot and last path separator in the path 
1508     size_t posLastDot 
= fullpath
.find_last_of(wxFILE_SEP_EXT
); 
1509     size_t posLastSlash 
= fullpath
.find_last_of(sepPath
); 
1511     if ( (posLastDot 
!= wxString::npos
) && 
1512             ((format 
== wxPATH_UNIX
) || (format 
== wxPATH_VMS
)) ) 
1514         if ( (posLastDot 
== 0) || 
1515              (fullpath
[posLastDot 
- 1] == sepPath
[0u] ) ) 
1517             // under Unix and VMS, dot may be (and commonly is) the first 
1518             // character of the filename, don't treat the entire filename as 
1519             // extension in this case 
1520             posLastDot 
= wxString::npos
; 
1524     // if we do have a dot and a slash, check that the dot is in the name part 
1525     if ( (posLastDot 
!= wxString::npos
) && 
1526          (posLastSlash 
!= wxString::npos
) && 
1527          (posLastDot 
< posLastSlash
) ) 
1529         // the dot is part of the path, not the start of the extension 
1530         posLastDot 
= wxString::npos
; 
1533     // now fill in the variables provided by user 
1536         if ( posLastSlash 
== wxString::npos 
) 
1543             // take everything up to the path separator but take care to make 
1544             // the path equal to something like '/', not empty, for the files 
1545             // immediately under root directory 
1546             size_t len 
= posLastSlash
; 
1548             // this rule does not apply to mac since we do not start with colons (sep) 
1549             // except for relative paths 
1550             if ( !len 
&& format 
!= wxPATH_MAC
) 
1553             *pstrPath 
= fullpath
.Left(len
); 
1555             // special VMS hack: remove the initial bracket 
1556             if ( format 
== wxPATH_VMS 
) 
1558                 if ( (*pstrPath
)[0u] == _T('[') ) 
1559                     pstrPath
->erase(0, 1); 
1566         // take all characters starting from the one after the last slash and 
1567         // up to, but excluding, the last dot 
1568         size_t nStart 
= posLastSlash 
== wxString::npos 
? 0 : posLastSlash 
+ 1; 
1570         if ( posLastDot 
== wxString::npos 
) 
1572             // take all until the end 
1573             count 
= wxString::npos
; 
1575         else if ( posLastSlash 
== wxString::npos 
) 
1579         else // have both dot and slash 
1581             count 
= posLastDot 
- posLastSlash 
- 1; 
1584         *pstrName 
= fullpath
.Mid(nStart
, count
); 
1589         if ( posLastDot 
== wxString::npos 
) 
1596             // take everything after the dot 
1597             *pstrExt 
= fullpath
.Mid(posLastDot 
+ 1); 
1603 void wxFileName::SplitPath(const wxString
& fullpath
, 
1607                            wxPathFormat format
) 
1610     SplitPath(fullpath
, &volume
, path
, name
, ext
, format
); 
1614         path
->Prepend(wxGetVolumeString(volume
, format
)); 
1618 // ---------------------------------------------------------------------------- 
1620 // ---------------------------------------------------------------------------- 
1624 bool wxFileName::SetTimes(const wxDateTime 
*dtAccess
, 
1625                           const wxDateTime 
*dtMod
, 
1626                           const wxDateTime 
*dtCreate
) 
1628 #if defined(__WIN32__) 
1631         // VZ: please let me know how to do this if you can 
1632         wxFAIL_MSG( _T("SetTimes() not implemented for the directories") ); 
1636         wxFileHandle 
fh(GetFullPath(), wxFileHandle::Write
); 
1639             FILETIME ftAccess
, ftCreate
, ftWrite
; 
1642                 ConvertWxToFileTime(&ftCreate
, *dtCreate
); 
1644                 ConvertWxToFileTime(&ftAccess
, *dtAccess
); 
1646                 ConvertWxToFileTime(&ftWrite
, *dtMod
); 
1648             if ( ::SetFileTime(fh
, 
1649                                dtCreate 
? &ftCreate 
: NULL
, 
1650                                dtAccess 
? &ftAccess 
: NULL
, 
1651                                dtMod 
? &ftWrite 
: NULL
) ) 
1657 #elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) 
1658     if ( !dtAccess 
&& !dtMod 
) 
1660         // can't modify the creation time anyhow, don't try 
1664     // if dtAccess or dtMod is not specified, use the other one (which must be 
1665     // non NULL because of the test above) for both times 
1667     utm
.actime 
= dtAccess 
? dtAccess
->GetTicks() : dtMod
->GetTicks(); 
1668     utm
.modtime 
= dtMod 
? dtMod
->GetTicks() : dtAccess
->GetTicks(); 
1669     if ( utime(GetFullPath().fn_str(), &utm
) == 0 ) 
1673 #else // other platform 
1676     wxLogSysError(_("Failed to modify file times for '%s'"), 
1677                   GetFullPath().c_str()); 
1682 bool wxFileName::Touch() 
1684 #if defined(__UNIX_LIKE__) 
1685     // under Unix touching file is simple: just pass NULL to utime() 
1686     if ( utime(GetFullPath().fn_str(), NULL
) == 0 ) 
1691     wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); 
1694 #else // other platform 
1695     wxDateTime dtNow 
= wxDateTime::Now(); 
1697     return SetTimes(&dtNow
, &dtNow
, NULL 
/* don't change create time */); 
1701 bool wxFileName::GetTimes(wxDateTime 
*dtAccess
, 
1703                           wxDateTime 
*dtCreate
) const 
1705 #if defined(__WIN32__) 
1706     // we must use different methods for the files and directories under 
1707     // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and 
1708     // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and 
1711     FILETIME ftAccess
, ftCreate
, ftWrite
; 
1714         // implemented in msw/dir.cpp 
1715         extern bool wxGetDirectoryTimes(const wxString
& dirname
, 
1716                                         FILETIME 
*, FILETIME 
*, FILETIME 
*); 
1718         // we should pass the path without the trailing separator to 
1719         // wxGetDirectoryTimes() 
1720         ok 
= wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME
), 
1721                                  &ftAccess
, &ftCreate
, &ftWrite
); 
1725         wxFileHandle 
fh(GetFullPath(), wxFileHandle::Read
); 
1728             ok 
= ::GetFileTime(fh
, 
1729                                dtCreate 
? &ftCreate 
: NULL
, 
1730                                dtAccess 
? &ftAccess 
: NULL
, 
1731                                dtMod 
? &ftWrite 
: NULL
) != 0; 
1742             ConvertFileTimeToWx(dtCreate
, ftCreate
); 
1744             ConvertFileTimeToWx(dtAccess
, ftAccess
); 
1746             ConvertFileTimeToWx(dtMod
, ftWrite
); 
1750 #elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || (defined(__DOS__) && defined(__WATCOMC__)) 
1752     if ( wxStat( GetFullPath().c_str(), &stBuf
) == 0 ) 
1755             dtAccess
->Set(stBuf
.st_atime
); 
1757             dtMod
->Set(stBuf
.st_mtime
); 
1759             dtCreate
->Set(stBuf
.st_ctime
); 
1763 #else // other platform 
1766     wxLogSysError(_("Failed to retrieve file times for '%s'"), 
1767                   GetFullPath().c_str()); 
1772 #endif // wxUSE_DATETIME 
1776 const short kMacExtensionMaxLength 
= 16 ; 
1777 class MacDefaultExtensionRecord
 
1780   MacDefaultExtensionRecord() 
1783     m_type 
= m_creator 
= NULL 
; 
1785   MacDefaultExtensionRecord( const MacDefaultExtensionRecord
& from 
) 
1787     strcpy( m_ext 
, from
.m_ext 
) ; 
1788     m_type 
= from
.m_type 
; 
1789     m_creator 
= from
.m_creator 
; 
1791   MacDefaultExtensionRecord( const char * extension 
, OSType type 
, OSType creator 
) 
1793     strncpy( m_ext 
, extension 
, kMacExtensionMaxLength 
) ; 
1794     m_ext
[kMacExtensionMaxLength
] = 0 ; 
1796     m_creator 
= creator 
; 
1798   char m_ext
[kMacExtensionMaxLength
] ; 
1803 #include "wx/dynarray.h" 
1804 WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord
, MacDefaultExtensionArray
) ; 
1806 bool gMacDefaultExtensionsInited 
= false ; 
1808 #include "wx/arrimpl.cpp" 
1810 WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray
) ; 
1812 MacDefaultExtensionArray gMacDefaultExtensions 
; 
1814 static void MacEnsureDefaultExtensionsLoaded() 
1816   if ( !gMacDefaultExtensionsInited 
) 
1819     // load the default extensions 
1820     MacDefaultExtensionRecord defaults
[1] = 
1822       MacDefaultExtensionRecord( "txt" , 'TEXT' , 'ttxt' ) , 
1825     // we could load the pc exchange prefs here too 
1827     for ( size_t i 
= 0 ; i 
< WXSIZEOF( defaults 
) ; ++i 
) 
1829       gMacDefaultExtensions
.Add( defaults
[i
] ) ; 
1831     gMacDefaultExtensionsInited 
= true ; 
1834 bool wxFileName::MacSetTypeAndCreator( wxUint32 type 
, wxUint32 creator 
) 
1838   wxMacFilename2FSSpec(GetFullPath(),&spec
) ; 
1839   OSErr err 
= FSpGetFInfo( &spec 
, &fndrInfo 
) ; 
1840   wxCHECK( err 
== noErr 
, false ) ; 
1842   fndrInfo
.fdType 
= type 
; 
1843   fndrInfo
.fdCreator 
= creator 
; 
1844   FSpSetFInfo( &spec 
, &fndrInfo 
) ; 
1848 bool wxFileName::MacGetTypeAndCreator( wxUint32 
*type 
, wxUint32 
*creator 
) 
1852   wxMacFilename2FSSpec(GetFullPath(),&spec
) ; 
1853   OSErr err 
= FSpGetFInfo( &spec 
, &fndrInfo 
) ; 
1854   wxCHECK( err 
== noErr 
, false ) ; 
1856   *type 
= fndrInfo
.fdType 
; 
1857   *creator 
= fndrInfo
.fdCreator 
; 
1861 bool wxFileName::MacSetDefaultTypeAndCreator() 
1863     wxUint32 type 
, creator 
; 
1864     if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type 
, 
1867         return MacSetTypeAndCreator( type 
, creator 
) ; 
1872 bool wxFileName::MacFindDefaultTypeAndCreator( const wxString
& ext 
, wxUint32 
*type 
, wxUint32 
*creator 
) 
1874   MacEnsureDefaultExtensionsLoaded() ; 
1875   wxString extl 
= ext
.Lower() ; 
1876   for( int i 
= gMacDefaultExtensions
.Count() - 1 ; i 
>= 0 ; --i 
) 
1878     if ( gMacDefaultExtensions
.Item(i
).m_ext 
== extl 
) 
1880       *type 
= gMacDefaultExtensions
.Item(i
).m_type 
; 
1881       *creator 
= gMacDefaultExtensions
.Item(i
).m_creator 
; 
1888 void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString
& ext 
, wxUint32 type 
, wxUint32 creator 
) 
1890   MacEnsureDefaultExtensionsLoaded() ; 
1891   MacDefaultExtensionRecord rec 
; 
1893   rec
.m_creator 
= creator 
; 
1894   strncpy( rec
.m_ext 
, ext
.Lower().c_str() , kMacExtensionMaxLength 
) ; 
1895   gMacDefaultExtensions
.Add( rec 
) ;