// Path.cpp: implementation of the CPath class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include ////////////////////////////////////////////////////////////////////// // Constants ////////////////////////////////////////////////////////////////////// LPCTSTR const DLL_EXTENSION = _T("dll"); LPCTSTR const INI_EXTENSION = _T("ini"); LPCTSTR const EXE_EXTENSION = _T("exe"); LPCTSTR const WILD_NAME_EXTENSION = _T("*.*"); const TCHAR WILD_ONE = '?'; const TCHAR WILD_ANY = '*'; LPCTSTR const WILD_SET = _T("?*"); LPCTSTR const DIR_DOUBLEDELIM = _T("\\\\"); const TCHAR DRIVE_DELIMITER = ':'; const TCHAR DIRECTORY_DELIMITER = '\\'; const TCHAR EXTENSION_DELIMITER = '.'; const TCHAR DIRECTORY_DELIMITER2 = '/'; HINSTANCE CPath::m_hInst = NULL; ////////////////////////////////////////////////////////////////////// // Helpers ////////////////////////////////////////////////////////////////////// void CPath::SethInst ( HINSTANCE hInst ) { m_hInst = hInst; } HINSTANCE CPath::GethInst() { return m_hInst; } ////////////////////////////////////////////////////////////////////// // Initialisation ////////////////////////////////////////////////////////////////////// //------------------------------------------------------------- // Task : Helper function for the various CPath constructors. // Initializes the data members and establishes various // class invariants //------------------------------------------------------------- inline void CPath::Init() { m_dwFindFileAttributes =0; m_hFindFile =NULL; } //------------------------------------------------------------- // Task : Helper function for the various CPath destructors. // Cleans up varios internals //------------------------------------------------------------- inline void CPath::Exit() { if(m_hFindFile != NULL) { FindClose(m_hFindFile); m_hFindFile =NULL; } } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// //------------------------------------------------------------- // Task : Constructs a path //------------------------------------------------------------- CPath::CPath() { Init(); Empty(); } //------------------------------------------------------------- // Task : Constructs a path as copy of another //------------------------------------------------------------- CPath::CPath(const CPath& rPath) { Init(); m_strPath =rPath.m_strPath; } //------------------------------------------------------------- // Task : Constructs a path and points it 2 lpszPath //------------------------------------------------------------- CPath::CPath(LPCTSTR lpszPath) { Init(); m_strPath =lpszPath ? lpszPath : _T(""); cleanPathString(m_strPath); } CPath::CPath(LPCTSTR lpszPath, LPCTSTR NameExten) { Init(); SetDriveDirectory(lpszPath); SetNameExtension(NameExten); } //------------------------------------------------------------- // Task : Constructs a path and points it 2 strPath //------------------------------------------------------------- CPath::CPath(const stdstr& strPath) { Init(); m_strPath =strPath; cleanPathString(m_strPath); } //------------------------------------------------------------- // Task : Constructs a path and points it 2 strPath //------------------------------------------------------------- CPath::CPath(const stdstr& strPath, LPCTSTR NameExten ) { Init(); SetDriveDirectory(strPath.c_str()); SetNameExtension(NameExten); } //------------------------------------------------------------- // Task : Constructs a path and points it 2 strPath //------------------------------------------------------------- CPath::CPath(const stdstr& strPath, const stdstr& NameExten ) { Init(); SetDriveDirectory(strPath.c_str()); SetNameExtension(NameExten.c_str()); } //------------------------------------------------------------- // Task : Cleanup and destruct a path object //------------------------------------------------------------- CPath::~CPath() { Exit(); } //------------------------------------------------------------- // Post : Return TRUE if paths are equal // Task : Check if the two path are the same //------------------------------------------------------------- BOOL CPath::operator ==(const CPath& rPath) const { // Get fully qualified versions of the paths stdstr FullyQualified1; stdstr FullyQualified2; GetFullyQualified(FullyQualified1); rPath.GetFullyQualified(FullyQualified2); // Compare them return _tcsicmp(FullyQualified1.c_str(),FullyQualified2.c_str()) == 0; } //------------------------------------------------------------- // Post : Return TRUE if paths are different // Task : Check if the two path are different //------------------------------------------------------------- BOOL CPath::operator !=(const CPath& rPath) const { return !(*this == rPath); } //------------------------------------------------------------- // Task : Assign a path 2 another //------------------------------------------------------------- CPath& CPath::operator =(const CPath& rPath) { if(this != &rPath) m_strPath =rPath.m_strPath; return *this; } //------------------------------------------------------------- // Post : Return the path, so that assignements can be chained // Task : Assign a string 2 a path //------------------------------------------------------------- CPath& CPath::operator =(LPCTSTR lpszPath) { m_strPath =lpszPath ? lpszPath : _T(""); return *this; } //------------------------------------------------------------- // Post : Return the path, so that assignements can be chained // Task : Assign a string 2 a path //------------------------------------------------------------- CPath& CPath::operator =(const stdstr& strPath) { 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 // of this class, it is possible 2 cast the result of this // function in any non-constant pointer and alter the data. // Very dangerous //------------------------------------------------------------- CPath::operator LPCTSTR() const { return (LPCTSTR)m_strPath.c_str(); } CPath::CPath(DIR_CURRENT_DIRECTORY /*sdt*/, LPCTSTR NameExten) { // Application's current directory Init(); CurrentDirectory(); if (NameExten) { SetNameExtension(NameExten); } } CPath::CPath(DIR_MODULE_DIRECTORY /*sdt*/, LPCTSTR NameExten) { // The directory where the executable of this app is Init(); ModuleDirectory(); if (NameExten) { SetNameExtension(NameExten); } } CPath::CPath(DIR_MODULE_FILE /*sdt*/) { // The directory where the executable of this app is Init(); Module(); } //------------------------------------------------------------- // Post : Returns the drive component without a colon, e.g. "c" // 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 : // Task : Return the individual components of this path. // For any given argument, you can pass NULL if you are not // interested in that component. // Do not rely on pNames being <= 8 characters, extensions // being <= 3 characters, or drives being 1 character //------------------------------------------------------------- void CPath::GetComponents(stdstr* pDrive, stdstr* pDirectory, stdstr* pName, stdstr* pExtension) const { TCHAR buff_drive[_MAX_DRIVE + 1]; TCHAR buff_dir [_MAX_DIR + 1]; TCHAR buff_name [_MAX_FNAME + 1]; TCHAR buff_ext [_MAX_EXT + 1]; ZeroMemory(buff_drive,sizeof(buff_drive)); ZeroMemory(buff_dir, sizeof(buff_dir)); ZeroMemory(buff_name, sizeof(buff_name)); ZeroMemory(buff_ext, sizeof(buff_ext)); _tsplitpath(m_strPath.c_str(), pDrive ? buff_drive : NULL, pDirectory ? buff_dir : NULL, pName ? buff_name : NULL, pExtension ? buff_ext : NULL); if(pDrive) *pDrive =buff_drive; if(pDirectory) *pDirectory =buff_dir; if(pName) *pName =buff_name; if(pExtension) *pExtension =buff_ext; // DOS's _splitpath returns "d:", we return "d" if(pDrive) StripTrailingChar(*pDrive,DRIVE_DELIMITER); // DOS's _splitpath returns "\dir\subdir\", we return "\dir\subdir" if(pDirectory) StripTrailingBackslash(*pDirectory); // DOS's _splitpath returns ".ext", we return "ext" if(pExtension) StripLeadingChar(*pExtension,EXTENSION_DELIMITER); } //------------------------------------------------------------- // Task : Get drive and directory from path //------------------------------------------------------------- void CPath::GetDriveDirectory(stdstr& rDriveDirectory) const { stdstr Drive; stdstr Directory; GetComponents(&Drive,&Directory); rDriveDirectory =Drive; if(!Drive.empty()) { rDriveDirectory += DRIVE_DELIMITER; rDriveDirectory += Directory; } } stdstr CPath::GetDriveDirectory(void) const { stdstr rDriveDirectory; GetDriveDirectory(rDriveDirectory); return rDriveDirectory; } //------------------------------------------------------------- // Task : Get directory from path //------------------------------------------------------------- void CPath::GetDirectory(stdstr& rDirectory) const { GetComponents(NULL,&rDirectory); } stdstr CPath::GetDirectory(void) const { stdstr rDirectory; GetComponents(NULL,&rDirectory); return rDirectory; } //------------------------------------------------------------- // Task : Get filename and extension from path //------------------------------------------------------------- void CPath::GetNameExtension(stdstr& rNameExtension) const { stdstr Name; stdstr Extension; GetComponents(NULL,NULL,&Name,&Extension); rNameExtension =Name; if(!Extension.empty()) { rNameExtension += EXTENSION_DELIMITER; rNameExtension += Extension; } } stdstr CPath::GetNameExtension(void) const { stdstr rNameExtension; GetNameExtension(rNameExtension); return rNameExtension; } //------------------------------------------------------------- // Task : Get filename from path //------------------------------------------------------------- void CPath::GetName(stdstr& rName) const { GetComponents(NULL,NULL,&rName); } stdstr CPath::GetName(void) const { stdstr rName; GetComponents(NULL,NULL,&rName); return rName; } //------------------------------------------------------------- // Task : Get file extension from path //------------------------------------------------------------- void CPath::GetExtension(stdstr& rExtension) const { GetComponents(NULL,NULL,NULL,&rExtension); } stdstr CPath::GetExtension(void) const { stdstr rExtension; GetComponents(NULL,NULL,NULL,&rExtension); return rExtension; } //------------------------------------------------------------- // Task : Get current directory //------------------------------------------------------------- void CPath::GetCurrentDirectory(stdstr& rDirectory) const { stdstr Directory; rDirectory = ""; GetDirectory(Directory); StripTrailingBackslash(Directory); if(Directory.empty()) return; stdstr::size_type nDelimiter =Directory.rfind(DIRECTORY_DELIMITER); rDirectory =Directory.substr(nDelimiter); StripLeadingBackslash(rDirectory); } stdstr CPath::GetCurrentDirectory(void) const { stdstr rDirecotry; GetCurrentDirectory(rDirecotry); return rDirecotry; } //------------------------------------------------------------- // Task : Get fully qualified path //------------------------------------------------------------- void CPath::GetFullyQualified(stdstr& rFullyQualified) const { TCHAR buff_fullname[MAX_PATH]; memset(buff_fullname, 0, sizeof(buff_fullname)); _tfullpath(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:\...) //------------------------------------------------------------- BOOL CPath::IsRelative() const { 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 //------------------------------------------------------------- void CPath::SetComponents(LPCTSTR lpszDrive, LPCTSTR lpszDirectory, LPCTSTR lpszName, LPCTSTR lpszExtension) { TCHAR buff_fullname[MAX_PATH]; memset(buff_fullname, 0, sizeof(buff_fullname)); _tmakepath(buff_fullname,lpszDrive,lpszDirectory,lpszName,lpszExtension); m_strPath.erase(); m_strPath =buff_fullname; } //------------------------------------------------------------- // Task : Set path's drive //------------------------------------------------------------- void CPath::SetDrive(TCHAR chDrive) { stdstr_f Drive(_T("%c"),chDrive); stdstr Directory; stdstr Name; stdstr Extension; GetComponents(NULL,&Directory,&Name,&Extension); SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),Extension.c_str()); } //------------------------------------------------------------- // Task : Set path's directory //------------------------------------------------------------- void CPath::SetDirectory(LPCTSTR lpszDirectory, BOOL bEnsureAbsolute /*= FALSE*/) { stdstr Drive; stdstr Directory =lpszDirectory; stdstr Name; stdstr Extension; if(bEnsureAbsolute) EnsureLeadingBackslash(Directory); EnsureTrailingBackslash(Directory); 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 //------------------------------------------------------------- void CPath::SetDriveDirectory(LPCTSTR lpszDriveDirectory) { stdstr DriveDirectory =lpszDriveDirectory; stdstr Name; stdstr Extension; EnsureTrailingBackslash(DriveDirectory); cleanPathString(DriveDirectory); GetComponents(NULL,NULL,&Name,&Extension); SetComponents(NULL,DriveDirectory.c_str(),Name.c_str(),Extension.c_str()); } //------------------------------------------------------------- // Task : Set path's filename //------------------------------------------------------------- void CPath::SetName(LPCTSTR lpszName) { stdstr Drive; stdstr Directory; stdstr Extension; 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) { stdstr Drive; stdstr Directory; stdstr Extension; TCHAR sName[33]; memset(sName, 0, sizeof(sName)); _itot(iName, sName, 10); GetComponents(&Drive,&Directory,NULL,&Extension); SetComponents(Drive.c_str(),Directory.c_str(),sName,Extension.c_str()); } //------------------------------------------------------------- // Task : Set path's file extension //------------------------------------------------------------- void CPath::SetExtension(LPCTSTR lpszExtension) { stdstr Drive; stdstr Directory; stdstr Name; 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) { stdstr Drive; stdstr Directory; stdstr Name; TCHAR sExtension[20]; memset(sExtension, 0, sizeof(sExtension)); _itot(iExtension, sExtension, 10); GetComponents(&Drive,&Directory,&Name); SetComponents(Drive.c_str(),Directory.c_str(),Name.c_str(),sExtension); } //------------------------------------------------------------- // Task : Set path's filename and extension //------------------------------------------------------------- void CPath::SetNameExtension(LPCTSTR lpszNameExtension) { stdstr Drive; stdstr Directory; GetComponents(&Drive,&Directory); SetComponents(Drive.c_str(),Directory.c_str(),lpszNameExtension,NULL); } //------------------------------------------------------------- // Task : Append a subdirectory 2 path's directory //------------------------------------------------------------- void CPath::AppendDirectory(LPCTSTR lpszSubDirectory) { stdstr Drive; stdstr Directory; stdstr SubDirectory =lpszSubDirectory; stdstr Name; stdstr Extension; if(SubDirectory.empty()) return; // Strip out any preceeding backslash StripLeadingBackslash(SubDirectory); EnsureTrailingBackslash(SubDirectory); GetComponents(&Drive,&Directory,&Name,&Extension); EnsureTrailingBackslash(Directory); Directory +=SubDirectory; 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 //------------------------------------------------------------- void CPath::UpDirectory(stdstr *pLastDirectory /*= NULL*/) { stdstr Directory; GetDirectory(Directory); StripTrailingBackslash(Directory); if(Directory.empty()) return; stdstr::size_type nDelimiter =Directory.rfind(DIRECTORY_DELIMITER); if(pLastDirectory != NULL) { *pLastDirectory =Directory.substr(nDelimiter); StripLeadingBackslash(*pLastDirectory); } if(nDelimiter != stdstr::npos) Directory =Directory.substr(0,nDelimiter); SetDirectory(Directory.c_str()); } //------------------------------------------------------------- // Task : Set path 2 current directory //------------------------------------------------------------- void CPath::CurrentDirectory() { TCHAR buff_path[MAX_PATH]; memset(buff_path, 0, sizeof(buff_path)); ::GetCurrentDirectory(MAX_PATH,buff_path); Empty(); SetDriveDirectory(buff_path); } //------------------------------------------------------------- // Task : Set path 2 the name of specified module //------------------------------------------------------------- void CPath::Module(HINSTANCE hInstance) { TCHAR buff_path[MAX_PATH]; memset(buff_path, 0, sizeof(buff_path)); GetModuleFileName(hInstance,buff_path,MAX_PATH); m_strPath =buff_path; } //------------------------------------------------------------- // Task : Set path 2 the name of current module //------------------------------------------------------------- void CPath::Module() { TCHAR buff_path[MAX_PATH]; memset(buff_path, 0, sizeof(buff_path)); GetModuleFileName(m_hInst,buff_path,MAX_PATH); m_strPath =buff_path; } //------------------------------------------------------------- // Task : Set path 2 the directory of specified module //------------------------------------------------------------- void CPath::ModuleDirectory(HINSTANCE hInstance) { Module(hInstance); SetNameExtension(_T("")); } //------------------------------------------------------------- // Task : Set path 2 the directory of current module //------------------------------------------------------------- void CPath::ModuleDirectory() { Module(); SetNameExtension(_T("")); } //--------------------------------------------------------------------------- // Post : Return TRUE if a directory // Task : Check if this path represents a directory //--------------------------------------------------------------------------- BOOL CPath::IsDirectory() const { // Check if this path has a filename stdstr file_name; GetNameExtension(file_name); 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 //------------------------------------------------------------- BOOL CPath::DirectoryExists() const { // Create test path CPath TestPath(m_strPath.c_str()); stdstr DirName; TestPath.UpDirectory(&DirName); TestPath.SetNameExtension(DirName.c_str()); WIN32_FIND_DATA FindData; HANDLE hFindFile =FindFirstFile((LPCTSTR)TestPath,&FindData); // Find anything BOOL bGotFile =(hFindFile != INVALID_HANDLE_VALUE); if(hFindFile != NULL) // Make sure we close the search FindClose(hFindFile); return bGotFile; } //------------------------------------------------------------- // Post : Return TRUE if these is such a file // Task : Check if file exists //------------------------------------------------------------- BOOL CPath::Exists() const { WIN32_FIND_DATA FindData; HANDLE hFindFile =FindFirstFile(m_strPath.c_str(),&FindData); BOOL bSuccess =(hFindFile != INVALID_HANDLE_VALUE); if(hFindFile != NULL) // Make sure we close the search FindClose(hFindFile); return bSuccess; } //------------------------------------------------------------- // Post : Return TRUE on success // Task : Delete file //------------------------------------------------------------- BOOL CPath::Delete(BOOL bEvenIfReadOnly) const { ULONG dwAttr =::GetFileAttributes(m_strPath.c_str()); if(dwAttr == (ULONG)-1) // File does not exists return FALSE; if(((dwAttr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) && !bEvenIfReadOnly) // File is read-only, and we're not allowed 2 delete it return FALSE; SetFileAttributes(m_strPath.c_str(),FILE_ATTRIBUTE_NORMAL); return DeleteFile(m_strPath.c_str()); } //------------------------------------------------------------- // 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 //------------------------------------------------------------- BOOL CPath::CopyTo(LPCTSTR lpcszTargetFile, BOOL bOverwrite) { // Check if the target file exists CPath TargetFile(lpcszTargetFile); if(TargetFile.Exists()) { // Yeah there is already such a target file // Decide if we should overwrite if(!bOverwrite) return FALSE; // Delete any previous target if(!TargetFile.Delete(TRUE)) return FALSE; } // CopyFile will set the target's attributes 2 the same as // the source after copying return CopyFile(m_strPath.c_str(),lpcszTargetFile,!bOverwrite); } //------------------------------------------------------------- // 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 //------------------------------------------------------------- BOOL CPath::MoveTo(LPCTSTR lpcszTargetFile, BOOL bOverwrite) { // Check if the target file exists CPath TargetFile(lpcszTargetFile); if(TargetFile.Exists()) { // Yeah there is already such a target file // Decide if we should overwrite if(!bOverwrite) return FALSE; // Delete any previous target if(!TargetFile.Delete(TRUE)) return FALSE; } return MoveFile(m_strPath.c_str(),lpcszTargetFile); } //------------------------------------------------------------- // Post : Return TRUE if attributes do match // Task : Compare finder attributes //------------------------------------------------------------- BOOL CPath::AttributesMatch(ULONG dwTargetAttributes, ULONG dwFileAttributes) { 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 // You can specify the current attributes of the file or directory // The attributes are represented by a combination (|) of the following // constants: // // _A_ARCH Archive. Set whenever the file is // changed, and cleared by the BACKUP command // _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 // _A_NORMAL Normal. File can be read or written to // without restriction // _A_RDONLY Read-only. File cannot be opened for writing, // and a file with the same name cannot be created // _A_SUBDIR Subdirectory // _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 //------------------------------------------------------------- BOOL CPath::FindFirst(ULONG dwAttributes /*= _A_NORMAL*/) { m_dwFindFileAttributes =dwAttributes; BOOL bGotFile; BOOL bWantSubdirectory =(BOOL)(_A_SUBDIR & dwAttributes); // Close handle to any previous enumeration Exit(); // 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); SetNameExtension(FindData.cFileName); if((_A_SUBDIR & FindData.dwFileAttributes) != 0) EnsureTrailingBackslash(m_strPath); return TRUE; // iv.) Not found match, get another LABEL_GetAnother: bGotFile =FindNextFile(m_hFindFile,&FindData); } return FALSE; } //------------------------------------------------------------- // Post : Return TRUE if a new match found // Task : Find the next file that meets the conditions specified // in the last FindFirst call //------------------------------------------------------------- BOOL CPath::FindNext() { if (m_hFindFile == NULL) return FALSE; WIN32_FIND_DATA FindData; while(FindNextFile(m_hFindFile,&FindData) != FALSE) { // while(FindNext(...)) 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 if (IsDirectory()) { // Found a directory UpDirectory(); } SetNameExtension(FindData.cFileName); } if((_A_SUBDIR & FindData.dwFileAttributes) == _A_SUBDIR) EnsureTrailingBackslash(m_strPath); return TRUE; } } return FALSE; } //------------------------------------------------------------- // Post : Return TRUE on success // Task : Change current working directory of application 2 path //------------------------------------------------------------- BOOL CPath::ChangeDirectory() { stdstr DriveDirectory; GetDriveDirectory(DriveDirectory); return SetCurrentDirectory(DriveDirectory.c_str()); } //------------------------------------------------------------- // Pre : If bCreateIntermediates is TRUE, create all eventually // missing parent directories too // Post : Return TRUE on success // Task : Create new directory //------------------------------------------------------------- BOOL CPath::CreateDirectory(BOOL bCreateIntermediates /*= TRUE*/) { stdstr PathText; BOOL bSuccess; GetDriveDirectory(PathText); StripTrailingBackslash(PathText); bSuccess =::CreateDirectory(PathText.c_str(),NULL); if(!bSuccess) { CPath CurrentDir(CPath::CURRENT_DIRECTORY); bSuccess = ChangeDirectory(); CurrentDir.ChangeDirectory(); } if(!bSuccess && bCreateIntermediates) { stdstr::size_type nDelimiter =PathText.rfind(DIRECTORY_DELIMITER); if(nDelimiter == stdstr::npos) return FALSE; PathText.resize(nDelimiter + 1); CPath SubPath(PathText); if(SubPath.CreateDirectory()) return CreateDirectory(FALSE); else return FALSE; } return bSuccess; } //Helpers //------------------------------------------------------------------------ // Task : Remove first character (if any) if it's chLeading //------------------------------------------------------------------------ void CPath::cleanPathString(stdstr& rDirectory) const { LPCSTR const DIR_DOUBLEDELIM = "\\\\"; 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 ); } bool AppendEnd = !_strnicmp(rDirectory.c_str(), "\\\\", 2); pos = rDirectory.find( DIR_DOUBLEDELIM ); while ( pos != std::string::npos ) { rDirectory.replace( pos, 1, &DIRECTORY_DELIMITER ); pos = rDirectory.find( DIR_DOUBLEDELIM, pos + 1 ); } if (AppendEnd) { rDirectory.insert(0, "\\"); } } void CPath::StripLeadingChar(stdstr& rText, TCHAR chLeading) const { stdstr::size_type nLength =rText.length(); if(nLength == 0) return; if(rText[0] == chLeading) rText =rText.substr(1); } //------------------------------------------------------------------------ // Task : Remove first character if \ //------------------------------------------------------------------------ void CPath::StripLeadingBackslash(stdstr& Directory) const { stdstr::size_type nLength =Directory.length(); // If Directory is of the form '\', don't do it if(nLength <= 1) return; if(Directory[0] == DIRECTORY_DELIMITER) Directory =Directory.substr(1); } //------------------------------------------------------------------------ // Task : Remove last character (if any) if it's chTrailing //------------------------------------------------------------------------ void CPath::StripTrailingChar(stdstr& rText, TCHAR chTrailing) const { stdstr::size_type nLength =rText.length(); if(nLength == 0) return; if(rText[nLength-1] == chTrailing) rText.resize(nLength-1); } //------------------------------------------------------------------------ // Task : Remove last character if \ //------------------------------------------------------------------------ void CPath::StripTrailingBackslash(stdstr& rDirectory) const { for (;;) { stdstr::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 //------------------------------------------------------------------------ void CPath::EnsureTrailingBackslash(stdstr& Directory) const { stdstr::size_type nLength =Directory.length(); 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 //------------------------------------------------------------------------ void CPath::EnsureLeadingBackslash(stdstr& Directory) const { if(Directory.empty() || (Directory[0] != DIRECTORY_DELIMITER)) { stdstr temp =Directory; Directory.Format(_T("%c%s"),DIRECTORY_DELIMITER,temp.c_str()); } }