]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/filename.cpp
minor cleanup of Unix GetInfo(): assert if invalid parameters are passed; don't use...
[wxWidgets.git] / src / common / filename.cpp
index ad01fde9184fd1faa239ff5c603a8767f3bd0cb1..f16ae7127bf9ab7af950bd6d2e656d52b2bb1371 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     28.12.2000
 // RCS-ID:      $Id$
 // Copyright:   (c) 2000 Robert Roebling
 // Created:     28.12.2000
 // RCS-ID:      $Id$
 // Copyright:   (c) 2000 Robert Roebling
-// Licence:     wxWindows license
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 /*
 /////////////////////////////////////////////////////////////////////////////
 
 /*
@@ -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
@@ -47,7 +47,7 @@
                 Note that VMS uses different separators unlike Unix:
                  : always after the device. If the path does not contain : than
                    the default (the device of the current directory) is assumed.
                 Note that VMS uses different separators unlike Unix:
                  : always after the device. If the path does not contain : than
                    the default (the device of the current directory) is assumed.
-                 [ start of directory specyfication
+                 [ start of directory specification
                  . separator between directory and subdirectory
                  ] between directory and file
  */
                  . separator between directory and subdirectory
                  ] between directory and file
  */
 // headers
 // ----------------------------------------------------------------------------
 
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __GNUG__
-    #pragma implementation "filename.h"
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
 // 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
+    #ifdef __WXMSW__
+        #include "wx/msw/wrapwin.h" // For GetShort/LongPathName
+    #endif
+    #include "wx/dynarray.h"
     #include "wx/intl.h"
     #include "wx/log.h"
     #include "wx/intl.h"
     #include "wx/log.h"
+    #include "wx/utils.h"
+    #include "wx/crt.h"
 #endif
 
 #include "wx/filename.h"
 #endif
 
 #include "wx/filename.h"
+#include "wx/private/filename.h"
 #include "wx/tokenzr.h"
 #include "wx/config.h"          // for wxExpandEnvVars
 #include "wx/tokenzr.h"
 #include "wx/config.h"          // for wxExpandEnvVars
-#include "wx/utils.h"
+#include "wx/dynlib.h"
+#include "wx/dir.h"
 
 
-#if wxUSE_DYNLIB_CLASS
-    #include "wx/dynlib.h"
+#if defined(__WIN32__) && defined(__MINGW32__)
+    #include "wx/msw/gccpriv.h"
 #endif
 
 #endif
 
-// For GetShort/LongPathName
-#ifdef __WIN32__
-    #include <windows.h>
+#ifdef __WXWINCE__
+#include "wx/msw/private.h"
+#endif
 
 
-    #include "wx/msw/winundef.h"
+#if defined(__WXMAC__)
+  #include  "wx/osx/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>
+#ifdef __MACH__
+#include <sys/types.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#else
+#include <stat.h>
+#include <unistd.h>
+#include <unix.h>
+#endif
+#endif
+
+#ifdef __WATCOMC__
+#include <io.h>
+#include <sys/utime.h>
+#include <sys/stat.h>
+#endif
+
+#ifdef __VISAGECPP__
+#ifndef MAX_PATH
+#define MAX_PATH 256
+#endif
+#endif
+
+#ifdef __EMX__
+#include <os2.h>
+#define MAX_PATH _MAX_PATH
 #endif
 
 #endif
 
+
+#if wxUSE_LONGLONG
+extern const wxULongLong wxInvalidSize = (unsigned)-1;
+#endif // wxUSE_LONGLONG
+
+
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
 class wxFileHandle
 {
 public:
 class wxFileHandle
 {
 public:
-    wxFileHandle(const wxString& filename)
+    enum OpenMode
+    {
+        Read,
+        Write
+    };
+
+    wxFileHandle(const wxString& filename, OpenMode mode, int flags = 0)
     {
         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.fn_str(),             // name
+                     mode == Read ? GENERIC_READ    // access mask
+                                  : GENERIC_WRITE,
+                     FILE_SHARE_READ |              // sharing mode
+                     FILE_SHARE_WRITE,              // (allow everything)
+                     NULL,                          // no secutity attr
+                     OPEN_EXISTING,                 // creation disposition
+                     flags,                         // 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());
+            if ( mode == Read )
+                wxLogSysError(_("Failed to open '%s' for reading"),
+                              filename.c_str());
+            else
+                wxLogSysError(_("Failed to open '%s' for writing"),
+                              filename.c_str());
         }
     }
 
         }
     }
 
@@ -148,7 +199,7 @@ public:
         }
     }
 
         }
     }
 
-    // return TRUE only if the file could be opened successfully
+    // return true only if the file could be opened successfully
     bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; }
 
     // get the handle
     bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; }
 
     // get the handle
@@ -164,40 +215,92 @@ private:
 // private functions
 // ----------------------------------------------------------------------------
 
 // private functions
 // ----------------------------------------------------------------------------
 
-#if defined(__WIN32__) && !defined(__WXMICROWIN__)
+#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)
 
 // 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 = (WORD)(dt.GetMonth() + 1);
+    st.wYear = (WORD)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"));
+    }
+
+    if ( !::LocalFileTimeToFileTime(&ftLocal, ft) )
+    {
+        wxLogLastError(_T("LocalFileTimeToFileTime"));
+    }
+}
+
+#endif // wxUSE_DATETIME && __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);
 
 
-    ft->dwHighDateTime = ll.GetHi();
-    ft->dwLowDateTime = ll.GetLo();
+        // 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;
 }
 
 }
 
-#endif // __WIN32__
+// return true if the format used is the DOS/Windows one and the string looks
+// like a UNC path
+static bool IsUNCPath(const wxString& path, wxPathFormat format)
+{
+    return format == wxPATH_DOS &&
+                path.length() >= 4 && // "\\a" can't be a UNC path
+                    path[0u] == wxFILE_SEP_PATH_DOS &&
+                        path[1u] == wxFILE_SEP_PATH_DOS &&
+                            path[2u] != wxFILE_SEP_PATH_DOS;
+}
 
 // ============================================================================
 // implementation
 
 // ============================================================================
 // implementation
@@ -213,40 +316,145 @@ 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;
+    m_hasExt = filepath.m_hasExt;
 }
 
 void wxFileName::Assign(const wxString& volume,
                         const wxString& path,
                         const wxString& name,
                         const wxString& ext,
 }
 
 void wxFileName::Assign(const wxString& volume,
                         const wxString& path,
                         const wxString& name,
                         const wxString& ext,
-                        wxPathFormat format )
+                        bool hasExt,
+                        wxPathFormat format)
 {
 {
-    wxStringTokenizer tn(path, GetPathSeparators(format));
+    // we should ignore paths which look like UNC shares because we already
+    // have the volume here and the UNC notation (\\server\path) is only valid
+    // for paths which don't start with a volume, so prevent SetPath() from
+    // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path
+    //
+    // note also that this is a rather ugly way to do what we want (passing
+    // some kind of flag telling to ignore UNC paths to SetPath() would be
+    // better) but this is the safest thing to do to avoid breaking backwards
+    // compatibility in 2.8
+    if ( IsUNCPath(path, format) )
+    {
+        // remove one of the 2 leading backslashes to ensure that it's not
+        // recognized as an UNC path by SetPath()
+        wxString pathNonUNC(path, 1, wxString::npos);
+        SetPath(pathNonUNC, format);
+    }
+    else // no UNC complications
+    {
+        SetPath(path, format);
+    }
 
 
+    m_volume = volume;
+    m_ext = ext;
+    m_name = name;
+
+    m_hasExt = hasExt;
+}
+
+void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format )
+{
     m_dirs.Clear();
     m_dirs.Clear();
+
+    if ( pathOrig.empty() )
+    {
+        // no path at all
+        m_relative = true;
+
+        return;
+    }
+
+    format = GetFormat( format );
+
+    // 0) deal with possible volume part first
+    wxString volume,
+             path;
+    SplitVolume(pathOrig, &volume, &path, format);
+    if ( !volume.empty() )
+    {
+        m_relative = false;
+
+        SetVolume(volume);
+    }
+
+    // 1) Determine if the path is relative or absolute.
+    wxChar leadingChar = path[0u];
+
+    switch (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)
+                path.erase( 0, 1 );
+            break;
+
+        case wxPATH_VMS:
+            // TODO: what is the relative path format here?
+            m_relative = false;
+            break;
+
+        default:
+            wxFAIL_MSG( _T("Unknown path format") );
+            // !! Fall through !!
+
+        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, format);
+            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( path, GetPathSeparators(format) );
+
     while ( tn.HasMoreTokens() )
     {
         wxString token = tn.GetNextToken();
 
     while ( tn.HasMoreTokens() )
     {
         wxString token = tn.GetNextToken();
 
-        // 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 );
+        // Remove empty token under DOS and Unix, interpret them
+        // as .. under Mac.
+        if (token.empty())
+        {
+            if (format == wxPATH_MAC)
+                m_dirs.Add( wxT("..") );
+            // else ignore
+        }
+        else
+        {
+           m_dirs.Add( token );
+        }
     }
     }
-
-    m_volume = volume;
-    m_ext = ext;
-    m_name = name;
 }
 
 void wxFileName::Assign(const wxString& fullpath,
                         wxPathFormat format)
 {
     wxString volume, path, name, ext;
 }
 
 void wxFileName::Assign(const wxString& fullpath,
                         wxPathFormat format)
 {
     wxString volume, path, name, ext;
-    SplitPath(fullpath, &volume, &path, &name, &ext, format);
+    bool hasExt;
+    SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format);
 
 
-    Assign(volume, path, name, ext, format);
+    Assign(volume, path, name, ext, hasExt, format);
 }
 
 void wxFileName::Assign(const wxString& fullpathOrig,
 }
 
 void wxFileName::Assign(const wxString& fullpathOrig,
@@ -256,21 +464,21 @@ void wxFileName::Assign(const wxString& fullpathOrig,
     // always recognize fullpath as directory, even if it doesn't end with a
     // slash
     wxString fullpath = fullpathOrig;
     // always recognize fullpath as directory, even if it doesn't end with a
     // slash
     wxString fullpath = fullpathOrig;
-    if ( !wxEndsWithPathSeparator(fullpath) )
+    if ( !fullpath.empty() && !wxEndsWithPathSeparator(fullpath) )
     {
     {
-        fullpath += GetPathSeparators(format)[0u];
+        fullpath += GetPathSeparator(format);
     }
 
     wxString volume, path, name, ext;
     }
 
     wxString volume, path, name, ext;
+    bool hasExt;
 
 
-    // do some consistency checks in debug mode: the name should be really just
-    // the filename and the path should be realyl just a path
-#ifdef __WXDEBUG__
-    wxString pathDummy, nameDummy, extDummy;
+    // do some consistency checks: the name should be really just the filename
+    // and the path should be really just a path
+    wxString volDummy, pathDummy, nameDummy, extDummy;
 
 
-    SplitPath(fullname, &pathDummy, &name, &ext, format);
+    SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format);
 
 
-    wxASSERT_MSG( pathDummy.empty(),
+    wxASSERT_MSG( volDummy.empty() && pathDummy.empty(),
                   _T("the file name shouldn't contain the path") );
 
     SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format);
                   _T("the file name shouldn't contain the path") );
 
     SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format);
@@ -278,17 +486,24 @@ void wxFileName::Assign(const wxString& fullpathOrig,
     wxASSERT_MSG( nameDummy.empty() && extDummy.empty(),
                   _T("the path shouldn't contain file name nor extension") );
 
     wxASSERT_MSG( nameDummy.empty() && extDummy.empty(),
                   _T("the path shouldn't contain file name nor extension") );
 
-#else // !__WXDEBUG__
-    SplitPath(fullname, NULL /* no path */, &name, &ext, format);
-    SplitPath(fullpath, &volume, &path, NULL, NULL, format);
-#endif // __WXDEBUG__/!__WXDEBUG__
+    Assign(volume, path, name, ext, hasExt, format);
+}
+
+void wxFileName::Assign(const wxString& pathOrig,
+                        const wxString& name,
+                        const wxString& ext,
+                        wxPathFormat format)
+{
+    wxString volume,
+             path;
+    SplitVolume(pathOrig, &volume, &path, format);
 
     Assign(volume, path, name, ext, format);
 }
 
 void wxFileName::AssignDir(const wxString& dir, wxPathFormat format)
 {
 
     Assign(volume, path, name, ext, format);
 }
 
 void wxFileName::AssignDir(const wxString& dir, wxPathFormat format)
 {
-    Assign(dir, _T(""), format);
+    Assign(dir, wxEmptyString, format);
 }
 
 void wxFileName::Clear()
 }
 
 void wxFileName::Clear()
@@ -298,19 +513,25 @@ 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;
+
+    // nor any extension
+    m_hasExt = false;
 }
 
 /* static */
 }
 
 /* static */
-wxFileName wxFileName::FileName(const wxString& file)
+wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format)
 {
 {
-    return wxFileName(file);
+    return wxFileName(file, format);
 }
 
 /* static */
 }
 
 /* static */
-wxFileName wxFileName::DirName(const wxString& dir)
+wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format)
 {
     wxFileName fn;
 {
     wxFileName fn;
-    fn.AssignDir(dir);
+    fn.AssignDir(dir, format);
     return fn;
 }
 
     return fn;
 }
 
@@ -318,7 +539,7 @@ wxFileName wxFileName::DirName(const wxString& dir)
 // existence tests
 // ----------------------------------------------------------------------------
 
 // existence tests
 // ----------------------------------------------------------------------------
 
-bool wxFileName::FileExists()
+bool wxFileName::FileExists() const
 {
     return wxFileName::FileExists( GetFullPath() );
 }
 {
     return wxFileName::FileExists( GetFullPath() );
 }
@@ -328,9 +549,9 @@ bool wxFileName::FileExists( const wxString &file )
     return ::wxFileExists( file );
 }
 
     return ::wxFileExists( file );
 }
 
-bool wxFileName::DirExists()
+bool wxFileName::DirExists() const
 {
 {
-    return wxFileName::DirExists( GetFullPath() );
+    return wxFileName::DirExists( GetPath() );
 }
 
 bool wxFileName::DirExists( const wxString &dir )
 }
 
 bool wxFileName::DirExists( const wxString &dir )
@@ -373,7 +594,7 @@ wxString wxFileName::GetCwd(const wxString& volume)
 
 bool wxFileName::SetCwd()
 {
 
 bool wxFileName::SetCwd()
 {
-    return wxFileName::SetCwd( GetFullPath() );
+    return wxFileName::SetCwd( GetPath() );
 }
 
 bool wxFileName::SetCwd( const wxString &cwd )
 }
 
 bool wxFileName::SetCwd( const wxString &cwd )
@@ -391,124 +612,219 @@ wxString wxFileName::GetHomeDir()
     return ::wxGetHomeDir();
 }
 
     return ::wxGetHomeDir();
 }
 
-void wxFileName::AssignTempFileName( const wxString& prefix )
+
+// ----------------------------------------------------------------------------
+// CreateTempFileName
+// ----------------------------------------------------------------------------
+
+#if wxUSE_FILE || wxUSE_FFILE
+
+
+#if !defined wx_fdopen && defined HAVE_FDOPEN
+    #define wx_fdopen fdopen
+#endif
+
+// NB: GetTempFileName() under Windows creates the file, so using
+//     O_EXCL there would fail
+#ifdef __WINDOWS__
+    #define wxOPEN_EXCL 0
+#else
+    #define wxOPEN_EXCL O_EXCL
+#endif
+
+
+#ifdef wxOpenOSFHandle
+#define WX_HAVE_DELETE_ON_CLOSE
+// On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags.
+//
+static int wxOpenWithDeleteOnClose(const wxString& filename)
 {
 {
-    wxString tempname = CreateTempFileName(prefix);
-    if ( tempname.empty() )
-    {
-        // error, failed to get temp file name
-        Clear();
-    }
-    else // ok
-    {
-        Assign(tempname);
-    }
+    DWORD access = GENERIC_READ | GENERIC_WRITE;
+
+    DWORD disposition = OPEN_ALWAYS;
+
+    DWORD attributes = FILE_ATTRIBUTE_TEMPORARY |
+                       FILE_FLAG_DELETE_ON_CLOSE;
+
+    HANDLE h = ::CreateFile(filename.fn_str(), access, 0, NULL,
+                            disposition, attributes, NULL);
+
+    return wxOpenOSFHandle(h, wxO_BINARY);
 }
 }
+#endif // wxOpenOSFHandle
 
 
-/* static */
-wxString wxFileName::CreateTempFileName(const wxString& prefix)
+
+// Helper to open the file
+//
+static int wxTempOpen(const wxString& path, bool *deleteOnClose)
 {
 {
-    wxString path, dir, name;
+#ifdef WX_HAVE_DELETE_ON_CLOSE
+    if (*deleteOnClose)
+        return wxOpenWithDeleteOnClose(path);
+#endif
 
 
-    // use the directory specified by the prefix
-    SplitPath(prefix, &dir, &name, NULL /* extension */);
+    *deleteOnClose = false;
 
 
-#if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
+    return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600);
+}
 
 
-#ifdef __WIN32__
-    if ( dir.empty() )
-    {
-        if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) )
-        {
-            wxLogLastError(_T("GetTempPath"));
-        }
 
 
-        if ( dir.empty() )
-        {
-            // GetTempFileName() fails if we pass it an empty string
-            dir = _T('.');
-        }
-    }
+#if wxUSE_FFILE
+// Helper to open the file and attach it to the wxFFile
+//
+static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose)
+{
+#ifndef wx_fdopen
+    *deleteOnClose = false;
+    return file->Open(path, _T("w+b"));
+#else // wx_fdopen
+    int fd = wxTempOpen(path, deleteOnClose);
+    if (fd == -1)
+        return false;
+    file->Attach(wx_fdopen(fd, "w+b"));
+    return file->IsOpened();
+#endif // wx_fdopen
+}
+#endif // wxUSE_FFILE
 
 
-    if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) )
-    {
-        wxLogLastError(_T("GetTempFileName"));
 
 
-        path.clear();
+#if !wxUSE_FILE
+    #define WXFILEARGS(x, y) y
+#elif !wxUSE_FFILE
+    #define WXFILEARGS(x, y) x
+#else
+    #define WXFILEARGS(x, y) x, y
+#endif
+
+
+// Implementation of wxFileName::CreateTempFileName().
+//
+static wxString wxCreateTempImpl(
+        const wxString& prefix,
+        WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
+        bool *deleteOnClose = NULL)
+{
+#if wxUSE_FILE && wxUSE_FFILE
+    wxASSERT(fileTemp == NULL || ffileTemp == NULL);
+#endif
+    wxString path, dir, name;
+    bool wantDeleteOnClose = false;
+
+    if (deleteOnClose)
+    {
+        // set the result to false initially
+        wantDeleteOnClose = *deleteOnClose;
+        *deleteOnClose = false;
     }
     }
-#else // Win16
-    if ( !::GetTempFileName(NULL, prefix, 0, wxStringBuffer(path, 1025)) )
+    else
     {
     {
-        path.clear();
+        // easier if it alwasys points to something
+        deleteOnClose = &wantDeleteOnClose;
     }
     }
-#endif // Win32/16
 
 
-#elif defined(__WXPM__)
-    // for now just create a file
-    //
-    // future enhancements can be to set some extended attributes for file
-    // systems OS/2 supports that have them (HPFS, FAT32) and security
-    // (HPFS386)
-    static const wxChar *szMktempSuffix = wxT("XXX");
-    path << dir << _T('/') << name << szMktempSuffix;
-
-    // Temporarily remove - MN
-    #ifndef __WATCOMC__
-        ::DosCreateDir(wxStringBuffer(MAX_PATH), NULL);
-    #endif
+    // use the directory specified by the prefix
+    wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */);
 
 
-#else // !Windows, !OS/2
-    if ( dir.empty() )
+    if (dir.empty())
     {
     {
-        dir = wxGetenv(_T("TMP"));
-        if ( path.empty() )
-        {
-            dir = wxGetenv(_T("TEMP"));
-        }
+        dir = wxFileName::GetTempDir();
+    }
 
 
-        if ( dir.empty() )
-        {
-            // default
-            dir = _T("/tmp");
-        }
+#if defined(__WXWINCE__)
+    path = dir + wxT("\\") + name;
+    int i = 1;
+    while (wxFileName::FileExists(path))
+    {
+        path = dir + wxT("\\") + name ;
+        path << i;
+        i ++;
+    }
+
+#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
+    if ( !::GetTempFileName(dir.fn_str(), name.fn_str(), 0,
+                            wxStringBuffer(path, MAX_PATH + 1)) )
+    {
+        wxLogLastError(_T("GetTempFileName"));
+
+        path.clear();
     }
 
     }
 
+#else // !Windows
     path = dir;
 
     if ( !wxEndsWithPathSeparator(dir) &&
             (name.empty() || !wxIsPathSeparator(name[0u])) )
     {
     path = dir;
 
     if ( !wxEndsWithPathSeparator(dir) &&
             (name.empty() || !wxIsPathSeparator(name[0u])) )
     {
-        path += _T('/');
+        path += wxFILE_SEP_PATH;
     }
 
     path += name;
 
     }
 
     path += name;
 
-#ifdef HAVE_MKSTEMP
+#if defined(HAVE_MKSTEMP)
     // 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(path.fn_str());
+
+    // 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 );
+
+    #if wxUSE_FILE
+        // avoid leaking the fd
+        if ( fileTemp )
+        {
+            fileTemp->Attach(fdTemp);
+        }
+        else
+    #endif
+
+    #if wxUSE_FFILE
+        if ( ffileTemp )
+        {
+        #ifdef wx_fdopen
+            ffileTemp->Attach(wx_fdopen(fdTemp, "r+b"));
+        #else
+            ffileTemp->Open(path, _T("r+b"));
+            close(fdTemp);
+        #endif
+        }
+        else
+    #endif
+
+        {
+            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( (char*)(const char*) buf ) )
     {
         path.clear();
     }
     {
         path.clear();
     }
-#else // !HAVE_MKTEMP
+    else
+    {
+        path = wxConvFile.cMB2WX( (const char*) buf );
+    }
+#else // !HAVE_MKTEMP (includes __DOS__)
     // generate the unique file name ourselves
     // generate the unique file name ourselves
+    #if !defined(__DOS__) && !defined(__PALMOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) )
     path << (unsigned int)getpid();
     path << (unsigned int)getpid();
+    #endif
 
     wxString pathTry;
 
 
     wxString pathTry;
 
@@ -516,8 +832,8 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
     for ( size_t n = 0; n < numTries; n++ )
     {
         // 3 hex digits is enough for numTries == 1000 < 4096
     for ( size_t n = 0; n < numTries; n++ )
     {
         // 3 hex digits is enough for numTries == 1000 < 4096
-        pathTry = path + wxString::Format(_T("%.03x"), n);
-        if ( !wxFile::Exists(pathTry) )
+        pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n);
+        if ( !wxFileName::FileExists(pathTry) )
         {
             break;
         }
         {
             break;
         }
@@ -528,12 +844,41 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
     path = pathTry;
 #endif // HAVE_MKTEMP/!HAVE_MKTEMP
 
     path = pathTry;
 #endif // HAVE_MKTEMP/!HAVE_MKTEMP
 
-    if ( !path.empty() )
+#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
+
+#endif // Windows/!Windows
+
+    if ( path.empty() )
+    {
+        wxLogSysError(_("Failed to create a temporary file name"));
+    }
+    else
     {
     {
-        // create the file - of course, there is a race condition here, this is
+        bool ok = true;
+
+        // 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) )
+    #if wxUSE_FILE
+        if ( fileTemp && !fileTemp->IsOpened() )
+        {
+            *deleteOnClose = wantDeleteOnClose;
+            int fd = wxTempOpen(path, deleteOnClose);
+            if (fd != -1)
+                fileTemp->Attach(fd);
+            else
+                ok = false;
+        }
+    #endif
+
+    #if wxUSE_FFILE
+        if ( ffileTemp && !ffileTemp->IsOpened() )
+        {
+            *deleteOnClose = wantDeleteOnClose;
+            ok = wxTempOpen(ffileTemp, path, deleteOnClose);
+        }
+    #endif
+
+        if ( !ok )
         {
             // 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)
@@ -545,83 +890,331 @@ 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;
 }
 
-// ----------------------------------------------------------------------------
-// directory operations
-// ----------------------------------------------------------------------------
 
 
-bool wxFileName::Mkdir( int perm, bool full )
+static bool wxCreateTempImpl(
+        const wxString& prefix,
+        WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
+        wxString *name)
 {
 {
-    return wxFileName::Mkdir( GetFullPath(), perm, full );
-}
+    bool deleteOnClose = true;
 
 
-bool wxFileName::Mkdir( const wxString &dir, int perm, bool full )
-{
-    if (full)
-    {
-        wxFileName filename(dir);
-        wxArrayString dirs = filename.GetDirs();
-        dirs.Add(filename.GetName());
+    *name = wxCreateTempImpl(prefix,
+                             WXFILEARGS(fileTemp, ffileTemp),
+                             &deleteOnClose);
 
 
-        size_t count = dirs.GetCount();
-        size_t i;
-        wxString currPath;
-        int noErrors = 0;
-        for ( i = 0; i < count; i++ )
-        {
-            currPath += dirs[i];
+    bool ok = !name->empty();
 
 
-            if (currPath.Last() == wxT(':'))
-            {
-                // Can't create a root directory so continue to next dir
-                currPath += wxFILE_SEP_PATH;
-                continue;
-            }
+    if (deleteOnClose)
+        name->clear();
+#ifdef __UNIX__
+    else if (ok && wxRemoveFile(*name))
+        name->clear();
+#endif
 
 
-            if (!DirExists(currPath))
-                if (!wxMkdir(currPath, perm))
-                    noErrors ++;
+    return ok;
+}
 
 
-            if ( (i < (count-1)) )
-                currPath += wxFILE_SEP_PATH;
-        }
 
 
-        return (noErrors == 0);
+static void wxAssignTempImpl(
+        wxFileName *fn,
+        const wxString& prefix,
+        WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp))
+{
+    wxString tempname;
+    tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp));
 
 
-    }
-    else
-        return ::wxMkdir( dir, perm );
+    if ( tempname.empty() )
+    {
+        // error, failed to get temp file name
+        fn->Clear();
+    }
+    else // ok
+    {
+        fn->Assign(tempname);
+    }
+}
+
+
+void wxFileName::AssignTempFileName(const wxString& prefix)
+{
+    wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL));
+}
+
+/* static */
+wxString wxFileName::CreateTempFileName(const wxString& prefix)
+{
+    return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL));
+}
+
+#endif // wxUSE_FILE || wxUSE_FFILE
+
+
+#if wxUSE_FILE
+
+wxString wxCreateTempFileName(const wxString& prefix,
+                              wxFile *fileTemp,
+                              bool *deleteOnClose)
+{
+    return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose);
+}
+
+bool wxCreateTempFile(const wxString& prefix,
+                      wxFile *fileTemp,
+                      wxString *name)
+{
+    return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name);
+}
+
+void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp)
+{
+    wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL));
+}
+
+/* static */
+wxString
+wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp)
+{
+    return wxCreateTempFileName(prefix, fileTemp);
+}
+
+#endif // wxUSE_FILE
+
+
+#if wxUSE_FFILE
+
+wxString wxCreateTempFileName(const wxString& prefix,
+                              wxFFile *fileTemp,
+                              bool *deleteOnClose)
+{
+    return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose);
+}
+
+bool wxCreateTempFile(const wxString& prefix,
+                      wxFFile *fileTemp,
+                      wxString *name)
+{
+    return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name);
+
+}
+
+void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp)
+{
+    wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp));
+}
+
+/* static */
+wxString
+wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp)
+{
+    return wxCreateTempFileName(prefix, fileTemp);
+}
+
+#endif // wxUSE_FFILE
+
+
+// ----------------------------------------------------------------------------
+// directory operations
+// ----------------------------------------------------------------------------
+
+// helper of GetTempDir(): check if the given directory exists and return it if
+// it does or an empty string otherwise
+namespace
+{
+
+wxString CheckIfDirExists(const wxString& dir)
+{
+    return wxFileName::DirExists(dir) ? dir : wxString();
+}
+
+} // anonymous namespace
+
+wxString wxFileName::GetTempDir()
+{
+    // first try getting it from environment: this allows overriding the values
+    // used by default if the user wants to create temporary files in another
+    // directory
+    wxString dir = CheckIfDirExists(wxGetenv("TMPDIR"));
+    if ( dir.empty() )
+    {
+        dir = CheckIfDirExists(wxGetenv("TMP"));
+        if ( dir.empty() )
+            dir = CheckIfDirExists(wxGetenv("TEMP"));
+    }
+
+    // if no environment variables are set, use the system default
+    if ( dir.empty() )
+    {
+#if defined(__WXWINCE__)
+        dir = CheckIfDirExists(wxT("\\temp"));
+#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
+        if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) )
+        {
+            wxLogLastError(_T("GetTempPath"));
+        }
+#elif defined(__WXMAC__) && wxOSX_USE_CARBON
+        dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder);
+#endif // systems with native way
+    }
+
+    // fall back to hard coded value
+    if ( dir.empty() )
+    {
+#ifdef __UNIX_LIKE__
+        dir = CheckIfDirExists("/tmp");
+        if ( dir.empty() )
+#endif // __UNIX_LIKE__
+            dir = ".";
+    }
+
+    return dir;
 }
 
 }
 
-bool wxFileName::Rmdir()
+bool wxFileName::Mkdir( int perm, int flags )
 {
 {
-    return wxFileName::Rmdir( GetFullPath() );
+    return wxFileName::Mkdir(GetPath(), perm, flags);
 }
 
 }
 
-bool wxFileName::Rmdir( const wxString &dir )
+bool wxFileName::Mkdir( const wxString& dir, int perm, int flags )
 {
 {
-    return ::wxRmdir( dir );
+    if ( flags & wxPATH_MKDIR_FULL )
+    {
+        // split the path in components
+        wxFileName filename;
+        filename.AssignDir(dir);
+
+        wxString currPath;
+        if ( filename.HasVolume())
+        {
+            currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE);
+        }
+
+        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 += dirs[i];
+
+            if (!DirExists(currPath))
+            {
+                if (!wxMkdir(currPath, perm))
+                {
+                    // no need to try creating further directories
+                    return false;
+                }
+            }
+        }
+
+        return true;
+
+    }
+
+    return ::wxMkdir( dir, perm );
+}
+
+bool wxFileName::Rmdir(int flags)
+{
+    return wxFileName::Rmdir( GetPath(), flags );
+}
+
+bool wxFileName::Rmdir(const wxString& dir, int flags)
+{
+#ifdef __WXMSW__
+    if ( flags & wxPATH_RMDIR_RECURSIVE )
+    {
+        // SHFileOperation needs double null termination string
+        // but without separator at the end of the path
+        wxString path(dir);
+        if ( path.Last() == wxFILE_SEP_PATH )
+            path.RemoveLast();
+        path += _T('\0');
+
+        SHFILEOPSTRUCT fileop;
+        wxZeroMemory(fileop);
+        fileop.wFunc = FO_DELETE;
+        fileop.pFrom = path.fn_str();
+        fileop.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
+    #ifndef __WXWINCE__
+        // FOF_NOERRORUI is not defined in WinCE
+        fileop.fFlags |= FOF_NOERRORUI;
+    #endif
+
+        int ret = SHFileOperation(&fileop);
+        if ( ret != 0 )
+        {
+            // SHFileOperation may return non-Win32 error codes, so the error
+            // message can be incorrect
+            wxLogApiError(_T("SHFileOperation"), ret);
+            return false;
+        }
+
+        return true;
+    }
+    else if ( flags & wxPATH_RMDIR_FULL )
+#else // !__WXMSW__
+    if ( flags != 0 )   // wxPATH_RMDIR_FULL or wxPATH_RMDIR_RECURSIVE
+#endif // !__WXMSW__
+    {
+        wxString path(dir);
+        if ( path.Last() != wxFILE_SEP_PATH )
+            path += wxFILE_SEP_PATH;
+
+        wxDir d(path);
+
+        if ( !d.IsOpened() )
+            return false;
+
+        wxString filename;
+
+        // first delete all subdirectories
+        bool cont = d.GetFirst(&filename, "", wxDIR_DIRS | wxDIR_HIDDEN);
+        while ( cont )
+        {
+            wxFileName::Rmdir(path + filename, flags);
+            cont = d.GetNext(&filename);
+        }
+
+#ifndef __WXMSW__
+        if ( flags & wxPATH_RMDIR_RECURSIVE )
+        {
+            // delete all files too
+            cont = d.GetFirst(&filename, "", wxDIR_FILES | wxDIR_HIDDEN);
+            while ( cont )
+            {
+                ::wxRemoveFile(path + filename);
+                cont = d.GetNext(&filename);
+            }
+        }
+#endif // !__WXMSW__
+    }
+
+    return ::wxRmdir(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)
 {
+    // deal with env vars renaming first as this may seriously change the path
+    if ( flags & wxPATH_NORM_ENV_VARS )
+    {
+        wxString pathOrig = GetFullPath(format);
+        wxString path = wxExpandEnvVars(pathOrig);
+        if ( path != pathOrig )
+        {
+            Assign(path);
+        }
+    }
+
     // the existing path components
     wxArrayString dirs = GetDirs();
 
     // the existing path components
     wxArrayString dirs = GetDirs();
 
@@ -630,8 +1223,8 @@ bool wxFileName::Normalize(wxPathNormalize flags,
 
     format = GetFormat(format);
 
 
     format = GetFormat(format);
 
-    // make the path absolute
-    if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute() )
+    // set up the directory to use for making the path absolute later
+    if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) )
     {
         if ( cwd.empty() )
         {
     {
         if ( cwd.empty() )
         {
@@ -641,20 +1234,6 @@ bool wxFileName::Normalize(wxPathNormalize flags,
         {
             curDir.AssignDir(cwd);
         }
         {
             curDir.AssignDir(cwd);
         }
-
-        // the path may be not absolute because it doesn't have the volume name
-        // but in this case we shouldn't modify the directory components of it
-        // but just set the current volume
-        if ( !HasVolume() && curDir.HasVolume() )
-        {
-            SetVolume(curDir.GetVolume());
-
-            if ( IsAbsolute() )
-            {
-                // yes, it was the case - we don't need curDir then
-                curDir.Clear();
-            }
-        }
     }
 
     // handle ~ stuff under Unix only
     }
 
     // handle ~ stuff under Unix only
@@ -665,8 +1244,18 @@ bool wxFileName::Normalize(wxPathNormalize flags,
             wxString dir = dirs[0u];
             if ( !dir.empty() && dir[0u] == _T('~') )
             {
             wxString dir = dirs[0u];
             if ( !dir.empty() && dir[0u] == _T('~') )
             {
+                // to make the path absolute use the home directory
                 curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
 
                 curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
 
+                // if we are expanding the tilde, then this path
+                // *should* be already relative (since we checked for
+                // the tilde only in the first char of the first dir);
+                // if m_relative==false, it's because it was initialized
+                // from a string which started with /~; in that case
+                // we reach this point but then need m_relative=true
+                // for relative->absolute expansion later
+                m_relative = true;
+
                 dirs.RemoveAt(0u);
             }
         }
                 dirs.RemoveAt(0u);
             }
         }
@@ -675,14 +1264,34 @@ bool wxFileName::Normalize(wxPathNormalize flags,
     // transform relative path into abs one
     if ( curDir.IsOk() )
     {
     // transform relative path into abs one
     if ( curDir.IsOk() )
     {
-        wxArrayString dirsNew = curDir.GetDirs();
-        size_t count = dirs.GetCount();
-        for ( size_t n = 0; n < count; n++ )
+        // this path may be relative because it doesn't have the volume name
+        // and still have m_relative=true; in this case we shouldn't modify
+        // our directory components but just set the current volume
+        if ( !HasVolume() && curDir.HasVolume() )
+        {
+            SetVolume(curDir.GetVolume());
+
+            if ( !m_relative )
         {
         {
-            dirsNew.Add(dirs[n]);
+                // yes, it was the case - we don't need curDir then
+                curDir.Clear();
+            }
         }
 
         }
 
-        dirs = dirsNew;
+        // finally, prepend curDir to the dirs array
+        wxArrayString dirsNew = curDir.GetDirs();
+        WX_PREPEND_ARRAY(dirs, dirsNew);
+
+        // if we used e.g. tilde expansion previously and wxGetUserHome didn't
+        // return for some reason an absolute path, then curDir maybe not be absolute!
+        if ( curDir.IsAbsolute(format) )
+        {
+            // we have prepended an absolute path and thus we are now an absolute
+            // file name too
+            m_relative = false;
+        }
+        // else if (flags & wxPATH_NORM_ABSOLUTE):
+        //   should we warn the user that we didn't manage to make the path absolute?
     }
 
     // now deal with ".", ".." and the rest
     }
 
     // now deal with ".", ".." and the rest
@@ -706,7 +1315,7 @@ bool wxFileName::Normalize(wxPathNormalize flags,
                 {
                     wxLogError(_("The path '%s' contains too many \"..\"!"),
                                GetFullPath().c_str());
                 {
                     wxLogError(_("The path '%s' contains too many \"..\"!"),
                                GetFullPath().c_str());
-                    return FALSE;
+                    return false;
                 }
 
                 m_dirs.RemoveAt(m_dirs.GetCount() - 1);
                 }
 
                 m_dirs.RemoveAt(m_dirs.GetCount() - 1);
@@ -714,45 +1323,206 @@ bool wxFileName::Normalize(wxPathNormalize flags,
             }
         }
 
             }
         }
 
-        if ( flags & wxPATH_NORM_ENV_VARS )
-        {
-            dir = wxExpandEnvVars(dir);
-        }
+        m_dirs.Add(dir);
+    }
 
 
-        if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
+#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
+    if ( (flags & wxPATH_NORM_SHORTCUT) )
+    {
+        wxString filename;
+        if (GetShortcutTarget(GetFullPath(format), filename))
         {
         {
-            dir.MakeLower();
+            m_relative = false;
+            Assign(filename);
         }
         }
+    }
+#endif
 
 
-        m_dirs.Add(dir);
+#if defined(__WIN32__)
+    if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) )
+    {
+        Assign(GetLongPath());
     }
     }
+#endif // Win32
 
 
+    // Change case  (this should be kept at the end of the function, to ensure
+    // that the path doesn't change any more after we normalize its case)
     if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
     {
     if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
     {
-        // VZ: expand env vars here too?
-
+        m_volume.MakeLower();
         m_name.MakeLower();
         m_ext.MakeLower();
         m_name.MakeLower();
         m_ext.MakeLower();
+
+        // directory entries must be made lower case as well
+        count = m_dirs.GetCount();
+        for ( size_t i = 0; i < count; i++ )
+        {
+            m_dirs[i].MakeLower();
+        }
     }
 
     }
 
-#if defined(__WIN32__)
-    if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) )
+    return true;
+}
+
+#ifndef __WXWINCE__
+bool wxFileName::ReplaceEnvVariable(const wxString& envname,
+                                    const wxString& replacementFmtString,
+                                    wxPathFormat format)
+{
+    // look into stringForm for the contents of the given environment variable
+    wxString val;
+    if (envname.empty() ||
+        !wxGetEnv(envname, &val))
+        return false;
+    if (val.empty())
+        return false;
+
+    wxString stringForm = GetPath(wxPATH_GET_VOLUME, format);
+        // do not touch the file name and the extension
+
+    wxString replacement = wxString::Format(replacementFmtString, envname);
+    stringForm.Replace(val, replacement);
+
+    // Now assign ourselves the modified path:
+    Assign(stringForm, GetFullName(), format);
+
+    return true;
+}
+#endif
+
+bool wxFileName::ReplaceHomeDir(wxPathFormat format)
+{
+    wxString homedir = wxGetHomeDir();
+    if (homedir.empty())
+        return false;
+
+    wxString stringForm = GetPath(wxPATH_GET_VOLUME, format);
+        // do not touch the file name and the extension
+
+    stringForm.Replace(homedir, "~");
+
+    // Now assign ourselves the modified path:
+    Assign(stringForm, GetFullName(), format);
+
+    return true;
+}
+
+// ----------------------------------------------------------------------------
+// get the shortcut target
+// ----------------------------------------------------------------------------
+
+// WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions.
+// The .lnk file is a plain text file so it should be easy to
+// make it work. Hint from Google Groups:
+// "If you open up a lnk file, you'll see a
+// number, followed by a pound sign (#), followed by more text. The
+// number is the number of characters that follows the pound sign. The
+// characters after the pound sign are the command line (which _can_
+// include arguments) to be executed. Any path (e.g. \windows\program
+// files\myapp.exe) that includes spaces needs to be enclosed in
+// quotation marks."
+
+#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
+// The following lines are necessary under WinCE
+// #include "wx/msw/private.h"
+// #include <ole2.h>
+#include <shlobj.h>
+#if defined(__WXWINCE__)
+#include <shlguid.h>
+#endif
+
+bool wxFileName::GetShortcutTarget(const wxString& shortcutPath,
+                                   wxString& targetFilename,
+                                   wxString* arguments)
+{
+    wxString path, file, ext;
+    wxFileName::SplitPath(shortcutPath, & path, & file, & ext);
+
+    HRESULT hres;
+    IShellLink* psl;
+    bool success = false;
+
+    // Assume it's not a shortcut if it doesn't end with lnk
+    if (ext.CmpNoCase(wxT("lnk"))!=0)
+        return false;
+
+    // create a ShellLink object
+    hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+                            IID_IShellLink, (LPVOID*) &psl);
+
+    if (SUCCEEDED(hres))
     {
     {
-        Assign(GetLongPath());
+        IPersistFile* ppf;
+        hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
+        if (SUCCEEDED(hres))
+        {
+            WCHAR wsz[MAX_PATH];
+
+            MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, shortcutPath.mb_str(), -1, wsz,
+                                MAX_PATH);
+
+            hres = ppf->Load(wsz, 0);
+            ppf->Release();
+
+            if (SUCCEEDED(hres))
+            {
+                wxChar buf[2048];
+                // Wrong prototype in early versions
+#if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2)
+                psl->GetPath((CHAR*) buf, 2048, NULL, SLGP_UNCPRIORITY);
+#else
+                psl->GetPath(buf, 2048, NULL, SLGP_UNCPRIORITY);
+#endif
+                targetFilename = wxString(buf);
+                success = (shortcutPath != targetFilename);
+
+                psl->GetArguments(buf, 2048);
+                wxString args(buf);
+                if (!args.empty() && arguments)
+                {
+                    *arguments = args;
+                }
+            }
+        }
+
+        psl->Release();
     }
     }
-#endif // Win32
+    return success;
+}
+
+#endif // __WIN32__ && !__WXWINCE__
 
 
-    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)
 {
 }
 
 bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
 {
-    wxFileName fnBase(pathBase, format);
+    wxFileName fnBase = wxFileName::DirName(pathBase, format);
 
     // get cwd only once - small time saving
     wxString cwd = wxGetCwd();
 
     // 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);
 
@@ -760,7 +1530,7 @@ bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
     if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) )
     {
         // nothing done
     if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) )
     {
         // nothing done
-        return FALSE;
+        return false;
     }
 
     // same drive, so we don't need our volume
     }
 
     // same drive, so we don't need our volume
@@ -781,31 +1551,44 @@ 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
     // we were modified
-    return TRUE;
+    return true;
 }
 
 // ----------------------------------------------------------------------------
 // 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() )
 
     if ( fn1.GetFullPath() == fn2.GetFullPath() )
-        return TRUE;
+        return true;
 
     // TODO: compare inodes for Unix, this works even when filenames are
     //       different but files are the same (symlinks) (VZ)
 
 
     // TODO: compare inodes for Unix, this works even when filenames are
     //       different but files are the same (symlinks) (VZ)
 
-    return FALSE;
+    return false;
 }
 
 /* static */
 }
 
 /* static */
@@ -815,59 +1598,47 @@ bool wxFileName::IsCaseSensitive( wxPathFormat format )
     return GetFormat(format) == wxPATH_UNIX;
 }
 
     return GetFormat(format) == wxPATH_UNIX;
 }
 
-bool wxFileName::IsAbsolute( wxPathFormat format )
+/* static */
+wxString wxFileName::GetForbiddenChars(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];
+    // Inits to forbidden characters that are common to (almost) all platforms.
+    wxString strForbiddenChars = wxT("*?");
 
 
-        return IsPathSeparator(ch, format) || ch == _T('~');
-    }
-    else // !Unix
+    // If asserts, wxPathFormat has been changed. In case of a new path format
+    // addition, the following code might have to be updated.
+    wxCOMPILE_TIME_ASSERT(wxPATH_MAX == 5, wxPathFormatChanged);
+    switch ( GetFormat(format) )
     {
     {
-        // must have the drive
-        if ( m_volume.empty() )
-            return FALSE;
+        default :
+            wxFAIL_MSG( wxT("Unknown path format") );
+            // !! Fall through !!
 
 
-        switch ( format )
-        {
-            default:
-                wxFAIL_MSG( _T("unknown wxPATH_XXX style") );
-                // fall through
+        case wxPATH_UNIX:
+            break;
 
 
-            case wxPATH_DOS:
-                return m_dirs[0u].empty();
+        case wxPATH_MAC:
+            // On a Mac even names with * and ? are allowed (Tested with OS
+            // 9.2.1 and OS X 10.2.5)
+            strForbiddenChars = wxEmptyString;
+            break;
 
 
-            case wxPATH_VMS:
-                // TODO: what is the relative path format here?
-                return TRUE;
+        case wxPATH_DOS:
+            strForbiddenChars += wxT("\\/:\"<>|");
+            break;
 
 
-            case wxPATH_MAC:
-                return !m_dirs[0u].empty();
-        }
+        case wxPATH_VMS:
+            break;
     }
     }
+
+    return strForbiddenChars;
 }
 
 /* static */
 }
 
 /* static */
-wxString wxFileName::GetVolumeSeparator(wxPathFormat format)
+wxString wxFileName::GetVolumeSeparator(wxPathFormat WXUNUSED_IN_WINCE(format))
 {
 {
+#ifdef __WXWINCE__
+    return wxEmptyString;
+#else
     wxString sepVol;
 
     if ( (GetFormat(format) == wxPATH_DOS) ||
     wxString sepVol;
 
     if ( (GetFormat(format) == wxPATH_DOS) ||
@@ -878,6 +1649,7 @@ wxString wxFileName::GetVolumeSeparator(wxPathFormat format)
     //else: leave empty
 
     return sepVol;
     //else: leave empty
 
     return sepVol;
+#endif
 }
 
 /* static */
 }
 
 /* static */
@@ -893,7 +1665,7 @@ wxString wxFileName::GetPathSeparators(wxPathFormat format)
             break;
 
         default:
             break;
 
         default:
-            wxFAIL_MSG( _T("unknown wxPATH_XXX style") );
+            wxFAIL_MSG( _T("Unknown wxPATH_XXX style") );
             // fall through
 
         case wxPATH_UNIX:
             // fall through
 
         case wxPATH_UNIX:
@@ -913,45 +1685,70 @@ wxString wxFileName::GetPathSeparators(wxPathFormat format)
 }
 
 /* static */
 }
 
 /* static */
-bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
+wxString wxFileName::GetPathTerminators(wxPathFormat format)
 {
 {
-    // wxString::Find() doesn't work as expected with NUL - it will always find
-    // it, so it is almost surely a bug if this function is called with NUL arg
-    wxASSERT_MSG( ch != _T('\0'), _T("shouldn't be called with NUL") );
+    format = GetFormat(format);
 
 
-    return GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
+    // under VMS the end of the path is ']', not the path separator used to
+    // separate the components
+    return format == wxPATH_VMS ? wxString(_T(']')) : GetPathSeparators(format);
 }
 
 }
 
-bool wxFileName::IsWild( wxPathFormat format )
+/* static */
+bool wxFileName::IsPathSeparator(wxChar ch, 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;
+    // wxString::Find() doesn't work as expected with NUL - it will always find
+    // it, so test for it separately
+    return ch != _T('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
 }
 
 // ----------------------------------------------------------------------------
 // path components manipulation
 // ----------------------------------------------------------------------------
 
 }
 
 // ----------------------------------------------------------------------------
 // path components manipulation
 // ----------------------------------------------------------------------------
 
-void wxFileName::AppendDir( const wxString &dir )
+/* static */ bool wxFileName::IsValidDirComponent(const wxString& dir)
 {
 {
-    m_dirs.Add( dir );
+    if ( dir.empty() )
+    {
+        wxFAIL_MSG( _T("empty directory passed to wxFileName::InsertDir()") );
+
+        return false;
+    }
+
+    const size_t len = dir.length();
+    for ( size_t n = 0; n < len; n++ )
+    {
+        if ( dir[n] == GetVolumeSeparator() || IsPathSeparator(dir[n]) )
+        {
+            wxFAIL_MSG( _T("invalid directory component in wxFileName") );
+
+            return false;
+        }
+    }
+
+    return true;
 }
 
 }
 
-void wxFileName::PrependDir( const wxString &dir )
+void wxFileName::AppendDir( const wxString& dir )
 {
 {
-    m_dirs.Insert( dir, 0 );
+    if ( IsValidDirComponent(dir) )
+        m_dirs.Add( dir );
 }
 
 }
 
-void wxFileName::InsertDir( int before, const wxString &dir )
+void wxFileName::PrependDir( const wxString& dir )
 {
 {
-    m_dirs.Insert( dir, before );
+    InsertDir(0, dir);
 }
 
 }
 
-void wxFileName::RemoveDir( int pos )
+void wxFileName::InsertDir(size_t before, const wxString& dir)
 {
 {
-    m_dirs.Remove( (size_t)pos );
+    if ( IsValidDirComponent(dir) )
+        m_dirs.Insert(dir, before);
+}
+
+void wxFileName::RemoveDir(size_t pos)
+{
+    m_dirs.RemoveAt(pos);
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -960,13 +1757,14 @@ void wxFileName::RemoveDir( int pos )
 
 void wxFileName::SetFullName(const wxString& fullname)
 {
 
 void wxFileName::SetFullName(const wxString& fullname)
 {
-    SplitPath(fullname, NULL /* no path */, &m_name, &m_ext);
+    SplitPath(fullname, NULL /* no volume */, NULL /* no path */,
+                        &m_name, &m_ext, &m_hasExt);
 }
 
 wxString wxFileName::GetFullName() const
 {
     wxString fullname = m_name;
 }
 
 wxString wxFileName::GetFullName() const
 {
     wxString fullname = m_name;
-    if ( !m_ext.empty() )
+    if ( m_hasExt )
     {
         fullname << wxFILE_SEP_EXT << m_ext;
     }
     {
         fullname << wxFILE_SEP_EXT << m_ext;
     }
@@ -974,88 +1772,123 @@ 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( wxT("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 start with a slash
+                // with one exception: the ones 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;
+    }
+
+    if ( m_dirs.empty() )
+    {
+        // there is nothing more
+        return fullpath;
     }
 
     // then concatenate all the path components using the path separator
     }
 
     // then concatenate all the path components using the path separator
-    size_t dirCount = m_dirs.GetCount();
-    if ( dirCount )
+    if ( format == wxPATH_VMS )
     {
     {
-        // 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;
-        }
+        fullpath += wxT('[');
+    }
 
 
-        wxChar chPathSep = GetPathSeparators(format)[0u];
-        if ( format == wxPATH_VMS )
+    const size_t dirCount = m_dirs.GetCount();
+    for ( size_t i = 0; i < dirCount; i++ )
+    {
+        switch (format)
         {
         {
-            fullpath += _T('[');
-        }
+            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].IsSameAs(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;
 
 
-        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;
+            case wxPATH_VMS:
+                // TODO: What to do with ".." under VMS
 
 
-            fullpath += m_dirs[i];
+                // convert back from ".." to nothing
+                if ( !m_dirs[i].IsSameAs(wxT("..")) )
+                    fullpath += m_dirs[i];
+                break;
         }
 
         }
 
-        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;
-        }
+        if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) )
+            fullpath += GetPathSeparator(format);
+    }
+
+    if ( format == wxPATH_VMS )
+    {
+        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;
@@ -1064,28 +1897,26 @@ wxString wxFileName::GetFullPath( wxPathFormat format ) const
 // Return the short form of the path (returns identity on non-Windows platforms)
 wxString wxFileName::GetShortPath() const
 {
 // Return the short form of the path (returns identity on non-Windows platforms)
 wxString wxFileName::GetShortPath() const
 {
-#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__)
     wxString path(GetFullPath());
     wxString path(GetFullPath());
-    wxString pathOut;
-    DWORD sz = ::GetShortPathName(path, NULL, 0);
-    bool ok = sz != 0;
-    if ( ok )
+
+#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+    DWORD sz = ::GetShortPathName(path.fn_str(), NULL, 0);
+    if ( sz != 0 )
     {
     {
-        ok = ::GetShortPathName
+        wxString pathOut;
+        if ( ::GetShortPathName
                (
                (
-                path,
-                pathOut.GetWriteBuf(sz),
+                path.fn_str(),
+                wxStringBuffer(pathOut, sz),
                 sz
                 sz
-               ) != 0;
-        pathOut.UngetWriteBuf();
+               ) != 0 )
+        {
+            return pathOut;
+        }
     }
     }
-    if (ok)
-        return pathOut;
+#endif // Windows
 
     return path;
 
     return path;
-#else
-    return GetFullPath();
-#endif
 }
 
 // Return the long form of the path (returns identity on non-Windows platforms)
 }
 
 // Return the long form of the path (returns identity on non-Windows platforms)
@@ -1094,107 +1925,118 @@ wxString wxFileName::GetLongPath() const
     wxString pathOut,
              path = GetFullPath();
 
     wxString pathOut,
              path = GetFullPath();
 
-#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 defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__)
 
 
-    static bool s_triedToLoad = FALSE;
+#if wxUSE_DYNLIB_CLASS
+    typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD);
 
 
-    if ( !s_triedToLoad )
+    // this is MT-safe as in the worst case we're going to resolve the function
+    // twice -- but as the result is the same in both threads, it's ok
+    static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL;
+    if ( !s_pfnGetLongPathName )
     {
     {
-        s_triedToLoad = TRUE;
-        wxDllType dllKernel = wxDllLoader::LoadLibrary(_T("kernel32"));
-        if ( dllKernel )
+        static bool s_triedToLoad = false;
+
+        if ( !s_triedToLoad )
         {
         {
-            // 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"));
-#else
-            s_pfnGetLongPathName = (GET_LONG_PATH_NAME) wxDllLoader::GetSymbol(dllKernel, _T("GetLongPathNameA"));
-#endif
+            s_triedToLoad = true;
+
+            wxDynamicLibrary dllKernel(_T("kernel32"));
 
 
-            wxDllLoader::UnloadLibrary(dllKernel);
+            const wxChar* GetLongPathName = _T("GetLongPathName")
+#if wxUSE_UNICODE
+                              _T("W");
+#else // ANSI
+                              _T("A");
+#endif // Unicode/ANSI
 
 
-            if ( s_pfnGetLongPathName )
+            if ( dllKernel.HasSymbol(GetLongPathName) )
             {
             {
-                DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0);
-                bool ok = dwSize > 0;
+                s_pfnGetLongPathName = (GET_LONG_PATH_NAME)
+                    dllKernel.GetSymbol(GetLongPathName);
+            }
 
 
-                if ( ok )
-                {
-                    DWORD sz = (*s_pfnGetLongPathName)(path, NULL, 0);
-                    ok = sz != 0;
-                    if ( ok )
-                    {
-                        ok = (*s_pfnGetLongPathName)
-                                (
-                                path,
-                                pathOut.GetWriteBuf(sz),
-                                sz
-                                ) != 0;
-                        pathOut.UngetWriteBuf();
-
-                        success = TRUE;
-                    }
-                }
+            // note that kernel32.dll can be unloaded, it stays in memory
+            // anyhow as all Win32 programs link to it and so it's safe to call
+            // GetLongPathName() even after unloading it
+        }
+    }
+
+    if ( s_pfnGetLongPathName )
+    {
+        DWORD dwSize = (*s_pfnGetLongPathName)(path.fn_str(), NULL, 0);
+        if ( dwSize > 0 )
+        {
+            if ( (*s_pfnGetLongPathName)
+                 (
+                  path.fn_str(),
+                  wxStringBuffer(pathOut, dwSize),
+                  dwSize
+                 ) != 0 )
+            {
+                return pathOut;
             }
         }
     }
             }
         }
     }
-    if (success)
-        return pathOut;
 #endif // wxUSE_DYNLIB_CLASS
 
 #endif // wxUSE_DYNLIB_CLASS
 
-    if (!success)
-    {
-        // The OS didn't support GetLongPathName, or some other error.
-        // We need to call FindFirstFile on each component in turn.
+    // The OS didn't support GetLongPathName, or some other error.
+    // We need to call FindFirstFile on each component in turn.
 
 
-        WIN32_FIND_DATA findFileData;
-        HANDLE hFind;
+    WIN32_FIND_DATA findFileData;
+    HANDLE hFind;
+
+    if ( HasVolume() )
+        pathOut = GetVolume() +
+                  GetVolumeSeparator(wxPATH_DOS) +
+                  GetPathSeparator(wxPATH_DOS);
+    else
         pathOut = wxEmptyString;
 
         pathOut = wxEmptyString;
 
-        wxArrayString dirs = GetDirs();
-        dirs.Add(GetFullName());
+    wxArrayString dirs = GetDirs();
+    dirs.Add(GetFullName());
 
 
-        wxString tmpPath;
+    wxString tmpPath;
 
 
-        size_t count = dirs.GetCount();
-        for ( size_t i = 0; i < count; i++ )
+    size_t count = dirs.GetCount();
+    for ( size_t i = 0; i < count; i++ )
+    {
+        const wxString& dir = dirs[i];
+
+        // We're using pathOut to collect the long-name path, but using a
+        // temporary for appending the last path component which may be
+        // short-name
+        tmpPath = pathOut + dir;
+
+        // We must not process "." or ".." here as they would be (unexpectedly)
+        // replaced by the corresponding directory names so just leave them
+        // alone
+        //
+        // And we can't pass a drive and root dir to FindFirstFile (VZ: why?)
+        if ( tmpPath.empty() || dir == '.' || dir == ".." ||
+                tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) )
         {
         {
-            // We're using pathOut to collect the long-name path, but using a
-            // temporary for appending the last path component which may be
-            // short-name
-            tmpPath = pathOut + dirs[i];
-
-            if ( tmpPath.empty() )
-                continue;
+            tmpPath += wxFILE_SEP_PATH;
+            pathOut = tmpPath;
+            continue;
+        }
 
 
-            if ( tmpPath.Last() == wxT(':') )
-            {
-                // Can't pass a drive and root dir to FindFirstFile,
-                // so continue to next dir
-                tmpPath += wxFILE_SEP_PATH;
-                pathOut = tmpPath;
-                continue;
-            }
+        hFind = ::FindFirstFile(tmpPath.fn_str(), &findFileData);
+        if (hFind == INVALID_HANDLE_VALUE)
+        {
+            // 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];
 
 
-            hFind = ::FindFirstFile(tmpPath, &findFileData);
-            if (hFind == INVALID_HANDLE_VALUE)
-            {
-                // Error: return immediately with the original path
-                return path;
-            }
+            return tmpPath;
+        }
 
 
-            pathOut += findFileData.cFileName;
-            if ( (i < (count-1)) )
-                pathOut += wxFILE_SEP_PATH;
+        pathOut += findFileData.cFileName;
+        if ( (i < (count-1)) )
+            pathOut += wxFILE_SEP_PATH;
 
 
-            ::FindClose(hFind);
-        }
+        ::FindClose(hFind);
     }
 #else // !Win32
     pathOut = path;
     }
 #else // !Win32
     pathOut = path;
@@ -1207,10 +2049,8 @@ wxPathFormat wxFileName::GetFormat( wxPathFormat format )
 {
     if (format == wxPATH_NATIVE)
     {
 {
     if (format == wxPATH_NATIVE)
     {
-#if defined(__WXMSW__) || defined(__WXPM__)
+#if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__)
         format = wxPATH_DOS;
         format = wxPATH_DOS;
-#elif defined(__WXMAC__) && !defined(__DARWIN__)
-        format = wxPATH_MAC;
 #elif defined(__VMS)
         format = wxPATH_VMS;
 #else
 #elif defined(__VMS)
         format = wxPATH_VMS;
 #else
@@ -1220,44 +2060,51 @@ wxPathFormat wxFileName::GetFormat( wxPathFormat format )
     return format;
 }
 
     return format;
 }
 
+#ifdef wxHAS_FILESYSTEM_VOLUMES
+
+/* static */
+wxString wxFileName::GetVolumeString(char drive, int flags)
+{
+    wxASSERT_MSG( !(flags & ~wxPATH_GET_SEPARATOR), "invalid flag specified" );
+
+    wxString vol(drive);
+    vol += wxFILE_SEP_DSK;
+    if ( flags & wxPATH_GET_SEPARATOR )
+        vol += wxFILE_SEP_PATH;
+
+    return vol;
+}
+
+#endif // wxHAS_FILESYSTEM_VOLUMES
+
 // ----------------------------------------------------------------------------
 // path splitting function
 // ----------------------------------------------------------------------------
 
 /* static */
 // ----------------------------------------------------------------------------
 // path splitting function
 // ----------------------------------------------------------------------------
 
 /* static */
-void wxFileName::SplitPath(const wxString& fullpathWithVolume,
-                           wxString *pstrVolume,
-                           wxString *pstrPath,
-                           wxString *pstrName,
-                           wxString *pstrExt,
-                           wxPathFormat format)
+void
+wxFileName::SplitVolume(const wxString& fullpathWithVolume,
+                        wxString *pstrVolume,
+                        wxString *pstrPath,
+                        wxPathFormat format)
 {
     format = GetFormat(format);
 
     wxString fullpath = fullpathWithVolume;
 
 {
     format = GetFormat(format);
 
     wxString fullpath = fullpathWithVolume;
 
-    // under VMS the end of the path is ']', not the path separator used to
-    // separate the components
-    wxString sepPath = format == wxPATH_VMS ? wxString(_T(']'))
-                                            : GetPathSeparators(format);
-
     // special Windows UNC paths hack: transform \\share\path into share:path
     // special Windows UNC paths hack: transform \\share\path into share:path
-    if ( format == wxPATH_DOS )
+    if ( IsUNCPath(fullpath, format) )
     {
     {
-        if ( fullpath.length() >= 4 &&
-                fullpath[0u] == wxFILE_SEP_PATH_DOS &&
-                    fullpath[1u] == wxFILE_SEP_PATH_DOS )
-        {
-            fullpath.erase(0, 2);
+        fullpath.erase(0, 2);
 
 
-            size_t posFirstSlash = fullpath.find_first_of(sepPath);
-            if ( posFirstSlash != wxString::npos )
-            {
-                fullpath[posFirstSlash] = wxFILE_SEP_DSK;
+        size_t posFirstSlash =
+            fullpath.find_first_of(GetPathTerminators(format));
+        if ( posFirstSlash != wxString::npos )
+        {
+            fullpath[posFirstSlash] = wxFILE_SEP_DSK;
 
 
-                // UNC paths are always absolute, right? (FIXME)
-                fullpath.insert(posFirstSlash + 1, wxFILE_SEP_PATH_DOS);
-            }
+            // UNC paths are always absolute, right? (FIXME)
+            fullpath.insert(posFirstSlash + 1, 1, wxFILE_SEP_PATH_DOS);
         }
     }
 
         }
     }
 
@@ -1265,7 +2112,7 @@ void wxFileName::SplitPath(const wxString& fullpathWithVolume,
     if ( format == wxPATH_DOS || format == wxPATH_VMS )
     {
         wxString sepVol = GetVolumeSeparator(format);
     if ( format == wxPATH_DOS || format == wxPATH_VMS )
     {
         wxString sepVol = GetVolumeSeparator(format);
-        
+
         size_t posFirstColon = fullpath.find_first_of(sepVol);
         if ( posFirstColon != wxString::npos )
         {
         size_t posFirstColon = fullpath.find_first_of(sepVol);
         if ( posFirstColon != wxString::npos )
         {
@@ -1279,21 +2126,38 @@ void wxFileName::SplitPath(const wxString& fullpathWithVolume,
         }
     }
 
         }
     }
 
+    if ( pstrPath )
+        *pstrPath = fullpath;
+}
+
+/* static */
+void wxFileName::SplitPath(const wxString& fullpathWithVolume,
+                           wxString *pstrVolume,
+                           wxString *pstrPath,
+                           wxString *pstrName,
+                           wxString *pstrExt,
+                           bool *hasExt,
+                           wxPathFormat format)
+{
+    format = GetFormat(format);
+
+    wxString fullpath;
+    SplitVolume(fullpathWithVolume, pstrVolume, &fullpath, format);
+
     // find the positions of the last dot and last path separator in the path
     size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT);
     // find the positions of the last dot and last path separator in the path
     size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT);
-    size_t posLastSlash = fullpath.find_last_of(sepPath);
+    size_t posLastSlash = fullpath.find_last_of(GetPathTerminators(format));
 
 
+    // check whether this dot occurs at the very beginning of a path component
     if ( (posLastDot != wxString::npos) &&
     if ( (posLastDot != wxString::npos) &&
-            ((format == wxPATH_UNIX) || (format == wxPATH_VMS)) )
+         (posLastDot == 0 ||
+            IsPathSeparator(fullpath[posLastDot - 1]) ||
+            (format == wxPATH_VMS && fullpath[posLastDot - 1] == _T(']'))) )
     {
     {
-        if ( (posLastDot == 0) ||
-             (fullpath[posLastDot - 1] == sepPath[0u] ) )
-        {
-            // under Unix and VMS, dot may be (and commonly is) the first
-            // character of the filename, don't treat the entire filename as
-            // extension in this case
-            posLastDot = wxString::npos;
-        }
+        // dot may be (and commonly -- at least under Unix -- is) the first
+        // character of the filename, don't treat the entire filename as
+        // extension in this case
+        posLastDot = wxString::npos;
     }
 
     // if we do have a dot and a slash, check that the dot is in the name part
     }
 
     // if we do have a dot and a slash, check that the dot is in the name part
@@ -1316,10 +2180,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);
@@ -1356,18 +2223,25 @@ void wxFileName::SplitPath(const wxString& fullpathWithVolume,
         *pstrName = fullpath.Mid(nStart, count);
     }
 
         *pstrName = fullpath.Mid(nStart, count);
     }
 
-    if ( pstrExt )
+    // finally deal with the extension here: we have an added complication that
+    // extension may be empty (but present) as in "foo." where trailing dot
+    // indicates the empty extension at the end -- and hence we must remember
+    // that we have it independently of pstrExt
+    if ( posLastDot == wxString::npos )
     {
     {
-        if ( posLastDot == wxString::npos )
-        {
-            // no extension
-            pstrExt->Empty();
-        }
-        else
-        {
-            // take everything after the dot
+        // no extension
+        if ( pstrExt )
+            pstrExt->clear();
+        if ( hasExt )
+            *hasExt = false;
+    }
+    else
+    {
+        // take everything after the dot
+        if ( pstrExt )
             *pstrExt = fullpath.Mid(posLastDot + 1);
             *pstrExt = fullpath.Mid(posLastDot + 1);
-        }
+        if ( hasExt )
+            *hasExt = true;
     }
 }
 
     }
 }
 
@@ -1381,142 +2255,410 @@ 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));
     }
 }
 
     }
 }
 
+/* static */
+wxString wxFileName::StripExtension(const wxString& fullpath)
+{
+    wxFileName fn(fullpath);
+    fn.SetExt("");
+    return fn.GetFullPath();
+}
+
 // ----------------------------------------------------------------------------
 // time functions
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 // time functions
 // ----------------------------------------------------------------------------
 
-bool wxFileName::SetTimes(const wxDateTime *dtCreate,
-                          const wxDateTime *dtAccess,
-                          const wxDateTime *dtMod)
+#if wxUSE_DATETIME
+
+bool wxFileName::SetTimes(const wxDateTime *dtAccess,
+                          const wxDateTime *dtMod,
+                          const wxDateTime *dtCreate)
 {
 {
-#if defined(__UNIX_LIKE__)
-    if ( !dtAccess && !dtMod )
+#if defined(__WIN32__)
+    FILETIME ftAccess, ftCreate, ftWrite;
+
+    if ( dtCreate )
+        ConvertWxToFileTime(&ftCreate, *dtCreate);
+    if ( dtAccess )
+        ConvertWxToFileTime(&ftAccess, *dtAccess);
+    if ( dtMod )
+        ConvertWxToFileTime(&ftWrite, *dtMod);
+
+    wxString path;
+    int flags;
+    if ( IsDir() )
     {
     {
-        // can't modify the creation time anyhow, don't try
-        return TRUE;
-    }
+        if ( wxGetOsVersion() == wxOS_WINDOWS_9X )
+        {
+            wxLogError(_("Setting directory access times is not supported "
+                         "under this OS version"));
+            return false;
+        }
 
 
-    // if dtAccess or dtMod is not specified, use the other one (which must be
-    // non NULL because of the test above) for both times
-    utimbuf utm;
-    utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks();
-    utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks();
-    if ( utime(GetFullPath(), &utm) == 0 )
+        path = GetPath();
+        flags = FILE_FLAG_BACKUP_SEMANTICS;
+    }
+    else // file
     {
     {
-        return TRUE;
+        path = GetFullPath();
+        flags = 0;
     }
     }
-#elif defined(__WIN32__)
-    wxFileHandle fh(GetFullPath());
+
+    wxFileHandle fh(path, wxFileHandle::Write, flags);
     if ( fh.IsOk() )
     {
     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) )
         {
         if ( ::SetFileTime(fh,
                            dtCreate ? &ftCreate : NULL,
                            dtAccess ? &ftAccess : NULL,
                            dtMod ? &ftWrite : NULL) )
         {
-            return TRUE;
+            return true;
         }
     }
         }
     }
+#elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__))
+    wxUnusedVar(dtCreate);
+
+    if ( !dtAccess && !dtMod )
+    {
+        // can't modify the creation time anyhow, don't try
+        return true;
+    }
+
+    // if dtAccess or dtMod is not specified, use the other one (which must be
+    // non NULL because of the test above) for both times
+    utimbuf utm;
+    utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks();
+    utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks();
+    if ( utime(GetFullPath().fn_str(), &utm) == 0 )
+    {
+        return true;
+    }
 #else // other platform
 #else // other platform
+    wxUnusedVar(dtAccess);
+    wxUnusedVar(dtMod);
+    wxUnusedVar(dtCreate);
 #endif // platforms
 
     wxLogSysError(_("Failed to modify file times for '%s'"),
                   GetFullPath().c_str());
 
 #endif // platforms
 
     wxLogSysError(_("Failed to modify file times for '%s'"),
                   GetFullPath().c_str());
 
-    return FALSE;
+    return false;
 }
 
 bool wxFileName::Touch()
 {
 #if defined(__UNIX_LIKE__)
     // under Unix touching file is simple: just pass NULL to utime()
 }
 
 bool wxFileName::Touch()
 {
 #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;
     }
 
     wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str());
 
     }
 
     wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str());
 
-    return FALSE;
+    return false;
 #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__)
-    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(__WXMAC__)
+#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__))
+    // no need to test for IsDir() here
     wxStructStat stBuf;
     wxStructStat stBuf;
-    if ( wxStat(GetFullPath(), &stBuf) == 0 )
+    if ( wxStat( GetFullPath().c_str(), &stBuf) == 0 )
     {
         if ( dtAccess )
             dtAccess->Set(stBuf.st_atime);
         if ( dtMod )
             dtMod->Set(stBuf.st_mtime);
     {
         if ( dtAccess )
             dtAccess->Set(stBuf.st_atime);
         if ( dtMod )
             dtMod->Set(stBuf.st_mtime);
-        if ( dtChange )
-            dtChange->Set(stBuf.st_ctime);
+        if ( dtCreate )
+            dtCreate->Set(stBuf.st_ctime);
 
 
-        return TRUE;
+        return true;
     }
     }
+#else // other platform
+    wxUnusedVar(dtAccess);
+    wxUnusedVar(dtMod);
+    wxUnusedVar(dtCreate);
+#endif // platforms
+
+    wxLogSysError(_("Failed to retrieve file times for '%s'"),
+                  GetFullPath().c_str());
+
+    return false;
+}
+
+#endif // wxUSE_DATETIME
+
+
+// ----------------------------------------------------------------------------
+// file size functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_LONGLONG
+
+/* static */
+wxULongLong wxFileName::GetSize(const wxString &filename)
+{
+    if (!wxFileExists(filename))
+        return wxInvalidSize;
+
+#if defined(__WXPALMOS__)
+    // TODO
+    return wxInvalidSize;
 #elif defined(__WIN32__)
 #elif defined(__WIN32__)
-    wxFileHandle fh(GetFullPath());
-    if ( fh.IsOk() )
+    wxFileHandle f(filename, wxFileHandle::Read);
+    if (!f.IsOk())
+        return wxInvalidSize;
+
+    DWORD lpFileSizeHigh;
+    DWORD ret = GetFileSize(f, &lpFileSizeHigh);
+    if ( ret == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR )
+        return wxInvalidSize;
+
+    return wxULongLong(lpFileSizeHigh, ret);
+#else // ! __WIN32__
+    wxStructStat st;
+#ifndef wxNEED_WX_UNISTD_H
+    if (wxStat( filename.fn_str() , &st) != 0)
+#else
+    if (wxStat( filename, &st) != 0)
+#endif
+        return wxInvalidSize;
+    return wxULongLong(st.st_size);
+#endif
+}
+
+/* static */
+wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs,
+                                          const wxString &nullsize,
+                                          int precision)
+{
+    static const double KILOBYTESIZE = 1024.0;
+    static const double MEGABYTESIZE = 1024.0*KILOBYTESIZE;
+    static const double GIGABYTESIZE = 1024.0*MEGABYTESIZE;
+    static const double TERABYTESIZE = 1024.0*GIGABYTESIZE;
+
+    if (bs == 0 || bs == wxInvalidSize)
+        return nullsize;
+
+    double bytesize = bs.ToDouble();
+    if (bytesize < KILOBYTESIZE)
+        return wxString::Format(_("%s B"), bs.ToString().c_str());
+    if (bytesize < MEGABYTESIZE)
+        return wxString::Format(_("%.*f kB"), precision, bytesize/KILOBYTESIZE);
+    if (bytesize < GIGABYTESIZE)
+        return wxString::Format(_("%.*f MB"), precision, bytesize/MEGABYTESIZE);
+    if (bytesize < TERABYTESIZE)
+        return wxString::Format(_("%.*f GB"), precision, bytesize/GIGABYTESIZE);
+
+    return wxString::Format(_("%.*f TB"), precision, bytesize/TERABYTESIZE);
+}
+
+wxULongLong wxFileName::GetSize() const
+{
+    return GetSize(GetFullPath());
+}
+
+wxString wxFileName::GetHumanReadableSize(const wxString &failmsg, int precision) const
+{
+    return GetHumanReadableSize(GetSize(), failmsg, precision);
+}
+
+#endif // wxUSE_LONGLONG
+
+// ----------------------------------------------------------------------------
+// Mac-specific functions
+// ----------------------------------------------------------------------------
+
+#if defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON
+
+namespace
+{
+
+class MacDefaultExtensionRecord
+{
+public:
+    MacDefaultExtensionRecord()
     {
     {
-        FILETIME ftAccess, ftCreate, ftWrite;
+        m_type =
+        m_creator = 0 ;
+    }
 
 
-        if ( ::GetFileTime(fh,
-                           dtMod ? &ftCreate : NULL,
-                           dtAccess ? &ftAccess : NULL,
-                           dtChange ? &ftWrite : NULL) )
+    // default copy ctor, assignment operator and dtor are ok
+
+    MacDefaultExtensionRecord(const wxString& ext, OSType type, OSType creator)
+        : m_ext(ext)
+    {
+        m_type = type;
+        m_creator = creator;
+    }
+
+    wxString m_ext;
+    OSType m_type;
+    OSType m_creator;
+};
+
+WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray);
+
+bool gMacDefaultExtensionsInited = false;
+
+#include "wx/arrimpl.cpp"
+
+WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray);
+
+MacDefaultExtensionArray gMacDefaultExtensions;
+
+// load the default extensions
+const MacDefaultExtensionRecord gDefaults[] =
+{
+    MacDefaultExtensionRecord( "txt", 'TEXT', 'ttxt' ),
+    MacDefaultExtensionRecord( "tif", 'TIFF', '****' ),
+    MacDefaultExtensionRecord( "jpg", 'JPEG', '****' ),
+};
+
+void MacEnsureDefaultExtensionsLoaded()
+{
+    if ( !gMacDefaultExtensionsInited )
+    {
+        // we could load the pc exchange prefs here too
+        for ( size_t i = 0 ; i < WXSIZEOF( gDefaults ) ; ++i )
         {
         {
-            if ( dtMod )
-                ConvertFileTimeToWx(dtMod, ftCreate);
-            if ( dtAccess )
-                ConvertFileTimeToWx(dtAccess, ftAccess);
-            if ( dtChange )
-                ConvertFileTimeToWx(dtChange, ftWrite);
-
-            return TRUE;
+            gMacDefaultExtensions.Add( gDefaults[i] ) ;
         }
         }
+        gMacDefaultExtensionsInited = true;
     }
     }
-#else // other platform
-#endif // platforms
+}
 
 
-    wxLogSysError(_("Failed to retrieve file times for '%s'"),
-                  GetFullPath().c_str());
+} // anonymous namespace
+
+bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator )
+{
+    FSRef fsRef ;
+    FSCatalogInfo catInfo;
+    FileInfo *finfo ;
+
+    if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr )
+    {
+        if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
+        {
+            finfo = (FileInfo*)&catInfo.finderInfo;
+            finfo->fileType = type ;
+            finfo->fileCreator = creator ;
+            FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ;
+            return true ;
+        }
+    }
+    return false ;
+}
+
+bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator )
+{
+    FSRef fsRef ;
+    FSCatalogInfo catInfo;
+    FileInfo *finfo ;
+
+    if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr )
+    {
+        if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
+        {
+            finfo = (FileInfo*)&catInfo.finderInfo;
+            *type = finfo->fileType ;
+            *creator = finfo->fileCreator ;
+            return true ;
+        }
+    }
+    return false ;
+}
+
+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 ;
+}
 
 
-    return FALSE;
+void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator )
+{
+  MacEnsureDefaultExtensionsLoaded();
+  MacDefaultExtensionRecord rec(ext.Lower(), type, creator);
+  gMacDefaultExtensions.Add( rec );
 }
 
 }
 
+#endif // defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON