]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/filename.cpp
Applied patch [ 649284 ] Fix wxODBC to work with MySQL 2.x
[wxWidgets.git] / src / common / filename.cpp
index ff25ddc3774dcfcdc233c623259aef18f7b8d9b9..f56ec3d5ef0829e639c9c7eb11275c2497773473 100644 (file)
@@ -32,9 +32,9 @@
                 or just
                     filename
                 (although :filename works as well).
                 or just
                     filename
                 (although :filename works as well).
-                :::filename.ext is not yet supported. TODO.
                 Since the volume is just part of the file path, it is not
                 Since the volume is just part of the file path, it is not
-                treated like a separate entity as it is done under DOS.
+                treated like a separate entity as it is done under DOS and
+                VMS, it is just treated as another dir.
 
    wxPATH_VMS:  VMS native format, absolute file names have the form
                     <device>:[dir1.dir2.dir3]file.txt
 
    wxPATH_VMS:  VMS native format, absolute file names have the form
                     <device>:[dir1.dir2.dir3]file.txt
 // ----------------------------------------------------------------------------
 
 #ifdef __GNUG__
 // ----------------------------------------------------------------------------
 
 #ifdef __GNUG__
-    #pragma implementation "filename.h"
+#pragma implementation "filename.h"
 #endif
 
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
 #endif
 
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-  #pragma hdrstop
+#pragma hdrstop
 #endif
 
 #ifndef WX_PRECOMP
 #endif
 
 #ifndef WX_PRECOMP
-    #include "wx/intl.h"
-    #include "wx/log.h"
+#include "wx/intl.h"
+#include "wx/log.h"
+#include "wx/file.h"
 #endif
 
 #include "wx/filename.h"
 #include "wx/tokenzr.h"
 #include "wx/config.h"          // for wxExpandEnvVars
 #include "wx/utils.h"
 #endif
 
 #include "wx/filename.h"
 #include "wx/tokenzr.h"
 #include "wx/config.h"          // for wxExpandEnvVars
 #include "wx/utils.h"
-
-#if wxUSE_DYNLIB_CLASS
-    #include "wx/dynlib.h"
-#endif
+#include "wx/file.h"
+#include "wx/dynlib.h"
 
 // For GetShort/LongPathName
 #ifdef __WIN32__
 
 // For GetShort/LongPathName
 #ifdef __WIN32__
-    #include <windows.h>
+#include <windows.h>
+#include "wx/msw/winundef.h"
+#endif
 
 
-    #include "wx/msw/winundef.h"
+#if defined(__WXMAC__)
+  #include  "wx/mac/private.h"  // includes mac headers
 #endif
 
 // utime() is POSIX so should normally be available on all Unices
 #ifdef __UNIX_LIKE__
 #endif
 
 // utime() is POSIX so should normally be available on all Unices
 #ifdef __UNIX_LIKE__
-    #include <sys/types.h>
-    #include <utime.h>
-    #include <sys/stat.h>
-    #include <unistd.h>
+#include <sys/types.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#ifdef __DJGPP__
+#include <unistd.h>
 #endif
 
 #ifdef __MWERKS__
 #endif
 
 #ifdef __MWERKS__
-    #include <stat.h>
-    #include <unistd.h>
-    #include <unix.h>
+#include <stat.h>
+#include <unistd.h>
+#include <unix.h>
 #endif
 
 #ifdef __WATCOMC__
 #endif
 
 #ifdef __WATCOMC__
-    #include <io.h>
-    #include <sys/utime.h>
-    #include <sys/stat.h>
+#include <io.h>
+#include <sys/utime.h>
+#include <sys/stat.h>
 #endif
 
 #ifdef __VISAGECPP__
 #endif
 
 #ifdef __VISAGECPP__
 #endif
 #endif
 
 #endif
 #endif
 
+#ifdef __EMX__
+#define MAX_PATH _MAX_PATH
+#endif
+
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
 class wxFileHandle
 {
 public:
 class wxFileHandle
 {
 public:
-    wxFileHandle(const wxString& filename)
+    enum OpenMode
+    {
+        Read,
+        Write
+    };
+
+    wxFileHandle(const wxString& filename, OpenMode mode)
     {
         m_hFile = ::CreateFile
                     (
     {
         m_hFile = ::CreateFile
                     (
-                     filename,          // name
-                     GENERIC_READ,      // access mask
-                     0,                 // no sharing
-                     NULL,              // no secutity attr
-                     OPEN_EXISTING,     // creation disposition
-                     0,                 // no flags
-                     NULL               // no template file
+                     filename,                      // name
+                     mode == Read ? GENERIC_READ    // access mask
+                                  : GENERIC_WRITE,
+                     0,                             // no sharing
+                     NULL,                          // no secutity attr
+                     OPEN_EXISTING,                 // creation disposition
+                     0,                             // no flags
+                     NULL                           // no template file
                     );
 
         if ( m_hFile == INVALID_HANDLE_VALUE )
         {
                     );
 
         if ( m_hFile == INVALID_HANDLE_VALUE )
         {
-            wxLogSysError(_("Failed to open '%s' for reading"),
-                          filename.c_str());
+            wxLogSysError(_("Failed to open '%s' for %s"),
+                          filename.c_str(),
+                          mode == Read ? _("reading") : _("writing"));
         }
     }
 
         }
     }
 
@@ -181,36 +199,77 @@ private:
 // convert between wxDateTime and FILETIME which is a 64-bit value representing
 // the number of 100-nanosecond intervals since January 1, 1601.
 
 // convert between wxDateTime and FILETIME which is a 64-bit value representing
 // the number of 100-nanosecond intervals since January 1, 1601.
 
-// the number of milliseconds between the Unix Epoch (January 1, 1970) and the
-// FILETIME reference point (January 1, 1601)
-static const wxLongLong FILETIME_EPOCH_OFFSET = wxLongLong(0xa97, 0x30b66800);
-
 static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
 {
 static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
 {
-    wxLongLong ll(ft.dwHighDateTime, ft.dwLowDateTime);
-
-    // convert 100ns to ms
-    ll /= 10000;
+    FILETIME ftcopy = ft;
+    FILETIME ftLocal;
+    if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) )
+    {
+        wxLogLastError(_T("FileTimeToLocalFileTime"));
+    }
 
 
-    // move it to our Epoch
-    ll -= FILETIME_EPOCH_OFFSET;
+    SYSTEMTIME st;
+    if ( !::FileTimeToSystemTime(&ftLocal, &st) )
+    {
+        wxLogLastError(_T("FileTimeToSystemTime"));
+    }
 
 
-    *dt = wxDateTime(ll);
+    dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear,
+            st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
 }
 
 static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
 {
 }
 
 static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
 {
-    // do the reverse of ConvertFileTimeToWx()
-    wxLongLong ll = dt.GetValue();
-    ll *= 10000;
-    ll += FILETIME_EPOCH_OFFSET;
+    SYSTEMTIME st;
+    st.wDay = dt.GetDay();
+    st.wMonth = dt.GetMonth() + 1;
+    st.wYear = dt.GetYear();
+    st.wHour = dt.GetHour();
+    st.wMinute = dt.GetMinute();
+    st.wSecond = dt.GetSecond();
+    st.wMilliseconds = dt.GetMillisecond();
+
+    FILETIME ftLocal;
+    if ( !::SystemTimeToFileTime(&st, &ftLocal) )
+    {
+        wxLogLastError(_T("SystemTimeToFileTime"));
+    }
 
 
-    ft->dwHighDateTime = ll.GetHi();
-    ft->dwLowDateTime = ll.GetLo();
+    if ( !::LocalFileTimeToFileTime(&ftLocal, ft) )
+    {
+        wxLogLastError(_T("LocalFileTimeToFileTime"));
+    }
 }
 
 #endif // __WIN32__
 
 }
 
 #endif // __WIN32__
 
+// return a string with the volume par
+static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format)
+{
+    wxString path;
+
+    if ( !volume.empty() )
+    {
+        format = wxFileName::GetFormat(format);
+
+        // Special Windows UNC paths hack, part 2: undo what we did in
+        // SplitPath() and make an UNC path if we have a drive which is not a
+        // single letter (hopefully the network shares can't be one letter only
+        // although I didn't find any authoritative docs on this)
+        if ( format == wxPATH_DOS && volume.length() > 1 )
+        {
+            path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume;
+        }
+        else if  ( format == wxPATH_DOS || format == wxPATH_VMS )
+        {
+            path << volume << wxFileName::GetVolumeSeparator(format);
+        }
+        // else ignore
+    }
+
+    return path;
+}
+
 // ============================================================================
 // implementation
 // ============================================================================
 // ============================================================================
 // implementation
 // ============================================================================
@@ -225,6 +284,7 @@ void wxFileName::Assign( const wxFileName &filepath )
     m_dirs = filepath.GetDirs();
     m_name = filepath.GetName();
     m_ext = filepath.GetExt();
     m_dirs = filepath.GetDirs();
     m_name = filepath.GetName();
     m_ext = filepath.GetExt();
+    m_relative = filepath.m_relative;
 }
 
 void wxFileName::Assign(const wxString& volume,
 }
 
 void wxFileName::Assign(const wxString& volume,
@@ -233,23 +293,91 @@ void wxFileName::Assign(const wxString& volume,
                         const wxString& ext,
                         wxPathFormat format )
 {
                         const wxString& ext,
                         wxPathFormat format )
 {
-    wxStringTokenizer tn(path, GetPathSeparators(format));
+    SetPath( path, format );
+
+    m_volume = volume;
+    m_ext = ext;
+    m_name = name;
+}
 
 
+void wxFileName::SetPath( const wxString &path, wxPathFormat format )
+{
     m_dirs.Clear();
     m_dirs.Clear();
-    while ( tn.HasMoreTokens() )
+
+    if ( !path.empty() )
     {
     {
-        wxString token = tn.GetNextToken();
+        wxPathFormat my_format = GetFormat( format );
+        wxString my_path = path;
 
 
-        // if the path starts with a slash, we do need the first empty dir
-        // entry to be able to tell later that it was an absolute path, but
-        // otherwise ignore the double slashes
-        if ( m_dirs.IsEmpty() || !token.IsEmpty() )
-            m_dirs.Add( token );
-    }
+        // 1) Determine if the path is relative or absolute.
+        wxChar leadingChar = my_path[0u];
 
 
-    m_volume = volume;
-    m_ext = ext;
-    m_name = name;
+        switch (my_format)
+        {
+            case wxPATH_MAC:
+                m_relative = leadingChar == wxT(':');
+
+                // We then remove a leading ":". The reason is in our
+                // storage form for relative paths:
+                // ":dir:file.txt" actually means "./dir/file.txt" in
+                // DOS notation and should get stored as
+                // (relative) (dir) (file.txt)
+                // "::dir:file.txt" actually means "../dir/file.txt"
+                // stored as (relative) (..) (dir) (file.txt)
+                // This is important only for the Mac as an empty dir
+                // actually means <UP>, whereas under DOS, double
+                // slashes can be ignored: "\\\\" is the same as "\\".
+                if (m_relative)
+                    my_path.erase( 0, 1 );
+                break;
+
+            case wxPATH_VMS:
+                // TODO: what is the relative path format here?
+                m_relative = FALSE;
+                break;
+
+            case wxPATH_UNIX:
+                // the paths of the form "~" or "~username" are absolute
+                m_relative = leadingChar != wxT('/') && leadingChar != _T('~');
+                break;
+
+            case wxPATH_DOS:
+                m_relative = !IsPathSeparator(leadingChar, my_format);
+                break;
+
+            default:
+                wxFAIL_MSG( wxT("error") );
+                break;
+        }
+
+        // 2) Break up the path into its members. If the original path
+        //    was just "/" or "\\", m_dirs will be empty. We know from
+        //    the m_relative field, if this means "nothing" or "root dir".
+
+        wxStringTokenizer tn( my_path, GetPathSeparators(my_format) );
+
+        while ( tn.HasMoreTokens() )
+        {
+            wxString token = tn.GetNextToken();
+
+            // Remove empty token under DOS and Unix, interpret them
+            // as .. under Mac.
+            if (token.empty())
+            {
+                if (my_format == wxPATH_MAC)
+                    m_dirs.Add( wxT("..") );
+                // else ignore
+            }
+            else
+            {
+               m_dirs.Add( token );
+            }
+        }
+    }
+    else // no path at all
+    {
+        m_relative = TRUE;
+    }
 }
 
 void wxFileName::Assign(const wxString& fullpath,
 }
 
 void wxFileName::Assign(const wxString& fullpath,
@@ -270,13 +398,13 @@ void wxFileName::Assign(const wxString& fullpathOrig,
     wxString fullpath = fullpathOrig;
     if ( !wxEndsWithPathSeparator(fullpath) )
     {
     wxString fullpath = fullpathOrig;
     if ( !wxEndsWithPathSeparator(fullpath) )
     {
-        fullpath += GetPathSeparators(format)[0u];
+        fullpath += GetPathSeparator(format);
     }
 
     wxString volume, path, name, ext;
 
     // do some consistency checks in debug mode: the name should be really just
     }
 
     wxString volume, path, name, ext;
 
     // do some consistency checks in debug mode: the name should be really just
-    // the filename and the path should be realyl just a path
+    // the filename and the path should be really just a path
 #ifdef __WXDEBUG__
     wxString pathDummy, nameDummy, extDummy;
 
 #ifdef __WXDEBUG__
     wxString pathDummy, nameDummy, extDummy;
 
@@ -310,6 +438,9 @@ void wxFileName::Clear()
     m_volume =
     m_name =
     m_ext = wxEmptyString;
     m_volume =
     m_name =
     m_ext = wxEmptyString;
+
+    // we don't have any absolute path for now
+    m_relative = TRUE;
 }
 
 /* static */
 }
 
 /* static */
@@ -403,9 +534,9 @@ wxString wxFileName::GetHomeDir()
     return ::wxGetHomeDir();
 }
 
     return ::wxGetHomeDir();
 }
 
-void wxFileName::AssignTempFileName( const wxString& prefix )
+void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp)
 {
 {
-    wxString tempname = CreateTempFileName(prefix);
+    wxString tempname = CreateTempFileName(prefix, fileTemp);
     if ( tempname.empty() )
     {
         // error, failed to get temp file name
     if ( tempname.empty() )
     {
         // error, failed to get temp file name
@@ -418,7 +549,8 @@ void wxFileName::AssignTempFileName( const wxString& prefix )
 }
 
 /* static */
 }
 
 /* static */
-wxString wxFileName::CreateTempFileName(const wxString& prefix)
+wxString
+wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp)
 {
     wxString path, dir, name;
 
 {
     wxString path, dir, name;
 
@@ -441,6 +573,12 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
             dir = _T('.');
         }
     }
             dir = _T('.');
         }
     }
+    else // we have a dir to create the file in
+    {
+        // ensure we use only the back slashes as GetTempFileName(), unlike all
+        // the other APIs, is picky and doesn't accept the forward ones
+        dir.Replace(_T("/"), _T("\\"));
+    }
 
     if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) )
     {
 
     if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) )
     {
@@ -468,12 +606,15 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
     #ifndef __WATCOMC__
         ::DosCreateDir(wxStringBuffer(path, MAX_PATH), NULL);
     #endif
     #ifndef __WATCOMC__
         ::DosCreateDir(wxStringBuffer(path, MAX_PATH), NULL);
     #endif
-    
+
 #else // !Windows, !OS/2
     if ( dir.empty() )
     {
 #else // !Windows, !OS/2
     if ( dir.empty() )
     {
+#if defined(__WXMAC__) && !defined(__DARWIN__)
+        dir = wxMacFindFolder(  (short) kOnSystemDisk, kTemporaryFolderType, kCreateFolder ) ;
+#else // !Mac
         dir = wxGetenv(_T("TMP"));
         dir = wxGetenv(_T("TMP"));
-        if ( path.empty() )
+        if ( dir.empty() )
         {
             dir = wxGetenv(_T("TEMP"));
         }
         {
             dir = wxGetenv(_T("TEMP"));
         }
@@ -482,11 +623,12 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
         {
             // default
             #ifdef __DOS__
         {
             // default
             #ifdef __DOS__
-            dir = _T(".");
+                dir = _T(".");
             #else
             #else
-            dir = _T("/tmp");
+                dir = _T("/tmp");
             #endif
         }
             #endif
         }
+#endif // Mac/!Mac
     }
 
     path = dir;
     }
 
     path = dir;
@@ -503,25 +645,46 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
     // scratch space for mkstemp()
     path += _T("XXXXXX");
 
     // scratch space for mkstemp()
     path += _T("XXXXXX");
 
-    // can use the cast here because the length doesn't change and the string
-    // is not shared
-    if ( mkstemp((char *)path.mb_str()) == -1 )
+    // we need to copy the path to the buffer in which mkstemp() can modify it
+    wxCharBuffer buf( wxConvFile.cWX2MB( path ) );
+
+    // cast is safe because the string length doesn't change
+    int fdTemp = mkstemp( (char*)(const char*) buf );
+    if ( fdTemp == -1 )
     {
         // this might be not necessary as mkstemp() on most systems should have
         // already done it but it doesn't hurt neither...
         path.clear();
     }
     {
         // this might be not necessary as mkstemp() on most systems should have
         // already done it but it doesn't hurt neither...
         path.clear();
     }
-    //else: file already created
+    else // mkstemp() succeeded
+    {
+        path = wxConvFile.cMB2WX( (const char*) buf );
+        
+        // avoid leaking the fd
+        if ( fileTemp )
+        {
+            fileTemp->Attach(fdTemp);
+        }
+        else
+        {
+            close(fdTemp);
+        }
+    }
 #else // !HAVE_MKSTEMP
 
 #ifdef HAVE_MKTEMP
     // same as above
     path += _T("XXXXXX");
 
 #else // !HAVE_MKSTEMP
 
 #ifdef HAVE_MKTEMP
     // same as above
     path += _T("XXXXXX");
 
-    if ( !mktemp((char *)path.mb_str()) )
+    wxCharBuffer buf = wxConvFile.cWX2MB( path );
+    if ( !mktemp( (const char*) buf ) )
     {
         path.clear();
     }
     {
         path.clear();
     }
+    else
+    {
+        path = wxConvFile.cMB2WX( (const char*) buf );
+    }
 #else // !HAVE_MKTEMP (includes __DOS__)
     // generate the unique file name ourselves
     #ifndef __DOS__
 #else // !HAVE_MKTEMP (includes __DOS__)
     // generate the unique file name ourselves
     #ifndef __DOS__
@@ -548,10 +711,29 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
 
     if ( !path.empty() )
     {
 
     if ( !path.empty() )
     {
-        // create the file - of course, there is a race condition here, this is
+    }
+#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
+
+#endif // Windows/!Windows
+
+    if ( path.empty() )
+    {
+        wxLogSysError(_("Failed to create a temporary file name"));
+    }
+    else if ( fileTemp && !fileTemp->IsOpened() )
+    {
+        // open the file - of course, there is a race condition here, this is
         // why we always prefer using mkstemp()...
         // why we always prefer using mkstemp()...
-        wxFile file;
-        if ( !file.Open(path, wxFile::write_excl, wxS_IRUSR | wxS_IWUSR) )
+        //
+        // NB: GetTempFileName() under Windows creates the file, so using
+        //     write_excl there would fail
+        if ( !fileTemp->Open(path,
+#if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
+                             wxFile::write,
+#else
+                             wxFile::write_excl,
+#endif
+                             wxS_IRUSR | wxS_IWUSR) )
         {
             // FIXME: If !ok here should we loop and try again with another
             //        file name?  That is the standard recourse if open(O_EXCL)
         {
             // FIXME: If !ok here should we loop and try again with another
             //        file name?  That is the standard recourse if open(O_EXCL)
@@ -563,14 +745,6 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
             path.clear();
         }
     }
             path.clear();
         }
     }
-#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
-
-#endif // Windows/!Windows
-
-    if ( path.empty() )
-    {
-        wxLogSysError(_("Failed to create a temporary file name"));
-    }
 
     return path;
 }
 
     return path;
 }
@@ -579,47 +753,48 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
 // directory operations
 // ----------------------------------------------------------------------------
 
 // directory operations
 // ----------------------------------------------------------------------------
 
-bool wxFileName::Mkdir( int perm, bool full )
+bool wxFileName::Mkdir( int perm, int flags )
 {
 {
-    return wxFileName::Mkdir( GetFullPath(), perm, full );
+    return wxFileName::Mkdir( GetFullPath(), perm, flags );
 }
 
 }
 
-bool wxFileName::Mkdir( const wxString &dir, int perm, bool full )
+bool wxFileName::Mkdir( const wxString& dir, int perm, int flags )
 {
 {
-    if (full)
+    if ( flags & wxPATH_MKDIR_FULL )
     {
     {
-        wxFileName filename(dir);
-        wxArrayString dirs = filename.GetDirs();
-        dirs.Add(filename.GetName());
+        // split the path in components
+        wxFileName filename;
+        filename.AssignDir(dir);
 
 
-        size_t count = dirs.GetCount();
-        size_t i;
         wxString currPath;
         wxString currPath;
-        int noErrors = 0;
-        for ( i = 0; i < count; i++ )
+        if ( filename.HasVolume())
         {
         {
-            currPath += dirs[i];
+            currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE);
+        }
 
 
-            if (currPath.Last() == wxT(':'))
-            {
-                // Can't create a root directory so continue to next dir
+        wxArrayString dirs = filename.GetDirs();
+        size_t count = dirs.GetCount();
+        for ( size_t i = 0; i < count; i++ )
+        {
+            if ( i > 0 || filename.IsAbsolute() )
                 currPath += wxFILE_SEP_PATH;
                 currPath += wxFILE_SEP_PATH;
-                continue;
-            }
+            currPath += dirs[i];
 
             if (!DirExists(currPath))
 
             if (!DirExists(currPath))
+            {
                 if (!wxMkdir(currPath, perm))
                 if (!wxMkdir(currPath, perm))
-                    noErrors ++;
-
-            if ( (i < (count-1)) )
-                currPath += wxFILE_SEP_PATH;
+                {
+                    // no need to try creating further directories
+                    return FALSE;
+                }
+            }
         }
 
         }
 
-        return (noErrors == 0);
+        return TRUE;
 
     }
 
     }
-    else
-        return ::wxMkdir( dir, perm );
+
+    return ::wxMkdir( dir, perm );
 }
 
 bool wxFileName::Rmdir()
 }
 
 bool wxFileName::Rmdir()
@@ -636,7 +811,7 @@ bool wxFileName::Rmdir( const wxString &dir )
 // path normalization
 // ----------------------------------------------------------------------------
 
 // path normalization
 // ----------------------------------------------------------------------------
 
-bool wxFileName::Normalize(wxPathNormalize flags,
+bool wxFileName::Normalize(int flags,
                            const wxString& cwd,
                            wxPathFormat format)
 {
                            const wxString& cwd,
                            wxPathFormat format)
 {
@@ -649,7 +824,7 @@ bool wxFileName::Normalize(wxPathNormalize flags,
     format = GetFormat(format);
 
     // make the path absolute
     format = GetFormat(format);
 
     // make the path absolute
-    if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute() )
+    if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) )
     {
         if ( cwd.empty() )
         {
     {
         if ( cwd.empty() )
         {
@@ -667,7 +842,7 @@ bool wxFileName::Normalize(wxPathNormalize flags,
         {
             SetVolume(curDir.GetVolume());
 
         {
             SetVolume(curDir.GetVolume());
 
-            if ( IsAbsolute() )
+            if ( !m_relative )
             {
                 // yes, it was the case - we don't need curDir then
                 curDir.Clear();
             {
                 // yes, it was the case - we don't need curDir then
                 curDir.Clear();
@@ -753,6 +928,11 @@ bool wxFileName::Normalize(wxPathNormalize flags,
         m_ext.MakeLower();
     }
 
         m_ext.MakeLower();
     }
 
+    // we do have the path now
+    //
+    // NB: need to do this before (maybe) calling Assign() below
+    m_relative = FALSE;
+
 #if defined(__WIN32__)
     if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) )
     {
 #if defined(__WIN32__)
     if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) )
     {
@@ -763,14 +943,36 @@ bool wxFileName::Normalize(wxPathNormalize flags,
     return TRUE;
 }
 
     return TRUE;
 }
 
+// ----------------------------------------------------------------------------
+// absolute/relative paths
+// ----------------------------------------------------------------------------
+
+bool wxFileName::IsAbsolute(wxPathFormat format) const
+{
+    // if our path doesn't start with a path separator, it's not an absolute
+    // path
+    if ( m_relative )
+        return FALSE;
+
+    if ( !GetVolumeSeparator(format).empty() )
+    {
+        // this format has volumes and an absolute path must have one, it's not
+        // enough to have the full path to bean absolute file under Windows
+        if ( GetVolume().empty() )
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
 bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
 {
     wxFileName fnBase(pathBase, format);
 
     // get cwd only once - small time saving
     wxString cwd = wxGetCwd();
 bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
 {
     wxFileName fnBase(pathBase, format);
 
     // get cwd only once - small time saving
     wxString cwd = wxGetCwd();
-    Normalize(wxPATH_NORM_ALL, cwd, format);
-    fnBase.Normalize(wxPATH_NORM_ALL, cwd, format);
+    Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
+    fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
 
     bool withCase = IsCaseSensitive(format);
 
 
     bool withCase = IsCaseSensitive(format);
 
@@ -799,6 +1001,19 @@ bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
         m_dirs.Insert(wxT(".."), 0u);
     }
 
         m_dirs.Insert(wxT(".."), 0u);
     }
 
+    if ( format == wxPATH_UNIX || format == wxPATH_DOS )
+    {
+        // a directory made relative with respect to itself is '.' under Unix
+        // and DOS, by definition (but we don't have to insert "./" for the
+        // files)
+        if ( m_dirs.IsEmpty() && IsDir() )
+        {
+            m_dirs.Add(_T('.'));
+        }
+    }
+
+    m_relative = TRUE;
+
     // we were modified
     return TRUE;
 }
     // we were modified
     return TRUE;
 }
@@ -807,15 +1022,15 @@ bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
 // filename kind tests
 // ----------------------------------------------------------------------------
 
 // filename kind tests
 // ----------------------------------------------------------------------------
 
-bool wxFileName::SameAs(const wxFileName &filepath, wxPathFormat format)
+bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const
 {
     wxFileName fn1 = *this,
                fn2 = filepath;
 
     // get cwd only once - small time saving
     wxString cwd = wxGetCwd();
 {
     wxFileName fn1 = *this,
                fn2 = filepath;
 
     // get cwd only once - small time saving
     wxString cwd = wxGetCwd();
-    fn1.Normalize(wxPATH_NORM_ALL, cwd, format);
-    fn2.Normalize(wxPATH_NORM_ALL, cwd, format);
+    fn1.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
+    fn2.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
 
     if ( fn1.GetFullPath() == fn2.GetFullPath() )
         return TRUE;
 
     if ( fn1.GetFullPath() == fn2.GetFullPath() )
         return TRUE;
@@ -833,56 +1048,6 @@ bool wxFileName::IsCaseSensitive( wxPathFormat format )
     return GetFormat(format) == wxPATH_UNIX;
 }
 
     return GetFormat(format) == wxPATH_UNIX;
 }
 
-bool wxFileName::IsAbsolute( wxPathFormat format )
-{
-    // if we have no path, we can't be an abs filename
-    if ( m_dirs.IsEmpty() )
-    {
-        return FALSE;
-    }
-
-    format = GetFormat(format);
-
-    if ( format == wxPATH_UNIX )
-    {
-        const wxString& str = m_dirs[0u];
-        if ( str.empty() )
-        {
-            // the path started with '/', it's an absolute one
-            return TRUE;
-        }
-
-        // the path is absolute if it starts with a path separator or
-        // with "~" or "~user"
-        wxChar ch = str[0u];
-
-        return IsPathSeparator(ch, format) || ch == _T('~');
-    }
-    else // !Unix
-    {
-        // must have the drive
-        if ( m_volume.empty() )
-            return FALSE;
-
-        switch ( format )
-        {
-            default:
-                wxFAIL_MSG( _T("unknown wxPATH_XXX style") );
-                // fall through
-
-            case wxPATH_DOS:
-                return m_dirs[0u].empty();
-
-            case wxPATH_VMS:
-                // TODO: what is the relative path format here?
-                return TRUE;
-
-            case wxPATH_MAC:
-                return !m_dirs[0u].empty();
-        }
-    }
-}
-
 /* static */
 wxString wxFileName::GetVolumeSeparator(wxPathFormat format)
 {
 /* static */
 wxString wxFileName::GetVolumeSeparator(wxPathFormat format)
 {
@@ -940,14 +1105,6 @@ bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
     return GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
 }
 
     return GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
 }
 
-bool wxFileName::IsWild( wxPathFormat format )
-{
-    // FIXME: this is probably false for Mac and this is surely wrong for most
-    //        of Unix shells (think about "[...]")
-    (void)format;
-    return m_name.find_first_of(_T("*?")) != wxString::npos;
-}
-
 // ----------------------------------------------------------------------------
 // path components manipulation
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // path components manipulation
 // ----------------------------------------------------------------------------
@@ -992,88 +1149,119 @@ wxString wxFileName::GetFullName() const
     return fullname;
 }
 
     return fullname;
 }
 
-wxString wxFileName::GetPath( bool add_separator, wxPathFormat format ) const
+wxString wxFileName::GetPath( int flags, wxPathFormat format ) const
 {
     format = GetFormat( format );
 
 {
     format = GetFormat( format );
 
-    wxString ret;
-    size_t count = m_dirs.GetCount();
-    for ( size_t i = 0; i < count; i++ )
+    wxString fullpath;
+
+    // return the volume with the path as well if requested
+    if ( flags & wxPATH_GET_VOLUME )
     {
     {
-        ret += m_dirs[i];
-        if ( add_separator || (i < count) )
-            ret += wxFILE_SEP_PATH;
+        fullpath += wxGetVolumeString(GetVolume(), format);
     }
 
     }
 
-    return ret;
-}
+    // the leading character
+    switch ( format )
+    {
+        case wxPATH_MAC:
+            if ( m_relative )
+                fullpath += wxFILE_SEP_PATH_MAC;
+            break;
 
 
-wxString wxFileName::GetFullPath( wxPathFormat format ) const
-{
-    format = GetFormat(format);
+        case wxPATH_DOS:
+            if (!m_relative)
+                fullpath += wxFILE_SEP_PATH_DOS;
+            break;
 
 
-    wxString fullpath;
+        default:
+            wxFAIL_MSG( _T("unknown path format") );
+            // fall through
 
 
-    // first put the volume
-    if ( !m_volume.empty() )
-    {
-       {
-               // Special Windows UNC paths hack, part 2: undo what we did in
-               // SplitPath() and make an UNC path if we have a drive which is not a
-               // single letter (hopefully the network shares can't be one letter only
-               // although I didn't find any authoritative docs on this)
-               if ( format == wxPATH_DOS && m_volume.length() > 1 )
-               {
-               fullpath << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << m_volume;
-               }
-               else // !UNC
-               {
-               fullpath << m_volume << GetVolumeSeparator(format);
+        case wxPATH_UNIX:
+            if ( !m_relative )
+            {
+                // normally the absolute file names starts with a slash with
+                // one exception: file names like "~/foo.bar" don't have it
+                if ( m_dirs.IsEmpty() || m_dirs[0u] != _T('~') )
+                {
+                    fullpath += wxFILE_SEP_PATH_UNIX;
+                }
             }
             }
-        }
+            break;
+
+        case wxPATH_VMS:
+            // no leading character here but use this place to unset
+            // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense as,
+            // if I understand correctly, there should never be a dot before
+            // the closing bracket
+            flags &= ~wxPATH_GET_SEPARATOR;
     }
 
     // then concatenate all the path components using the path separator
     size_t dirCount = m_dirs.GetCount();
     if ( dirCount )
     {
     }
 
     // then concatenate all the path components using the path separator
     size_t dirCount = m_dirs.GetCount();
     if ( dirCount )
     {
-        // under Mac, we must have a path separator in the beginning of the
-        // relative path - otherwise it would be parsed as an absolute one
-        if ( format == wxPATH_MAC && m_dirs[0].empty() )
-        {
-            fullpath += wxFILE_SEP_PATH_MAC;
-        }
-
-        wxChar chPathSep = GetPathSeparators(format)[0u];
         if ( format == wxPATH_VMS )
         {
         if ( format == wxPATH_VMS )
         {
-            fullpath += _T('[');
+            fullpath += wxT('[');
         }
 
         for ( size_t i = 0; i < dirCount; i++ )
         {
         }
 
         for ( size_t i = 0; i < dirCount; i++ )
         {
-            // under VMS, we shouldn't have a leading dot
-            if ( i && (format != wxPATH_VMS || !m_dirs[i - 1].empty()) )
-                fullpath += chPathSep;
+            switch (format)
+            {
+                case wxPATH_MAC:
+                    if ( m_dirs[i] == wxT(".") )
+                    {
+                        // skip appending ':', this shouldn't be done in this
+                        // case as "::" is interpreted as ".." under Unix
+                        continue;
+                    }
+
+                    // convert back from ".." to nothing
+                    if ( m_dirs[i] != wxT("..") )
+                         fullpath += m_dirs[i];
+                    break;
+
+                default:
+                    wxFAIL_MSG( wxT("unexpected path format") );
+                    // still fall through
+
+                case wxPATH_DOS:
+                case wxPATH_UNIX:
+                    fullpath += m_dirs[i];
+                    break;
+
+                case wxPATH_VMS:
+                    // TODO: What to do with ".." under VMS
 
 
-            fullpath += m_dirs[i];
+                    // convert back from ".." to nothing
+                    if ( m_dirs[i] != wxT("..") )
+                        fullpath += m_dirs[i];
+                    break;
+            }
+
+            if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) )
+                fullpath += GetPathSeparator(format);
         }
 
         if ( format == wxPATH_VMS )
         {
         }
 
         if ( format == wxPATH_VMS )
         {
-            fullpath += _T(']');
-        }
-        else // !VMS
-        {
-            // separate the file name from the last directory, notice that we
-            // intentionally do it even if the name and extension are empty as
-            // this allows us to distinguish the directories from the file
-            // names (the directories have the trailing slash)
-            fullpath += chPathSep;
+            fullpath += wxT(']');
         }
     }
 
         }
     }
 
-    // finally add the file name and extension
+    return fullpath;
+}
+
+wxString wxFileName::GetFullPath( wxPathFormat format ) const
+{
+    // we already have a function to get the path
+    wxString fullpath = GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR,
+                                format);
+
+    // now just add the file name and extension to it
     fullpath += GetFullName();
 
     return fullpath;
     fullpath += GetFullName();
 
     return fullpath;
@@ -1115,28 +1303,28 @@ wxString wxFileName::GetLongPath() const
 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
     bool success = FALSE;
 
 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
     bool success = FALSE;
 
-    // VZ: this code was disabled, why?
-#if 0 // wxUSE_DYNLIB_CLASS
-    typedef DWORD (*GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD);
+#if wxUSE_DYNAMIC_LOADER
+    typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD);
 
     static bool s_triedToLoad = FALSE;
 
     if ( !s_triedToLoad )
     {
 
     static bool s_triedToLoad = FALSE;
 
     if ( !s_triedToLoad )
     {
+        // suppress the errors about missing GetLongPathName[AW]
+        wxLogNull noLog;
+
         s_triedToLoad = TRUE;
         s_triedToLoad = TRUE;
-        wxDllType dllKernel = wxDllLoader::LoadLibrary(_T("kernel32"));
-        if ( dllKernel )
+        wxDynamicLibrary dllKernel(_T("kernel32"));
+        if ( dllKernel.IsLoaded() )
         {
             // may succeed or fail depending on the Windows version
             static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL;
 #ifdef _UNICODE
         {
             // may succeed or fail depending on the Windows version
             static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL;
 #ifdef _UNICODE
-            s_pfnGetLongPathName = (GET_LONG_PATH_NAME) wxDllLoader::GetSymbol(dllKernel, _T("GetLongPathNameW"));
+            s_pfnGetLongPathName = (GET_LONG_PATH_NAME) dllKernel.GetSymbol(_T("GetLongPathNameW"));
 #else
 #else
-            s_pfnGetLongPathName = (GET_LONG_PATH_NAME) wxDllLoader::GetSymbol(dllKernel, _T("GetLongPathNameA"));
+            s_pfnGetLongPathName = (GET_LONG_PATH_NAME) dllKernel.GetSymbol(_T("GetLongPathNameA"));
 #endif
 
 #endif
 
-            wxDllLoader::UnloadLibrary(dllKernel);
-
             if ( s_pfnGetLongPathName )
             {
                 DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0);
             if ( s_pfnGetLongPathName )
             {
                 DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0);
@@ -1162,9 +1350,10 @@ wxString wxFileName::GetLongPath() const
             }
         }
     }
             }
         }
     }
+
     if (success)
         return pathOut;
     if (success)
         return pathOut;
-#endif // wxUSE_DYNLIB_CLASS
+#endif // wxUSE_DYNAMIC_LOADER
 
     if (!success)
     {
 
     if (!success)
     {
@@ -1173,7 +1362,13 @@ wxString wxFileName::GetLongPath() const
 
         WIN32_FIND_DATA findFileData;
         HANDLE hFind;
 
         WIN32_FIND_DATA findFileData;
         HANDLE hFind;
-        pathOut = wxEmptyString;
+
+        if ( HasVolume() )
+            pathOut = GetVolume() +
+                      GetVolumeSeparator(wxPATH_DOS) +
+                      GetPathSeparator(wxPATH_DOS);
+        else
+            pathOut = wxEmptyString;
 
         wxArrayString dirs = GetDirs();
         dirs.Add(GetFullName());
 
         wxArrayString dirs = GetDirs();
         dirs.Add(GetFullName());
@@ -1191,7 +1386,8 @@ wxString wxFileName::GetLongPath() const
             if ( tmpPath.empty() )
                 continue;
 
             if ( tmpPath.empty() )
                 continue;
 
-            if ( tmpPath.Last() == wxT(':') )
+            // can't see this being necessary? MF
+            if ( tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) )
             {
                 // Can't pass a drive and root dir to FindFirstFile,
                 // so continue to next dir
             {
                 // Can't pass a drive and root dir to FindFirstFile,
                 // so continue to next dir
@@ -1203,8 +1399,12 @@ wxString wxFileName::GetLongPath() const
             hFind = ::FindFirstFile(tmpPath, &findFileData);
             if (hFind == INVALID_HANDLE_VALUE)
             {
             hFind = ::FindFirstFile(tmpPath, &findFileData);
             if (hFind == INVALID_HANDLE_VALUE)
             {
-                // Error: return immediately with the original path
-                return path;
+                // Error: most likely reason is that path doesn't exist, so
+                // append any unprocessed parts and return
+                for ( i += 1; i < count; i++ )
+                    tmpPath += wxFILE_SEP_PATH + dirs[i];
+
+                return tmpPath;
             }
 
             pathOut += findFileData.cFileName;
             }
 
             pathOut += findFileData.cFileName;
@@ -1334,10 +1534,13 @@ void wxFileName::SplitPath(const wxString& fullpathWithVolume,
         else
         {
             // take everything up to the path separator but take care to make
         else
         {
             // take everything up to the path separator but take care to make
-            // tha path equal to something like '/', not empty, for the files
+            // the path equal to something like '/', not empty, for the files
             // immediately under root directory
             size_t len = posLastSlash;
             // immediately under root directory
             size_t len = posLastSlash;
-            if ( !len )
+
+            // this rule does not apply to mac since we do not start with colons (sep)
+            // except for relative paths
+            if ( !len && format != wxPATH_MAC)
                 len++;
 
             *pstrPath = fullpath.Left(len);
                 len++;
 
             *pstrPath = fullpath.Left(len);
@@ -1399,9 +1602,9 @@ void wxFileName::SplitPath(const wxString& fullpath,
     wxString volume;
     SplitPath(fullpath, &volume, path, name, ext, format);
 
     wxString volume;
     SplitPath(fullpath, &volume, path, name, ext, format);
 
-    if ( path && !volume.empty() )
+    if ( path )
     {
     {
-        path->Prepend(volume + GetVolumeSeparator(format));
+        path->Prepend(wxGetVolumeString(volume, format));
     }
 }
 
     }
 }
 
@@ -1409,11 +1612,40 @@ void wxFileName::SplitPath(const wxString& fullpath,
 // time functions
 // ----------------------------------------------------------------------------
 
 // time functions
 // ----------------------------------------------------------------------------
 
-bool wxFileName::SetTimes(const wxDateTime *dtCreate,
-                          const wxDateTime *dtAccess,
-                          const wxDateTime *dtMod)
+bool wxFileName::SetTimes(const wxDateTime *dtAccess,
+                          const wxDateTime *dtMod,
+                          const wxDateTime *dtCreate)
 {
 {
-#if defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__))
+#if defined(__WIN32__)
+    if ( IsDir() )
+    {
+        // VZ: please let me know how to do this if you can
+        wxFAIL_MSG( _T("SetTimes() not implemented for the directories") );
+    }
+    else // file
+    {
+        wxFileHandle fh(GetFullPath(), wxFileHandle::Write);
+        if ( fh.IsOk() )
+        {
+            FILETIME ftAccess, ftCreate, ftWrite;
+
+            if ( dtCreate )
+                ConvertWxToFileTime(&ftCreate, *dtCreate);
+            if ( dtAccess )
+                ConvertWxToFileTime(&ftAccess, *dtAccess);
+            if ( dtMod )
+                ConvertWxToFileTime(&ftWrite, *dtMod);
+
+            if ( ::SetFileTime(fh,
+                               dtCreate ? &ftCreate : NULL,
+                               dtAccess ? &ftAccess : NULL,
+                               dtMod ? &ftWrite : NULL) )
+            {
+                return TRUE;
+            }
+        }
+    }
+#elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__))
     if ( !dtAccess && !dtMod )
     {
         // can't modify the creation time anyhow, don't try
     if ( !dtAccess && !dtMod )
     {
         // can't modify the creation time anyhow, don't try
@@ -1425,31 +1657,10 @@ bool wxFileName::SetTimes(const wxDateTime *dtCreate,
     utimbuf utm;
     utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks();
     utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks();
     utimbuf utm;
     utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks();
     utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks();
-    if ( utime(GetFullPath(), &utm) == 0 )
+    if ( utime(GetFullPath().fn_str(), &utm) == 0 )
     {
         return TRUE;
     }
     {
         return TRUE;
     }
-#elif defined(__WIN32__)
-    wxFileHandle fh(GetFullPath());
-    if ( fh.IsOk() )
-    {
-        FILETIME ftAccess, ftCreate, ftWrite;
-
-        if ( dtCreate )
-            ConvertWxToFileTime(&ftCreate, *dtCreate);
-        if ( dtAccess )
-            ConvertWxToFileTime(&ftAccess, *dtAccess);
-        if ( dtMod )
-            ConvertWxToFileTime(&ftWrite, *dtMod);
-
-        if ( ::SetFileTime(fh,
-                           dtCreate ? &ftCreate : NULL,
-                           dtAccess ? &ftAccess : NULL,
-                           dtMod ? &ftWrite : NULL) )
-        {
-            return TRUE;
-        }
-    }
 #else // other platform
 #endif // platforms
 
 #else // other platform
 #endif // platforms
 
@@ -1463,7 +1674,7 @@ bool wxFileName::Touch()
 {
 #if defined(__UNIX_LIKE__)
     // under Unix touching file is simple: just pass NULL to utime()
 {
 #if defined(__UNIX_LIKE__)
     // under Unix touching file is simple: just pass NULL to utime()
-    if ( utime(GetFullPath(), NULL) == 0 )
+    if ( utime(GetFullPath().fn_str(), NULL) == 0 )
     {
         return TRUE;
     }
     {
         return TRUE;
     }
@@ -1474,47 +1685,71 @@ bool wxFileName::Touch()
 #else // other platform
     wxDateTime dtNow = wxDateTime::Now();
 
 #else // other platform
     wxDateTime dtNow = wxDateTime::Now();
 
-    return SetTimes(NULL /* don't change create time */, &dtNow, &dtNow);
+    return SetTimes(&dtNow, &dtNow, NULL /* don't change create time */);
 #endif // platforms
 }
 
 bool wxFileName::GetTimes(wxDateTime *dtAccess,
                           wxDateTime *dtMod,
 #endif // platforms
 }
 
 bool wxFileName::GetTimes(wxDateTime *dtAccess,
                           wxDateTime *dtMod,
-                          wxDateTime *dtChange) const
+                          wxDateTime *dtCreate) const
 {
 {
-#if defined(__UNIX_LIKE__) || defined(__WXMAC__) || (defined(__DOS__) && defined(__WATCOMC__))
-    wxStructStat stBuf;
-    if ( wxStat(GetFullPath(), &stBuf) == 0 )
+#if defined(__WIN32__)
+    // we must use different methods for the files and directories under
+    // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and
+    // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and
+    // not 9x
+    bool ok;
+    FILETIME ftAccess, ftCreate, ftWrite;
+    if ( IsDir() )
+    {
+        // implemented in msw/dir.cpp
+        extern bool wxGetDirectoryTimes(const wxString& dirname,
+                                        FILETIME *, FILETIME *, FILETIME *);
+
+        // we should pass the path without the trailing separator to
+        // wxGetDirectoryTimes()
+        ok = wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME),
+                                 &ftAccess, &ftCreate, &ftWrite);
+    }
+    else // file
     {
     {
+        wxFileHandle fh(GetFullPath(), wxFileHandle::Read);
+        if ( fh.IsOk() )
+        {
+            ok = ::GetFileTime(fh,
+                               dtCreate ? &ftCreate : NULL,
+                               dtAccess ? &ftAccess : NULL,
+                               dtMod ? &ftWrite : NULL) != 0;
+        }
+        else
+        {
+            ok = FALSE;
+        }
+    }
+
+    if ( ok )
+    {
+        if ( dtCreate )
+            ConvertFileTimeToWx(dtCreate, ftCreate);
         if ( dtAccess )
         if ( dtAccess )
-            dtAccess->Set(stBuf.st_atime);
+            ConvertFileTimeToWx(dtAccess, ftAccess);
         if ( dtMod )
         if ( dtMod )
-            dtMod->Set(stBuf.st_mtime);
-        if ( dtChange )
-            dtChange->Set(stBuf.st_ctime);
+            ConvertFileTimeToWx(dtMod, ftWrite);
 
         return TRUE;
     }
 
         return TRUE;
     }
-#elif defined(__WIN32__)
-    wxFileHandle fh(GetFullPath());
-    if ( fh.IsOk() )
+#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || (defined(__DOS__) && defined(__WATCOMC__))
+    wxStructStat stBuf;
+    if ( wxStat( GetFullPath().c_str(), &stBuf) == 0 )
     {
     {
-        FILETIME ftAccess, ftCreate, ftWrite;
-
-        if ( ::GetFileTime(fh,
-                           dtMod ? &ftCreate : NULL,
-                           dtAccess ? &ftAccess : NULL,
-                           dtChange ? &ftWrite : NULL) )
-        {
-            if ( dtMod )
-                ConvertFileTimeToWx(dtMod, ftCreate);
-            if ( dtAccess )
-                ConvertFileTimeToWx(dtAccess, ftAccess);
-            if ( dtChange )
-                ConvertFileTimeToWx(dtChange, ftWrite);
+        if ( dtAccess )
+            dtAccess->Set(stBuf.st_atime);
+        if ( dtMod )
+            dtMod->Set(stBuf.st_mtime);
+        if ( dtCreate )
+            dtCreate->Set(stBuf.st_ctime);
 
 
-            return TRUE;
-        }
+        return TRUE;
     }
 #else // other platform
 #endif // platforms
     }
 #else // other platform
 #endif // platforms
@@ -1525,3 +1760,127 @@ bool wxFileName::GetTimes(wxDateTime *dtAccess,
     return FALSE;
 }
 
     return FALSE;
 }
 
+#ifdef __WXMAC__
+
+const short kMacExtensionMaxLength = 16 ;
+class MacDefaultExtensionRecord
+{
+public :
+  MacDefaultExtensionRecord()
+  {
+    m_ext[0] = 0 ;
+    m_type = m_creator = NULL ;
+  }
+  MacDefaultExtensionRecord( const MacDefaultExtensionRecord& from )
+  {
+    strcpy( m_ext , from.m_ext ) ;
+    m_type = from.m_type ;
+    m_creator = from.m_creator ;
+  }
+  MacDefaultExtensionRecord( const char * extension , OSType type , OSType creator )
+  {
+    strncpy( m_ext , extension , kMacExtensionMaxLength ) ;
+    m_ext[kMacExtensionMaxLength] = 0 ;
+    m_type = type ;
+    m_creator = creator ;
+  }
+  char m_ext[kMacExtensionMaxLength] ;
+  OSType m_type ;
+  OSType m_creator ;
+}  ;
+
+#include "wx/dynarray.h"
+WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray) ;
+
+bool gMacDefaultExtensionsInited = false ;
+
+#include "wx/arrimpl.cpp"
+
+WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray) ;
+
+MacDefaultExtensionArray gMacDefaultExtensions ;
+
+static void MacEnsureDefaultExtensionsLoaded()
+{
+  if ( !gMacDefaultExtensionsInited )
+  {
+
+    // load the default extensions
+    MacDefaultExtensionRecord defaults[1] =
+    {
+      MacDefaultExtensionRecord( "txt" , 'TEXT' , 'ttxt' ) ,
+
+    } ;
+    // we could load the pc exchange prefs here too
+
+    for ( size_t i = 0 ; i < WXSIZEOF( defaults ) ; ++i )
+    {
+      gMacDefaultExtensions.Add( defaults[i] ) ;
+    }
+    gMacDefaultExtensionsInited = true ;
+  }
+}
+bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator )
+{
+  FInfo fndrInfo ;
+  FSSpec spec ;
+  wxMacFilename2FSSpec(GetFullPath(),&spec) ;
+  OSErr err = FSpGetFInfo( &spec , &fndrInfo ) ;
+  wxCHECK( err == noErr , false ) ;
+
+  fndrInfo.fdType = type ;
+  fndrInfo.fdCreator = creator ;
+  FSpSetFInfo( &spec , &fndrInfo ) ;
+  return true ;
+}
+
+bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator )
+{
+  FInfo fndrInfo ;
+  FSSpec spec ;
+  wxMacFilename2FSSpec(GetFullPath(),&spec) ;
+  OSErr err = FSpGetFInfo( &spec , &fndrInfo ) ;
+  wxCHECK( err == noErr , false ) ;
+
+  *type = fndrInfo.fdType ;
+  *creator = fndrInfo.fdCreator ;
+  return true ;
+}
+
+bool wxFileName::MacSetDefaultTypeAndCreator()
+{
+    wxUint32 type , creator ;
+    if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type ,
+      &creator ) )
+    {
+        return MacSetTypeAndCreator( type , creator ) ;
+    }
+    return false;
+}
+
+bool wxFileName::MacFindDefaultTypeAndCreator( const wxString& ext , wxUint32 *type , wxUint32 *creator )
+{
+  MacEnsureDefaultExtensionsLoaded() ;
+  wxString extl = ext.Lower() ;
+  for( int i = gMacDefaultExtensions.Count() - 1 ; i >= 0 ; --i )
+  {
+    if ( gMacDefaultExtensions.Item(i).m_ext == extl )
+    {
+      *type = gMacDefaultExtensions.Item(i).m_type ;
+      *creator = gMacDefaultExtensions.Item(i).m_creator ;
+      return true ;
+    }
+  }
+  return false ;
+}
+
+void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator )
+{
+  MacEnsureDefaultExtensionsLoaded() ;
+  MacDefaultExtensionRecord rec ;
+  rec.m_type = type ;
+  rec.m_creator = creator ;
+  strncpy( rec.m_ext , ext.Lower().c_str() , kMacExtensionMaxLength ) ;
+  gMacDefaultExtensions.Add( rec ) ;
+}
+#endif