+bool wxFileName::Mkdir( const wxString& dir, int perm, int flags )
+{
+ 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
+// ----------------------------------------------------------------------------
+
+bool wxFileName::Normalize(int flags,
+ 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 path to prepend in front to make the path absolute
+ wxFileName curDir;
+
+ format = GetFormat(format);
+
+ // set up the directory to use for making the path absolute later
+ if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) )
+ {
+ if ( cwd.empty() )
+ {
+ curDir.AssignCwd(GetVolume());
+ }
+ else // cwd provided
+ {
+ curDir.AssignDir(cwd);
+ }
+ }
+
+ // handle ~ stuff under Unix only
+ if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) )
+ {
+ if ( !dirs.IsEmpty() )
+ {
+ 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));
+
+ // 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);
+ }
+ }
+ }
+
+ // transform relative path into abs one
+ if ( curDir.IsOk() )
+ {
+ // 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 )
+ {
+ // yes, it was the case - we don't need curDir then
+ curDir.Clear();
+ }
+ }
+
+ // 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
+ m_dirs.Empty();
+ size_t count = dirs.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ wxString dir = dirs[n];
+
+ if ( flags & wxPATH_NORM_DOTS )
+ {
+ if ( dir == wxT(".") )
+ {
+ // just ignore
+ continue;
+ }
+
+ if ( dir == wxT("..") )
+ {
+ if ( m_dirs.IsEmpty() )
+ {
+ wxLogError(_("The path '%s' contains too many \"..\"!"),
+ GetFullPath().c_str());
+ return false;
+ }
+
+ m_dirs.RemoveAt(m_dirs.GetCount() - 1);
+ continue;
+ }
+ }
+
+ m_dirs.Add(dir);
+ }
+
+#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
+ if ( (flags & wxPATH_NORM_SHORTCUT) )
+ {
+ wxString filename;
+ if (GetShortcutTarget(GetFullPath(format), filename))
+ {
+ m_relative = false;
+ Assign(filename);
+ }
+ }
+#endif
+
+#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) )
+ {
+ m_volume.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();
+ }
+ }
+
+ 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))
+ {
+ 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();
+ }
+ return success;
+}
+
+#endif // __WIN32__ && !__WXWINCE__
+
+
+// ----------------------------------------------------------------------------
+// absolute/relative paths
+// ----------------------------------------------------------------------------
+
+bool wxFileName::IsAbsolute(wxPathFormat format) const
+{
+ // if our path doesn't start with a path separator, it's not an absolute
+ // path
+ if ( m_relative )
+ return false;
+
+ if ( !GetVolumeSeparator(format).empty() )
+ {
+ // this format has volumes and an absolute path must have one, it's not
+ // enough to have the full path to bean absolute file under Windows
+ if ( GetVolume().empty() )
+ return false;
+ }
+
+ return true;
+}
+
+bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
+{
+ wxFileName fnBase = wxFileName::DirName(pathBase, format);
+
+ // get cwd only once - small time saving
+ wxString cwd = wxGetCwd();
+ Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
+ fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
+
+ bool withCase = IsCaseSensitive(format);
+
+ // we can't do anything if the files live on different volumes
+ if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) )
+ {
+ // nothing done
+ return false;
+ }
+
+ // same drive, so we don't need our volume
+ m_volume.clear();
+
+ // remove common directories starting at the top
+ while ( !m_dirs.IsEmpty() && !fnBase.m_dirs.IsEmpty() &&
+ m_dirs[0u].IsSameAs(fnBase.m_dirs[0u], withCase) )
+ {
+ m_dirs.RemoveAt(0);
+ fnBase.m_dirs.RemoveAt(0);
+ }
+
+ // add as many ".." as needed
+ size_t count = fnBase.m_dirs.GetCount();
+ for ( size_t i = 0; i < count; i++ )
+ {
+ m_dirs.Insert(wxT(".."), 0u);
+ }
+
+ if ( format == wxPATH_UNIX || format == wxPATH_DOS )
+ {
+ // a directory made relative with respect to itself is '.' under Unix
+ // and DOS, by definition (but we don't have to insert "./" for the
+ // files)
+ if ( m_dirs.IsEmpty() && IsDir() )
+ {
+ m_dirs.Add(_T('.'));
+ }
+ }
+
+ m_relative = true;
+
+ // we were modified
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// filename kind tests
+// ----------------------------------------------------------------------------
+
+bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const