1168 lines
31 KiB
C++
1168 lines
31 KiB
C++
// ==========================================================================
|
|
// Class Implementation : COXPathSpec
|
|
// ==========================================================================
|
|
|
|
// Source file : path.cpp
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h" // standard MFC include
|
|
#include "path.h" // class specification
|
|
#include "xstring.h" // for string-int conversion
|
|
#ifndef WIN32
|
|
#include "toolhelp.h" // To determine the module handle
|
|
#endif
|
|
|
|
#include <direct.h> // For directory functions (_fullpath, ...)
|
|
#include <dos.h> // For _dos_setfileattr, ...
|
|
#include <io.h> // For _chsize()
|
|
|
|
#include "UTBStrOp.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
IMPLEMENT_DYNAMIC(COXPathSpec, COXDirSpec)
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Definition of static members
|
|
|
|
|
|
// Data members -------------------------------------------------------------
|
|
// protected:
|
|
|
|
// private:
|
|
|
|
// Member functions ---------------------------------------------------------
|
|
// public:
|
|
|
|
COXPathSpec::COXPathSpec()
|
|
{
|
|
}
|
|
|
|
COXPathSpec::COXPathSpec(LPCTSTR pszPath)
|
|
{
|
|
if (!SetPath(pszPath))
|
|
{
|
|
TRACE(_T("COXPathSpec::COXPathSpec : An invalid path (%s) was specified, clearing object\n"),
|
|
pszPath);
|
|
SetPath(_T(""));
|
|
}
|
|
}
|
|
|
|
COXPathSpec::COXPathSpec(const COXPathSpec& pathSrc)
|
|
:
|
|
COXDirSpec(pathSrc),
|
|
COXFileSpec(pathSrc)
|
|
{
|
|
}
|
|
|
|
COXPathSpec& COXPathSpec::operator=(const COXPathSpec& pathSrc)
|
|
{
|
|
COXDirSpec::operator=(pathSrc);
|
|
COXFileSpec::operator=(pathSrc);
|
|
return *this;
|
|
}
|
|
|
|
CString COXPathSpec::GetPath() const
|
|
{
|
|
CString sDir = GetDirectory();
|
|
CString sFile = GetFileName();
|
|
CString sPath;
|
|
if (!sFile.IsEmpty())
|
|
if (!sDir.IsEmpty())
|
|
if (sDir.Right(1) != CString(_T("\\")))
|
|
// \\DIR and AAA.BBB
|
|
sPath = sDir + _T("\\") + sFile;
|
|
else
|
|
// \\ and AAA.BBB
|
|
sPath = sDir + sFile;
|
|
else
|
|
// empty and AAA.BBB
|
|
sPath = sFile;
|
|
else
|
|
// \\DIR and empty
|
|
sPath = sDir;
|
|
return sPath;;
|
|
}
|
|
|
|
BOOL COXPathSpec::SetPath(LPCTSTR pszPath)
|
|
{
|
|
TCHAR pszDrive[_MAX_DRIVE];
|
|
TCHAR pszSubdir[_MAX_DIR];
|
|
TCHAR pszBaseName[_MAX_FNAME];
|
|
TCHAR pszExtender[_MAX_EXT];
|
|
|
|
UTBStr::tsplitpath(pszPath, pszDrive, _MAX_DRIVE, pszSubdir, _MAX_DIR, pszBaseName, _MAX_FNAME, pszExtender, _MAX_EXT);
|
|
// _tsplitpath(pszPath, pszDrive, pszSubdir, pszBaseName, pszExtender);
|
|
|
|
size_t nSubDir = _tcsclen(pszSubdir);
|
|
if (1 < nSubDir)
|
|
// ... When not empty and not root, remove trailing back slash
|
|
pszSubdir[nSubDir - 1] = _T('\0');
|
|
size_t nExt = _tcsclen(pszExtender);
|
|
if (1 <= nExt)
|
|
// ... Remove leading full stop
|
|
UTBStr::tcscpy(pszExtender, _MAX_EXT, pszExtender + 1);
|
|
|
|
return SetDrive(pszDrive) && SetSubdirectory(pszSubdir) &&
|
|
SetExtender(pszExtender) && SetBaseName(pszBaseName);
|
|
}
|
|
|
|
void COXPathSpec::ForceSetPath(LPCTSTR pszPath)
|
|
{
|
|
TCHAR pszDrive[_MAX_DRIVE];
|
|
TCHAR pszSubdir[_MAX_DIR];
|
|
TCHAR pszBaseName[_MAX_FNAME];
|
|
TCHAR pszExtender[_MAX_EXT];
|
|
|
|
UTBStr::tsplitpath(pszPath, pszDrive, _MAX_DRIVE, pszSubdir, _MAX_DIR, pszBaseName, _MAX_FNAME, pszExtender, _MAX_EXT);
|
|
|
|
size_t nSubDir = _tcsclen(pszSubdir);
|
|
if (1 < nSubDir)
|
|
// ... When not empty and not root, remove trailing back slash
|
|
pszSubdir[nSubDir - 1] = '\0';
|
|
size_t nExt = _tcsclen(pszExtender);
|
|
if (1 <= nExt)
|
|
// ... Remove leading full stop
|
|
UTBStr::tcscpy(pszExtender, _MAX_EXT, pszExtender + 1);
|
|
|
|
ForceSetDrive(pszDrive);
|
|
ForceSetSubdirectory(pszSubdir);
|
|
|
|
ForceSetExtender(pszExtender);
|
|
ForceSetBaseName(pszBaseName);
|
|
}
|
|
|
|
BOOL COXPathSpec::SetPath(const COXDirSpec& dirSpec, const COXFileSpec& fileSpec)
|
|
{
|
|
COXDirSpec::operator=(dirSpec);
|
|
COXFileSpec::operator=(fileSpec);
|
|
return TRUE;
|
|
}
|
|
|
|
CString COXPathSpec::GetShortDescription()
|
|
{
|
|
// ... If path spec is empty, just return
|
|
if (GetPath().IsEmpty())
|
|
return _T("");
|
|
|
|
COXPathSpec tempPath(*this);
|
|
CString sLastSubdir;
|
|
CString sEliminatedDirs = _T("\\..\\");
|
|
|
|
// First try to make absolute path
|
|
if (!tempPath.MakeAbsolute())
|
|
{
|
|
TRACE(_T("COXPathSpec::GetShortDescription : Could not make absolute path, returning full path spec\n"));
|
|
return GetPath();
|
|
}
|
|
|
|
// Get the last subdir
|
|
sLastSubdir = tempPath.GetLastSubdirectory().GetSubdirectory();
|
|
// ... Last subdir should never contain back slashes
|
|
ASSERT(sLastSubdir.Find(_T('\\')) == -1);
|
|
// ... If last subdir is empty (root) or equals dir itself,
|
|
// no subdirs have been eliminated
|
|
if (sLastSubdir.IsEmpty())
|
|
sEliminatedDirs.Empty();
|
|
else if ((_T("\\") + sLastSubdir) == tempPath.GetSubdirectory())
|
|
sEliminatedDirs = _T("\\");
|
|
|
|
// Return the composed short description
|
|
return tempPath.GetDrive() + sEliminatedDirs + sLastSubdir + _T("\\") + tempPath.GetFileName();
|
|
}
|
|
|
|
BOOL COXPathSpec::GetShortPathName(CString& sShortPath)
|
|
{
|
|
sShortPath=GetPath();
|
|
// ... If path spec is empty, just return
|
|
if (sShortPath.IsEmpty())
|
|
return FALSE;
|
|
|
|
#ifdef WIN32
|
|
COXPathSpec tempPath(*this);
|
|
// First try to make absolute path
|
|
tempPath.MakeAbsolute();
|
|
|
|
CString sPath=tempPath.GetPath();
|
|
BOOL bResult=(::GetShortPathName(sPath,sShortPath.GetBuffer(MAX_PATH),
|
|
MAX_PATH)>0);
|
|
sShortPath.ReleaseBuffer();
|
|
|
|
return bResult;
|
|
#else
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
BOOL COXPathSpec::MakeTemp(BOOL bCreateEmpty /* = TRUE */, LPCTSTR pszPrefix /* = _T("TMP") */,
|
|
LPCTSTR pszTempDir /* = _T("") */)
|
|
{
|
|
TCHAR path_buffer[_MAX_PATH + 1];
|
|
*path_buffer = _T('\0');
|
|
|
|
#ifdef WIN32
|
|
// Get temp path
|
|
BOOL bSucces = TRUE;
|
|
CString sTempPath(pszTempDir);
|
|
if (sTempPath.IsEmpty())
|
|
{
|
|
bSucces = ::GetTempPath(_MAX_PATH, sTempPath.GetBuffer(_MAX_PATH));
|
|
sTempPath.ReleaseBuffer();
|
|
}
|
|
|
|
if (!bSucces)
|
|
return FALSE;
|
|
|
|
if (!::GetTempFileName(sTempPath, // Use the default drive
|
|
pszPrefix, // Temporary file name prefix
|
|
0, // Generate number and create file
|
|
path_buffer)) // Result
|
|
return FALSE;
|
|
|
|
#else
|
|
// Get temp path
|
|
pszTempDir;
|
|
::GetTempFileName(0, // Use the default drive
|
|
pszPrefix, // Temporary file name prefix
|
|
0, // Generate number and create file
|
|
path_buffer); // Result
|
|
#endif
|
|
|
|
if (*path_buffer != _T('\0'))
|
|
{
|
|
BOOL bResult = SetPath(path_buffer);
|
|
if (bCreateEmpty)
|
|
{
|
|
// Empty file should have been created by ::GetTempFileName
|
|
ASSERT(Exists());
|
|
}
|
|
else
|
|
{
|
|
// Delete empty file created by ::GetTempFileName
|
|
VERIFY(DoRemove());
|
|
ASSERT(!Exists());
|
|
}
|
|
return bResult;
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXPathSpec::MakeTemp : Could not make temporary path spec\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL COXPathSpec::MakeAbsolute()
|
|
{
|
|
// If no file name was specified, just return
|
|
// Apparently in WIN32 _fullpath returns the apllications full path
|
|
// in this case (??)
|
|
if (GetFileName().IsEmpty())
|
|
return TRUE;
|
|
|
|
TCHAR pszFullPath[_MAX_PATH];
|
|
|
|
if (_tfullpath(pszFullPath, (LPCTSTR)GetPath(), _MAX_PATH) != NULL)
|
|
return SetPath(pszFullPath);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COXPathSpec::MakeUnique()
|
|
{
|
|
if (GetBaseName().IsEmpty())
|
|
SetBaseName(_T("unique"));
|
|
|
|
if (!Exists())
|
|
return TRUE;
|
|
|
|
// Change the name by first adding underscores, until 8 characters are used.
|
|
// Then the last character(s) are replaced by a number starting from 2,
|
|
// until a unique name is found.
|
|
COXString sNumber = _T("2");
|
|
CString sBaseName = GetBaseName().Left(8);
|
|
while (sBaseName.GetLength() < 8)
|
|
sBaseName += _T("_");
|
|
|
|
ASSERT(sBaseName.GetLength() == 8);
|
|
ASSERT(Exists());
|
|
do
|
|
{
|
|
sBaseName = sBaseName.Left(8 - sNumber.GetLength());
|
|
sBaseName += sNumber;
|
|
VERIFY(SetBaseName(sBaseName));
|
|
sNumber = sNumber.GetInt() + 1; // Implicit conversion to int
|
|
}
|
|
while(Exists());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXPathSpec::Exists() const
|
|
{
|
|
CFileStatus fileStatus;
|
|
return CFile::GetStatus(GetPath(), fileStatus);
|
|
}
|
|
|
|
BOOL COXPathSpec::IsEmpty() const
|
|
{
|
|
return COXDirSpec::IsEmpty() && COXFileSpec::IsEmpty();
|
|
}
|
|
|
|
void COXPathSpec::Empty()
|
|
{
|
|
COXDirSpec::Empty();
|
|
COXFileSpec::Empty();
|
|
}
|
|
|
|
BOOL COXPathSpec::DoSearch(COXFileSpec fileName, COXDirSpec startingDir /* = COXDirSpec() */,
|
|
BOOL bRecursively /* = FALSE */)
|
|
{
|
|
COXPathSpec resultPath;
|
|
COXDirSpec currentDir;
|
|
|
|
// First store the current dir
|
|
VERIFY(currentDir.DoGetCurrentDir());
|
|
|
|
// 1. Check the specified directory
|
|
if (!startingDir.IsEmpty())
|
|
{
|
|
resultPath.SetPath(startingDir, fileName);
|
|
if (resultPath.Exists())
|
|
{
|
|
*this = resultPath;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// 2. Check the subdirectories of the specified directory
|
|
|
|
// ... Recursive search is not yet implemented
|
|
ASSERT(!bRecursively);
|
|
bRecursively;
|
|
|
|
// 3 Check the EXE-directory
|
|
TCHAR pszModulePath[_MAX_PATH];
|
|
if (::GetModuleFileName(GetThisModule(), pszModulePath, _MAX_PATH) != 0)
|
|
{
|
|
VERIFY(resultPath.SetPath(pszModulePath));
|
|
resultPath.COXFileSpec::operator=(fileName);
|
|
if (resultPath.Exists())
|
|
{
|
|
*this = resultPath;
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSearch : Could not retrieve the path of the running application\n"));
|
|
}
|
|
|
|
// 4. Check the current directory
|
|
if (!currentDir.IsEmpty())
|
|
{
|
|
resultPath.SetPath(currentDir, fileName);
|
|
if (resultPath.Exists())
|
|
{
|
|
*this = resultPath;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// 5. Check the Windows directory
|
|
TCHAR pszWinDir[_MAX_DIR];
|
|
if (::GetWindowsDirectory(pszWinDir, _MAX_DIR) != 0)
|
|
{
|
|
VERIFY(resultPath.SetDirectory(pszWinDir));
|
|
resultPath.COXFileSpec::operator=(fileName);
|
|
if (resultPath.Exists())
|
|
{
|
|
*this = resultPath;
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSearch : Could not retrieve the Windows directory\n"));
|
|
}
|
|
|
|
// 6. Check the System directory
|
|
TCHAR pszSystemDir[_MAX_DIR];
|
|
if (::GetSystemDirectory(pszSystemDir, _MAX_DIR) != 0)
|
|
{
|
|
VERIFY(resultPath.SetDirectory(pszSystemDir));
|
|
resultPath.COXFileSpec::operator=(fileName);
|
|
if (resultPath.Exists())
|
|
{
|
|
*this = resultPath;
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSearch : Could not retrieve the Windows directory\n"));
|
|
}
|
|
|
|
// 7. Check the directories of PATH-environment variable
|
|
TCHAR pszResultPath[_MAX_PATH];
|
|
if (SearchEnvironment(fileName.GetFileName(), _T("PATH"), pszResultPath))
|
|
{
|
|
ASSERT(*pszResultPath != '\0');
|
|
VERIFY(SetPath(pszResultPath));
|
|
return TRUE;
|
|
}
|
|
|
|
// If still not returned, the file was not found
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COXPathSpec::DoCopy(COXPathSpec destinationPath)
|
|
{
|
|
ASSERT(!GetFileName().IsEmpty()); // Source file must be specified
|
|
CString sSourcePath;
|
|
CString sDestPath;
|
|
if (destinationPath.GetFileName().IsEmpty())
|
|
// ... Make destination file name equal to source
|
|
destinationPath.SetFileName(GetFileName());
|
|
sSourcePath = GetPath();
|
|
sDestPath = destinationPath.GetPath();
|
|
|
|
#ifdef _DEBUG
|
|
if (!Exists())
|
|
{
|
|
TRACE(_T("COXPathSpec::DoCopy : Source file %s does not exist\n"), sSourcePath);
|
|
return FALSE;
|
|
}
|
|
else
|
|
if (destinationPath.Exists())
|
|
TRACE(_T("COXPathSpec::DoCopy : Destination file %s already exists, truncating ...\n"), sDestPath);
|
|
#endif
|
|
|
|
const int nBufferLength = 2048;
|
|
BYTE pBuffer[nBufferLength + 1];
|
|
int nLengthRead;
|
|
CFile source;
|
|
CFile dest;
|
|
MSG msg;
|
|
|
|
BOOL bSuccess = TRUE;
|
|
TRY
|
|
{
|
|
if ( (source.Open(sSourcePath,CFile::modeRead | CFile::shareCompat) != 0) &&
|
|
(dest.Open(sDestPath, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive) != 0) )
|
|
{
|
|
do
|
|
{
|
|
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
nLengthRead = source.Read(pBuffer, nBufferLength);
|
|
dest.Write(pBuffer, nLengthRead);
|
|
}
|
|
while (nLengthRead == nBufferLength); // So while not EOF
|
|
source.Close();
|
|
dest.Close();
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXPathSpec::DoCopy : Could not open files\n"));
|
|
bSuccess = FALSE;
|
|
}
|
|
}
|
|
CATCH(CFileException, pxFile)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoCopy : Catching FileException (%XH)\n"), pxFile->m_cause);
|
|
|
|
source.Close();
|
|
dest.Close();
|
|
destinationPath.DoRemove();
|
|
|
|
bSuccess = FALSE;
|
|
}
|
|
END_CATCH
|
|
|
|
// copy original time/date of creation and file attributes
|
|
DoGetInfo();
|
|
destinationPath.SetTime(GetTime());
|
|
destinationPath.DoSetTime();
|
|
destinationPath.SetAttributes((CFile::Attribute)GetAttributes());
|
|
destinationPath.DoSetAttributes();
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXPathSpec::DoMove(COXPathSpec destinationPath) const
|
|
{
|
|
if (destinationPath.GetDrive() == _T(""))
|
|
VERIFY(destinationPath.SetDrive(GetDrive()));
|
|
if (destinationPath.GetSubdirectory() == _T(""))
|
|
VERIFY(destinationPath.SetSubdirectory(GetSubdirectory()));
|
|
if (destinationPath.GetFileName() == _T(""))
|
|
VERIFY(destinationPath.SetFileName(GetFileName()));
|
|
if (*this == destinationPath)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoMove : Source and destination files are the same %s\n"),
|
|
(LPCTSTR)GetPath());
|
|
// ... Nothing to do
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
if (!Exists())
|
|
TRACE(_T("COXPathSpec::DoMove : Source file %s does not exist\n"),
|
|
(LPCTSTR)GetPath());
|
|
if (destinationPath.Exists())
|
|
TRACE(_T("COXPathSpec::DoMove : Destination file %s does not exist\n"),
|
|
(LPCTSTR)destinationPath.GetPath());
|
|
#endif
|
|
|
|
// ... Assume success
|
|
BOOL bSuccess = TRUE;
|
|
TRY
|
|
{
|
|
CFile::Rename(GetPath(), destinationPath.GetPath());
|
|
}
|
|
CATCH(CFileException, px)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoMove : CFile::Rename(%s, %s) failed with CFileException cause %i\n"),
|
|
(LPCTSTR)GetPath(), (LPCTSTR)destinationPath.GetPath(), px->m_cause);
|
|
bSuccess = FALSE;
|
|
}
|
|
END_CATCH
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXPathSpec::DoRemove(BOOL bIgnoreReadOnly /* = FALSE */) const
|
|
{
|
|
CString sPath = GetPath();
|
|
|
|
// ... This function may only be used to remove a file,
|
|
// not a directory. So the file name must not be empty
|
|
ASSERT(!GetFileName().IsEmpty());
|
|
|
|
#ifdef _DEBUG
|
|
if (!Exists())
|
|
TRACE(_T("COXPathSpec::DoRemove : File %s does not exist\n"), sPath);
|
|
#endif
|
|
if (bIgnoreReadOnly)
|
|
#ifdef WIN32
|
|
if (!SetFileAttributes(sPath, CFile::normal))
|
|
#else
|
|
if(_dos_setfileattr(sPath, CFile::normal))
|
|
#endif
|
|
{
|
|
TRACE(_T("COXPathSpec::DoRemove : File not found or cannot remove R/O attribute of %s\n"), sPath);
|
|
return FALSE;
|
|
}
|
|
|
|
if (_tremove(sPath))
|
|
{
|
|
TRACE(_T("COXPathSpec::DoRemove : Cannot remove file %s\n"), sPath);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXPathSpec::DoGetInfo()
|
|
{
|
|
CFileStatus fileStatus;
|
|
if (CFile::GetStatus(GetPath(), fileStatus))
|
|
{
|
|
m_time = fileStatus.m_mtime;
|
|
m_lnLength = (LONG) fileStatus.m_size;
|
|
m_eAttributes = fileStatus.m_attribute;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("COXPathSpec::DoGetInfo : Could not get file status of %s\n"),
|
|
GetPath());
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL COXPathSpec::DoSetTime()
|
|
{
|
|
CFileStatus fileStatus;
|
|
|
|
if (!CFile::GetStatus(GetPath(), fileStatus))
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetTime : Could not even get the present status, failing\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Set new time, (DOS only knows one type of time)
|
|
fileStatus.m_ctime = m_time;;
|
|
fileStatus.m_mtime = fileStatus.m_ctime;
|
|
fileStatus.m_atime = fileStatus.m_ctime;
|
|
|
|
BOOL bSuccess = TRUE;
|
|
TRY
|
|
{
|
|
CFile::SetStatus(GetPath(), fileStatus);
|
|
}
|
|
CATCH(CFileException, pxFile)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetTime : Catching file exception (cause %XH)"),
|
|
((CFileException*)pxFile)->m_cause);
|
|
bSuccess = FALSE;
|
|
}
|
|
END_CATCH
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXPathSpec::DoSetLength()
|
|
{
|
|
// SetStatus does not set the file length, so we use direct dos access
|
|
#ifdef WIN32
|
|
HANDLE hFile;
|
|
hFile = CreateFile(GetPath(), GENERIC_READ | GENERIC_WRITE,
|
|
0,NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetLength : Could not open file %s, failing\n"),
|
|
(LPCTSTR)GetPath());
|
|
return FALSE;
|
|
}
|
|
SetFilePointer(hFile,m_lnLength, NULL,FILE_BEGIN);
|
|
if(GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetLength : Could set new length of %s, failing\n"),
|
|
(LPCTSTR)GetPath());
|
|
return FALSE;
|
|
}
|
|
SetEndOfFile(hFile);
|
|
if(GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetLength : Could not set end of %s, failing\n"),
|
|
(LPCTSTR)GetPath());
|
|
return FALSE;
|
|
}
|
|
if (!CloseHandle(hFile))
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetLength : Could not close file %s, failing\n"),
|
|
(LPCTSTR)GetPath());
|
|
return FALSE;
|
|
}
|
|
|
|
#else
|
|
UINT nErr;
|
|
int handle;
|
|
if ((nErr = _dos_open(GetPath(), CFile::modeReadWrite, &handle)) != 0)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetLength : Could not open file %s, failing\n"),
|
|
(LPCTSTR)GetPath());
|
|
return FALSE;
|
|
}
|
|
if ((nErr = _chsize(handle, m_lnLength)) != 0)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetLength : Could set new length of %s, failing\n"),
|
|
(LPCTSTR)GetPath());
|
|
return FALSE;
|
|
}
|
|
if ((nErr = _dos_close(handle)) != 0)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetLength : Could not close file %s, failing\n"),
|
|
(LPCTSTR)GetPath());
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXPathSpec::DoSetAttributes()
|
|
{
|
|
CFileStatus fileStatus;
|
|
|
|
if (!CFile::GetStatus(GetPath(), fileStatus))
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetAttributes : Could not even get the present status, failing\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Set new attributes
|
|
fileStatus.m_attribute = m_eAttributes;;
|
|
|
|
BOOL bSuccess = TRUE;
|
|
TRY
|
|
{
|
|
CFile::SetStatus(GetPath(), fileStatus);
|
|
}
|
|
CATCH(CFileException, pxFile)
|
|
{
|
|
TRACE(_T("COXPathSpec::DoSetAttributes : Catching file exception (cause %XH)"),
|
|
((CFileException*)pxFile)->m_cause);
|
|
bSuccess = FALSE;
|
|
}
|
|
END_CATCH
|
|
return bSuccess;
|
|
}
|
|
|
|
void COXPathSpec::Serialize(CArchive& archive)
|
|
{
|
|
COXDirSpec::Serialize(archive);
|
|
COXFileSpec::Serialize(archive);
|
|
}
|
|
|
|
// To avoid conflict between '#define new DEBUG_NEW' and 'operator new'
|
|
#undef new
|
|
|
|
#ifndef _DEBUG
|
|
void* COXPathSpec::operator new(size_t nSize)
|
|
{
|
|
return COXDirSpec::operator new(nSize);
|
|
}
|
|
#else
|
|
void* COXPathSpec::operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
|
|
{
|
|
return COXDirSpec::operator new(nSize, lpszFileName, nLine);
|
|
}
|
|
#endif
|
|
|
|
void COXPathSpec::operator delete(void* p)
|
|
{
|
|
COXDirSpec::operator delete(p);
|
|
}
|
|
|
|
BOOL COXPathSpec::operator==(const COXPathSpec& pathSpec) const
|
|
{
|
|
return COXDirSpec::operator==(pathSpec) &&
|
|
COXFileSpec::operator==(pathSpec);
|
|
}
|
|
|
|
BOOL COXPathSpec::operator!=(const COXPathSpec& pathSpec) const
|
|
{
|
|
return COXDirSpec::operator!=(pathSpec) ||
|
|
COXFileSpec::operator!=(pathSpec);
|
|
}
|
|
|
|
BOOL COXPathSpec::operator<=(const COXPathSpec& pathSpec) const
|
|
{
|
|
return COXDirSpec::operator<=(pathSpec) &&
|
|
COXFileSpec::operator<=(pathSpec);
|
|
}
|
|
BOOL COXPathSpec::operator<(const COXPathSpec& pathSpec) const
|
|
{
|
|
return COXDirSpec::operator<(pathSpec) &&
|
|
COXFileSpec::operator<(pathSpec);
|
|
}
|
|
BOOL COXPathSpec::operator>=(const COXPathSpec& pathSpec) const
|
|
{
|
|
return COXDirSpec::operator>=(pathSpec) &&
|
|
COXFileSpec::operator>=(pathSpec);
|
|
}
|
|
BOOL COXPathSpec::operator>(const COXPathSpec& pathSpec) const
|
|
{
|
|
return COXDirSpec::operator>(pathSpec) &&
|
|
COXFileSpec::operator>(pathSpec);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
void COXPathSpec::Dump(CDumpContext& dc) const
|
|
{
|
|
COXDirSpec::Dump(dc);
|
|
COXFileSpec::Dump(dc);
|
|
}
|
|
|
|
void COXPathSpec::AssertValid() const
|
|
{
|
|
COXDirSpec::AssertValid();
|
|
COXFileSpec::AssertValid();
|
|
}
|
|
#endif
|
|
|
|
COXPathSpec::~COXPathSpec()
|
|
{
|
|
}
|
|
|
|
// protected:
|
|
HMODULE COXPathSpec::GetThisModule()
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns : The module handle of the running task
|
|
// --- Effect :
|
|
{
|
|
HMODULE hThisModule = NULL;
|
|
|
|
#ifdef WIN32
|
|
hThisModule = GetModuleHandle(NULL);
|
|
#else
|
|
// WIN16 does not have a direct function which returns the module handle of the running application
|
|
// Therefor TOOLHELP is used to calculate it from the running task
|
|
HTASK hCurrentTask;
|
|
TASKENTRY taskEntry;
|
|
taskEntry.dwSize = sizeof(taskEntry);
|
|
hCurrentTask = GetCurrentTask();
|
|
if (hCurrentTask == NULL)
|
|
return NULL;
|
|
TaskFindHandle(&taskEntry, hCurrentTask);
|
|
hThisModule = taskEntry.hModule;
|
|
|
|
// An alternative (but undocumented) ways is the following
|
|
// HMODULE hThisModule2 = (HMODULE)*(LPWORD)MAKELP(GetCurrentTask(), 0x1E);
|
|
#endif
|
|
|
|
return hThisModule;
|
|
}
|
|
|
|
BOOL COXPathSpec::SearchEnvironment(LPCTSTR pszFileName, LPCTSTR pszVarName, LPTSTR pszPathName)
|
|
// --- In : pszFileName : The name of the file to search for
|
|
// pszVarName : The name of the environment variable
|
|
// --- Out : pszPathName : The full path of the file if found, otherwise empty
|
|
// --- Returns : Whether the specified file was found
|
|
// --- Effect : Searches all the directories of the specified environment variable
|
|
// for the specified file
|
|
// An environment variable is case-sensitive
|
|
// --- Remark : This function is an implementation of the C-RunTime function _searchenv
|
|
// This function also works when called from a DLL, which _searchenv does not
|
|
{
|
|
const int nMaxEntriesLength(300);
|
|
TCHAR szEntries[nMaxEntriesLength + 1];
|
|
LPTSTR pszToken;
|
|
DWORD dwEntriesLength;
|
|
|
|
// ... Assume failure, so initialize out-parameter
|
|
ASSERT(pszPathName != NULL);
|
|
ASSERT(AfxIsValidAddress(pszPathName, 1));
|
|
*pszPathName = _T('\0');
|
|
|
|
// ... First get the environment value
|
|
dwEntriesLength = GetEnvironmentVar(pszVarName, szEntries, nMaxEntriesLength);
|
|
if (dwEntriesLength == 0)
|
|
// ... Failure : Environment variable does not exist
|
|
return FALSE;
|
|
#ifdef _DEBUG
|
|
if (nMaxEntriesLength < dwEntriesLength)
|
|
TRACE(_T("COXPathSpec::SearchEnv : Environment variable value length (%u) exceeds maximum length (%u) and will be truncated\n"),
|
|
dwEntriesLength, nMaxEntriesLength);
|
|
#endif
|
|
|
|
// Iterate all the directory entries, which are seperated by a semi-colon
|
|
BOOL bFound = FALSE;
|
|
CFileStatus fileStatus;
|
|
TCHAR szPath[_MAX_PATH];
|
|
LPTSTR pszConcat;
|
|
TCHAR * nextToken;
|
|
pszToken = UTBStr::tcstok(szEntries, _T(";"), &nextToken);
|
|
while (!bFound && (pszToken != NULL))
|
|
{
|
|
UTBStr::tcscpy(szPath, _MAX_PATH, pszToken);
|
|
// ... String cannot be empty because (pszToken != '\0')
|
|
ASSERT(1 <= _tcsclen(szPath));
|
|
// ... Examine the last char of the directory spec,
|
|
// if it is not back slash and not a colon (relative path), add a back slash
|
|
pszConcat = &szPath[_tcsclen(szPath) - 1];
|
|
if ( (*pszConcat != _T('\\')) && (*pszConcat != _T(':')) )
|
|
*(++pszConcat) = _T('\\');
|
|
// ... Position after last char of directory spec
|
|
pszConcat++;
|
|
// ... Add file name
|
|
UTBStr::tcscpy(pszConcat, _tcsclen(szPath) - 1, pszFileName);
|
|
bFound = CFile::GetStatus(szPath, fileStatus);
|
|
|
|
TCHAR * nextToken;
|
|
pszToken = UTBStr::tcstok(NULL, _T(";"), &nextToken);
|
|
}
|
|
if (bFound)
|
|
{
|
|
ASSERT(AfxIsValidAddress(pszPathName, _tcsclen(szPath) + 1));
|
|
UTBStr::tcscpy(pszPathName, _MAX_PATH, szPath);
|
|
}
|
|
return bFound;
|
|
}
|
|
|
|
DWORD COXPathSpec::GetEnvironmentVar(LPCTSTR pszVarName, LPTSTR pszValue, DWORD nLength)
|
|
// --- In : pszVarName : The name of the environment variable
|
|
// pszValue : Buffer into which the result will be stored
|
|
// nLength : The length of the buffer
|
|
// --- Out : pszValue : The result (the environment table entry containing
|
|
// the current string value of pszVarName)
|
|
// --- Returns : The number of characters stored into the buffer pointed to by pszValue,
|
|
// not including the terminating null character.
|
|
// When the variable name was not found the return value is zero.
|
|
// If the buffer pointed to by pszValue is not large enough,
|
|
// the return value is the buffer size, in characters,
|
|
// required to hold the value string and its terminating null character.
|
|
// --- Effect : Searches the list of environment variables for the specified entry
|
|
// An environment variable is case-sensitive
|
|
// --- Remark : This function is an implementation of the C-RunTime function getenv
|
|
// This function also works when called from a DLL, which in WIN16 getenv does not
|
|
// See Also MS Developers Network Q78542 :
|
|
// Retreiving MS-DOS Environment Vars from a Windows DLL
|
|
{
|
|
#ifdef WIN32
|
|
// Functionality exists in WIN32, so just call Windows API function
|
|
return ::GetEnvironmentVariable(pszVarName, pszValue, nLength);
|
|
#else
|
|
// ... Assume failure, so initialize out-parameter
|
|
ASSERT(pszValue != NULL);
|
|
ASSERT(AfxIsValidAddress(pszValue, (UINT)nLength));
|
|
*pszValue = _T('\0');
|
|
|
|
LPTSTR lpEnvSearch;
|
|
LPCTSTR lpszVarSearch;
|
|
|
|
// ... Check for empty var
|
|
if (*pszVarName == _T('\0'))
|
|
{
|
|
TRACE(_T("COXPathSpec::GetEnvironmentVar : Empty environment variable, returning 0\n"));
|
|
return 0;
|
|
}
|
|
|
|
// ... Get a pointer to the MS-DOS environment block
|
|
lpEnvSearch = GetDOSEnvironment();
|
|
// ... Iterat all strings in the environment table
|
|
while (*lpEnvSearch != _T('\0'))
|
|
{
|
|
// ... Check to see if the variable names match
|
|
lpszVarSearch = pszVarName;
|
|
while ( (*lpEnvSearch != _T('\0')) && (*lpszVarSearch != _T('\0')) &&
|
|
(*lpEnvSearch == *lpszVarSearch) )
|
|
{
|
|
lpEnvSearch++;
|
|
lpszVarSearch++;
|
|
}
|
|
// ... If the names match, the lpEnvSearch pointer is on the "="
|
|
// character and lpszVarSearch is on a null terminator.
|
|
// Increment and return lpszEnvSearch, which will point to the
|
|
// environment variable's contents.
|
|
if ((*lpEnvSearch == _T('=')) && (*lpszVarSearch == _T('\0')))
|
|
{
|
|
lpEnvSearch++;
|
|
strncpy(pszValue, lpEnvSearch, (size_t)nLength);
|
|
pszValue[nLength] = _T('\0');
|
|
return _tcsclen(lpEnvSearch);
|
|
}
|
|
// ... If the names do not match, increment lpEnvSearch until it
|
|
// reaches the end of the current variable string.
|
|
else
|
|
while (*lpEnvSearch != _T('\0'))
|
|
lpEnvSearch++;
|
|
// ... At this point the end of the environment variable's string
|
|
// has been reached. Increment lpEnvSearch to move to the
|
|
// next variable in the environment block. If it is NULL,
|
|
// the end of the environment block has been reached.
|
|
lpEnvSearch++;
|
|
}
|
|
|
|
// If this section of code is reached, the variable was not found.
|
|
TRACE(_T("COXPathSpec::GetEnvironmentVar : Environment variable (%s) not found, returning NULL\n"), pszVarName);
|
|
return 0;
|
|
#endif // WIN32
|
|
}
|
|
|
|
BOOL COXPathSpec::GetFirstFile(COXPathIterator& FIterator) const
|
|
{
|
|
COXPathSpec searchPath(*this);
|
|
if (searchPath.GetFileName().IsEmpty())
|
|
VERIFY(searchPath.SetFileName(_T("*.*")));
|
|
|
|
BOOL bGoodFileFound = FALSE;
|
|
BOOL bJustFileFound = TRUE;
|
|
FIterator.m_bValid = TRUE;
|
|
|
|
#ifdef WIN32
|
|
FIterator.m_hFindFile = FindFirstFile(searchPath.GetPath(), &FIterator.m_FindFileData);
|
|
|
|
if (FIterator.m_hFindFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(FIterator.m_hFindFile);
|
|
FIterator.m_hFindFile = NULL;
|
|
FIterator.m_bValid = FALSE;
|
|
}
|
|
else
|
|
{
|
|
while (!bGoodFileFound && bJustFileFound)
|
|
{
|
|
if (!IsChildDir(&FIterator.m_FindFileData) &&
|
|
(FIterator.m_FindFileData.cFileName[0] != _T('.')))
|
|
bGoodFileFound = TRUE;
|
|
|
|
if (!bGoodFileFound)
|
|
bJustFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
|
|
}
|
|
}
|
|
#else
|
|
|
|
bGoodFileFound = !_dos_findfirst(searchPath.GetPath(), _A_NORMAL | _A_ARCH, &FIterator.m_FileInfo);
|
|
|
|
#endif
|
|
|
|
FIterator.m_bValid = bGoodFileFound;
|
|
return FIterator.m_bValid;
|
|
}
|
|
|
|
COXFileSpec COXPathSpec::GetNextFile(COXPathIterator& FIterator) const
|
|
{
|
|
ASSERT_VALID(&FIterator);
|
|
|
|
COXFileSpec ActualFile;
|
|
|
|
BOOL bDirFound(TRUE);
|
|
#ifdef WIN32
|
|
BOOL bFileFound;
|
|
ActualFile.SetFileName(FIterator.m_FindFileData.cFileName);
|
|
ActualFile.SetTime(CTime(FIterator.m_FindFileData.ftLastWriteTime));
|
|
ASSERT(FIterator.m_FindFileData.nFileSizeHigh == 0);
|
|
ActualFile.SetLength(FIterator.m_FindFileData.nFileSizeLow);
|
|
ActualFile.SetAttributes((CFile::Attribute)FIterator.m_FindFileData.dwFileAttributes);
|
|
|
|
bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
|
|
while (bFileFound && bDirFound)
|
|
{
|
|
if (!IsChildDir(&FIterator.m_FindFileData) &&
|
|
(FIterator.m_FindFileData.cFileName[0] != _T('.')))
|
|
bDirFound = FALSE;
|
|
|
|
if (bDirFound)
|
|
bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
|
|
}
|
|
|
|
if (!bFileFound)
|
|
{
|
|
FindClose(FIterator.m_hFindFile);
|
|
FIterator.m_hFindFile = NULL;
|
|
FIterator.m_bValid = FALSE;
|
|
}
|
|
|
|
#else
|
|
ActualFile.SetFileName(FIterator.m_FileInfo.name);
|
|
ActualFile.SetTime(CTime((WORD)FIterator.m_FileInfo.wr_date, (WORD)FIterator.m_FileInfo.wr_time));
|
|
ActualFile.SetLength(FIterator.m_FileInfo.size);
|
|
ActualFile.SetAttributes((CFile::Attribute)FIterator.m_FileInfo.attrib);
|
|
|
|
if (_dos_findnext(&FIterator.m_FileInfo) != 0)
|
|
{
|
|
FIterator.m_bValid = FALSE;
|
|
}
|
|
#endif
|
|
|
|
return ActualFile;
|
|
}
|
|
|
|
BOOL COXPathSpec::GetFirstDir(COXPathIterator& FIterator) const
|
|
{
|
|
COXPathSpec searchPath(*this);
|
|
if (searchPath.GetFileName().IsEmpty())
|
|
VERIFY(searchPath.SetFileName(_T("*.*")));
|
|
|
|
FIterator.m_bValid = TRUE;
|
|
BOOL bFileFound(TRUE);
|
|
BOOL bDirFound(FALSE);
|
|
|
|
#ifdef WIN32
|
|
FIterator.m_hFindFile = FindFirstFile(searchPath.GetPath(), &FIterator.m_FindFileData);
|
|
|
|
if (FIterator.m_hFindFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(FIterator.m_hFindFile);
|
|
FIterator.m_hFindFile = NULL;
|
|
FIterator.m_bValid = FALSE;
|
|
}
|
|
else
|
|
{
|
|
while (!bDirFound && bFileFound)
|
|
{
|
|
if (IsChildDir(&FIterator.m_FindFileData))
|
|
bDirFound = TRUE;
|
|
|
|
if (!bDirFound)
|
|
bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
|
|
}
|
|
}
|
|
|
|
#else
|
|
bFileFound = !_dos_findfirst(searchPath.GetPath(), _A_NORMAL | _A_ARCH | _A_SUBDIR, &FIterator.m_FileInfo);
|
|
while (bFileFound && !bDirFound)
|
|
{
|
|
if (((FIterator.m_FileInfo.attrib & _A_SUBDIR) == _A_SUBDIR) && (strcmp(FIterator.m_FileInfo.name, _T(".")) != 0) &&
|
|
(strcmp(FIterator.m_FileInfo.name, _T("..")) != 0))
|
|
bDirFound = TRUE;
|
|
|
|
if (!bDirFound)
|
|
bFileFound = (_dos_findnext(&FIterator.m_FileInfo) == 0);
|
|
}
|
|
|
|
#endif
|
|
|
|
FIterator.m_bValid = bDirFound;
|
|
return FIterator.m_bValid;
|
|
}
|
|
|
|
COXDirSpec COXPathSpec::GetNextDir(COXPathIterator& FIterator) const
|
|
{
|
|
ASSERT_VALID(&FIterator);
|
|
|
|
COXDirSpec ActualDir;
|
|
|
|
BOOL bFileFound;
|
|
BOOL bDirFound(FALSE);
|
|
|
|
#ifdef WIN32
|
|
ActualDir.SetDrive(m_sDrive);
|
|
ActualDir.SetSubdirectory(m_sSubdirectory);
|
|
ActualDir.AppendDirectory(COXDirSpec(FIterator.m_FindFileData.cFileName));
|
|
|
|
bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
|
|
while (bFileFound && !bDirFound)
|
|
{
|
|
if (IsChildDir(&FIterator.m_FindFileData))
|
|
bDirFound = TRUE;
|
|
|
|
if (!bDirFound)
|
|
bFileFound = FindNextFile(FIterator.m_hFindFile, &FIterator.m_FindFileData);
|
|
}
|
|
|
|
if (!bFileFound)
|
|
{
|
|
FindClose(FIterator.m_hFindFile);
|
|
FIterator.m_hFindFile = NULL;
|
|
FIterator.m_bValid = FALSE;
|
|
}
|
|
|
|
#else
|
|
|
|
ActualDir.SetDrive(m_sDrive);
|
|
ActualDir.SetSubdirectory(m_sSubdirectory);
|
|
ActualDir.AppendDirectory(COXDirSpec(FIterator.m_FileInfo.name));
|
|
|
|
bFileFound = !_dos_findnext(&FIterator.m_FileInfo);
|
|
while (bFileFound && !bDirFound)
|
|
{
|
|
if (((FIterator.m_FileInfo.attrib & _A_SUBDIR) == _A_SUBDIR) && (strcmp(FIterator.m_FileInfo.name, _T(".")) != 0) &&
|
|
(strcmp(FIterator.m_FileInfo.name, _T("..")) != 0))
|
|
bDirFound = TRUE;
|
|
|
|
if (!bDirFound)
|
|
bFileFound = (_dos_findnext(&FIterator.m_FileInfo) == 0);
|
|
}
|
|
|
|
FIterator.m_bValid = bDirFound;
|
|
#endif
|
|
|
|
return ActualDir;
|
|
}
|
|
|
|
// private:
|
|
|
|
// ==========================================================================
|