X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5bb596668f594b06c2b56199c5fbd2411eab5ad8..9572bf1d442006beba3528dc00c3fc05eb523c24:/src/common/filename.cpp diff --git a/src/common/filename.cpp b/src/common/filename.cpp index 130d429510..882581cded 100644 --- a/src/common/filename.cpp +++ b/src/common/filename.cpp @@ -22,7 +22,16 @@ drive:\dir1\dir2\...\dirN\filename.ext where drive is a single letter. "." and ".." as for Unix but no "~". - There are also UNC names of the form \\share\fullpath + There are also UNC names of the form \\share\fullpath and + MSW unique volume names of the form \\?\Volume{GUID}\fullpath. + + The latter provide a uniform way to access a volume regardless of + its current mount point, i.e. you can change a volume's mount + point from D: to E:, or even remove it, and still be able to + access it through its unique volume name. More on the subject can + be found in MSDN's article "Naming a Volume" that is currently at + http://msdn.microsoft.com/en-us/library/aa365248(VS.85).aspx. + wxPATH_MAC: Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file names have the form @@ -89,7 +98,7 @@ #include "wx/msw/gccpriv.h" #endif -#ifdef __WXWINCE__ +#ifdef __WXMSW__ #include "wx/msw/private.h" #endif @@ -144,6 +153,13 @@ extern const wxULongLong wxInvalidSize = (unsigned)-1; #endif // wxUSE_LONGLONG +#ifdef __WIN32__ + // this define is missing from VC6 headers + #ifndef INVALID_FILE_ATTRIBUTES + #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) + #endif +#endif // __WIN32__ + namespace { @@ -172,7 +188,7 @@ public: // access time (see #10567) m_hFile = ::CreateFile ( - filename.fn_str(), // name + filename.t_str(), // name mode == ReadAttr ? FILE_READ_ATTRIBUTES // access mask : FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | // sharing mode @@ -289,7 +305,18 @@ static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format) // 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; + // We also have to check for Windows unique volume names here and + // return it with '\\?\' prepended to it + if ( wxFileName::IsMSWUniqueVolumeNamePath("\\\\?\\" + volume + "\\", + format) ) + { + path << "\\\\?\\" << volume; + } + else + { + // it must be a UNC path + path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume; + } } else if ( format == wxPATH_DOS || format == wxPATH_VMS ) { @@ -319,6 +346,13 @@ static bool IsUNCPath(const wxString& path, wxPathFormat format) !IsDOSPathSep(path[2u]); } +// ---------------------------------------------------------------------------- +// private constants +// ---------------------------------------------------------------------------- + +// length of \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ string +static const size_t wxMSWUniqueVolumePrefixLength = 49; + } // anonymous namespace // ============================================================================ @@ -574,12 +608,12 @@ bool wxFileName::FileExists() const /* static */ bool wxFileName::FileExists( const wxString &filePath ) { - #if defined(__WXPALMOS__) +#if defined(__WXPALMOS__) return false; #elif defined(__WIN32__) && !defined(__WXMICROWIN__) // we must use GetFileAttributes() instead of the ANSI C functions because // it can cope with network (UNC) paths unlike them - DWORD ret = ::GetFileAttributes(filePath.fn_str()); + DWORD ret = ::GetFileAttributes(filePath.t_str()); return (ret != INVALID_FILE_ATTRIBUTES) && !(ret & FILE_ATTRIBUTE_DIRECTORY); #else // !__WIN32__ @@ -587,16 +621,13 @@ bool wxFileName::FileExists( const wxString &filePath ) #define S_ISREG(mode) ((mode) & S_IFREG) #endif wxStructStat st; -#ifndef wxNEED_WX_UNISTD_H - return (wxStat( filePath.fn_str() , &st) == 0 && S_ISREG(st.st_mode)) + + return (wxStat( filePath, &st) == 0 && S_ISREG(st.st_mode)) #ifdef __OS2__ || (errno == EACCES) // if access is denied something with that name // exists and is opened in exclusive mode. #endif ; -#else - return wxStat( filePath , &st) == 0 && S_ISREG(st.st_mode); -#endif #endif // __WIN32__/!__WIN32__ } @@ -613,12 +644,17 @@ bool wxFileName::DirExists( const wxString &dirPath ) #if defined(__WINDOWS__) || defined(__OS2__) // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, // so remove all trailing backslashes from the path - but don't do this for - // the paths "d:\" (which are different from "d:") nor for just "\" + // the paths "d:\" (which are different from "d:"), for just "\" or for + // windows unique volume names ("\\?\Volume{GUID}\") while ( wxEndsWithPathSeparator(strPath) ) { size_t len = strPath.length(); - if ( len == 1 || (len == 3 && strPath[len - 2] == wxT(':')) ) + if ( len == 1 || (len == 3 && strPath[len - 2] == wxT(':')) || + (len == wxMSWUniqueVolumePrefixLength && + wxFileName::IsMSWUniqueVolumeNamePath(strPath))) + { break; + } strPath.Truncate(len - 1); } @@ -634,7 +670,7 @@ bool wxFileName::DirExists( const wxString &dirPath ) return false; #elif defined(__WIN32__) && !defined(__WXMICROWIN__) // stat() can't cope with network paths - DWORD ret = ::GetFileAttributes(strPath.fn_str()); + DWORD ret = ::GetFileAttributes(strPath.t_str()); return (ret != INVALID_FILE_ATTRIBUTES) && (ret & FILE_ATTRIBUTE_DIRECTORY); #elif defined(__OS2__) @@ -649,10 +685,10 @@ bool wxFileName::DirExists( const wxString &dirPath ) wxStructStat st; #ifndef __VISAGECPP__ - return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR); + return wxStat(strPath, &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR); #else // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only - return wxStat(strPath.c_str(), &st) == 0 && (st.st_mode == S_IFDIR); + return wxStat(strPath, &st) == 0 && (st.st_mode == S_IFDIR); #endif #endif // __WIN32__/!__WIN32__ @@ -840,8 +876,8 @@ static wxString wxCreateTempImpl( } #elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) - if ( !::GetTempFileName(dir.fn_str(), name.fn_str(), 0, - wxStringBuffer(path, MAX_PATH + 1)) ) + if (!::GetTempFileName(dir.t_str(), name.t_str(), 0, + wxStringBuffer(path, MAX_PATH + 1))) { wxLogLastError(wxT("GetTempFileName")); @@ -1155,9 +1191,24 @@ wxString wxFileName::GetTempDir() wxLogLastError(wxT("GetTempPath")); } #elif defined(__WXMAC__) && wxOSX_USE_CARBON - dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder); + dir = wxMacFindFolderNoSeparator(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder); #endif // systems with native way } + else // we got directory from an environment variable + { + // remove any trailing path separators, we don't want to ever return + // them from this function for consistency + const size_t lastNonSep = dir.find_last_not_of(GetPathSeparators()); + if ( lastNonSep == wxString::npos ) + { + // the string consists entirely of separators, leave only one + dir = GetPathSeparator(); + } + else + { + dir.erase(lastNonSep + 1); + } + } // fall back to hard coded value if ( dir.empty() ) @@ -1236,7 +1287,11 @@ bool wxFileName::Rmdir(const wxString& dir, int flags) SHFILEOPSTRUCT fileop; wxZeroMemory(fileop); fileop.wFunc = FO_DELETE; + #if defined(__CYGWIN__) && defined(wxUSE_UNICODE) + fileop.pFrom = path.wc_str(); + #else fileop.pFrom = path.fn_str(); + #endif fileop.fFlags = FOF_SILENT | FOF_NOCONFIRMATION; #ifndef __WXWINCE__ // FOF_NOERRORUI is not defined in WinCE @@ -1803,6 +1858,18 @@ bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format) return ch != wxT('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND; } +/* static */ +bool +wxFileName::IsMSWUniqueVolumeNamePath(const wxString& path, wxPathFormat format) +{ + // return true if the format used is the DOS/Windows one and the string begins + // with a Windows unique volume name ("\\?\Volume{guid}\") + return format == wxPATH_DOS && + path.length() >= wxMSWUniqueVolumePrefixLength && + path.StartsWith(wxS("\\\\?\\Volume{")) && + path[wxMSWUniqueVolumePrefixLength - 1] == wxFILE_SEP_PATH_DOS; +} + // ---------------------------------------------------------------------------- // path components manipulation // ---------------------------------------------------------------------------- @@ -1995,13 +2062,13 @@ wxString wxFileName::GetShortPath() const wxString path(GetFullPath()); #if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - DWORD sz = ::GetShortPathName(path.fn_str(), NULL, 0); + DWORD sz = ::GetShortPathName(path.t_str(), NULL, 0); if ( sz != 0 ) { wxString pathOut; if ( ::GetShortPathName ( - path.fn_str(), + path.t_str(), wxStringBuffer(pathOut, sz), sz ) != 0 ) @@ -2059,12 +2126,12 @@ wxString wxFileName::GetLongPath() const if ( s_pfnGetLongPathName ) { - DWORD dwSize = (*s_pfnGetLongPathName)(path.fn_str(), NULL, 0); + DWORD dwSize = (*s_pfnGetLongPathName)(path.t_str(), NULL, 0); if ( dwSize > 0 ) { if ( (*s_pfnGetLongPathName) ( - path.fn_str(), + path.t_str(), wxStringBuffer(pathOut, dwSize), dwSize ) != 0 ) @@ -2116,7 +2183,7 @@ wxString wxFileName::GetLongPath() const continue; } - hFind = ::FindFirstFile(tmpPath.fn_str(), &findFileData); + hFind = ::FindFirstFile(tmpPath.t_str(), &findFileData); if (hFind == INVALID_HANDLE_VALUE) { // Error: most likely reason is that path doesn't exist, so @@ -2187,9 +2254,26 @@ wxFileName::SplitVolume(const wxString& fullpathWithVolume, wxString fullpath = fullpathWithVolume; - // special Windows UNC paths hack: transform \\share\path into share:path - if ( IsUNCPath(fullpath, format) ) + if ( IsMSWUniqueVolumeNamePath(fullpath, format) ) { + // special Windows unique volume names hack: transform + // \\?\Volume{guid}\path into Volume{guid}:path + // note: this check must be done before the check for UNC path + + // we know the last backslash from the unique volume name is located + // there from IsMSWUniqueVolumeNamePath + fullpath[wxMSWUniqueVolumePrefixLength - 1] = wxFILE_SEP_DSK; + + // paths starting with a unique volume name should always be absolute + fullpath.insert(wxMSWUniqueVolumePrefixLength, 1, wxFILE_SEP_PATH_DOS); + + // remove the leading "\\?\" part + fullpath.erase(0, 4); + } + else if ( IsUNCPath(fullpath, format) ) + { + // special Windows UNC paths hack: transform \\share\path into share:path + fullpath.erase(0, 2); size_t posFirstSlash = @@ -2519,7 +2603,7 @@ bool wxFileName::GetTimes(wxDateTime *dtAccess, #elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__)) // no need to test for IsDir() here wxStructStat stBuf; - if ( wxStat( GetFullPath().c_str(), &stBuf) == 0 ) + if ( wxStat( GetFullPath(), &stBuf) == 0 ) { if ( dtAccess ) dtAccess->Set(stBuf.st_atime); @@ -2573,11 +2657,7 @@ wxULongLong wxFileName::GetSize(const wxString &filename) 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 @@ -2586,27 +2666,54 @@ wxULongLong wxFileName::GetSize(const wxString &filename) /* static */ wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs, const wxString &nullsize, - int precision) + int precision, + wxSizeConvention conv) { - 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) + // deal with trivial case first + 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); + // depending on the convention used the multiplier may be either 1000 or + // 1024 and the binary infix may be empty (for "KB") or "i" (for "KiB") + double multiplier = 1024.; + wxString biInfix; + + switch ( conv ) + { + case wxSIZE_CONV_TRADITIONAL: + // nothing to do, this corresponds to the default values of both + // the multiplier and infix string + break; + + case wxSIZE_CONV_IEC: + biInfix = "i"; + break; + + case wxSIZE_CONV_SI: + multiplier = 1000; + break; + } + + const double kiloByteSize = multiplier; + const double megaByteSize = multiplier * kiloByteSize; + const double gigaByteSize = multiplier * megaByteSize; + const double teraByteSize = multiplier * gigaByteSize; + + const double bytesize = bs.ToDouble(); + + wxString result; + if ( bytesize < kiloByteSize ) + result.Printf("%s B", bs.ToString()); + else if ( bytesize < megaByteSize ) + result.Printf("%.*f K%sB", precision, bytesize/kiloByteSize, biInfix); + else if (bytesize < gigaByteSize) + result.Printf("%.*f M%sB", precision, bytesize/megaByteSize, biInfix); + else if (bytesize < teraByteSize) + result.Printf("%.*f G%sB", precision, bytesize/gigaByteSize, biInfix); + else + result.Printf("%.*f T%sB", precision, bytesize/teraByteSize, biInfix); - return wxString::Format(_("%.*f TB"), precision, bytesize/TERABYTESIZE); + return result; } wxULongLong wxFileName::GetSize() const @@ -2614,9 +2721,11 @@ wxULongLong wxFileName::GetSize() const return GetSize(GetFullPath()); } -wxString wxFileName::GetHumanReadableSize(const wxString &failmsg, int precision) const +wxString wxFileName::GetHumanReadableSize(const wxString& failmsg, + int precision, + wxSizeConvention conv) const { - return GetHumanReadableSize(GetSize(), failmsg, precision); + return GetHumanReadableSize(GetSize(), failmsg, precision, conv); } #endif // wxUSE_LONGLONG