+ wxString pathTry;
+
+ static const size_t numTries = 1000;
+ for ( size_t n = 0; n < numTries; n++ )
+ {
+ // 3 hex digits is enough for numTries == 1000 < 4096
+ pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n);
+ if ( !wxFileName::FileExists(pathTry) )
+ {
+ break;
+ }
+
+ pathTry.clear();
+ }
+
+ path = pathTry;
+#endif // HAVE_MKTEMP/!HAVE_MKTEMP
+
+#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
+
+#endif // Windows/!Windows
+
+ if ( path.empty() )
+ {
+ wxLogSysError(_("Failed to create a temporary file name"));
+ }
+ else
+ {
+ bool ok = true;
+
+ // open the file - of course, there is a race condition here, this is
+ // why we always prefer using mkstemp()...
+ #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)
+ // fails, though of course it should be protected against
+ // possible infinite looping too.
+
+ wxLogError(_("Failed to open temporary file."));
+
+ path.clear();
+ }
+ }
+
+ return path;
+}
+
+
+static bool wxCreateTempImpl(
+ const wxString& prefix,
+ WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
+ wxString *name)
+{
+ bool deleteOnClose = true;
+
+ *name = wxCreateTempImpl(prefix,
+ WXFILEARGS(fileTemp, ffileTemp),
+ &deleteOnClose);
+
+ bool ok = !name->empty();
+
+ if (deleteOnClose)
+ name->clear();
+#ifdef __UNIX__
+ else if (ok && wxRemoveFile(*name))
+ name->clear();
+#endif
+
+ return ok;
+}
+
+
+static void wxAssignTempImpl(
+ wxFileName *fn,
+ const wxString& prefix,
+ WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp))
+{
+ wxString tempname;
+ tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp));
+
+ 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
+// ----------------------------------------------------------------------------
+
+wxString wxFileName::GetTempDir()
+{
+ wxString dir;
+ dir = wxGetenv(_T("TMPDIR"));
+ if (dir.empty())
+ {
+ dir = wxGetenv(_T("TMP"));
+ if (dir.empty())
+ {
+ dir = wxGetenv(_T("TEMP"));
+ }
+ }
+
+#if defined(__WXWINCE__)
+ if (dir.empty())
+ {
+ // FIXME. Create \temp dir?
+ if (DirExists(wxT("\\temp")))
+ dir = wxT("\\temp");
+ }
+#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
+
+ 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('.');
+ }
+ }
+#else // !Windows
+
+ if ( dir.empty() )
+ {
+ // default
+#if defined(__DOS__) || defined(__OS2__)
+ dir = _T(".");
+#elif defined(__WXMAC__) && !defined(__WXOSX_IPHONE__)
+ dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder);
+#else
+ dir = _T("/tmp");
+#endif
+ }
+#endif
+
+ return dir;
+}
+
+bool wxFileName::Mkdir( int perm, int flags )
+{
+ return wxFileName::Mkdir(GetPath(), perm, flags);
+}
+
+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()
+{
+ return wxFileName::Rmdir( GetPath() );
+}
+
+bool wxFileName::Rmdir( const wxString &dir )
+{
+ 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;
+}
+
+// ----------------------------------------------------------------------------
+// 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;
+ wxSplitPath(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;