project64/Source/Common/path.cpp

1143 lines
36 KiB
C++
Raw Normal View History

// Path.cpp: implementation of the CPath class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <Shlobj.h>
2015-10-25 11:10:54 +00:00
#include <dos.h>
//////////////////////////////////////////////////////////////////////
// Constants
//////////////////////////////////////////////////////////////////////
2016-01-12 12:19:50 +00:00
const char DRIVE_DELIMITER = ':';
2016-01-12 06:52:59 +00:00
const char * const DIR_DOUBLEDELIM = "\\\\";
2016-01-12 12:19:50 +00:00
const char DIRECTORY_DELIMITER = '\\';
const char DIRECTORY_DELIMITER2 = '/';
const char EXTENSION_DELIMITER = '.';
2015-10-25 11:10:54 +00:00
void * CPath::m_hInst = NULL;
//////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////
2016-01-12 06:52:59 +00:00
void CPath::SethInst(void * hInst)
{
2016-01-12 06:52:59 +00:00
m_hInst = hInst;
}
2015-10-25 11:10:54 +00:00
void * CPath::GethInst()
{
2016-01-12 06:52:59 +00:00
return m_hInst;
}
//////////////////////////////////////////////////////////////////////
// Initialisation
//////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------
2016-01-12 06:52:59 +00:00
// Task : Helper function for the various CPath constructors.
// Initializes the data members and establishes various
// class invariants
//-------------------------------------------------------------
inline void CPath::Init()
{
2016-01-12 06:52:59 +00:00
m_dwFindFileAttributes = 0;
m_hFindFile = NULL;
}
//-------------------------------------------------------------
// Task : Helper function for the various CPath destructors.
// Cleans up varios internals
//-------------------------------------------------------------
inline void CPath::Exit()
{
2016-01-12 06:52:59 +00:00
if (m_hFindFile != NULL)
{
2016-01-12 06:52:59 +00:00
FindClose(m_hFindFile);
m_hFindFile = NULL;
}
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------
// Task : Constructs a path
//-------------------------------------------------------------
CPath::CPath()
{
2016-01-12 06:52:59 +00:00
Init();
Empty();
}
//-------------------------------------------------------------
// Task : Constructs a path as copy of another
//-------------------------------------------------------------
CPath::CPath(const CPath& rPath)
{
2016-01-12 06:52:59 +00:00
Init();
m_strPath = rPath.m_strPath;
}
//-------------------------------------------------------------
// Task : Constructs a path and points it 2 lpszPath
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
CPath::CPath(const char * lpszPath)
{
2016-01-12 06:52:59 +00:00
Init();
m_strPath = lpszPath ? lpszPath : "";
cleanPathString(m_strPath);
}
2015-10-25 11:10:54 +00:00
CPath::CPath(const char * lpszPath, const char * NameExten)
{
2016-01-12 06:52:59 +00:00
Init();
SetDriveDirectory(lpszPath);
SetNameExtension(NameExten);
}
//-------------------------------------------------------------
// Task : Constructs a path and points it 2 strPath
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
CPath::CPath(const std::string& strPath)
{
Init();
2016-01-12 06:52:59 +00:00
m_strPath = strPath;
cleanPathString(m_strPath);
}
//-------------------------------------------------------------
// Task : Constructs a path and points it 2 strPath
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
CPath::CPath(const std::string& strPath, const char * NameExten)
{
2016-01-12 06:52:59 +00:00
Init();
SetDriveDirectory(strPath.c_str());
SetNameExtension(NameExten);
}
//-------------------------------------------------------------
// Task : Constructs a path and points it 2 strPath
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
CPath::CPath(const std::string& strPath, const std::string& NameExten)
{
2016-01-12 06:52:59 +00:00
Init();
SetDriveDirectory(strPath.c_str());
SetNameExtension(NameExten.c_str());
}
//-------------------------------------------------------------
// Task : Cleanup and destruct a path object
//-------------------------------------------------------------
CPath::~CPath()
{
2016-01-12 06:52:59 +00:00
Exit();
}
//-------------------------------------------------------------
// Post : Return TRUE if paths are equal
// Task : Check if the two path are the same
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::operator ==(const CPath& rPath) const
{
// Get fully qualified versions of the paths
2016-01-12 06:52:59 +00:00
std::string FullyQualified1;
2015-10-25 11:10:54 +00:00
std::string FullyQualified2;
2016-01-12 06:52:59 +00:00
GetFullyQualified(FullyQualified1);
rPath.GetFullyQualified(FullyQualified2);
// Compare them
2016-01-12 06:52:59 +00:00
return _stricmp(FullyQualified1.c_str(), FullyQualified2.c_str()) == 0;
}
//-------------------------------------------------------------
// Post : Return TRUE if paths are different
// Task : Check if the two path are different
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::operator !=(const CPath& rPath) const
{
return !(*this == rPath);
}
//-------------------------------------------------------------
// Task : Assign a path 2 another
//-------------------------------------------------------------
CPath& CPath::operator =(const CPath& rPath)
2016-01-12 06:52:59 +00:00
{
if (this != &rPath)
{
2016-01-12 06:52:59 +00:00
m_strPath = rPath.m_strPath;
}
return *this;
}
//-------------------------------------------------------------
// Post : Return the path, so that assignements can be chained
// Task : Assign a string 2 a path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
CPath& CPath::operator =(const char * lpszPath)
{
2016-01-12 06:52:59 +00:00
m_strPath = lpszPath ? lpszPath : "";
return *this;
}
//-------------------------------------------------------------
// Post : Return the path, so that assignements can be chained
// Task : Assign a string 2 a path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
CPath& CPath::operator =(const std::string& strPath)
{
2016-01-12 06:52:59 +00:00
m_strPath = strPath;
return *this;
}
//-------------------------------------------------------------
// Post : Converts path 2 string
// Task : Convert path 2 string
// Warning: because this pointer 2 string point in the data
2016-01-12 06:52:59 +00:00
// of this class, it is possible 2 cast the result of this
// function in any non-constant pointer and alter the data.
// Very dangerous
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
CPath::operator const char *() const
{
2015-10-25 11:10:54 +00:00
return (const char *)m_strPath.c_str();
}
2015-10-25 11:10:54 +00:00
CPath::CPath(DIR_CURRENT_DIRECTORY /*sdt*/, const char * NameExten)
{
2016-01-12 06:52:59 +00:00
// Application's current directory
Init();
CurrentDirectory();
if (NameExten) { SetNameExtension(NameExten); }
}
2015-10-25 11:10:54 +00:00
CPath::CPath(DIR_MODULE_DIRECTORY /*sdt*/, const char * NameExten)
{
2016-01-12 06:52:59 +00:00
// The directory where the executable of this app is
Init();
ModuleDirectory();
if (NameExten) { SetNameExtension(NameExten); }
}
CPath::CPath(DIR_MODULE_FILE /*sdt*/)
{
2016-01-12 06:52:59 +00:00
// The directory where the executable of this app is
Init();
Module();
}
//-------------------------------------------------------------
// Post : Returns the drive component without a colon, e.g. "c"
2016-01-12 06:52:59 +00:00
// Returns the directory component with a leading backslash,
// but no trailing backslash, e.g. "\dir\subdir"
// Returns name compleletely without delimiters, e.g "letter"
// Returns extension completely without delimiters, e.g. "doc"
// Globals :
// I/O :
2016-01-12 06:52:59 +00:00
// Task : Return the individual components of this path.
// For any given argument, you can pass NULL if you are not
// interested in that component.
2016-01-12 06:52:59 +00:00
// Do not rely on pNames being <= 8 characters, extensions
// being <= 3 characters, or drives being 1 character
//-------------------------------------------------------------
2016-01-12 12:19:50 +00:00
void CPath::GetComponents(std::string* pDrive, std::string* pDirectory, std::string* pName, std::string* pExtension) const
{
2016-01-12 12:19:50 +00:00
char buff_drive[_MAX_DRIVE + 1];
char buff_dir[_MAX_DIR + 1];
char buff_name[_MAX_FNAME + 1];
char buff_ext[_MAX_EXT + 1];
2016-01-12 06:52:59 +00:00
ZeroMemory(buff_drive, sizeof(buff_drive));
ZeroMemory(buff_dir, sizeof(buff_dir));
ZeroMemory(buff_name, sizeof(buff_name));
2016-01-12 06:52:59 +00:00
ZeroMemory(buff_ext, sizeof(buff_ext));
2016-01-12 12:19:50 +00:00
_splitpath(m_strPath.c_str(), pDrive ? buff_drive : NULL, pDirectory ? buff_dir : NULL, pName ? buff_name : NULL, pExtension ? buff_ext : NULL);
2016-01-12 06:52:59 +00:00
if (pDrive)
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
*pDrive = buff_drive;
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
if (pDirectory)
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
*pDirectory = buff_dir;
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
if (pName)
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
*pName = buff_name;
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
if (pExtension)
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
*pExtension = buff_ext;
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
// DOS's _splitpath returns "d:", we return "d"
if (pDrive)
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
StripTrailingChar(*pDrive, DRIVE_DELIMITER);
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
// DOS's _splitpath returns "\dir\subdir\", we return "\dir\subdir"
if (pDirectory)
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
StripTrailingBackslash(*pDirectory);
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
// DOS's _splitpath returns ".ext", we return "ext"
if (pExtension)
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
StripLeadingChar(*pExtension, EXTENSION_DELIMITER);
2016-01-12 12:19:50 +00:00
}
}
//-------------------------------------------------------------
// Task : Get drive and directory from path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::GetDriveDirectory(std::string& rDriveDirectory) const
{
2015-10-25 11:10:54 +00:00
std::string Drive;
std::string Directory;
2016-01-12 06:52:59 +00:00
GetComponents(&Drive, &Directory);
rDriveDirectory = Drive;
if (!Drive.empty())
{
2016-01-12 06:52:59 +00:00
rDriveDirectory += DRIVE_DELIMITER;
rDriveDirectory += Directory;
}
}
2015-10-25 11:10:54 +00:00
std::string CPath::GetDriveDirectory(void) const
{
2016-01-12 06:52:59 +00:00
std::string rDriveDirectory;
GetDriveDirectory(rDriveDirectory);
return rDriveDirectory;
}
//-------------------------------------------------------------
// Task : Get directory from path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::GetDirectory(std::string& rDirectory) const
{
2016-01-12 06:52:59 +00:00
GetComponents(NULL, &rDirectory);
}
2015-10-25 11:10:54 +00:00
std::string CPath::GetDirectory(void) const
{
2016-01-12 06:52:59 +00:00
std::string rDirectory;
2016-01-12 12:19:50 +00:00
GetDirectory(rDirectory);
2016-01-12 06:52:59 +00:00
return rDirectory;
}
//-------------------------------------------------------------
// Task : Get filename and extension from path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::GetNameExtension(std::string& rNameExtension) const
{
2015-10-25 11:10:54 +00:00
std::string Name;
std::string Extension;
2016-01-12 06:52:59 +00:00
GetComponents(NULL, NULL, &Name, &Extension);
rNameExtension = Name;
if (!Extension.empty())
{
2016-01-12 06:52:59 +00:00
rNameExtension += EXTENSION_DELIMITER;
rNameExtension += Extension;
}
}
2015-10-25 11:10:54 +00:00
std::string CPath::GetNameExtension(void) const
{
2016-01-12 06:52:59 +00:00
std::string rNameExtension;
GetNameExtension(rNameExtension);
return rNameExtension;
}
//-------------------------------------------------------------
// Task : Get filename from path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::GetName(std::string& rName) const
{
2016-01-12 06:52:59 +00:00
GetComponents(NULL, NULL, &rName);
}
2015-10-25 11:10:54 +00:00
std::string CPath::GetName(void) const
{
2016-01-12 06:52:59 +00:00
std::string rName;
2016-01-12 12:19:50 +00:00
GetName(rName);
2016-01-12 06:52:59 +00:00
return rName;
}
//-------------------------------------------------------------
// Task : Get file extension from path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::GetExtension(std::string& rExtension) const
{
2016-01-12 06:52:59 +00:00
GetComponents(NULL, NULL, NULL, &rExtension);
}
2015-10-25 11:10:54 +00:00
std::string CPath::GetExtension(void) const
{
2016-01-12 06:52:59 +00:00
std::string rExtension;
2016-01-12 12:19:50 +00:00
GetExtension(rExtension);
2016-01-12 06:52:59 +00:00
return rExtension;
}
//-------------------------------------------------------------
// Task : Get current directory
//-------------------------------------------------------------
void CPath::GetLastDirectory(std::string& rDirectory) const
{
2016-01-12 06:52:59 +00:00
std::string Directory;
rDirectory = "";
GetDirectory(Directory);
StripTrailingBackslash(Directory);
if (Directory.empty())
{
return;
}
std::string::size_type nDelimiter = Directory.rfind(DIRECTORY_DELIMITER);
2016-01-12 06:52:59 +00:00
rDirectory = Directory.substr(nDelimiter);
StripLeadingBackslash(rDirectory);
}
std::string CPath::GetLastDirectory(void) const
{
2016-01-12 06:52:59 +00:00
std::string rDirecotry;
GetLastDirectory(rDirecotry);
return rDirecotry;
}
//-------------------------------------------------------------
// Task : Get fully qualified path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::GetFullyQualified(std::string& rFullyQualified) const
{
2016-01-12 12:19:50 +00:00
char buff_fullname[MAX_PATH];
2016-01-12 06:52:59 +00:00
memset(buff_fullname, 0, sizeof(buff_fullname));
2016-01-12 06:52:59 +00:00
_fullpath(buff_fullname, m_strPath.c_str(), MAX_PATH - 1);
rFullyQualified = buff_fullname;
}
//-------------------------------------------------------------
// Post : Return TRUE if path does not start from filesystem root
// Task : Check if path is a relative one (e.g. doesn't start with C:\...)
2016-01-12 06:52:59 +00:00
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::IsRelative() const
{
2016-01-12 06:52:59 +00:00
if (m_strPath.length() > 1 && m_strPath[1] == DRIVE_DELIMITER)
{
return false;
}
if (m_strPath.length() > 1 && m_strPath[0] == DIRECTORY_DELIMITER && m_strPath[1] == DIRECTORY_DELIMITER)
{
return false;
}
return true;
}
//-------------------------------------------------------------
// Task : Set path components
//-------------------------------------------------------------
2016-01-12 12:19:50 +00:00
void CPath::SetComponents(const char * lpszDrive, const char * lpszDirectory, const char * lpszName, const char * lpszExtension)
{
2016-01-12 12:19:50 +00:00
char buff_fullname[MAX_PATH];
2016-01-12 06:52:59 +00:00
memset(buff_fullname, 0, sizeof(buff_fullname));
if (lpszDirectory == NULL || strlen(lpszDirectory) == 0)
{
static char empty_dir[] = { DIRECTORY_DELIMITER, '\0' };
lpszDirectory = empty_dir;
}
2016-01-12 06:52:59 +00:00
_makepath(buff_fullname, lpszDrive, lpszDirectory, lpszName, lpszExtension);
m_strPath.erase();
2016-01-12 06:52:59 +00:00
m_strPath = buff_fullname;
}
//-------------------------------------------------------------
// Task : Set path's drive
//-------------------------------------------------------------
2016-01-12 12:19:50 +00:00
void CPath::SetDrive(char chDrive)
{
2016-01-12 06:52:59 +00:00
stdstr_f Drive("%c", chDrive);
std::string Directory;
std::string Name;
std::string Extension;
GetComponents(NULL, &Directory, &Name, &Extension);
SetComponents(Drive.c_str(), Directory.c_str(), Name.c_str(), Extension.c_str());
}
//-------------------------------------------------------------
// Task : Set path's directory
//-------------------------------------------------------------
2016-01-12 12:19:50 +00:00
void CPath::SetDirectory(const char * lpszDirectory, bool bEnsureAbsolute /*= false*/)
{
2016-01-12 06:52:59 +00:00
std::string Directory = lpszDirectory;
std::string Name;
std::string Extension;
if (bEnsureAbsolute)
{
EnsureLeadingBackslash(Directory);
}
if (Directory.length() > 0)
{
EnsureTrailingBackslash(Directory);
}
2016-01-12 12:19:50 +00:00
std::string Drive;
2016-01-12 06:52:59 +00:00
GetComponents(&Drive, NULL, &Name, &Extension);
SetComponents(Drive.c_str(), Directory.c_str(), Name.c_str(), Extension.c_str());
}
//-------------------------------------------------------------
// Task : Set path's drive and directory
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::SetDriveDirectory(const char * lpszDriveDirectory)
{
2016-01-12 06:52:59 +00:00
std::string DriveDirectory = lpszDriveDirectory;
std::string Name;
std::string Extension;
if (DriveDirectory.length() > 0)
{
EnsureTrailingBackslash(DriveDirectory);
cleanPathString(DriveDirectory);
}
2016-01-12 06:52:59 +00:00
GetComponents(NULL, NULL, &Name, &Extension);
SetComponents(NULL, DriveDirectory.c_str(), Name.c_str(), Extension.c_str());
}
//-------------------------------------------------------------
// Task : Set path's filename
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::SetName(const char * lpszName)
{
2016-01-12 06:52:59 +00:00
std::string Directory;
std::string Extension;
2016-01-12 12:19:50 +00:00
std::string Drive;
2016-01-12 06:52:59 +00:00
GetComponents(&Drive, &Directory, NULL, &Extension);
SetComponents(Drive.c_str(), Directory.c_str(), lpszName, Extension.c_str());
}
//-------------------------------------------------------------
// Task : Set path's filename
//-------------------------------------------------------------
void CPath::SetName(int iName)
{
2016-01-12 06:52:59 +00:00
std::string Directory;
std::string Extension;
2016-01-12 12:19:50 +00:00
char sName[33];
2016-01-12 06:52:59 +00:00
memset(sName, 0, sizeof(sName));
2016-01-12 12:19:50 +00:00
_snprintf(sName, sizeof(sName), "%d", iName);
2016-01-12 12:19:50 +00:00
std::string Drive;
2016-01-12 06:52:59 +00:00
GetComponents(&Drive, &Directory, NULL, &Extension);
SetComponents(Drive.c_str(), Directory.c_str(), sName, Extension.c_str());
}
//-------------------------------------------------------------
// Task : Set path's file extension
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::SetExtension(const char * lpszExtension)
{
2016-01-12 06:52:59 +00:00
std::string Directory;
std::string Name;
2016-01-12 12:19:50 +00:00
std::string Drive;
2016-01-12 06:52:59 +00:00
GetComponents(&Drive, &Directory, &Name);
SetComponents(Drive.c_str(), Directory.c_str(), Name.c_str(), lpszExtension);
}
//-------------------------------------------------------------
// Task : Set path's file extension
//-------------------------------------------------------------
void CPath::SetExtension(int iExtension)
{
2016-01-12 06:52:59 +00:00
std::string Directory;
std::string Name;
2016-01-12 12:19:50 +00:00
char sExtension[20];
2016-01-12 06:52:59 +00:00
memset(sExtension, 0, sizeof(sExtension));
2016-01-12 12:19:50 +00:00
_snprintf(sExtension, sizeof(sExtension), "%d", iExtension);
2016-01-12 12:19:50 +00:00
std::string Drive;
2016-01-12 06:52:59 +00:00
GetComponents(&Drive, &Directory, &Name);
SetComponents(Drive.c_str(), Directory.c_str(), Name.c_str(), sExtension);
}
//-------------------------------------------------------------
// Task : Set path's filename and extension
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::SetNameExtension(const char * lpszNameExtension)
{
2016-01-12 06:52:59 +00:00
std::string Directory;
2016-01-12 12:19:50 +00:00
std::string Drive;
2016-01-12 06:52:59 +00:00
GetComponents(&Drive, &Directory);
SetComponents(Drive.c_str(), Directory.c_str(), lpszNameExtension, NULL);
}
//-------------------------------------------------------------
// Task : Append a subdirectory 2 path's directory
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::AppendDirectory(const char * lpszSubDirectory)
2016-01-12 06:52:59 +00:00
{
std::string Directory;
std::string SubDirectory = lpszSubDirectory;
std::string Name;
std::string Extension;
if (SubDirectory.empty())
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
return;
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
// Strip out any preceeding backslash
StripLeadingBackslash(SubDirectory);
EnsureTrailingBackslash(SubDirectory);
2016-01-12 12:19:50 +00:00
std::string Drive;
2016-01-12 06:52:59 +00:00
GetComponents(&Drive, &Directory, &Name, &Extension);
EnsureTrailingBackslash(Directory);
Directory += SubDirectory;
2016-01-12 06:52:59 +00:00
SetComponents(Drive.c_str(), Directory.c_str(), Name.c_str(), Extension.c_str());
}
//-------------------------------------------------------------
// Pre : If pLastDirectory is given we will store the name of the
// deepest directory (the one we're just exiting) in it
// Task : Remove deepest subdirectory from path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::UpDirectory(std::string *pLastDirectory /*= NULL*/)
{
2016-01-12 06:52:59 +00:00
std::string Directory;
GetDirectory(Directory);
StripTrailingBackslash(Directory);
if (Directory.empty())
return;
std::string::size_type nDelimiter = Directory.rfind(DIRECTORY_DELIMITER);
2016-01-12 06:52:59 +00:00
if (pLastDirectory != NULL)
{
*pLastDirectory = Directory.substr(nDelimiter);
StripLeadingBackslash(*pLastDirectory);
}
if (nDelimiter != std::string::npos)
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
Directory = Directory.substr(0, nDelimiter);
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
SetDirectory(Directory.c_str());
}
//-------------------------------------------------------------
// Task : Set path 2 current directory
//-------------------------------------------------------------
void CPath::CurrentDirectory()
{
2016-01-12 12:19:50 +00:00
char buff_path[MAX_PATH];
2016-01-12 06:52:59 +00:00
memset(buff_path, 0, sizeof(buff_path));
::GetCurrentDirectory(MAX_PATH, buff_path);
2016-01-12 06:52:59 +00:00
Empty();
SetDriveDirectory(buff_path);
}
//-------------------------------------------------------------
// Task : Set path 2 the name of specified module
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::Module(void * hInstance)
{
2016-01-12 12:19:50 +00:00
char buff_path[MAX_PATH];
2016-01-12 06:52:59 +00:00
memset(buff_path, 0, sizeof(buff_path));
2016-01-12 06:52:59 +00:00
GetModuleFileName((HINSTANCE)hInstance, buff_path, MAX_PATH);
m_strPath = buff_path;
}
//-------------------------------------------------------------
// Task : Set path 2 the name of current module
//-------------------------------------------------------------
void CPath::Module()
{
2016-01-12 12:19:50 +00:00
Module(m_hInst);
}
//-------------------------------------------------------------
// Task : Set path 2 the directory of specified module
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::ModuleDirectory(void * hInstance)
{
2016-01-12 12:19:50 +00:00
Module(hInstance);
2016-01-12 06:52:59 +00:00
SetNameExtension("");
}
//-------------------------------------------------------------
// Task : Set path 2 the directory of current module
//-------------------------------------------------------------
void CPath::ModuleDirectory()
{
2016-01-12 06:52:59 +00:00
Module();
SetNameExtension("");
}
//---------------------------------------------------------------------------
// Post : Return TRUE if a directory
// Task : Check if this path represents a directory
//---------------------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::IsDirectory() const
{
// Check if this path has a filename
2015-10-25 11:10:54 +00:00
std::string file_name;
GetNameExtension(file_name);
2016-01-12 06:52:59 +00:00
return file_name.empty();
}
//-------------------------------------------------------------
// Post : Return TRUE if directory exists
// Task : To determine if the directory exists, we need to
// create a test path with a wildcard (*.*) extension
// and see if FindFirstFile returns anything. We don't
// use CPath::FindFirst() because that routine parses out
// '.' and '..', which fails for empty directories
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::DirectoryExists() const
{
2016-01-12 06:52:59 +00:00
// Create test path
CPath TestPath(m_strPath.c_str());
2016-01-12 06:52:59 +00:00
std::string DirName;
TestPath.UpDirectory(&DirName);
TestPath.SetNameExtension(DirName.c_str());
2016-01-12 06:52:59 +00:00
WIN32_FIND_DATA FindData;
HANDLE hFindFile = FindFirstFile((const char *)TestPath, &FindData); // Find anything
bool bGotDirectory = (hFindFile != INVALID_HANDLE_VALUE) && (FindData.dwFileAttributes && FILE_ATTRIBUTE_DIRECTORY != 0);
2016-01-12 06:52:59 +00:00
if (hFindFile != NULL) // Make sure we close the search
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
FindClose(hFindFile);
2016-01-12 12:19:50 +00:00
}
return bGotDirectory;
2016-01-12 06:52:59 +00:00
}
//-------------------------------------------------------------
// Post : Return TRUE if these is such a file
// Task : Check if file exists
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::Exists() const
{
2016-01-12 06:52:59 +00:00
WIN32_FIND_DATA FindData;
HANDLE hFindFile = FindFirstFile(m_strPath.c_str(), &FindData);
bool bSuccess = (hFindFile != INVALID_HANDLE_VALUE);
2016-01-12 06:52:59 +00:00
if (hFindFile != NULL) // Make sure we close the search
2016-01-12 12:19:50 +00:00
{
2016-01-12 06:52:59 +00:00
FindClose(hFindFile);
2016-01-12 12:19:50 +00:00
}
2016-01-12 06:52:59 +00:00
return bSuccess;
}
//-------------------------------------------------------------
// Post : Return TRUE on success
// Task : Delete file
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::Delete(bool bEvenIfReadOnly) const
{
2016-01-12 06:52:59 +00:00
uint32_t dwAttr = ::GetFileAttributes(m_strPath.c_str());
if (dwAttr == (uint32_t)-1)
2016-01-12 12:19:50 +00:00
{
// File does not exists
2016-01-12 12:19:50 +00:00
return false;
}
2016-01-12 06:52:59 +00:00
if (((dwAttr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) && !bEvenIfReadOnly)
2016-01-12 12:19:50 +00:00
{
// File is read-only, and we're not allowed 2 delete it
2016-01-12 12:19:50 +00:00
return false;
}
2016-01-12 06:52:59 +00:00
SetFileAttributes(m_strPath.c_str(), FILE_ATTRIBUTE_NORMAL);
2015-10-25 11:10:54 +00:00
return DeleteFile(m_strPath.c_str()) != 0;
2016-01-12 06:52:59 +00:00
}
//-------------------------------------------------------------
2016-01-12 12:19:50 +00:00
// Post : Return TRUE on success, false if there is such a target file
// and we weren't granted permission 2 overwrite file or some error
// Task : Copy file
// Since ::CopyFile will not overwrite read only files
// we will make sure the target file is writable first
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::CopyTo(const char * lpcszTargetFile, bool bOverwrite)
{
// Check if the target file exists
CPath TargetFile(lpcszTargetFile);
2016-01-12 06:52:59 +00:00
if (TargetFile.Exists())
{
2016-01-12 06:52:59 +00:00
// Yeah there is already such a target file
// Decide if we should overwrite
2016-01-12 06:52:59 +00:00
if (!bOverwrite)
2016-01-12 12:19:50 +00:00
{
return false;
}
// Delete any previous target
2016-01-12 12:19:50 +00:00
if (!TargetFile.Delete(true))
{
return false;
}
}
2016-01-12 06:52:59 +00:00
// CopyFile will set the target's attributes 2 the same as
// the source after copying
2016-01-12 06:52:59 +00:00
return CopyFile(m_strPath.c_str(), lpcszTargetFile, !bOverwrite) != 0;
}
//-------------------------------------------------------------
2016-01-12 12:19:50 +00:00
// Post : Return TRUE on success, false if there is such a target file
// and we weren't granted permission 2 overwrite file or some error
// Task : Move file
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::MoveTo(const char * lpcszTargetFile, bool bOverwrite)
{
// Check if the target file exists
CPath TargetFile(lpcszTargetFile);
2016-01-12 06:52:59 +00:00
if (TargetFile.Exists())
{
2016-01-12 06:52:59 +00:00
// Yeah there is already such a target file
// Decide if we should overwrite
2016-01-12 06:52:59 +00:00
if (!bOverwrite)
2016-01-12 12:19:50 +00:00
{
return false;
}
// Delete any previous target
2016-01-12 06:52:59 +00:00
if (!TargetFile.Delete(TRUE))
2016-01-12 12:19:50 +00:00
{
return false;
}
}
2016-01-12 06:52:59 +00:00
return MoveFile(m_strPath.c_str(), lpcszTargetFile) != 0;
}
//-------------------------------------------------------------
// Post : Return TRUE if attributes do match
// Task : Compare finder attributes
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::AttributesMatch(uint32_t dwTargetAttributes, uint32_t dwFileAttributes)
{
2016-01-12 06:52:59 +00:00
if (dwTargetAttributes == _A_ALLFILES)
{
return true;
}
if (dwTargetAttributes == _A_NORMAL)
{
return ((_A_SUBDIR & dwFileAttributes) == 0);
}
return (((dwTargetAttributes & dwFileAttributes) != 0) && ((_A_SUBDIR & dwTargetAttributes) == (_A_SUBDIR & dwFileAttributes)));
}
//-------------------------------------------------------------
// Post : Return TRUE if any match found
// Task : Find the first file that meets this path and the specified attributes
2016-01-12 06:52:59 +00:00
// You can specify the current attributes of the file or directory
// The attributes are represented by a combination (|) of the following
// constants:
//
2016-01-12 06:52:59 +00:00
// _A_ARCH Archive. Set whenever the file is
// changed, and cleared by the BACKUP command
2016-01-12 06:52:59 +00:00
// _A_HIDDEN Hidden file. Not normally seen with
// the DIR command, unless the /AH option
// is used. Returns information about normal
// files as well as files with this attribute
2016-01-12 06:52:59 +00:00
// _A_NORMAL Normal. File can be read or written to
// without restriction
2016-01-12 06:52:59 +00:00
// _A_RDONLY Read-only. File cannot be opened for writing,
// and a file with the same name cannot be created
// _A_SUBDIR Subdirectory
2016-01-12 06:52:59 +00:00
// _A_SYSTEM System file. Not normally seen with the DIR
// command, unless the /AS option is used
//
// These attributes do not follow a simple additive logic
// Note that _A_NORMAL is 0x00, so it effectively cannot be
// removed from the attribute set. You will therefore always
// get normal files, and may also get Archive, Hidden, etc.
// if you specify those attributes
// See aso: FindFirstFile, FindNextFile
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::FindFirst(uint32_t dwAttributes /*= _A_NORMAL*/)
{
2016-01-12 06:52:59 +00:00
m_dwFindFileAttributes = dwAttributes;
BOOL bGotFile;
BOOL bWantSubdirectory = (BOOL)(_A_SUBDIR & dwAttributes);
// Close handle to any previous enumeration
Exit();
2016-01-12 06:52:59 +00:00
// i.) Finding first candidate file
WIN32_FIND_DATA FindData;
m_hFindFile = FindFirstFile(m_strPath.c_str(), &FindData);
bGotFile = (m_hFindFile != INVALID_HANDLE_VALUE);
while (bGotFile)
{
// ii.) Compare candidate to attributes, and filter out the "." and ".." folders
if (!AttributesMatch(m_dwFindFileAttributes, FindData.dwFileAttributes))
goto LABEL_GetAnother;
if (bWantSubdirectory && (FindData.cFileName[0] == '.'))
goto LABEL_GetAnother;
// iii.) Found match, prepare result
if ((_A_SUBDIR & FindData.dwFileAttributes) != 0)
StripTrailingBackslash(m_strPath);
2016-01-12 06:52:59 +00:00
SetNameExtension(FindData.cFileName);
2016-01-12 06:52:59 +00:00
if ((_A_SUBDIR & FindData.dwFileAttributes) != 0)
EnsureTrailingBackslash(m_strPath);
2016-01-12 06:52:59 +00:00
return TRUE;
// iv.) Not found match, get another
LABEL_GetAnother:
bGotFile = FindNextFile(m_hFindFile, &FindData);
}
2016-01-12 12:19:50 +00:00
return false;
}
//-------------------------------------------------------------
// Post : Return TRUE if a new match found
2016-01-12 06:52:59 +00:00
// Task : Find the next file that meets the conditions specified
// in the last FindFirst call
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::FindNext()
{
if (m_hFindFile == NULL)
2016-01-12 12:19:50 +00:00
{
return false;
}
2016-01-12 06:52:59 +00:00
WIN32_FIND_DATA FindData;
2016-01-12 12:19:50 +00:00
while (FindNextFile(m_hFindFile, &FindData) != false)
{ // while(FindNext(...))
2016-01-12 06:52:59 +00:00
if (AttributesMatch(m_dwFindFileAttributes, FindData.dwFileAttributes))
{ // if(AttributesMatch(...)
if ((_A_SUBDIR & FindData.dwFileAttributes) == _A_SUBDIR)
{
if (IsDirectory())
{
// Found a directory
UpDirectory();
}
else
{
SetNameExtension("");
}
AppendDirectory(FindData.cFileName);
}
else
{
// Found a file
2016-01-12 06:52:59 +00:00
if (IsDirectory())
{
// Found a directory
UpDirectory();
}
SetNameExtension(FindData.cFileName);
}
if ((_A_SUBDIR & FindData.dwFileAttributes) == _A_SUBDIR)
EnsureTrailingBackslash(m_strPath);
return TRUE;
}
}
2016-01-12 12:19:50 +00:00
return false;
}
//-------------------------------------------------------------
// Post : Return TRUE on success
// Task : Change current working directory of application 2 path
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::ChangeDirectory()
{
2016-01-12 06:52:59 +00:00
std::string DriveDirectory;
GetDriveDirectory(DriveDirectory);
2015-10-25 11:10:54 +00:00
return SetCurrentDirectory(DriveDirectory.c_str()) != 0;
}
//-------------------------------------------------------------
// Pre : If bCreateIntermediates is TRUE, create all eventually
// missing parent directories too
// Post : Return TRUE on success
// Task : Create new directory
//-------------------------------------------------------------
2015-10-25 11:10:54 +00:00
bool CPath::DirectoryCreate(bool bCreateIntermediates /*= TRUE*/)
{
2016-01-12 06:52:59 +00:00
std::string PathText;
bool bSuccess;
GetDriveDirectory(PathText);
StripTrailingBackslash(PathText);
2016-01-12 06:52:59 +00:00
bSuccess = ::CreateDirectory(PathText.c_str(), NULL) != 0;
if (!bSuccess)
{
CPath CurrentDir(CPath::CURRENT_DIRECTORY);
bSuccess = ChangeDirectory() != 0;
CurrentDir.ChangeDirectory();
}
if (!bSuccess && bCreateIntermediates)
{
std::string::size_type nDelimiter = PathText.rfind(DIRECTORY_DELIMITER);
if (nDelimiter == std::string::npos)
2016-01-12 12:19:50 +00:00
{
return false;
}
2016-01-12 06:52:59 +00:00
PathText.resize(nDelimiter + 1);
CPath SubPath(PathText);
2016-01-12 12:19:50 +00:00
return SubPath.DirectoryCreate() ? DirectoryCreate(false) : false;
2016-01-12 06:52:59 +00:00
}
return bSuccess;
}
//Helpers
//------------------------------------------------------------------------
// Task : Remove first character (if any) if it's chLeading
//------------------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::cleanPathString(std::string& rDirectory) const
{
2016-01-12 06:52:59 +00:00
std::string::size_type pos = rDirectory.find(DIRECTORY_DELIMITER2);
while (pos != std::string::npos)
{
rDirectory.replace(pos, 1, &DIRECTORY_DELIMITER);
pos = rDirectory.find(DIRECTORY_DELIMITER2, pos + 1);
}
2016-01-12 12:19:50 +00:00
bool AppendEnd = !_strnicmp(rDirectory.c_str(), DIR_DOUBLEDELIM, 2);
2016-01-12 06:52:59 +00:00
pos = rDirectory.find(DIR_DOUBLEDELIM);
while (pos != std::string::npos)
{
rDirectory.replace(pos, 2, &DIRECTORY_DELIMITER);
pos = rDirectory.find(DIR_DOUBLEDELIM, pos + 1);
}
if (AppendEnd)
{
rDirectory.insert(0, stdstr_f("%c", DIRECTORY_DELIMITER).c_str());
2016-01-12 06:52:59 +00:00
}
}
2016-01-12 12:19:50 +00:00
void CPath::StripLeadingChar(std::string& rText, char chLeading) const
{
2016-01-12 06:52:59 +00:00
std::string::size_type nLength = rText.length();
if (nLength == 0)
return;
2016-01-12 06:52:59 +00:00
if (rText[0] == chLeading)
rText = rText.substr(1);
}
//------------------------------------------------------------------------
// Task : Remove first character if \
//------------------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::StripLeadingBackslash(std::string& Directory) const
{
2016-01-12 06:52:59 +00:00
std::string::size_type nLength = Directory.length();
// If Directory is of the form '\', don't do it
2016-01-12 06:52:59 +00:00
if (nLength <= 1)
return;
2016-01-12 06:52:59 +00:00
if (Directory[0] == DIRECTORY_DELIMITER)
Directory = Directory.substr(1);
}
//------------------------------------------------------------------------
// Task : Remove last character (if any) if it's chTrailing
//------------------------------------------------------------------------
2016-01-12 12:19:50 +00:00
void CPath::StripTrailingChar(std::string& rText, char chTrailing) const
{
2016-01-12 06:52:59 +00:00
std::string::size_type nLength = rText.length();
if (nLength == 0)
return;
if (rText[nLength - 1] == chTrailing)
rText.resize(nLength - 1);
}
//------------------------------------------------------------------------
// Task : Remove last character if \
//------------------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::StripTrailingBackslash(std::string& rDirectory) const
{
2016-01-12 06:52:59 +00:00
for (;;)
{
std::string::size_type nLength = rDirectory.length();
if (nLength <= 1)
{
return;
}
if (rDirectory[nLength - 1] == DIRECTORY_DELIMITER || rDirectory[nLength - 1] == DIRECTORY_DELIMITER2)
{
rDirectory.resize(nLength - 1);
continue;
}
return;
}
}
//------------------------------------------------------------------------
// Task : Add a backslash to the end of Directory if there is
// not already one there
//------------------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::EnsureTrailingBackslash(std::string& Directory) const
{
2016-01-12 06:52:59 +00:00
std::string::size_type nLength = Directory.length();
2016-01-12 06:52:59 +00:00
if (Directory.empty() || (Directory[nLength - 1] != DIRECTORY_DELIMITER))
{
Directory += DIRECTORY_DELIMITER;
}
}
//------------------------------------------------------------------------
// Task : Add a backslash to the beginning of Directory if there
// is not already one there
//------------------------------------------------------------------------
2015-10-25 11:10:54 +00:00
void CPath::EnsureLeadingBackslash(std::string & Directory) const
{
2016-01-12 06:52:59 +00:00
if (Directory.empty() || (Directory[0] != DIRECTORY_DELIMITER))
{
2016-01-12 06:52:59 +00:00
Directory = stdstr_f("%c%s", DIRECTORY_DELIMITER, Directory.c_str());
}
2016-01-12 06:52:59 +00:00
}