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
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
{
// 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 )
{
!IsDOSPathSep(path[2u]);
}
+// ----------------------------------------------------------------------------
+// private constants
+// ----------------------------------------------------------------------------
+
+// length of \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ string
+static const size_t wxMSWUniqueVolumePrefixLength = 49;
+
} // anonymous namespace
// ============================================================================
return wxFileName::FileExists( GetFullPath() );
}
-bool wxFileName::FileExists( const wxString &file )
+/* static */
+bool wxFileName::FileExists( const wxString &filePath )
{
- return ::wxFileExists( file );
+#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());
+
+ return (ret != INVALID_FILE_ATTRIBUTES) && !(ret & FILE_ATTRIBUTE_DIRECTORY);
+#else // !__WIN32__
+ #ifndef S_ISREG
+ #define S_ISREG(mode) ((mode) & S_IFREG)
+ #endif
+ wxStructStat st;
+
+ 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
+ ;
+#endif // __WIN32__/!__WIN32__
}
bool wxFileName::DirExists() const
return wxFileName::DirExists( GetPath() );
}
-bool wxFileName::DirExists( const wxString &dir )
+/* static */
+bool wxFileName::DirExists( const wxString &dirPath )
{
- return ::wxDirExists( dir );
+ wxString strPath(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:"), 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(':')) ||
+ (len == wxMSWUniqueVolumePrefixLength &&
+ wxFileName::IsMSWUniqueVolumeNamePath(strPath)))
+ {
+ break;
+ }
+
+ strPath.Truncate(len - 1);
+ }
+#endif // __WINDOWS__
+
+#ifdef __OS2__
+ // OS/2 can't handle "d:", it wants either "d:\" or "d:."
+ if (strPath.length() == 2 && strPath[1u] == wxT(':'))
+ strPath << wxT('.');
+#endif
+
+#if defined(__WXPALMOS__)
+ return false;
+#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
+ // stat() can't cope with network paths
+ DWORD ret = ::GetFileAttributes(strPath.fn_str());
+
+ return (ret != INVALID_FILE_ATTRIBUTES) && (ret & FILE_ATTRIBUTE_DIRECTORY);
+#elif defined(__OS2__)
+ FILESTATUS3 Info = {{0}};
+ APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD,
+ (void*) &Info, sizeof(FILESTATUS3));
+
+ return ((rc == NO_ERROR) && (Info.attrFile & FILE_DIRECTORY)) ||
+ (rc == ERROR_SHARING_VIOLATION);
+ // If we got a sharing violation, there must be something with this name.
+#else // !__WIN32__
+
+ wxStructStat st;
+#ifndef __VISAGECPP__
+ 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, &st) == 0 && (st.st_mode == S_IFDIR);
+#endif
+
+#endif // __WIN32__/!__WIN32__
}
// ----------------------------------------------------------------------------
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
// ----------------------------------------------------------------------------
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 =
#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);
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
/* 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
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