//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1995, 1996 by Borland International, All Rights Reserved
//
/// \file
/// TFileName class implementation.
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/filename.h>
#include <owl/private/memory.h>
#include <owl/commdial.h>
namespace owl {
#define WIN95_LONGFILENAME_MAX 260
static tchar serverNamePrefix[] = _T("\\\\");
const int serverNamePrefixLen = sizeof serverNamePrefix / sizeof(tchar) - 1;
// static tchar devTerminator[] = "\\/:";
static tchar ldevTerminatorCh = _T(':');
static tchar ldevTerminatorStr[] = _T(":");
#if defined(UNIX)
static tchar dirSeparator[] = _T("/");
// static tchar dirSeparatorCh = _T('/');
static tchar dirSeparatorStr[] = _T("/");
#else
static tchar dirSeparator[] = _T("\\/");
// static tchar dirSeparatorCh = _T('\\');
static tchar dirSeparatorStr[] = _T("\\");
#endif //if UNIX
static tchar extSeparatorCh = _T('.');
static tchar extSeparatorStr[] = _T(".");
//
// Some Win32 APIs that are available under Win16 via DOS calls
//
//
// overloaded functions to perform string scanning
//
static const tchar* fn_strend(const tchar* str)
{
while (*str)
str++;
return str;
}
static const tchar* fn_find(const tchar* start, const tchar* end, int match)
{
while (start != end && *start != match)
start++;
return start;
}
static const tchar* fn_find(const tchar* start, const tchar* end, const tchar* set)
{
const tchar* setend = set + ::_tcslen(set);
while (start != end && fn_find(set, setend, *start) == setend)
start++;
return start;
}
static const tchar* fn_findl(const tchar* start, const tchar* end, int match)
{
while (start != end && *start != match)
start--;
return start;
}
static const tchar* fn_findl(const tchar* start, const tchar* end, const tchar* set)
{
const tchar* setend = set + ::_tcslen(set);
while (start != end && fn_find(set, setend, *start) == setend)
start--;
return start;
}
static const tchar* fn_skipstr(const tchar* start, const tchar* end,
const tchar* skip)
{
while (start != end && *skip && *start == *skip)
start++, skip++;
return start;
/*
// TODO: Verify this does not break anything -jhh
if ((start[0] == '\\') && (start[1] == '\\'))
return &start[2];
else
return start;
//jhh while (*skip && *start == *skip && start != end)
//jhh start++, skip++;
//jhh
//jhh return start;
*/
}
//-----
// Low level helper functions for parsing filename parts
//
//
//
//
static
tstring __formServer(const tchar* serverName)
{
if (!serverName)
return serverName;
const tchar* serverNameEnd = fn_strend(serverName);
if (_tcsncmp(serverName, serverNamePrefix, serverNamePrefixLen) == 0)
serverName += serverNamePrefixLen; // skip "\\"
const tchar* ds = fn_find(serverName, serverNameEnd, dirSeparator);
return tstring(serverName, 0, (int)(ds - serverName));
}
//
//
//
static
tstring __formDevice(const tchar* deviceName, bool isUNC)
{
if (!deviceName)
return deviceName;
const tchar* deviceNameEnd = fn_strend(deviceName);
if (isUNC)
deviceNameEnd = fn_find(deviceName, deviceNameEnd, dirSeparator);
else
deviceNameEnd = fn_find(deviceName, deviceNameEnd, ldevTerminatorCh);
return tstring(deviceName, 0, (int)(deviceNameEnd - deviceName));
}
//
// Return a well formed path from any kind of filename part. A lone name
// is assumed to be just the path
//
static
tstring __formPath(const tchar* path)
{
if (!path)
return path;
const tchar* pathEnd = fn_strend(path);
// Find the start of the path, skipping logical device or server+share
//
const tchar* dvs = fn_find(path, pathEnd, ldevTerminatorCh);
if (dvs < pathEnd) {
path = dvs + 1; // skip logical device
}
return tstring(path, 0, (int)(pathEnd - path));
}
//
// Return a well formed file from any kind of filename part. A lone name
// is assumed to be just the file
//
// "dir.x\file.ext" -> "file"
// "dir.x\" -> ""
// "file" -> "file"
//
static
tstring __formFile(const tchar* file)
{
if (!file)
return file;
const tchar* fileEnd = fn_strend(file);
const tchar* ds = fn_findl(fileEnd-1, file-1, dirSeparator);
if (ds >= file)
file = ds + 1;
const tchar* es = fn_findl(fileEnd-1, file-1, extSeparatorCh);
if (es >= file)
fileEnd = es;
return tstring(file, 0, (int)(fileEnd - file));
}
//
// Return a well formed extension from any kind of filename part. A lone name
// is assumed to be just the extension and a '.' is prepended
//
// "dir.x\file.ext" -> ".ext"
// "dir.x\" -> "."
// "ext" -> ".ext"
//
static
tstring __formExt(const tchar* ext)
{
if (!ext)
return ext; // or extSeparatorCh?
const tchar* extEnd = fn_strend(ext);
const tchar* ds = fn_findl(extEnd-1, ext-1, dirSeparator);
if (ds >= ext)
ext = ds + 1;
const tchar* es = fn_findl(extEnd-1, ext-1, extSeparatorCh);
if (es >= ext)
return es;
return tstring(extSeparatorStr) + ext;
}
//
/// Constructs an empty filename.
//
TFileName::TFileName()
{
}
//
/// Constructs a filename from another filename.
//
TFileName::TFileName(const TFileName& src)
:
Unc(src.Unc),
ServerStr(src.ServerStr),
DeviceStr(src.DeviceStr),
PathStr(src.PathStr),
FileStr(src.FileStr),
ExtStr(src.ExtStr)
{
FormCanonicalName();
}
//
/// Constructs a filename from its parts. Use 0 to skip any of the parameters.
/// The form is:
/// \code
/// filename := [[servername]devicename][path][file[ext]]
/// \endcode
/// where:
/// \code
/// servername := \\multiname\ //
/// devicename := name(: | \ | :\)
/// sharename := name
/// logicaldevice := name
///
/// path := multiname\[...]
/// file := multiname
/// ext := [.[name]]
///
/// name := (filecharset)[...]
/// multiname := (filecharset | .)[...]
/// \endcode
TFileName::TFileName(LPCTSTR serverName, LPCTSTR deviceName, LPCTSTR path,
LPCTSTR file, LPCTSTR ext)
{
ServerStr = __formServer(serverName);
Unc = serverName != 0;
DeviceStr = __formDevice(deviceName, Unc);
PathStr += __formPath(path);
FileStr += __formFile(file);
ExtStr += __formExt(ext);
FormCanonicalName();
}
//
/// Parses the freeform string into the filename parts.
//
void
TFileName::Parse(LPCTSTR freeform, bool pathOnly)
{
const tchar* nextp;
const tchar* freeformEnd = fn_strend(freeform);
if (*freeform == '\0')
{
Unc = false;
ServerStr = _T("");
DeviceStr = _T("");
ExtStr = _T("");
PathStr = _T("");
FileStr = _T("");
FormCanonicalName();
return;
}
// Parse from the left, the server name and device if UNC "\\", or the
// logical device name if one.
//
nextp = fn_skipstr(freeform, freeformEnd, serverNamePrefix);
if (nextp >= freeform+serverNamePrefixLen) {
Unc = true;
freeform = nextp; // skip "\\"
nextp = fn_find(freeform, freeformEnd, dirSeparator);
ServerStr = tstring(freeform, 0, (int)(nextp-freeform));
freeform = nextp + 1; // skip past "\"
nextp = fn_find(freeform, freeformEnd, dirSeparator);
DeviceStr = tstring(freeform, 0, (int)(nextp-freeform));
freeform = nextp + 1; // skip past "\"
}
else {
Unc = false;
ServerStr = _T("");
nextp = fn_find(freeform, freeformEnd, ldevTerminatorCh);
if (nextp != freeformEnd) {
DeviceStr = tstring(freeform, 0, (int)(nextp-freeform));
freeform = nextp + 1; // skip past "\/:"
}
else
DeviceStr = _T("");
}
if (!pathOnly){
// Parse the extension and filename from the right.
//
nextp = fn_findl(freeformEnd-1, freeform-1, extSeparatorCh);
//DLN freeform is just before first char in string, so boundschecker will
// report an erroneous error here
const tchar* dirp = fn_findl(freeformEnd-1, freeform-1, dirSeparator);
if (nextp > dirp) {
ExtStr = tstring(nextp, 0, (int)(freeformEnd-nextp));
freeformEnd = nextp;
}
else
ExtStr = _T("");
FileStr = tstring(dirp+1, 0, (int)(freeformEnd - (dirp+1)));
freeformEnd = dirp;
}
else{
FileStr = _T("");
ExtStr = _T("");
}
// What is left is the path
//
if (freeformEnd > freeform)
PathStr = tstring(freeform, 0, (int)(freeformEnd-freeform));
else
PathStr = _T("");
FormCanonicalName();
}
//
/// Construct a filename given the full path in any form
//
TFileName::TFileName(LPCTSTR freeform, bool pathOnly)
{
Parse(freeform,pathOnly);
}
//
/// Construct a filename given the full path in any form
//
TFileName::TFileName(const tstring& freeform, bool pathOnly)
{
Parse(freeform.c_str(),pathOnly);
}
//
/// Construct a filename representing a special file or directory. The parameter
/// type can be specified from TSpecialType.
/// \todo Looks like not all the types are implemented or work correctly. Need to research.
///
//
TFileName::TFileName(TFileName::TSpecialType type)
{
switch (type) {
case TempFile:
case TempDir: {
int tmpLen = ::GetTempPath(0,0);
TTmpBuffer<tchar> __clnObj(tmpLen);
tchar* tmpPath = __clnObj;
::GetTempPath(tmpLen, tmpPath);
if (type == TempDir) {
//_tcscat(tmpPath,dirSeparatorStr); // !BUG: Writes past EOB. Also, path already has trailing backslash. [VH]
Parse(tmpPath,true);
}
else {
TTmpBuffer<tchar> tmpFile(WIN95_LONGFILENAME_MAX);
::GetTempFileName((tchar*)tmpPath, _T("TFN"), 0, tmpFile);
Parse((tchar*)tmpFile);
}
}
break;
case CurrentDir: {
TTmpBuffer<tchar> buffer(WIN95_LONGFILENAME_MAX);
::GetCurrentDirectory(WIN95_LONGFILENAME_MAX, (tchar*)buffer);
_tcscat((tchar*)buffer, dirSeparatorStr);
Parse((tchar*)buffer,true);
}
break;
case HomeDir: {
TTmpBuffer<tchar> buffer(WIN95_LONGFILENAME_MAX);
::GetWindowsDirectory((tchar*)buffer, WIN95_LONGFILENAME_MAX);
_tcscat((tchar*)buffer,dirSeparatorStr);
Parse((tchar*)buffer,true);
}
break;
case BootDir:{
LPCTSTR path = _tgetenv(_T("wonbootdir"));
if(path)
Parse(path,true);
break;
}
case MachineDir:
// !Y.B ??????????????
case SharedDir:
// !Y.B ??????????????
break;
case SysDir: {
tchar tmp[WIN95_LONGFILENAME_MAX];
::GetSystemDirectory(tmp, WIN95_LONGFILENAME_MAX);
_tcscat(tmp,dirSeparatorStr);
Parse(tmp,true);
}
break;
case ComputerName: {
tchar tmp[WIN95_LONGFILENAME_MAX];
DWORD size = WIN95_LONGFILENAME_MAX;
::GetComputerName(tmp, &size);
Parse(tmp);
}
break;
}
}
//
/// Assigns new filename or freeform to this name.
//
TFileName&
TFileName::operator =(const TFileName& src)
{
Unc = src.Unc;
ServerStr = src.ServerStr;
DeviceStr = src.DeviceStr;
PathStr = src.PathStr;
FileStr = src.FileStr;
ExtStr = src.ExtStr;
FormCanonicalName();
return *this;
}
//
//
//
// JJH this function is not used
//static void
//ForceFullPath(string& canonical)
//{
// if (canonical != "")
// {
// tchar buffer[WIN95_LONGFILENAME_MAX];
// ::GetFullPathName(canonical.c_str(), WIN95_LONGFILENAME_MAX, buffer, 0);
// canonical = buffer;
// }
//}
tchar* TFileName::GetFullFileName()
{
return (tchar*)CanonicalStr();
}
//
// Reassemble the filename parts into a canonical form & expand any relative
// dirs
//
//string TFileName::Canonical(bool forceUNC) const
void TFileName::FormCanonicalName()
{
// if (forceUNC)
// {
// strcpy(NameBuffer,serverNamePrefix);
// strcat(NameBuffer,DeviceStr);
// strcat(NameBuffer, dirSeparatorStr);
// strcat(NameBuffer,PathStr);
// strcat(NameBuffer,dirSeparatorStr);
// strcat(NameBuffer,FileStr);
// strcat(NameBuffer,ExtStr);
// else
GetParts(Server|Device|Path|File|Ext); //fills NameBuffer
if (_tcscmp(NameBuffer,_T(""))) //if file name is not blank
{ // use it to get official file name
tchar buffer[WIN95_LONGFILENAME_MAX];
::GetFullPathName(NameBuffer, WIN95_LONGFILENAME_MAX, buffer, 0);
FullCanonicalName = buffer;
}
else
FullCanonicalName = NameBuffer;
// return NameBuffer;
}
/// Return normal fully qualified path string. Convert a possibly logical drive based
/// name to a UNC name if indicated.
const tstring& TFileName::Canonical(bool) const
{
return FullCanonicalName;
}
tchar* TFileName::GetNameNoExt()
{
return (tchar*)GetParts(File);
}
tchar* TFileName::GetNameAndExt() const
{
return (tchar*)GetParts(File|Ext);
}
tchar* TFileName::GetFullFileNameNoExt()
{
return (tchar*)GetParts(Server|Device|Path|File); //fills NameBuffer
}
//
/// Returns the short file path. Convert a possibly logical drive based name to a
/// UNC name if indicated.
//
const tchar*
TFileName::ShortName(bool forceUNC) const
{
tchar tmp[WIN95_LONGFILENAME_MAX];
::GetShortPathName(CanonicalStr(forceUNC), tmp, WIN95_LONGFILENAME_MAX);
_tcscpy(NameBuffer,tmp);
return (tchar*)NameBuffer;
}
//
/// The Title member function uses system conventions to get a human-readable
/// rendering of the filename appropriate for use in titles.
/// \note Returns null string for directory names or malformed names. For
/// directories, try Canonical() instead.
//
const tchar* TFileName::Title() const
{
tstring canonical = Canonical();
tchar tmp[WIN95_LONGFILENAME_MAX];
if (GetFileTitle(canonical.c_str(), tmp, COUNTOF(tmp)) == 0)
_tcscpy(NameBuffer,tmp);
else
NameBuffer[0] = _T('\0');
return (tchar*)NameBuffer;
}
//
// input filemame.ext
// output file...
//
static tstring& trimmStr(tstring& s, uint len)
{
if(s.length() < len)
return s;
s.erase(len-3);
s += _T("...");
return s;
}
//
// input ProgrammFiles\Common File\New Files\Short
// output ProgrammFiles\...\Short
//
static tstring& trimPath(tstring& s, uint len)
{
if(s.length() < len)
return s;
const tchar* addPath = _T("\\...");
// find ?
// 1. get last path path1\path2\path3 -> \path3
tstring subpath = s;
const auto pos = subpath.find_last_of(dirSeparatorStr);
if (pos == subpath.npos || len <= 5)
{
s = addPath;
return s;
}
tstring lastpath = subpath.substr(pos);
subpath.erase(pos);
// calculate minimum path length include "\\..."
int length = static_cast<int>(len - 4 - lastpath.length());
while(length < 0 && lastpath.length() > 0){
lastpath = lastpath.substr(1); //Remove the first character
length = static_cast<int>(len - 4 - lastpath.length());
}
uint iteration = 0;
// while remainig string greater then our length
while(static_cast<int>(subpath.length()) > length && subpath.length() > 0){
const auto pos = subpath.find_last_of(dirSeparatorStr);
if (pos != subpath.npos)
subpath.erase(pos);
else
subpath = _T("");
iteration++;
}
// if was only one path1 -> lastpath => path1, and subpath => 0
if(iteration){
s = subpath;
s += addPath;
s += lastpath;
}
else if(s.length() > len){
s = subpath;
s += addPath;
}
return s;
}
//
static tstring getAttempt(const TFileName& This, const tstring& name,
int index)
{
uint parts[] = {
TFileName::Server | TFileName::Device | TFileName::Path, // Whole thing
TFileName::Server | TFileName::Device,
TFileName::File | TFileName::Ext,
};
tstring attempt = This.GetParts(parts[index]);
if(!attempt.empty()){
tchar lastCh = attempt.c_str()[attempt.length()-1];
if(lastCh != _T('\\') && lastCh != _T('/'))
attempt += dirSeparatorStr;
}
attempt += name;
return attempt;
}
//
/// Obtains a human-readable form of the filename. The name length is at most maxLen
/// characters.
/// \code
/// lpszCanon = C:\MYAPP\DEBUGS\C\TESWIN.C
///
/// maxLen b Result
/// ------ - ---------
/// 1-3 F <empty>
/// 4 F T...
/// 5 F TE...
/// 6 F TES...
/// 7 F TESW...
/// 4- 7 T TESWIN.C
/// 8-14 x TESWIN.C
/// 15-16 x C:\...\TESWIN.C
/// 17-23 x C:\MYAPP\...\TESWIN.C
/// 24-25 x C:\MYAPP\...\C\TESWIN.C
/// 26+ x C:\MYAPP\DEBUGS\C\TESWIN.C
/// \endcode
//
const tchar* TFileName::Squeezed(int maxLen, bool keepName) const
{
if (maxLen <= 3)
return _T("");
const uint n = static_cast<uint>(maxLen);
tstring fname = Title();
tstring attempt = getAttempt(*this, fname, 0); // full path
// If maxLen is not enough to hold the full path name, then trim.
// If maxLen is enough to hold at least the basename, and enough
// to hold at least server/device and "...\", trim the path,
// otherwise trim (or keep) only the basename.
if (n < attempt.length())
{
const tstring dname = getAttempt(*this, fname, 1); // server-device/name
if (n > dname.length() + 3)
{
tstring p = PathStr;
trimPath(p, n - static_cast<int>(dname.length()));
if (p.length() > 0 && p[p.length() - 1] != dirSeparatorStr[0])
p += dirSeparatorStr;
attempt = GetParts(Server | Device) + p + fname;
}
else
{
attempt = keepName ? fname : trimmStr(fname, n);
}
}
CHECK(attempt.length() < _MAX_PATH - 1);
_tcscpy(NameBuffer,attempt.c_str());
return NameBuffer;
}
//
/// Determines whether a filename is valid.
//
bool
TFileName::IsValid() const
{
OFSTRUCT ofs;
ofs.cBytes = sizeof ofs;
_USES_CONVERSION;
return ::OpenFile(_W2A(CanonicalStr()), &ofs, OF_PARSE) != -1;
}
//
/// Determines whether the device, directory, or file exists.
//
bool
TFileName::Exists() const
{
#if 0
OFSTRUCT ofs;
ofs.cBytes = sizeof ofs;
_USES_CONVERSION;
return ::OpenFile(_W2A(Canonical().c_str()), &ofs, OF_EXIST) != -1;
#else
HANDLE h;
{
WIN32_FIND_DATA data;
h = ::FindFirstFile(CanonicalStr(), &data);
::FindClose(h);
}
return (h != INVALID_HANDLE_VALUE);
#endif
}
//
/// Reassembles any logical subset of filename parts. More than one part can be
/// checked for by bitwise oring in the parameter p. See TFileName::TPart.
//
const tchar*
TFileName::GetParts(uint p) const
{
*NameBuffer = 0; //JRB This crashes GWANGI
if (Unc)
{
if (p & Server)
{
_tcscat(NameBuffer,serverNamePrefix);
_tcscat(NameBuffer,ServerStr.c_str());
if (p & Device)
_tcscat(NameBuffer,dirSeparatorStr);
}
if ((p & Device) && DeviceStr.length() > 0) {
_tcscat(NameBuffer, DeviceStr.c_str());
if ((p & Path) || (p & File))
_tcscat(NameBuffer, dirSeparatorStr);
}
}
else
{
if ((p & Device) && DeviceStr.length() > 0) {
_tcscat(NameBuffer, DeviceStr.c_str());
_tcscat(NameBuffer, ldevTerminatorStr);
if ((p & Path) && PathStr.length() == 0) {
_tcscat(NameBuffer, dirSeparatorStr);
}
}
}
if ((p & Path) && PathStr.length() > 0)
{
_tcscat(NameBuffer,PathStr.c_str());
_tcscat(NameBuffer, dirSeparatorStr);
}
if ((p & File) && FileStr.length() > 0)
_tcscat(NameBuffer, FileStr.c_str());
if ((p & Ext) && ExtStr.length() > 0)
_tcscat(NameBuffer, ExtStr.c_str());
return (tchar*)NameBuffer;
}
//
/// Returns true if any of the parts specified by p are used. More than one part can
/// be checked for by bitwise oring in the parameter p. See TFileName::TPart.
//
bool
TFileName::HasParts(uint p) const
{
bool has = false;
if (p & Server)
has |= (ServerStr.length() > 0);
if (p & Device)
has |= (DeviceStr.length() > 0);
if (p & Path)
has |= (PathStr.length() > 0);
if (p & File)
has |= (FileStr.length() > 0);
if (p & Ext)
has |= (ExtStr.length() > 0);
return has;
}
//
/// Replaces the specified filename parts with parts extracted from partStr. More
/// than one part can be checked for by bitwise oring in the parameter p. See TFileName::TPart.
//
TFileName&
TFileName::SetPart(uint p, const tstring& partStr)
{
if (p & Server)
ServerStr = partStr;
if (p & Device)
DeviceStr = partStr;
if (p & Path)
PathStr = partStr;
if (p & File)
FileStr = partStr;
if (p & Ext)
ExtStr = partStr;
FormCanonicalName();
return *this;
}
//
/// Replaces the specified parts in this with the parts from source. More than one
/// part can be merged by bitwise oring in the parameter p. See TFileName::TPart.
//
TFileName&
TFileName::MergeParts(uint p, const TFileName& source)
{
// Walk thru bits & SetPart(p) from source.GetParts(p)
//
if (p & Server)
ServerStr = source.ServerStr;//source.GetParts(Server);
if (p & Device)
DeviceStr = source.DeviceStr;//source.GetParts(Device);
if (p & Path)
PathStr = source.PathStr;//source.GetParts(Path);
if (p & File)
FileStr = source.FileStr;//source.GetParts(File);
if (p & Ext)
ExtStr = source.ExtStr;//source.GetParts(Ext);
FormCanonicalName(); // BUGFIX: FullCanonicalName wasn't updated! (VH, 2005-07-26)
return *this;
}
//
/// Removes the specified filename parts from this set of parts. More than one part
/// can be checked for by bitwise oring in the parameter p. See TFileName::TPart.
//
TFileName&
TFileName::StripParts(uint p)
{
if (p & Server)
ServerStr = _T("");
if (p & Device)
DeviceStr = _T("");
if (p & Path)
PathStr = _T("");
if (p & File)
FileStr = _T("");
if (p & Ext)
ExtStr = _T("");
FormCanonicalName(); // BUGFIX: FullCanonicalName wasn't updated! (VH, 2005-07-26)
return *this;
}
//
/// Deletes this file associated with this name if possible; otherwise attempts to
/// delete the directory associated with this name (which must be empty).
//
bool
TFileName::Remove() const
{
if (!::DeleteFile(CanonicalStr()))
if(!::RemoveDirectory(CanonicalStr()))
return false;
return true;
}
//
/// Move (rename) the file associated with this filename, and change this name to
/// the new name.
///
/// Under WinNT how is used to specifie how the file is to be copied:
/// - ReplaceExisting = 1
/// - CopyAllowed = 2
/// - DelayUntilReboot = 4
//
bool
TFileName::Move(const TFileName& newName, uint32 how)
{
bool retval = ::MoveFileEx(CanonicalStr(), newName.CanonicalStr(), how);
if(retval){
*this = newName;
return true;
}
return false;
}
//
/// Copy the file associated with this filename to a new file. If failIfExists is
/// true, the copy will not take place if a file newName already exists.
//
bool
TFileName::Copy(const TFileName& newName, bool failIfExists) const
{
return ::CopyFile(CanonicalStr(), newName.CanonicalStr(), failIfExists) != FALSE;
}
//
/// Creates the directory associated with this filename.
///
/// Returns a non-zero value on success. Call LastError for extended information.
//
int
TFileName::CreateDir() const
{
return ::CreateDirectory(CanonicalStr(), 0) != FALSE; //LPSECURITY_ATTRIBUTES
}
//
/// Changes the current directory to the directory associated with this filename.
///
/// Returns a non-zero value on success. Call LastError for extended information.
//
int
TFileName::ChangeDir() const
{
return ::SetCurrentDirectory(CanonicalStr()) != FALSE;
}
TFileName&
TFileName::AddSubDir(const tstring& subdir)
{
if (_tcschr(dirSeparator, subdir[0]) == 0) // The subdir does not begin with the separator
PathStr += dirSeparatorStr;
PathStr += subdir;
if (_tcschr(dirSeparator, PathStr[PathStr.length() - 1]) != 0) // The resultring string ends with the separator
PathStr = PathStr.substr(0, PathStr.length() - 1);
FormCanonicalName();
return *this;
}
///////////////////////
// struct __TFindFileStr
// ~~~~~~ ~~~~~~~~~~~~~~
//
/// \cond
struct __TFindFileStr{
HANDLE Handle;
WIN32_FIND_DATA Data;
tstring Direct;
};
/// \endcond
TTime __MakeTTime(uint16 fdt, uint16 ftm);
void __MakeDosTime(const TTime& ctm, uint16& fdm, uint16& ftm);
uint __sys2Atr(uint32 attrib);
uint __attr2Sys( uint attrib);
static
void __FillFileStr( __TFindFileStr& data, TFileStatus& status);
static
void __FillFileStr( __TFindFileStr& data, TFileStatus& status)
{
::_tcscpy(status.fullName, data.Data.cFileName);
status.attribute = __sys2Atr(data.Data.dwFileAttributes);
status.createTime = TTime(TFileTime(data.Data.ftCreationTime));
status.modifyTime = TTime(TFileTime(data.Data.ftLastWriteTime));
status.accessTime = TTime(TFileTime(data.Data.ftLastAccessTime));
status.size = data.Data.nFileSizeLow;
}
//
/// Get the file status struct for the item associated with this filename.
//
int TFileName::GetStatus(TFileStatus& status) const
{
tstring fileName = Canonical();
__TFindFileStr findData;
findData.Handle = ::FindFirstFile(fileName.c_str(), &findData.Data);
if(findData.Handle == INVALID_HANDLE_VALUE)
return false;
__FillFileStr(findData, status);
::_tcscpy(status.fullName, fileName.c_str());
::FindClose(findData.Handle);
return true;
}
//
/// Fills the status structure for the file associated with this filename with
/// information from status.
//
int TFileName::SetStatus(const TFileStatus& status)
{
tstring fileName = Canonical();
{
TFile File(fileName.c_str(), TFile::WriteOnly|TFile::PermExclusive|TFile::OpenExisting);
if(!File.IsOpen())
return false;
if(!File.Length(status.size))
return false;
TFileTime ftCreation(status.createTime);
TFileTime ftLastAccess(status.accessTime);
TFileTime ftLastWrite(status.modifyTime);
// will work only for TDiskFileHandle
TDiskFileHandle* handle = TYPESAFE_DOWNCAST(File.GetHandle(),TDiskFileHandle);
if(!::SetFileTime(handle->Handle, &ftCreation, &ftLastAccess, &ftLastWrite))
return false;
}
uint attr = __attr2Sys(status.attribute);
if(!::SetFileAttributes(fileName.c_str(), attr))
{
# pragma warn -ccc
WARN(1, "TFile::SetStatus() error ::SetFileAttributes(), line: " << __LINE__);
# pragma warn .ccc
return false;
}
return true;
}
//
//
/// Under Win32 a WIN32_FIND_DATA structure (the Data member) is allocated and
/// intialized. If a file is not found the Done member is set true; otherwise the
/// data structure is filled in.
///
/// wildName may contain wild card characters and a path.
//
TFileNameIterator::TFileNameIterator(const tstring& wildName)
:
Done(false)
{
__TFindFileStr* data = new __TFindFileStr;
Data = data;
tchar* p = (tchar*)_tcsrchr(wildName.c_str(),_T('\\'));
if(p){
tchar c = *p;
*p = _T('\0');
data->Direct = tstring(wildName.c_str()) + _T("\\");
*p = c;
}
data->Handle = ::FindFirstFile(wildName.c_str(), &data->Data);
if(data->Handle != INVALID_HANDLE_VALUE){
__FillFileStr( *data, Status);
}
else
Done = true;
}
//------------------------------------------------------------------------------
/// Deletes the find file Data structure.
TFileNameIterator::~TFileNameIterator()
{
if (Data && ((__TFindFileStr*)Data)->Handle != INVALID_HANDLE_VALUE)
::FindClose(((__TFindFileStr*)Data)->Handle);
delete (__TFindFileStr*)Data;
}
//------------------------------------------------------------------------------
/// Attempts to find the next file. Returns a true if found, false otherwise.
//
bool TFileNameIterator::FindNext(TFileStatus& status, void* findData)
{
__TFindFileStr& data = *(__TFindFileStr*)findData;
if (!::FindNextFile(data.Handle, &data.Data))
return false;
__FillFileStr(data, status);
return true;
}
//==============================================================================
} // OWL namespace
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(ds - serverName)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(deviceNameEnd - deviceName)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(pathEnd - path)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(fileEnd - file)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(nextp - freeform)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(nextp - freeform)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(nextp - freeform)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(freeformEnd - nextp)'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(freeformEnd - (dirp + 1))'.
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '(freeformEnd - freeform)'.
↑ V1051 Consider checking for misprints. It's possible that the 'serverNameEnd' should be used inside '_tcsncmp' function.
↑ V522 There might be dereferencing of a potential null pointer 'handle'.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: NameBuffer, Unc.
↑ V601 The 'false' value is implicitly cast to the integer type.
↑ V601 The 'true' value is implicitly cast to the integer type.
↑ V601 The 'false' value is implicitly cast to the integer type.
↑ V601 The 'false' value is implicitly cast to the integer type.
↑ V601 The 'false' value is implicitly cast to the integer type.
↑ V601 The 'false' value is implicitly cast to the integer type.
↑ V601 The 'true' value is implicitly cast to the integer type.
↑ V730 It is possible that not all members of a class are initialized inside the constructor. Consider inspecting: NameBuffer.
↑ V730 It is possible that not all members of a class are initialized inside the constructor. Consider inspecting: NameBuffer.
↑ V815 Decreased performance. Consider replacing the expression 'subpath = ""' with 'subpath.clear()'.
↑ V832 It's better to use '= default;' syntax instead of empty constructor body.
↑ V815 Decreased performance. Consider replacing the expression 'ServerStr = ""' with 'ServerStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'DeviceStr = ""' with 'DeviceStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'ExtStr = ""' with 'ExtStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'PathStr = ""' with 'PathStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'FileStr = ""' with 'FileStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'ServerStr = ""' with 'ServerStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'DeviceStr = ""' with 'DeviceStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'ExtStr = ""' with 'ExtStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'FileStr = ""' with 'FileStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'ExtStr = ""' with 'ExtStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'PathStr = ""' with 'PathStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'ServerStr = ""' with 'ServerStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'DeviceStr = ""' with 'DeviceStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'PathStr = ""' with 'PathStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'FileStr = ""' with 'FileStr.clear()'.
↑ V815 Decreased performance. Consider replacing the expression 'ExtStr = ""' with 'ExtStr.clear()'.