X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/489f6cf713b6b5bd9746af238b260c7d13d1dc40..d632789924e1ef1427c5321476215bd473dfe4d6:/src/common/filename.cpp?ds=sidebyside diff --git a/src/common/filename.cpp b/src/common/filename.cpp index c85163a67c..88fe2d48ea 100644 --- a/src/common/filename.cpp +++ b/src/common/filename.cpp @@ -60,10 +60,6 @@ // headers // ---------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) -#pragma implementation "filename.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -72,24 +68,23 @@ #endif #ifndef WX_PRECOMP -#include "wx/intl.h" -#include "wx/log.h" -#include "wx/file.h" + #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/utils.h" #endif #include "wx/filename.h" +#include "wx/private/filename.h" #include "wx/tokenzr.h" #include "wx/config.h" // for wxExpandEnvVars -#include "wx/utils.h" -#include "wx/file.h" #include "wx/dynlib.h" -// For GetShort/LongPathName -#ifdef __WIN32__ -#include "wx/msw/wrapwin.h" -#if defined(__MINGW32__) -#include "wx/msw/gccpriv.h" -#endif +#if defined(__WIN32__) && defined(__MINGW32__) + #include "wx/msw/gccpriv.h" #endif #ifdef __WXWINCE__ @@ -142,6 +137,10 @@ #define MAX_PATH _MAX_PATH #endif + +wxULongLong wxInvalidSize = (unsigned)-1; + + // ---------------------------------------------------------------------------- // private classes // ---------------------------------------------------------------------------- @@ -522,12 +521,12 @@ bool wxFileName::FileExists( const wxString &file ) bool wxFileName::DirExists() const { - return wxFileName::DirExists( GetFullPath() ); + return wxFileName::DirExists( GetPath() ); } bool wxFileName::DirExists( const wxString &dir ) { - return ::wxPathExists( dir ); + return ::wxDirExists( dir ); } // ---------------------------------------------------------------------------- @@ -565,7 +564,7 @@ wxString wxFileName::GetCwd(const wxString& volume) bool wxFileName::SetCwd() { - return wxFileName::SetCwd( GetFullPath() ); + return wxFileName::SetCwd( GetPath() ); } bool wxFileName::SetCwd( const wxString &cwd ) @@ -583,68 +582,135 @@ wxString wxFileName::GetHomeDir() return ::wxGetHomeDir(); } -#if wxUSE_FILE -void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp) +// ---------------------------------------------------------------------------- +// 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, fileTemp); - 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, access, 0, NULL, + disposition, attributes, NULL); + + return wxOpenOSFHandle(h, 0); } +#endif // wxOpenOSFHandle -/* static */ -wxString -wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) + +// Helper to open the file +// +static int wxTempOpen(const wxString& path, bool *deleteOnClose) +{ +#ifdef WX_HAVE_DELETE_ON_CLOSE + if (*deleteOnClose) + return wxOpenWithDeleteOnClose(path); +#endif + + *deleteOnClose = false; + + return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600); +} + + +#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 !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 + { + // easier if it alwasys points to something + deleteOnClose = &wantDeleteOnClose; + } // use the directory specified by the prefix - SplitPath(prefix, &dir, &name, NULL /* extension */); + wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */); -#if defined(__WXWINCE__) if (dir.empty()) { - // FIXME. Create \temp dir? - dir = wxT("\\"); + dir = wxFileName::GetTempDir(); } - path = dir + wxT("\\") + prefix; + +#if defined(__WXWINCE__) + path = dir + wxT("\\") + name; int i = 1; - while (FileExists(path)) + while (wxFileName::FileExists(path)) { - path = dir + wxT("\\") + prefix ; + path = dir + wxT("\\") + name ; path << i; i ++; } #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 // we have a dir to create the file in - { - // ensure we use only the back slashes as GetTempFileName(), unlike all - // the other APIs, is picky and doesn't accept the forward ones - dir.Replace(_T("/"), _T("\\")); - } - if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) ) { wxLogLastError(_T("GetTempFileName")); @@ -653,29 +719,6 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) } #else // !Windows - if ( dir.empty() ) - { -#if defined(__WXMAC__) && !defined(__DARWIN__) - dir = wxMacFindFolder( (short) kOnSystemDisk, kTemporaryFolderType, kCreateFolder ) ; -#else // !Mac - dir = wxGetenv(_T("TMP")); - if ( dir.empty() ) - { - dir = wxGetenv(_T("TEMP")); - } - - if ( dir.empty() ) - { - // default - #if defined(__DOS__) || defined(__OS2__) - dir = _T("."); - #else - dir = _T("/tmp"); - #endif - } -#endif // Mac/!Mac - } - path = dir; if ( !wxEndsWithPathSeparator(dir) && @@ -705,12 +748,28 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) { 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); } @@ -722,7 +781,7 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) path += _T("XXXXXX"); wxCharBuffer buf = wxConvFile.cWX2MB( path ); - if ( !mktemp( (const char*) buf ) ) + if ( !mktemp( (char*)(const char*) buf ) ) { path.clear(); } @@ -743,7 +802,7 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) { // 3 hex digits is enough for numTries == 1000 < 4096 pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n); - if ( !FileExists(pathTry) ) + if ( !wxFileName::FileExists(pathTry) ) { break; } @@ -754,9 +813,6 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) path = pathTry; #endif // HAVE_MKTEMP/!HAVE_MKTEMP - if ( !path.empty() ) - { - } #endif // HAVE_MKSTEMP/!HAVE_MKSTEMP #endif // Windows/!Windows @@ -765,20 +821,33 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) { wxLogSysError(_("Failed to create a temporary file name")); } - else if ( fileTemp && !fileTemp->IsOpened() ) + else { + bool ok = true; + // open the file - of course, there is a race condition here, this is // why we always prefer using mkstemp()... - // - // NB: GetTempFileName() under Windows creates the file, so using - // write_excl there would fail - if ( !fileTemp->Open(path, -#if defined(__WINDOWS__) && !defined(__WXMICROWIN__) - wxFile::write, -#else - wxFile::write_excl, -#endif - wxS_IRUSR | wxS_IWUSR) ) + #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) @@ -794,15 +863,188 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) 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__) + dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder); +#else + dir = _T("/tmp"); +#endif + } +#endif + + return dir; +} + bool wxFileName::Mkdir( int perm, int flags ) { - return wxFileName::Mkdir( GetFullPath(), perm, flags ); + return wxFileName::Mkdir(GetPath(), perm, flags); } bool wxFileName::Mkdir( const wxString& dir, int perm, int flags ) @@ -853,7 +1095,7 @@ bool wxFileName::Mkdir( const wxString& dir, int perm, int flags ) bool wxFileName::Rmdir() { - return wxFileName::Rmdir( GetFullPath() ); + return wxFileName::Rmdir( GetPath() ); } bool wxFileName::Rmdir( const wxString &dir ) @@ -889,7 +1131,7 @@ bool wxFileName::Normalize(int flags, format = GetFormat(format); - // make the path absolute + // set up the directory to use for making the path absolute later if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) ) { if ( cwd.empty() ) @@ -900,20 +1142,6 @@ bool wxFileName::Normalize(int flags, { 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 ( !m_relative ) - { - // yes, it was the case - we don't need curDir then - curDir.Clear(); - } - } } // handle ~ stuff under Unix only @@ -924,8 +1152,18 @@ bool wxFileName::Normalize(int flags, 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); } } @@ -934,14 +1172,34 @@ bool wxFileName::Normalize(int flags, // 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() ) { - dirsNew.Add(dirs[n]); + SetVolume(curDir.GetVolume()); + + if ( !m_relative ) + { + // 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 @@ -1007,11 +1265,6 @@ bool wxFileName::Normalize(int flags, m_ext.MakeLower(); } - // we do have the path now - // - // NB: need to do this before (maybe) calling Assign() below - m_relative = false; - #if defined(__WIN32__) if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) ) { @@ -1046,7 +1299,9 @@ bool wxFileName::Normalize(int flags, #include #endif -bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, wxString& targetFilename, wxString* arguments) +bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, + wxString& targetFilename, + wxString* arguments) { wxString path, file, ext; wxSplitPath(shortcutPath, & path, & file, & ext); @@ -1075,6 +1330,8 @@ bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, wxString& targe MAX_PATH); hres = ppf->Load(wsz, 0); + ppf->Release(); + if (SUCCEEDED(hres)) { wxChar buf[2048]; @@ -1095,11 +1352,13 @@ bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, wxString& targe } } } + + psl->Release(); } - psl->Release(); return success; } -#endif + +#endif // __WIN32__ && !__WXWINCE__ // ---------------------------------------------------------------------------- @@ -1243,8 +1502,11 @@ wxString wxFileName::GetForbiddenChars(wxPathFormat format) } /* 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) || @@ -1255,6 +1517,7 @@ wxString wxFileName::GetVolumeSeparator(wxPathFormat format) //else: leave empty return sepVol; +#endif } /* static */ @@ -1502,27 +1765,26 @@ wxString wxFileName::GetFullPath( wxPathFormat format ) 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__) && !defined(__WXWINCE__) wxString path(GetFullPath()); - wxString pathOut; + +#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) DWORD sz = ::GetShortPathName(path, NULL, 0); - bool ok = sz != 0; - if ( ok ) + if ( sz != 0 ) { - ok = ::GetShortPathName + wxString pathOut; + if ( ::GetShortPathName ( path, wxStringBuffer(pathOut, sz), sz - ) != 0; + ) != 0 ) + { + return pathOut; + } } - if (ok) - return pathOut; +#endif // Windows return path; -#else - return GetFullPath(); -#endif } // Return the long form of the path (returns identity on non-Windows platforms) @@ -1532,116 +1794,115 @@ wxString wxFileName::GetLongPath() const path = GetFullPath(); #if defined(__WIN32__) && !defined(__WXMICROWIN__) - bool success = false; #if wxUSE_DYNAMIC_LOADER typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD); - static bool s_triedToLoad = false; - - 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 ) { - // suppress the errors about missing GetLongPathName[AW] - wxLogNull noLog; + static bool s_triedToLoad = false; - s_triedToLoad = true; - wxDynamicLibrary dllKernel(_T("kernel32")); - if ( dllKernel.IsLoaded() ) + 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) dllKernel.GetSymbol(_T("GetLongPathNameW")); -#else - s_pfnGetLongPathName = (GET_LONG_PATH_NAME) dllKernel.GetSymbol(_T("GetLongPathNameA")); -#endif + s_triedToLoad = true; - if ( s_pfnGetLongPathName ) - { - DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0); - bool ok = dwSize > 0; + wxDynamicLibrary dllKernel(_T("kernel32")); - if ( ok ) - { - DWORD sz = (*s_pfnGetLongPathName)(path, NULL, 0); - ok = sz != 0; - if ( ok ) - { - ok = (*s_pfnGetLongPathName) - ( - path, - wxStringBuffer(pathOut, sz), - sz - ) != 0; - success = true; - } - } + const wxChar* GetLongPathName = _T("GetLongPathName") +#if wxUSE_UNICODE + _T("W"); +#else // ANSI + _T("A"); +#endif // Unicode/ANSI + + if ( dllKernel.HasSymbol(GetLongPathName) ) + { + s_pfnGetLongPathName = (GET_LONG_PATH_NAME) + dllKernel.GetSymbol(GetLongPathName); } + + // 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 (success) - return pathOut; + if ( s_pfnGetLongPathName ) + { + DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0); + if ( dwSize > 0 ) + { + if ( (*s_pfnGetLongPathName) + ( + path, + wxStringBuffer(pathOut, dwSize), + dwSize + ) != 0 ) + { + return pathOut; + } + } + } #endif // wxUSE_DYNAMIC_LOADER - 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; + if ( HasVolume() ) + pathOut = GetVolume() + + GetVolumeSeparator(wxPATH_DOS) + + GetPathSeparator(wxPATH_DOS); + else + pathOut = wxEmptyString; - wxArrayString dirs = GetDirs(); - dirs.Add(GetFullName()); + wxArrayString dirs = GetDirs(); + dirs.Add(GetFullName()); - wxString tmpPath; + wxString tmpPath; - size_t count = dirs.GetCount(); - for ( size_t i = 0; i < count; 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 + dirs[i]; + size_t count = dirs.GetCount(); + for ( size_t i = 0; i < count; 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 + dirs[i]; - if ( tmpPath.empty() ) - continue; + if ( tmpPath.empty() ) + continue; - // can't see this being necessary? MF - if ( tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) ) - { - // Can't pass a drive and root dir to FindFirstFile, - // so continue to next dir - tmpPath += wxFILE_SEP_PATH; - pathOut = tmpPath; - continue; - } + // can't see this being necessary? MF + if ( tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) ) + { + // Can't pass a drive and root dir to FindFirstFile, + // so continue to next dir + tmpPath += wxFILE_SEP_PATH; + pathOut = tmpPath; + continue; + } - hFind = ::FindFirstFile(tmpPath, &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: most likely reason is that path doesn't exist, so + // append any unprocessed parts and return + for ( i += 1; i < count; i++ ) + tmpPath += wxFILE_SEP_PATH + dirs[i]; - return tmpPath; - } + 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; @@ -1896,6 +2157,8 @@ bool wxFileName::SetTimes(const wxDateTime *dtAccess, } } #elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) + wxUnusedVar(dtCreate); + if ( !dtAccess && !dtMod ) { // can't modify the creation time anyhow, don't try @@ -1912,6 +2175,9 @@ bool wxFileName::SetTimes(const wxDateTime *dtAccess, return true; } #else // other platform + wxUnusedVar(dtAccess); + wxUnusedVar(dtMod); + wxUnusedVar(dtCreate); #endif // platforms wxLogSysError(_("Failed to modify file times for '%s'"), @@ -1950,7 +2216,7 @@ bool wxFileName::GetTimes(wxDateTime *dtAccess, // not 9x bool ok; FILETIME ftAccess, ftCreate, ftWrite; - if ( IsDir() ) + if ( DirExists() ) // Don't use IsDir, because it returns false even if it's a directory { // implemented in msw/dir.cpp extern bool wxGetDirectoryTimes(const wxString& dirname, @@ -1988,7 +2254,7 @@ bool wxFileName::GetTimes(wxDateTime *dtAccess, return true; } -#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || (defined(__DOS__) && defined(__WATCOMC__)) +#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__)) wxStructStat stBuf; if ( wxStat( GetFullPath().c_str(), &stBuf) == 0 ) { @@ -2002,6 +2268,9 @@ bool wxFileName::GetTimes(wxDateTime *dtAccess, return true; } #else // other platform + wxUnusedVar(dtAccess); + wxUnusedVar(dtMod); + wxUnusedVar(dtCreate); #endif // platforms wxLogSysError(_("Failed to retrieve file times for '%s'"), @@ -2012,6 +2281,87 @@ bool wxFileName::GetTimes(wxDateTime *dtAccess, #endif // wxUSE_DATETIME + +// ---------------------------------------------------------------------------- +// file size functions +// ---------------------------------------------------------------------------- + +/* static */ +wxULongLong wxFileName::GetSize(const wxString &filename) +{ + if (!wxFileExists(filename)) + return wxInvalidSize; + +#if defined(__WXPALMOS__) + // TODO + return wxInvalidSize; +#elif defined(__WIN32__) + wxFileHandle f(filename, wxFileHandle::Read); + if (!f.IsOk()) + return wxInvalidSize; + + DWORD lpFileSizeHigh; + DWORD ret = GetFileSize(f, &lpFileSizeHigh); + if (ret == INVALID_FILE_SIZE) + return wxInvalidSize; + + // compose the low-order and high-order byte sizes + return wxULongLong(ret | (lpFileSizeHigh << sizeof(WORD)*2)); + +#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); +} + + +// ---------------------------------------------------------------------------- +// Mac-specific functions +// ---------------------------------------------------------------------------- + #ifdef __WXMAC__ const short kMacExtensionMaxLength = 16 ; @@ -2041,7 +2391,6 @@ public : OSType m_creator ; } ; -#include "wx/dynarray.h" WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray) ; bool gMacDefaultExtensionsInited = false ;