X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/85b1997c095b18cd5e9e54e9d39feaa71c5ffa06..b2edb8f3c524f302b727386bb0a694c44fb57e7d:/src/common/filename.cpp diff --git a/src/common/filename.cpp b/src/common/filename.cpp index 49c5ed0f57..8fa76ef7bf 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 @@ -296,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 ) { @@ -326,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 // ============================================================================ @@ -594,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__ } @@ -620,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); } @@ -656,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__ @@ -1810,6 +1839,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 // ---------------------------------------------------------------------------- @@ -2194,9 +2235,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 = @@ -2526,7 +2584,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); @@ -2580,11 +2638,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 @@ -2593,27 +2647,53 @@ 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; + wxString biInfix; + + switch ( conv ) + { + case wxSIZE_CONV_IEC: + biInfix = "i"; + // fall through + + case wxSIZE_CONV_TRADIONAL: + multiplier = 1024.; + 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 @@ -2621,9 +2701,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