//////////////////////////////////////////////////////////////////////
// Implemented by Samuel Gonzalo
//
// You may freely use or modify this code
//////////////////////////////////////////////////////////////////////
//
// Path.cpp: implementation of the CPath class.
// http://www.codeproject.com/file/CFileFinderEx.asp
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Path.h"
#include "Shlwapi.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPath::CPath()
{
_bIsRelative = FALSE;
}
CPath::CPath(LPCTSTR szPath, BOOL bIsFolderPath, BOOL bHasArguments)
{
SetPath(szPath, bIsFolderPath, bHasArguments);
}
CPath::CPath(DWORD dwSpecial)
{
SetPath(dwSpecial);
}
CPath::~CPath()
{
}
void CPath::SetPath(DWORD dwSpecial)
{
switch (dwSpecial)
{
case PATH_CMDLINE:
SetPath(GetCommandLine(), FALSE, TRUE);
break;
case PATH_MODULE:
{
char szPath[_MAX_PATH];
GetModuleFileName(0, szPath, _MAX_PATH);
SetPath(szPath);
}
break;
}
}
void CPath::SetPath(LPCTSTR szPath, BOOL bIsFolderPath, BOOL bHasArguments)
{
char szParamPath[_MAX_PATH];
char szDrive[_MAX_DRIVE], szDir[_MAX_DIR];
char szName[_MAX_FNAME], szExt[_MAX_EXT];
// Reset
_sOriginalPath.Empty();
_sDriveLabel.Empty();
_bIsRelative = FALSE;
_aDir.RemoveAll();
_sExtName.Empty();
_aArgs.RemoveAll();
// Original path
_sOriginalPath = szPath;
// Get args and remove them from path
szParamPath[0] = 0x0;
strcpy(szParamPath, szPath);
if (bHasArguments)
{
_sArgs = PathGetArgs(szParamPath);
PathRemoveArgs(szParamPath);
}
PathUnquoteSpaces(szParamPath);
if (szParamPath[0] == 0x0) return;
_splitpath(szParamPath, szDrive, szDir, szName, szExt);
// Drive
_sDrive = szDrive;
// Directory
_sDir = szDir;
_sDir.Replace('/', '\\');
if (!_sDir.IsEmpty()) _bIsRelative = (_sDir[0] != '\\');
// FileTitle
if (bIsFolderPath)
{
_sDir = CPath::AddBackSlash(_sDir);
_sDir += szName;
_sDir = CPath::AddBackSlash(_sDir);
}
else
{
_sFileTitle = szName;
}
// Get extension name (e.g.: "txt")
if (IsFilePath())
{
_sExtName = szExt;
_sExtName.Remove('.');
}
}
BOOL CPath::IsLocalPath()
{
return !_sDrive.IsEmpty() && !_bIsRelative;
}
BOOL CPath::IsRelativePath()
{
return _bIsRelative;
}
BOOL CPath::IsFilePath()
{
return !_sFileTitle.IsEmpty();
}
BOOL CPath::ExistFile()
{
if (!IsFilePath()) return FALSE;
return PathFileExists(GetPath());
}
BOOL CPath::ExistLocation()
{
return PathFileExists(GetLocation());
}
CString CPath::GetAbsolutePath(LPCTSTR szBaseFolder)
{
if (!IsRelativePath()) return sCEmptyString;
char szAbsolutePath[_MAX_PATH];
CString sFullPath(szBaseFolder);
if (sFullPath.IsEmpty()) return sCEmptyString;
sFullPath = CPath::AddBackSlash(sFullPath);
sFullPath += GetPath();
if (!PathCanonicalize(szAbsolutePath, sFullPath)) return sCEmptyString;
return szAbsolutePath;
}
CString CPath::GetRelativePath(LPCTSTR szBaseFolder)
{
if (IsRelativePath()) return sCEmptyString;
char szRelativePath[_MAX_PATH];
CString sRelPath;
PathRelativePathTo(szRelativePath, szBaseFolder, FILE_ATTRIBUTE_DIRECTORY,
GetPath(), IsFilePath() ? 0 : FILE_ATTRIBUTE_DIRECTORY);
sRelPath = szRelativePath;
if (sRelPath.GetLength() > 1)
{
// Remove ".\" from the beginning
if ((sRelPath[0] == '.') && (sRelPath[1] == '\\'))
sRelPath.Right(sRelPath.GetLength() - 2);
}
return sRelPath;
}
CString CPath::GetPath(BOOL bAppendArgs, BOOL bOriginal)
{
CString sPath;
if (bOriginal)
sPath = _sOriginalPath;
else
sPath = GetLocation() + GetFileName();
if (bAppendArgs) sPath += GetArgument();
return sPath;
}
CString CPath::GetShortPath()
{
char szShortPath[_MAX_PATH];
szShortPath[0] = 0x0;
//GetShortPathName(GetPath(), szShortPath, _MAX_PATH);
return szShortPath;
}
CString CPath::GetLongPath()
{
char szLongPath[_MAX_PATH];
szLongPath[0] = 0x0;
//GetLongPathName(GetPath(), szLongPath, _MAX_PATH);
return szLongPath;
}
CString CPath::GetDrive()
{
return _sDrive;
}
CString CPath::GetDriveLabel(BOOL bPCNameIfNetwork)
{
if (_sDriveLabel.IsEmpty() && !IsRelativePath())
{
if ((bPCNameIfNetwork) && (!IsLocalPath()))
_sDriveLabel = GetDir(0);
else
{
CString sRoot;
char szVolumeName[256];
szVolumeName[0] = '\0';
if (IsLocalPath())
{
sRoot = _sDrive + CString("\\");
}
else if (GetDirCount() > 1)
{
sRoot.Format("\\\\%s\\%s\\", GetDir(0), GetDir(1));
}
GetVolumeInformation(sRoot, szVolumeName, 255, NULL, NULL, NULL, NULL, 0);
_sDriveLabel = szVolumeName;
}
}
return _sDriveLabel;
}
int CPath::GetDirCount()
{
FillDirArray();
return _aDir.GetSize();
}
CString CPath::GetDir(int nIndex)
{
if (nIndex < 0)
return _sDir;
else if (nIndex < GetDirCount())
{
FillDirArray();
return _aDir[nIndex];
}
return sCEmptyString;
}
CString CPath::GetLocation()
{
return _sDrive + GetDir();
}
CString CPath::GetFileTitle()
{
return _sFileTitle;
}
CString CPath::GetFileName()
{
return _sFileTitle + GetExtension();
}
CString CPath::GetExtension()
{
if (_sExtName.IsEmpty()) return sCEmptyString;
return CString(".") + _sExtName;
}
CString CPath::GetExtName()
{
return _sExtName;
}
int CPath::GetArgCount()
{
FillArgArray();
return _aArgs.GetSize();
}
CString CPath::GetArgument(int nIndex, BOOL bGetFlag)
{
if (nIndex < 0)
{
if (_sArgs.IsEmpty())
{
for (int nItem = 0; nItem < _aArgs.GetSize(); nItem++)
_sArgs += _aArgs[nItem].GetString();
_sArgs.TrimLeft();
}
return _sArgs;
}
else if (nIndex < GetArgCount())
{
FillArgArray();
if (bGetFlag)
return _aArgs[nIndex].sFlag;
else
return _aArgs[nIndex].sValue;
}
return sCEmptyString;
}
void CPath::SetArguments(LPCTSTR szArgs)
{
_aArgs.RemoveAll();
_sArgs = szArgs;
}
void CPath::AddSetArgument(LPCTSTR szFlag, LPCTSTR szArgument)
{
int nIndex;
nIndex = FindArgument(szFlag);
if (nIndex != -1)
{
// An argument with the same flag already exists. Update it!
_aArgs[nIndex].sValue = szArgument;
}
else
{
CArgument arg;
arg.sValue = szArgument;
arg.SetFlag(szFlag);
_aArgs.Add(arg);
_sArgs.Empty();
}
}
void CPath::RemoveArgument(int nIndex)
{
if ((nIndex >= 0) && (nIndex < _aArgs.GetSize()))
{
_aArgs.RemoveAt(nIndex);
_sArgs.Empty();
}
}
int CPath::FindArgument(LPCTSTR szFlag)
{
bool bFound = false;
int nIndex = -1 ;
CArgument arg;
FillArgArray();
arg.SetFlag(szFlag);
if (!arg.sFlag.IsEmpty())
{
for (nIndex = 0; nIndex < _aArgs.GetSize(); nIndex++)
{
bFound = (_aArgs[nIndex].sFlag.CompareNoCase(arg.sFlag) == 0);
if (bFound) break;
}
}
return (bFound ? nIndex : -1);
}
BOOL CPath::GetFileSize(__int64 &nSize)
{
BOOL bResult;
bResult = FillFileInfoStruct();
nSize = ((__int64)_fis.nFileSizeHigh * (__int64)MAXDWORD) + (__int64)_fis.nFileSizeLow;
return bResult;
}
BOOL CPath::GetFileTime(CTime &time, DWORD dwType)
{
BOOL bResult;
FILETIME *pTime = NULL;
bResult = FillFileInfoStruct();
switch (dwType)
{
case FILE_CREATION: pTime = &_fis.ftCreationTime; break;
case FILE_WRITE: pTime = &_fis.ftLastWriteTime; break;
case FILE_ACCESS:
default: pTime = &_fis.ftLastAccessTime; break;
}
if (pTime != NULL) time = CTime(*pTime);
return bResult;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Private methods
// This function must be called whenever _aDir array is needed, since this
// method is the one which parses _sDir and fill _aDir
void CPath::FillDirArray()
{
if (_sDir.IsEmpty() || (_aDir.GetSize() > 0)) return;
int nFrom, nTo;
// nFrom: 0 - relative / 1 - local / 2 - network
nFrom = IsLocalPath() ? 1 : (IsRelativePath() ? 0 : 2);
while ((nTo = _sDir.Find('\\', nFrom)) != -1)
{
_aDir.Add(_sDir.Mid(nFrom, nTo - nFrom));
nFrom = nTo + 1;
}
}
// This function must be called whenever _aArgs array is needed, since this
// method is the one which parses _sArgs and fill _aArgs
void CPath::FillArgArray()
{
if (_sArgs.IsEmpty() || (_aArgs.GetSize() > 0)) return;
CString sArgs(_sArgs);
int nFrom, nTo;
bool bQuotedArg = false;
CArgument arg;
sArgs.TrimLeft();
sArgs.TrimRight();
// add a blank space at the end of the string to include the last argument
sArgs += " ";
while ((nTo = sArgs.FindOneOf(" \"")) != -1)
{
bQuotedArg = (sArgs[nTo] == '\"');
if (bQuotedArg)
{
nFrom = nTo + 1;
if ((nTo = sArgs.Find('\"', nFrom)) == -1) break;
arg.sValue = sArgs.Mid(nFrom, nTo - nFrom);
}
else
{
CString *pStr;
if ((sArgs[0] == '/') || (sArgs[0] == '-'))
{
if (!arg.sFlag.IsEmpty())
{
arg.SetFlag(arg.sFlag);
_aArgs.Add(arg);
arg.sFlag.Empty();
arg.sValue.Empty();
}
pStr = &arg.sFlag;
}
else
pStr = &arg.sValue;
*pStr = sArgs.Left(nTo);
}
if (!arg.sValue.IsEmpty())
{
arg.SetFlag(arg.sFlag);
_aArgs.Add(arg);
arg.sFlag.Empty();
arg.sValue.Empty();
}
sArgs = sArgs.Right(sArgs.GetLength() - nTo - 1);
sArgs.TrimLeft();
}
// if the last argument is only a flag it hasn't been added yet
if (!arg.sFlag.IsEmpty())
{
arg.SetFlag(arg.sFlag);
_aArgs.Add(arg);
}
}
BOOL CPath::FillFileInfoStruct()
{
HANDLE hFile;
BOOL bResult;
::memset(&_fis, 0, sizeof(_fis));
hFile = CreateFile(GetPath(), GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM, NULL);
if (hFile == INVALID_HANDLE_VALUE) return FALSE;
bResult = GetFileInformationByHandle(hFile, &_fis);
CloseHandle(hFile);
return bResult;
}
CString CPath::AddBackSlash(LPCTSTR szFolderPath, BOOL bInverted)
{
CString sResult(szFolderPath);
int nLastChar = sResult.GetLength() - 1;
if (nLastChar >= 0)
{
if ((sResult[nLastChar] != '\\') && (sResult[nLastChar] != '/'))
sResult += bInverted ? '/' : '\\';
}
return sResult;
}
CString CPath::RemoveBackSlash(LPCTSTR szFolderPath)
{
CString sResult(szFolderPath);
int nLastChar = sResult.GetLength() - 1;
if (nLastChar >= 0)
{
if ((sResult[nLastChar] == '\\') || (sResult[nLastChar] == '/'))
sResult = sResult.Left(nLastChar);
}
return sResult;
}
CPath::operator LPCTSTR ()
{
_sLPCTSTRPath = GetPath();
return _sLPCTSTRPath;
}
const CPath& CPath::operator = (LPCTSTR szPath)
{
SetPath(szPath);
return *this;
}
const CPath& CPath::operator = (CPath &ref)
{
_aArgs.RemoveAll();
_aArgs.Copy(ref._aArgs);
_aDir.RemoveAll();
_aDir.Copy(ref._aDir);
_bIsRelative = ref._bIsRelative;
_fis = ref._fis;
_sArgs = ref._sArgs;
_sDir = ref._sDir;
_sDrive = ref._sDrive;
_sDriveLabel = ref._sDriveLabel;
_sExtName = ref._sExtName;
_sFileTitle = ref._sFileTitle;
_sOriginalPath = ref._sOriginalPath;
return *this;
}