Index: src/libchcore/IFilesystem.h =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/IFilesystem.h (.../IFilesystem.h) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/IFilesystem.h (.../IFilesystem.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -57,7 +57,7 @@ virtual bool FastMove(const TSmartPath& pathSource, const TSmartPath& pathDestination) = 0; virtual IFilesystemFindPtr CreateFinderObject(const TSmartPath& pathDir, const TSmartPath& pathMask) = 0; - virtual IFilesystemFilePtr CreateFileObject() = 0; + virtual IFilesystemFilePtr CreateFileObject(const TSmartPath& pathFile) = 0; virtual EPathsRelation GetPathsRelation(const TSmartPath& pathFirst, const TSmartPath& pathSecond) = 0; Index: src/libchcore/IFilesystemFile.cpp =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/IFilesystemFile.cpp (.../IFilesystemFile.cpp) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/IFilesystemFile.cpp (.../IFilesystemFile.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -19,10 +19,9 @@ #include "stdafx.h" #include "IFilesystemFile.h" -BEGIN_CHCORE_NAMESPACE - -IFilesystemFile::~IFilesystemFile() +namespace chcore { + IFilesystemFile::~IFilesystemFile() + { + } } - -END_CHCORE_NAMESPACE Index: src/libchcore/IFilesystemFile.h =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/IFilesystemFile.h (.../IFilesystemFile.h) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/IFilesystemFile.h (.../IFilesystemFile.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -23,35 +23,35 @@ #include "TPath.h" #include "TOverlappedDataBuffer.h" -BEGIN_CHCORE_NAMESPACE - -class LIBCHCORE_API IFilesystemFile +namespace chcore { -public: - static const unsigned int MaxSectorSize = 4096; + class LIBCHCORE_API IFilesystemFile + { + public: + static const unsigned int MaxSectorSize = 4096; -public: - virtual ~IFilesystemFile(); + public: + virtual ~IFilesystemFile(); - virtual bool OpenExistingForReading(const TSmartPath& pathFile, bool bNoBuffering) = 0; - virtual bool CreateNewForWriting(const TSmartPath& pathFile, bool bNoBuffering) = 0; - virtual bool OpenExistingForWriting(const TSmartPath& pathFile, bool bNoBuffering) = 0; + virtual bool OpenExistingForReading(bool bNoBuffering) = 0; + virtual bool CreateNewForWriting(bool bNoBuffering) = 0; + virtual bool OpenExistingForWriting(bool bNoBuffering) = 0; - virtual bool SetFilePointer(long long llNewPos, DWORD dwMoveMethod) = 0; - virtual bool SetEndOfFile() = 0; + virtual bool Truncate(long long ullNewSize) = 0; - virtual bool ReadFile(TOverlappedDataBuffer& rBuffer) = 0; - virtual bool WriteFile(TOverlappedDataBuffer& rBuffer) = 0; - virtual bool FinalizeFile(TOverlappedDataBuffer& rBuffer) = 0; + virtual bool ReadFile(TOverlappedDataBuffer& rBuffer) = 0; + virtual bool WriteFile(TOverlappedDataBuffer& rBuffer) = 0; + virtual bool FinalizeFile(TOverlappedDataBuffer& rBuffer) = 0; - virtual bool IsOpen() const = 0; - virtual unsigned long long GetFileSize() const = 0; + virtual bool IsOpen() const = 0; + virtual unsigned long long GetFileSize() const = 0; - virtual void Close() = 0; -}; + virtual void Close() = 0; -typedef std::shared_ptr IFilesystemFilePtr; + virtual TSmartPath GetFilePath() const = 0; + }; -END_CHCORE_NAMESPACE + typedef std::shared_ptr IFilesystemFilePtr; +} #endif Index: src/libchcore/TFakeFileDescription.cpp =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFakeFileDescription.cpp (.../TFakeFileDescription.cpp) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/TFakeFileDescription.cpp (.../TFakeFileDescription.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -19,8 +19,39 @@ #include "stdafx.h" #include "TFakeFileDescription.h" -BEGIN_CHCORE_NAMESPACE +namespace chcore +{ + TFakeFileDescription::TFakeFileDescription() + { + } + TFakeFileDescription::TFakeFileDescription(TFileInfo fileInfo, TSparseRangeMap sparseRangeMap) : + m_fiData(fileInfo), + m_mapDamagedRanges(sparseRangeMap) + { + } + TFakeFileDescription::~TFakeFileDescription() + { + } -END_CHCORE_NAMESPACE + TFileInfo& TFakeFileDescription::GetFileInfo() + { + return m_fiData; + } + + const TFileInfo& TFakeFileDescription::GetFileInfo() const + { + return m_fiData; + } + + TSparseRangeMap& TFakeFileDescription::GetDamageMap() + { + return m_mapDamagedRanges; + } + + const TSparseRangeMap& TFakeFileDescription::GetDamageMap() const + { + return m_mapDamagedRanges; + } +} Index: src/libchcore/TFakeFileDescription.h =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFakeFileDescription.h (.../TFakeFileDescription.h) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/TFakeFileDescription.h (.../TFakeFileDescription.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -21,19 +21,29 @@ #include "libchcore.h" #include "TFileInfo.h" +#include "TSparseRangeMap.h" -BEGIN_CHCORE_NAMESPACE - -class LIBCHCORE_API TFakeFileDescription +namespace chcore { -public: - TFakeFileDescription(); - ~TFakeFileDescription(); + class LIBCHCORE_API TFakeFileDescription + { + public: + TFakeFileDescription(); + TFakeFileDescription(TFileInfo fileInfo, TSparseRangeMap sparseRangeMap); + ~TFakeFileDescription(); -private: - TFileInfo m_fiData; -}; + TFileInfo& GetFileInfo(); + const TFileInfo& GetFileInfo() const; -END_CHCORE_NAMESPACE + TSparseRangeMap& GetDamageMap(); + const TSparseRangeMap& GetDamageMap() const; + private: + TFileInfo m_fiData; + TSparseRangeMap m_mapDamagedRanges; + }; + + typedef std::shared_ptr TFakeFileDescriptionPtr; +} + #endif Index: src/libchcore/TFakeFilesystem.cpp =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFakeFilesystem.cpp (.../TFakeFilesystem.cpp) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/TFakeFilesystem.cpp (.../TFakeFilesystem.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -18,15 +18,346 @@ // ============================================================================ #include "stdafx.h" #include "TFakeFilesystem.h" +#include "RoundingFunctions.h" +#include "TCoreException.h" +#include "ErrorCodes.h" +#include "TFakeFilesystemFile.h" +#include "TFakeFilesystemFind.h" +#include "TPathContainer.h" -BEGIN_CHCORE_NAMESPACE - -TFakeFilesystem::TFakeFilesystem() +namespace chcore { -} + TFakeFilesystem::TFakeFilesystem() + { + } -TFakeFilesystem::~TFakeFilesystem() -{ -} + TFakeFilesystem::~TFakeFilesystem() + { + } -END_CHCORE_NAMESPACE + bool TFakeFilesystem::PathExist(const TSmartPath& strPath) + { + for (const TFakeFileDescriptionPtr& spDesc : m_listFilesystemContent) + { + if (spDesc->GetFileInfo().GetFullFilePath() == strPath) + return true; + } + + return false; + } + + bool TFakeFilesystem::GetDynamicFreeSpace(const TSmartPath& path, unsigned long long& rullFree) + { + // get total size of volume + file_size_t fsSize = std::numeric_limits::max(); + wchar_t wchDrive = path.GetDriveLetter(); + auto iterFind = m_mapVolumeInfo.find(wchDrive); + if (iterFind != m_mapVolumeInfo.end()) + fsSize = iterFind->second.GetTotalSize(); + + // decrease by file sizes + for (const TFakeFileDescriptionPtr& spDesc : m_listFilesystemContent) + { + file_size_t fsFileSize(RoundUp(spDesc->GetFileInfo().GetLength64(), (file_size_t)IFilesystemFile::MaxSectorSize)); + if (fsFileSize > fsSize) + return false; + fsSize -= RoundUp(spDesc->GetFileInfo().GetLength64(), (file_size_t)IFilesystemFile::MaxSectorSize); + } + + rullFree = fsSize; + return false; + } + + IFilesystem::EPathsRelation TFakeFilesystem::GetPathsRelation(const TSmartPath& pathFirst, const TSmartPath& pathSecond) + { + UINT uiFirstDriveType = DRIVE_FIXED; + UINT uiSecondDriveType = DRIVE_FIXED; + + auto iterFirst = m_mapVolumeInfo.find(pathFirst.GetDriveLetter()); + auto iterSecond = m_mapVolumeInfo.find(pathSecond.GetDriveLetter()); + if (iterFirst != m_mapVolumeInfo.end()) + uiFirstDriveType = iterFirst->second.GetDriveType(); + if (iterSecond != m_mapVolumeInfo.end()) + uiSecondDriveType = iterSecond->second.GetDriveType(); + + // what kind of relation... + EPathsRelation eRelation = eRelation_Other; + if (uiFirstDriveType == DRIVE_REMOTE || uiSecondDriveType == DRIVE_REMOTE) + eRelation = eRelation_Network; + else if (uiFirstDriveType == DRIVE_CDROM || uiSecondDriveType == DRIVE_CDROM) + eRelation = eRelation_CDRom; + else if (uiFirstDriveType == DRIVE_FIXED && uiSecondDriveType == DRIVE_FIXED) + { + // two hdd's - is this the same physical disk ? + wchar_t wchFirstDrive = pathFirst.GetDriveLetter(); + wchar_t wchSecondDrive = pathSecond.GetDriveLetter(); + + if (wchFirstDrive == L'\0' || wchSecondDrive == L'\0') + THROW_CORE_EXCEPTION(eErr_FixedDriveWithoutDriveLetter); + + if (wchFirstDrive == wchSecondDrive) + eRelation = eRelation_SinglePhysicalDisk; + else + { + DWORD dwFirstPhysicalDisk = 0; + DWORD dwSecondPhysicalDisk = 1; + + if (iterFirst != m_mapVolumeInfo.end()) + dwFirstPhysicalDisk = iterFirst->second.GetPhysicalDriveNumber(); + if (iterSecond != m_mapVolumeInfo.end()) + dwSecondPhysicalDisk = iterSecond->second.GetPhysicalDriveNumber(); + + if (dwFirstPhysicalDisk == std::numeric_limits::max() || dwSecondPhysicalDisk == std::numeric_limits::max()) + { + // NOTE: disabled throwing an exception here - when testing, it came out that some DRIVE_FIXED + // volumes might have problems handling this detection (TrueCrypt volumes for example). + // So for now we report it as two different physical disks. + //THROW(_T("Problem with physical disk detection"), 0, 0, 0); + eRelation = eRelation_TwoPhysicalDisks; + } + + if (dwFirstPhysicalDisk == dwSecondPhysicalDisk) + eRelation = eRelation_SinglePhysicalDisk; + else + eRelation = eRelation_TwoPhysicalDisks; + } + } + + return eRelation; + } + + IFilesystemFilePtr TFakeFilesystem::CreateFileObject(const TSmartPath& spFilename) + { + IFilesystemFilePtr spFile = std::make_shared(spFilename, this); + return spFile; + } + + IFilesystemFindPtr TFakeFilesystem::CreateFinderObject(const TSmartPath& pathDir, const TSmartPath& pathMask) + { + // check if directory exists + TFakeFileDescriptionPtr spFileDesc = FindFileByLocation(pathDir); + if (!spFileDesc) + return nullptr; + + IFilesystemFindPtr spFind = std::make_shared(pathDir, pathMask, this); + return spFind; + } + + bool TFakeFilesystem::FastMove(const TSmartPath& pathSource, const TSmartPath& pathDestination) + { + TFakeFileDescriptionPtr spFileDesc = FindFileByLocation(pathSource); + if (!spFileDesc) + return false; + + // check parent of pathDestination + TSmartPath pathParent = pathDestination.GetParent(); + if (pathParent.IsEmpty()) + return false; + + TFakeFileDescriptionPtr spParentDesc = FindFileByLocation(pathParent); + if (!spParentDesc) + return false; + + spFileDesc->GetFileInfo().SetFilePath(pathDestination); + return true; + } + + bool TFakeFilesystem::GetFileInfo(const TSmartPath& pathFile, TFileInfoPtr& rFileInfo, const TBasePathDataPtr& spBasePathData) + { + TFakeFileDescriptionPtr spFileDesc = FindFileByLocation(pathFile); + if (!spFileDesc) + { + FILETIME fi = { 0, 0 }; + rFileInfo->Init(TSmartPath(), (DWORD)-1, 0, fi, fi, fi, 0); + return false; + } + + // copy data from W32_F_D + rFileInfo->Init(spBasePathData, pathFile, spFileDesc->GetFileInfo().GetAttributes(), + spFileDesc->GetFileInfo().GetLength64(), + spFileDesc->GetFileInfo().GetCreationTime().GetAsFiletime(), + spFileDesc->GetFileInfo().GetLastAccessTime().GetAsFiletime(), + spFileDesc->GetFileInfo().GetLastWriteTime().GetAsFiletime(), + 0); + + return true; + } + + bool TFakeFilesystem::DeleteFile(const TSmartPath& pathFile) + { + // check parent of pathDestination + TSmartPath pathParent = pathFile.GetParent(); + if (pathParent.IsEmpty()) + return false; + + TFakeFileDescriptionPtr spParentDesc = FindFileByLocation(pathParent); + if (!spParentDesc) + return false; + + // similar to FindFileByLocation(), but operating on iterators + for (auto iterList = m_listFilesystemContent.begin(); iterList != m_listFilesystemContent.end(); ++iterList) + { + TFakeFileDescriptionPtr spDesc = (*iterList); + if (spDesc->GetFileInfo().GetFullFilePath() == pathFile) + { + if (spDesc->GetFileInfo().IsDirectory()) + return false; + + m_listFilesystemContent.erase(iterList); + return true; + } + } + + return false; + } + + bool TFakeFilesystem::RemoveDirectory(const TSmartPath& pathFile) + { + // check parent of pathDestination + TSmartPath pathParent = pathFile.GetParent(); + if (pathParent.IsEmpty()) + return false; + + TFakeFileDescriptionPtr spParentDesc = FindFileByLocation(pathParent); + if (!spParentDesc) + return false; + + for (auto iterList = m_listFilesystemContent.begin(); iterList != m_listFilesystemContent.end(); ++iterList) + { + TFakeFileDescriptionPtr spDesc = (*iterList); + if (spDesc->GetFileInfo().GetFullFilePath() == pathFile) + { + if (!spDesc->GetFileInfo().IsDirectory()) + return false; + + m_listFilesystemContent.erase(iterList); + return true; + } + } + + return false; + } + + bool TFakeFilesystem::CreateDirectory(const TSmartPath& pathDirectory, bool bCreateFullPath) + { + // check parent of pathDestination + TFakeFileDescriptionPtr spDesc = FindFileByLocation(pathDirectory); + if (spDesc) + return true; + + if(!bCreateFullPath) + { + TSmartPath pathParent = pathDirectory.GetParent(); + if (pathParent.IsEmpty()) + return false; + + TFakeFileDescriptionPtr spParentDesc = FindFileByLocation(pathParent); + if (!spParentDesc) + return false; + + CreateFakeDirectory(pathDirectory); + } + else + CreateFSObjectByLocation(pathDirectory); + + return true; + } + + bool TFakeFilesystem::SetAttributes(const TSmartPath& pathFileDir, DWORD dwAttributes) + { + TFakeFileDescriptionPtr spFileDesc = FindFileByLocation(pathFileDir); + if (!spFileDesc) + return false; + + if (spFileDesc->GetFileInfo().IsDirectory() && !(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) + return false; + if (!spFileDesc->GetFileInfo().IsDirectory() && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)) + return false; + + spFileDesc->GetFileInfo().SetAttributes(dwAttributes); + return true; + } + + bool TFakeFilesystem::SetFileDirectoryTime(const TSmartPath& pathFileDir, const TFileTime& ftCreationTime, const TFileTime& ftLastAccessTime, const TFileTime& ftLastWriteTime) + { + TFakeFileDescriptionPtr spFileDesc = FindFileByLocation(pathFileDir); + if (!spFileDesc) + return false; + + spFileDesc->GetFileInfo().SetFileTimes(ftCreationTime, ftLastAccessTime, ftLastWriteTime); + return true; + } + + void TFakeFilesystem::SetVolumeInfo(wchar_t wchVolumeLetter, file_size_t fsSize, UINT uiDriveType, DWORD dwPhysicalDiskNumber) + { + if (wchVolumeLetter >= L'a' && wchVolumeLetter <= L'z') + wchVolumeLetter = wchVolumeLetter - 'a' + 'A'; + else if (wchVolumeLetter < L'A' || wchVolumeLetter > L'Z') + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + auto iterMap = m_mapVolumeInfo.find(wchVolumeLetter); + if (iterMap == m_mapVolumeInfo.end()) + m_mapVolumeInfo.emplace(std::make_pair(wchVolumeLetter, TFakeVolumeInfo(fsSize, uiDriveType, dwPhysicalDiskNumber))); + else + { + iterMap->second.SetDriveType(uiDriveType); + iterMap->second.SetTotalSize(fsSize); + } + } + + TFakeFileDescriptionPtr TFakeFilesystem::FindFileByLocation(const TSmartPath& rPath) + { + for (TFakeFileDescriptionPtr spFile : m_listFilesystemContent) + { + if (spFile->GetFileInfo().GetFullFilePath() == rPath) + return spFile; + } + + return nullptr; + } + + TFakeFileDescriptionPtr TFakeFilesystem::CreateFSObjectByLocation(const TSmartPath& pathFSObject) + { + TPathContainer pathParts; + pathFSObject.SplitPath(pathParts); + + TSmartPath pathPartial; + TFakeFileDescriptionPtr spFileDesc; + for (size_t stIndex = 0; stIndex != pathParts.GetCount(); ++stIndex) + { + if (stIndex == 0 && (!pathParts.GetAt(stIndex).IsDrive() && !pathParts.GetAt(stIndex).IsServerName())) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + pathPartial += pathParts.GetAt(stIndex); + + spFileDesc = FindFileByLocation(pathPartial); + if (!spFileDesc) + CreateFakeDirectory(pathPartial); + } + + return spFileDesc; + } + + FILETIME TFakeFilesystem::GetCurrentFileTime() + { + SYSTEMTIME st; + GetSystemTime(&st); + + FILETIME ft; + SystemTimeToFileTime(&st, &ft); + + return ft; + } + + TFakeFileDescriptionPtr TFakeFilesystem::CreateFakeDirectory(const TSmartPath& pathDir) + { + FILETIME ftCurrent = GetCurrentFileTime(); + TFakeFileDescriptionPtr spDesc = std::make_shared( + TFileInfo(nullptr, pathDir, FILE_ATTRIBUTE_DIRECTORY, 0, ftCurrent, ftCurrent, ftCurrent, 0), + TSparseRangeMap() + ); + + m_listFilesystemContent.emplace_back(std::move(spDesc)); + return spDesc; + } +} Index: src/libchcore/TFakeFilesystem.h =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFakeFilesystem.h (.../TFakeFilesystem.h) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/TFakeFilesystem.h (.../TFakeFilesystem.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -20,19 +20,52 @@ #define __TFAKEFILESYSTEM_H__ #include "libchcore.h" +#include "TFakeFileDescription.h" +#include "IFilesystem.h" +#include "TFakeVolumeInfo.h" -BEGIN_CHCORE_NAMESPACE - -class LIBCHCORE_API TFakeFilesystem +namespace chcore { -public: - TFakeFilesystem(); - ~TFakeFilesystem(); + class LIBCHCORE_API TFakeFilesystem : public IFilesystem + { + public: + TFakeFilesystem(); + ~TFakeFilesystem(); -private: + // interface implementation + virtual bool PathExist(const TSmartPath& strPath) override; + virtual bool SetFileDirectoryTime(const TSmartPath& pathFileDir, const TFileTime& ftCreationTime, const TFileTime& ftLastAccessTime, const TFileTime& ftLastWriteTime) override; + virtual bool SetAttributes(const TSmartPath& pathFileDir, DWORD dwAttributes) override; + virtual bool CreateDirectory(const TSmartPath& pathDirectory, bool bCreateFullPath) override; + virtual bool RemoveDirectory(const TSmartPath& pathFile) override; + virtual bool DeleteFile(const TSmartPath& pathFile) override; + virtual bool GetFileInfo(const TSmartPath& pathFile, TFileInfoPtr& rFileInfo, const TBasePathDataPtr& spBasePathData = TBasePathDataPtr()) override; + virtual bool FastMove(const TSmartPath& pathSource, const TSmartPath& pathDestination) override; + virtual IFilesystemFindPtr CreateFinderObject(const TSmartPath& pathDir, const TSmartPath& pathMask) override; + virtual IFilesystemFilePtr CreateFileObject(const TSmartPath& spFilename) override; + virtual EPathsRelation GetPathsRelation(const TSmartPath& pathFirst, const TSmartPath& pathSecond) override; + virtual bool GetDynamicFreeSpace(const TSmartPath& path, unsigned long long& rullFree) override; -}; + // fake handling api + void SetVolumeInfo(wchar_t wchVolumeLetter, file_size_t fsSize, UINT uiDriveType, DWORD dwPhysicalDiskNumber); + void AddFSObjectDescription(const TFakeFileDescriptionPtr& spFileDesc); -END_CHCORE_NAMESPACE + private: + TFakeFileDescriptionPtr FindFileByLocation(const TSmartPath& rPath); + TFakeFileDescriptionPtr CreateFSObjectByLocation(const TSmartPath& pathFSObject); + static FILETIME GetCurrentFileTime(); + TFakeFileDescriptionPtr CreateFakeDirectory(const TSmartPath& pathDir); + private: +#pragma warning(push) +#pragma warning(disable: 4251) + std::list m_listFilesystemContent; + std::map m_mapVolumeInfo; +#pragma warning(pop) + + friend class TFakeFilesystemFile; + friend class TFakeFilesystemFind; + }; +} + #endif Index: src/libchcore/TFakeFilesystemFile.cpp =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFakeFilesystemFile.cpp (.../TFakeFilesystemFile.cpp) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/TFakeFilesystemFile.cpp (.../TFakeFilesystemFile.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -18,15 +18,275 @@ // ============================================================================ #include "stdafx.h" #include "TFakeFilesystemFile.h" +#include "TCoreException.h" +#include "ErrorCodes.h" +#include "TFakeFilesystem.h" +#include -BEGIN_CHCORE_NAMESPACE - -TFakeFilesystemFile::TFakeFilesystemFile() +namespace { + struct APCINFO + { + OVERLAPPED* pOverlapped; + DWORD dwError; + DWORD dwNumberOfBytesTransfered; + }; + + enum EStatus : DWORD + { + STATUS_OK = 0, + STATUS_END_OF_FILE = 0xc0000011 + }; } -TFakeFilesystemFile::~TFakeFilesystemFile() +namespace chcore { -} + VOID CALLBACK ReadCompleted(ULONG_PTR dwParam) + { + APCINFO* pApcInfo = (APCINFO*)dwParam; + OverlappedReadCompleted(pApcInfo->dwError, pApcInfo->dwNumberOfBytesTransfered, pApcInfo->pOverlapped); -END_CHCORE_NAMESPACE + delete pApcInfo; + } + + VOID CALLBACK WriteCompleted(ULONG_PTR dwParam) + { + APCINFO* pApcInfo = (APCINFO*)dwParam; + OverlappedWriteCompleted(pApcInfo->dwError, pApcInfo->dwNumberOfBytesTransfered, pApcInfo->pOverlapped); + + delete pApcInfo; + } + + TFakeFilesystemFile::TFakeFilesystemFile(const TSmartPath& pathFile, TFakeFilesystem* pFilesystem) : + m_pathFile(pathFile), + m_pFilesystem(pFilesystem), + m_bIsOpen(false), + m_bNoBuffering(false), + m_bModeReading(true) + { + if (!pFilesystem || pathFile.IsEmpty()) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + } + + TFakeFilesystemFile::~TFakeFilesystemFile() + { + } + + void TFakeFilesystemFile::Close() + { + m_bIsOpen = false; + } + + TSmartPath TFakeFilesystemFile::GetFilePath() const + { + return m_pathFile; + } + + unsigned long long TFakeFilesystemFile::GetFileSize() const + { + TFakeFileDescriptionPtr spFileDesc = m_pFilesystem->FindFileByLocation(m_pathFile); + if (!spFileDesc) + return 0; + + return spFileDesc->GetFileInfo().GetLength64(); + } + + bool TFakeFilesystemFile::IsOpen() const + { + return m_bIsOpen; + } + + bool TFakeFilesystemFile::FinalizeFile(TOverlappedDataBuffer& /*rBuffer*/) + { + // does nothing + return true; + } + + bool TFakeFilesystemFile::WriteFile(TOverlappedDataBuffer& rBuffer) + { + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); + + // file should have been created already by create for write functions + TFakeFileDescriptionPtr spFileDesc = m_pFilesystem->FindFileByLocation(m_pathFile); + if (!spFileDesc) + return false; + + APCINFO* pInfo = new APCINFO; + unsigned long long ullNewSize = 0; + unsigned long long ullGrow = 0; + if (rBuffer.GetFilePosition() >= spFileDesc->GetFileInfo().GetLength64()) + { + ullNewSize = rBuffer.GetFilePosition() + rBuffer.GetRealDataSize(); + ullGrow = ullNewSize - spFileDesc->GetFileInfo().GetLength64(); + } + else + { + ullNewSize = std::max(rBuffer.GetFilePosition() + rBuffer.GetRealDataSize(), spFileDesc->GetFileInfo().GetLength64()); + ullGrow = ullNewSize - spFileDesc->GetFileInfo().GetLength64(); + } + + spFileDesc->GetFileInfo().SetLength64(ullNewSize); + + rBuffer.SetStatusCode(STATUS_OK); + rBuffer.SetBytesTransferred(rBuffer.GetRealDataSize()); + pInfo->dwError = ERROR_SUCCESS; + pInfo->dwNumberOfBytesTransfered = rBuffer.GetRealDataSize(); + pInfo->pOverlapped = &rBuffer; + + if (QueueUserAPC(WriteCompleted, GetCurrentThread(), (ULONG_PTR)pInfo) == 0) + THROW_CORE_EXCEPTION(eErr_InternalProblem); + + return true; + } + + bool TFakeFilesystemFile::ReadFile(TOverlappedDataBuffer& rBuffer) + { + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); + + // check if we're reading the undamaged data + TFakeFileDescriptionPtr spFileDesc = m_pFilesystem->FindFileByLocation(m_pathFile); + if (!spFileDesc) + return false; + + const TSparseRangeMap& rmapDamage = spFileDesc->GetDamageMap(); + if (rmapDamage.OverlapsRange(rBuffer.GetFilePosition(), rBuffer.GetRequestedDataSize())) + { + APCINFO* pInfo = new APCINFO; + pInfo->dwError = ERROR_READ_FAULT; + pInfo->dwNumberOfBytesTransfered = 0; + pInfo->pOverlapped = &rBuffer; + + if (QueueUserAPC(ReadCompleted, GetCurrentThread(), (ULONG_PTR)pInfo) == 0) + THROW_CORE_EXCEPTION(eErr_InternalProblem); + } + else + { + APCINFO* pInfo = new APCINFO; + + if (rBuffer.GetFilePosition() >= spFileDesc->GetFileInfo().GetLength64()) + { + rBuffer.SetStatusCode(STATUS_END_OF_FILE); + rBuffer.SetBytesTransferred(0); + pInfo->dwError = ERROR_HANDLE_EOF; + pInfo->dwNumberOfBytesTransfered = 0; + pInfo->pOverlapped = &rBuffer; + } + else if (rBuffer.GetFilePosition() + rBuffer.GetRequestedDataSize() > spFileDesc->GetFileInfo().GetLength64()) + { + file_size_t fsRemaining = spFileDesc->GetFileInfo().GetLength64() - rBuffer.GetFilePosition(); + + rBuffer.SetStatusCode(STATUS_OK); + rBuffer.SetBytesTransferred(fsRemaining); + pInfo->dwError = ERROR_SUCCESS; + pInfo->dwNumberOfBytesTransfered = boost::numeric_cast(fsRemaining); + pInfo->pOverlapped = &rBuffer; + } + else + { + rBuffer.SetStatusCode(STATUS_OK); + rBuffer.SetBytesTransferred(rBuffer.GetRequestedDataSize()); + pInfo->dwError = ERROR_SUCCESS; + pInfo->dwNumberOfBytesTransfered = rBuffer.GetRequestedDataSize(); + pInfo->pOverlapped = &rBuffer; + } + + GenerateBufferContent(rBuffer); + + if (QueueUserAPC(ReadCompleted, GetCurrentThread(), (ULONG_PTR)pInfo) == 0) + THROW_CORE_EXCEPTION(eErr_InternalProblem); + } + + return true; + } + + bool TFakeFilesystemFile::Truncate(long long llNewSize) + { + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); + + // check if we're reading the undamaged data + TFakeFileDescriptionPtr spFileDesc = m_pFilesystem->FindFileByLocation(m_pathFile); + if (!spFileDesc) + return false; + + spFileDesc->GetFileInfo().SetLength64(llNewSize); + return true; + } + + bool TFakeFilesystemFile::OpenExistingForWriting(bool bNoBuffering) + { + TFakeFileDescriptionPtr spFileDesc = m_pFilesystem->FindFileByLocation(m_pathFile); + if (!spFileDesc) + return false; + + Close(); + + m_bIsOpen = true; + m_bNoBuffering = bNoBuffering; + m_bModeReading = false; + + return true; + } + + bool TFakeFilesystemFile::CreateNewForWriting(bool bNoBuffering) + { + TFakeFileDescriptionPtr spFileDesc = m_pFilesystem->FindFileByLocation(m_pathFile); + if(!spFileDesc) + { + TFakeFileDescriptionPtr parentDesc = m_pFilesystem->FindFileByLocation(m_pathFile.GetParent()); + if (!parentDesc) + return false; + + FILETIME ftCurrent = m_pFilesystem->GetCurrentFileTime(); + TFakeFileDescriptionPtr spNewFile(std::make_shared( + TFileInfo(nullptr, m_pathFile, FILE_ATTRIBUTE_NORMAL, 0, ftCurrent, ftCurrent, ftCurrent, 0), + TSparseRangeMap() + )); + + m_pFilesystem->m_listFilesystemContent.push_back(spNewFile); + } + + Close(); + + m_bIsOpen = true; + m_bNoBuffering = bNoBuffering; + m_bModeReading = false; + + return true; + } + + bool TFakeFilesystemFile::OpenExistingForReading(bool bNoBuffering) + { + TFakeFileDescriptionPtr spFileDesc = m_pFilesystem->FindFileByLocation(m_pathFile); + if (!spFileDesc) + return false; + + Close(); + + m_bIsOpen = true; + m_bNoBuffering = bNoBuffering; + m_bModeReading = true; + + return true; + } + + void TFakeFilesystemFile::GenerateBufferContent(TOverlappedDataBuffer &rBuffer) + { + if(rBuffer.GetBytesTransferred() > 0) + { + ZeroMemory(rBuffer.GetBufferPtr(), rBuffer.GetBufferSize()); + + size_t stCount = rBuffer.GetBytesTransferred() / sizeof(file_size_t); + if (stCount > 0) + { + file_size_t* pBuffer = (file_size_t*)rBuffer.GetBufferPtr(); + for (size_t stIndex = 0; stIndex != stCount; ++stIndex) + { + pBuffer[stIndex] = rBuffer.GetFilePosition() + stIndex * sizeof(file_size_t); + } + } + } + } +} Index: src/libchcore/TFakeFilesystemFile.h =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFakeFilesystemFile.h (.../TFakeFilesystemFile.h) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/TFakeFilesystemFile.h (.../TFakeFilesystemFile.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -20,19 +20,45 @@ #define __TFAKEFILESYSTEMFILE_H__ #include "libchcore.h" +#include "IFilesystemFile.h" +#include "TFakeFileDescription.h" -BEGIN_CHCORE_NAMESPACE - -class LIBCHCORE_API TFakeFilesystemFile +namespace chcore { -public: - TFakeFilesystemFile(); - ~TFakeFilesystemFile(); + class TFakeFilesystem; -private: - -}; + class LIBCHCORE_API TFakeFilesystemFile : public IFilesystemFile + { + public: + TFakeFilesystemFile(const TSmartPath& pathFile, TFakeFilesystem* pFilesystem); + ~TFakeFilesystemFile(); -END_CHCORE_NAMESPACE + virtual bool OpenExistingForReading(bool bNoBuffering) override; + virtual bool CreateNewForWriting(bool bNoBuffering) override; + virtual bool OpenExistingForWriting(bool bNoBuffering) override; + virtual bool Truncate(long long ullNewSize) override; + virtual bool ReadFile(TOverlappedDataBuffer& rBuffer) override; + void GenerateBufferContent(TOverlappedDataBuffer &rBuffer); + + virtual bool WriteFile(TOverlappedDataBuffer& rBuffer) override; + virtual bool FinalizeFile(TOverlappedDataBuffer& rBuffer) override; + virtual bool IsOpen() const override; + virtual unsigned long long GetFileSize() const override; + virtual void Close() override; + + virtual TSmartPath GetFilePath() const override; + + private: +#pragma warning(push) +#pragma warning(disable: 4251) + TSmartPath m_pathFile; +#pragma warning(pop) + bool m_bIsOpen; + bool m_bNoBuffering; + bool m_bModeReading; + TFakeFilesystem* m_pFilesystem; + }; +} + #endif Index: src/libchcore/TFakeFilesystemFind.cpp =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFakeFilesystemFind.cpp (.../TFakeFilesystemFind.cpp) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/TFakeFilesystemFind.cpp (.../TFakeFilesystemFind.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -18,15 +18,65 @@ // ============================================================================ #include "stdafx.h" #include "TFakeFilesystemFind.h" +#include "TFakeFilesystem.h" +#include "TCoreException.h" +#include "ErrorCodes.h" +#include "TStringPattern.h" -BEGIN_CHCORE_NAMESPACE - -TFakeFilesystemFind::TFakeFilesystemFind() +namespace chcore { -} + TFakeFilesystemFind::TFakeFilesystemFind(const TSmartPath& pathDir, const TSmartPath& pathMask, TFakeFilesystem* pFakeFilesystem) : + m_pathDir(pathDir), + m_pathMask(pathMask), + m_pFilesystem(pFakeFilesystem) + { + if (!pFakeFilesystem) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + } -TFakeFilesystemFind::~TFakeFilesystemFind() -{ -} + TFakeFilesystemFind::~TFakeFilesystemFind() + { + } -END_CHCORE_NAMESPACE + bool TFakeFilesystemFind::FindNext(TFileInfoPtr& rspFileInfo) + { + if (!m_bScanned) + { + Prescan(); + m_bScanned = true; + } + + if (m_iterCurrent == m_vItems.end()) + return false; + + *rspFileInfo = *m_iterCurrent++; + return true; + } + + void TFakeFilesystemFind::Close() + { + m_vItems.clear(); + m_iterCurrent = m_vItems.end(); + m_bScanned = false; + } + + void TFakeFilesystemFind::Prescan() + { + m_vItems.clear(); + m_iterCurrent = m_vItems.end(); + + for (TFakeFileDescriptionPtr spFileInfoDesc : m_pFilesystem->m_listFilesystemContent) + { + if (spFileInfoDesc->GetFileInfo().GetFullFilePath().StartsWith(m_pathDir)) + { + TStringPattern pattern(m_pathMask.ToString()); + if (pattern.Matches(spFileInfoDesc->GetFileInfo().GetFullFilePath().ToWString())) + { + m_vItems.push_back(spFileInfoDesc->GetFileInfo()); + } + } + } + + m_iterCurrent = m_vItems.begin(); + } +} Index: src/libchcore/TFakeFilesystemFind.h =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFakeFilesystemFind.h (.../TFakeFilesystemFind.h) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/TFakeFilesystemFind.h (.../TFakeFilesystemFind.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -20,19 +20,37 @@ #define __TFAKEFILESYSTEMFIND_H__ #include "libchcore.h" +#include "IFilesystemFind.h" +#include "TPath.h" -BEGIN_CHCORE_NAMESPACE - -class LIBCHCORE_API TFakeFilesystemFind +namespace chcore { -public: - TFakeFilesystemFind(); - ~TFakeFilesystemFind(); + class TFakeFilesystem; -private: + class LIBCHCORE_API TFakeFilesystemFind : public IFilesystemFind + { + public: + TFakeFilesystemFind(const TSmartPath& pathDir, const TSmartPath& pathMask, TFakeFilesystem* pFakeFilesystem); + ~TFakeFilesystemFind(); -}; + virtual bool FindNext(TFileInfoPtr& rspFileInfo) override; + virtual void Close() override; -END_CHCORE_NAMESPACE + private: + void Prescan(); + private: + TSmartPath m_pathDir; + TSmartPath m_pathMask; + TFakeFilesystem* m_pFilesystem; + +#pragma warning(push) +#pragma warning(disable: 4251) + bool m_bScanned = false; + std::vector m_vItems; + std::vector::iterator m_iterCurrent; +#pragma warning(pop) + }; +} + #endif Index: src/libchcore/TFakeVolumeInfo.cpp =================================================================== diff -u -N --- src/libchcore/TFakeVolumeInfo.cpp (revision 0) +++ src/libchcore/TFakeVolumeInfo.cpp (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -0,0 +1,65 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#include "stdafx.h" +#include "TFakeVolumeInfo.h" + +BEGIN_CHCORE_NAMESPACE + +TFakeVolumeInfo::TFakeVolumeInfo(file_size_t fsTotalSize, UINT uiDriveType, DWORD dwPhysicalDriveNumber) : + m_fsTotalSize(fsTotalSize), + m_uiDriveType(uiDriveType), + m_dwPhysicalDriveNumber(dwPhysicalDriveNumber) +{ +} + +TFakeVolumeInfo::~TFakeVolumeInfo() +{ +} + +void TFakeVolumeInfo::SetTotalSize(file_size_t fsTotalSize) +{ + m_fsTotalSize = fsTotalSize; +} + +file_size_t TFakeVolumeInfo::GetTotalSize() const +{ + return m_fsTotalSize; +} + +void TFakeVolumeInfo::SetDriveType(UINT uiDriveType) +{ + m_uiDriveType = uiDriveType; +} + +UINT TFakeVolumeInfo::GetDriveType() const +{ + return m_uiDriveType; +} + +void TFakeVolumeInfo::SetPhysicalDriveNumber(DWORD dwDriveNumber) +{ + m_dwPhysicalDriveNumber = dwDriveNumber; +} + +DWORD TFakeVolumeInfo::GetPhysicalDriveNumber() const +{ + return m_dwPhysicalDriveNumber; +} + +END_CHCORE_NAMESPACE Index: src/libchcore/TFakeVolumeInfo.h =================================================================== diff -u -N --- src/libchcore/TFakeVolumeInfo.h (revision 0) +++ src/libchcore/TFakeVolumeInfo.h (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -0,0 +1,50 @@ +// ============================================================================ +// Copyright (C) 2001-2015 by Jozef Starosczyk +// ixen@copyhandler.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// (version 2) as published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// ============================================================================ +#ifndef __TFAKEVOLUMEINFO_H__ +#define __TFAKEVOLUMEINFO_H__ + +#include "libchcore.h" +#include "CommonDataTypes.h" + +BEGIN_CHCORE_NAMESPACE + +class LIBCHCORE_API TFakeVolumeInfo +{ +public: + TFakeVolumeInfo(file_size_t fsTotalSize, UINT uiDriveType, DWORD dwPhysicalDriveNumber); + ~TFakeVolumeInfo(); + + void SetTotalSize(file_size_t fsTotalSize); + file_size_t GetTotalSize() const; + + void SetDriveType(UINT uiDriveType); + UINT GetDriveType() const; + + void SetPhysicalDriveNumber(DWORD dwDriveNumber); + DWORD GetPhysicalDriveNumber() const; + +private: + file_size_t m_fsTotalSize; + UINT m_uiDriveType; + DWORD m_dwPhysicalDriveNumber; +}; + +END_CHCORE_NAMESPACE + +#endif Index: src/libchcore/TFileInfo.cpp =================================================================== diff -u -N -r95a466ca0a4f95851dcacf2b80e2084e0168b7e4 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFileInfo.cpp (.../TFileInfo.cpp) (revision 95a466ca0a4f95851dcacf2b80e2084e0168b7e4) +++ src/libchcore/TFileInfo.cpp (.../TFileInfo.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -25,303 +25,329 @@ #include "ISerializerRowData.h" #include "ISerializerContainer.h" -BEGIN_CHCORE_NAMESPACE +namespace chcore +{ + ////////////////////////////////////////////////////////////////////// + // Construction/Destruction + ////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// + TFileInfo::TFileInfo() : + m_pathFile(m_setModifications), + m_spBasePathData(m_setModifications), + m_dwAttributes(m_setModifications, 0), + m_uhFileSize(m_setModifications, 0), + m_ftCreation(m_setModifications), + m_ftLastAccess(m_setModifications), + m_ftLastWrite(m_setModifications), + m_uiFlags(m_setModifications, 0), + m_oidObjectID(0) + { + m_setModifications[eMod_Added] = true; + } -TFileInfo::TFileInfo() : - m_pathFile(m_setModifications), - m_spBasePathData(m_setModifications), - m_dwAttributes(m_setModifications, 0), - m_uhFileSize(m_setModifications, 0), - m_ftCreation(m_setModifications), - m_ftLastAccess(m_setModifications), - m_ftLastWrite(m_setModifications), - m_uiFlags(m_setModifications, 0), - m_oidObjectID(0) -{ - m_setModifications[eMod_Added] = true; -} + TFileInfo::TFileInfo(const TFileInfo& rSrc) : + m_pathFile(m_setModifications, rSrc.m_pathFile), + m_spBasePathData(m_setModifications, rSrc.m_spBasePathData), + m_dwAttributes(m_setModifications, rSrc.m_dwAttributes), + m_uhFileSize(m_setModifications, rSrc.m_uhFileSize), + m_ftCreation(m_setModifications, rSrc.m_ftCreation), + m_ftLastAccess(m_setModifications, rSrc.m_ftLastAccess), + m_ftLastWrite(m_setModifications, rSrc.m_ftLastWrite), + m_uiFlags(m_setModifications, rSrc.m_uiFlags), + m_oidObjectID(rSrc.m_oidObjectID) + { + m_setModifications = rSrc.m_setModifications; + } -TFileInfo::TFileInfo(const TFileInfo& rSrc) : - m_pathFile(m_setModifications, rSrc.m_pathFile), - m_spBasePathData(m_setModifications, rSrc.m_spBasePathData), - m_dwAttributes(m_setModifications, rSrc.m_dwAttributes), - m_uhFileSize(m_setModifications, rSrc.m_uhFileSize), - m_ftCreation(m_setModifications, rSrc.m_ftCreation), - m_ftLastAccess(m_setModifications, rSrc.m_ftLastAccess), - m_ftLastWrite(m_setModifications, rSrc.m_ftLastWrite), - m_uiFlags(m_setModifications, rSrc.m_uiFlags), - m_oidObjectID(rSrc.m_oidObjectID) -{ - m_setModifications = rSrc.m_setModifications; -} + TFileInfo::TFileInfo(const TBasePathDataPtr& spBasePathData, const TSmartPath& rpathFile, DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, FILETIME ftLastAccess, FILETIME ftLastWrite, uint_t uiFlags) : + m_pathFile(m_setModifications, rpathFile), + m_spBasePathData(m_setModifications, spBasePathData), + m_dwAttributes(m_setModifications, dwAttributes), + m_uhFileSize(m_setModifications, uhFileSize), + m_ftCreation(m_setModifications, ftCreation), + m_ftLastAccess(m_setModifications, ftLastAccess), + m_ftLastWrite(m_setModifications, ftLastWrite), + m_uiFlags(m_setModifications, uiFlags), + m_oidObjectID(0) + { + if (m_spBasePathData.Get()) + m_pathFile.Modify().MakeRelativePath(m_spBasePathData.Get()->GetSrcPath()); + } -TFileInfo::~TFileInfo() -{ -} + TFileInfo::~TFileInfo() + { + } -TFileInfo& TFileInfo::operator=(const TFileInfo& rSrc) -{ - if(this != & rSrc) + TFileInfo& TFileInfo::operator=(const TFileInfo& rSrc) { - m_pathFile = rSrc.m_pathFile; - m_spBasePathData = rSrc.m_spBasePathData; - m_dwAttributes = rSrc.m_dwAttributes; - m_uhFileSize = rSrc.m_uhFileSize; - m_ftCreation = rSrc.m_ftCreation; - m_ftLastAccess = rSrc.m_ftLastAccess; - m_ftLastWrite = rSrc.m_ftLastWrite; - m_uiFlags = rSrc.m_uiFlags; - m_oidObjectID = rSrc.m_oidObjectID; - m_setModifications = rSrc.m_setModifications; + if (this != &rSrc) + { + m_pathFile = rSrc.m_pathFile; + m_spBasePathData = rSrc.m_spBasePathData; + m_dwAttributes = rSrc.m_dwAttributes; + m_uhFileSize = rSrc.m_uhFileSize; + m_ftCreation = rSrc.m_ftCreation; + m_ftLastAccess = rSrc.m_ftLastAccess; + m_ftLastWrite = rSrc.m_ftLastWrite; + m_uiFlags = rSrc.m_uiFlags; + m_oidObjectID = rSrc.m_oidObjectID; + m_setModifications = rSrc.m_setModifications; + } + + return *this; } - return *this; -} + void TFileInfo::Init(const TBasePathDataPtr& spBasePathData, const TSmartPath& rpathFile, + DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, FILETIME ftLastAccess, FILETIME ftLastWrite, + uint_t uiFlags) + { + m_pathFile = rpathFile; + m_spBasePathData = spBasePathData; + m_dwAttributes = dwAttributes; + m_uhFileSize = uhFileSize; + m_ftCreation = ftCreation; + m_ftLastAccess = ftLastAccess; + m_ftLastWrite = ftLastWrite; + m_uiFlags = uiFlags; -void TFileInfo::Init(const TBasePathDataPtr& spBasePathData, const TSmartPath& rpathFile, - DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, FILETIME ftLastAccess, FILETIME ftLastWrite, - uint_t uiFlags) -{ - m_pathFile = rpathFile; - m_spBasePathData = spBasePathData; - m_dwAttributes = dwAttributes; - m_uhFileSize = uhFileSize; - m_ftCreation = ftCreation; - m_ftLastAccess = ftLastAccess; - m_ftLastWrite = ftLastWrite; - m_uiFlags = uiFlags; + if (m_spBasePathData.Get()) + m_pathFile.Modify().MakeRelativePath(m_spBasePathData.Get()->GetSrcPath()); + } - if(m_spBasePathData.Get()) - m_pathFile.Modify().MakeRelativePath(m_spBasePathData.Get()->GetSrcPath()); -} + void TFileInfo::Init(const TSmartPath& rpathFile, DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, FILETIME ftLastAccess, FILETIME ftLastWrite, + uint_t uiFlags) + { + m_pathFile = rpathFile; + m_spBasePathData.Modify().reset(); + m_dwAttributes = dwAttributes; + m_uhFileSize = uhFileSize; + m_ftCreation = ftCreation; + m_ftLastAccess = ftLastAccess; + m_ftLastWrite = ftLastWrite; + m_uiFlags = uiFlags; + } -void TFileInfo::Init(const TSmartPath& rpathFile, DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, FILETIME ftLastAccess, FILETIME ftLastWrite, - uint_t uiFlags) -{ - m_pathFile = rpathFile; - m_spBasePathData.Modify().reset(); - m_dwAttributes = dwAttributes; - m_uhFileSize = uhFileSize; - m_ftCreation = ftCreation; - m_ftLastAccess = ftLastAccess; - m_ftLastWrite = ftLastWrite; - m_uiFlags = uiFlags; -} + void TFileInfo::SetParentObject(const TBasePathDataPtr& spBasePathData) + { + // cannot set parent object if there is already one specified + if (m_spBasePathData.Get()) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); -void TFileInfo::SetParentObject(const TBasePathDataPtr& spBasePathData) -{ - // cannot set parent object if there is already one specified - if(m_spBasePathData.Get()) - THROW_CORE_EXCEPTION(eErr_InvalidArgument); + m_spBasePathData = spBasePathData; + if (m_spBasePathData.Get()) + m_pathFile.Modify().MakeRelativePath(m_spBasePathData.Get()->GetSrcPath()); + } - m_spBasePathData = spBasePathData; - if(m_spBasePathData.Get()) - m_pathFile.Modify().MakeRelativePath(m_spBasePathData.Get()->GetSrcPath()); -} + bool TFileInfo::operator==(const TFileInfo& rInfo) const + { + return (rInfo.m_dwAttributes == m_dwAttributes && + rInfo.m_ftCreation.Get() == m_ftCreation.Get() && + rInfo.m_ftLastWrite.Get() == m_ftLastWrite.Get() && + rInfo.m_uhFileSize == m_uhFileSize); + } -bool TFileInfo::operator==(const TFileInfo& rInfo) const -{ - return (rInfo.m_dwAttributes == m_dwAttributes && - rInfo.m_ftCreation.Get() == m_ftCreation.Get() && - rInfo.m_ftLastWrite.Get() == m_ftLastWrite.Get() && - rInfo.m_uhFileSize == m_uhFileSize); -} + TSmartPath TFileInfo::GetFullFilePath() const + { + if (m_spBasePathData.Get()) + { + TSmartPath pathCombined = m_spBasePathData.Get()->GetSrcPath(); + pathCombined += m_pathFile; + return pathCombined; + } + else + return m_pathFile; + } -TSmartPath TFileInfo::GetFullFilePath() const -{ - if(m_spBasePathData.Get()) + object_id_t TFileInfo::GetSrcObjectID() const { - TSmartPath pathCombined = m_spBasePathData.Get()->GetSrcPath(); - pathCombined += m_pathFile; - return pathCombined; + if (m_spBasePathData.Get()) + return m_spBasePathData.Get()->GetObjectID(); + return (object_id_t)-1; } - else - return m_pathFile; -} -object_id_t TFileInfo::GetSrcObjectID() const -{ - if(m_spBasePathData.Get()) - return m_spBasePathData.Get()->GetObjectID(); - return (object_id_t)-1; -} + TBasePathDataPtr TFileInfo::GetBasePathData() const + { + return m_spBasePathData; + } -TBasePathDataPtr TFileInfo::GetBasePathData() const -{ - return m_spBasePathData; -} + void TFileInfo::MarkAsProcessed(bool bProcessed) + { + if (bProcessed) + m_uiFlags.Modify() |= eFlag_Processed; + else + m_uiFlags.Modify() &= ~eFlag_Processed; + } -void TFileInfo::MarkAsProcessed(bool bProcessed) -{ - if(bProcessed) - m_uiFlags.Modify() |= eFlag_Processed; - else - m_uiFlags.Modify() &= ~eFlag_Processed; -} + bool TFileInfo::IsProcessed() const + { + return m_uiFlags & eFlag_Processed; + } -bool TFileInfo::IsProcessed() const -{ - return m_uiFlags & eFlag_Processed; -} + ULONGLONG TFileInfo::GetLength64() const + { + return m_uhFileSize; + } -ULONGLONG TFileInfo::GetLength64() const -{ - return m_uhFileSize; -} + void TFileInfo::SetLength64(ULONGLONG uhSize) + { + m_uhFileSize = uhSize; + } -void TFileInfo::SetLength64(ULONGLONG uhSize) -{ - m_uhFileSize=uhSize; -} + void TFileInfo::SetFileTimes(const TFileTime& rCreation, const TFileTime& rLastAccess, const TFileTime& rLastWrite) + { + m_ftCreation = rCreation; + m_ftLastAccess = rLastAccess; + m_ftLastWrite = rLastWrite; + } -const TSmartPath& TFileInfo::GetFilePath() const -{ - return m_pathFile; -} + const TSmartPath& TFileInfo::GetFilePath() const + { + return m_pathFile; + } -void TFileInfo::SetFilePath(const TSmartPath& tPath) -{ - m_pathFile = tPath; -} + void TFileInfo::SetFilePath(const TSmartPath& tPath) + { + m_pathFile = tPath; + } -const TFileTime& TFileInfo::GetCreationTime() const -{ - return m_ftCreation; -} + const TFileTime& TFileInfo::GetCreationTime() const + { + return m_ftCreation; + } -const TFileTime& TFileInfo::GetLastAccessTime() const -{ - return m_ftLastAccess; -} + const TFileTime& TFileInfo::GetLastAccessTime() const + { + return m_ftLastAccess; + } -const TFileTime& TFileInfo::GetLastWriteTime() const -{ - return m_ftLastWrite; -} + const TFileTime& TFileInfo::GetLastWriteTime() const + { + return m_ftLastWrite; + } -DWORD TFileInfo::GetAttributes() const -{ - return m_dwAttributes; -} + DWORD TFileInfo::GetAttributes() const + { + return m_dwAttributes; + } -bool TFileInfo::IsDirectory() const -{ - return (m_dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; -} + void TFileInfo::SetAttributes(DWORD dwAttributes) + { + m_dwAttributes = dwAttributes; + } -bool TFileInfo::IsArchived() const -{ - return (m_dwAttributes & FILE_ATTRIBUTE_ARCHIVE) != 0; -} + bool TFileInfo::IsDirectory() const + { + return (m_dwAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + } -bool TFileInfo::IsReadOnly() const -{ - return (m_dwAttributes & FILE_ATTRIBUTE_READONLY) != 0; -} + bool TFileInfo::IsArchived() const + { + return (m_dwAttributes & FILE_ATTRIBUTE_ARCHIVE) != 0; + } -bool TFileInfo::IsCompressed() const -{ - return (m_dwAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0; -} + bool TFileInfo::IsReadOnly() const + { + return (m_dwAttributes & FILE_ATTRIBUTE_READONLY) != 0; + } -bool TFileInfo::IsSystem() const -{ - return (m_dwAttributes & FILE_ATTRIBUTE_SYSTEM) != 0; -} + bool TFileInfo::IsCompressed() const + { + return (m_dwAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0; + } -bool TFileInfo::IsHidden() const -{ - return (m_dwAttributes & FILE_ATTRIBUTE_HIDDEN) != 0; -} + bool TFileInfo::IsSystem() const + { + return (m_dwAttributes & FILE_ATTRIBUTE_SYSTEM) != 0; + } -bool TFileInfo::IsTemporary() const -{ - return (m_dwAttributes & FILE_ATTRIBUTE_TEMPORARY) != 0; -} + bool TFileInfo::IsHidden() const + { + return (m_dwAttributes & FILE_ATTRIBUTE_HIDDEN) != 0; + } -bool TFileInfo::IsNormal() const -{ - return m_dwAttributes == 0; -} + bool TFileInfo::IsTemporary() const + { + return (m_dwAttributes & FILE_ATTRIBUTE_TEMPORARY) != 0; + } -void TFileInfo::Store(const ISerializerContainerPtr& spContainer) const -{ - if(m_setModifications.any()) + bool TFileInfo::IsNormal() const { - ISerializerRowData& rRow = spContainer->GetRow(m_oidObjectID, m_setModifications[eMod_Added]); + return m_dwAttributes == 0; + } - if(m_setModifications[eMod_Path]) - rRow.SetValue(_T("rel_path"), m_pathFile); - if(m_setModifications[eMod_BasePath]) - rRow.SetValue(_T("base_path_id"), m_spBasePathData.Get()->GetObjectID()); - if(m_setModifications[eMod_Attributes]) - rRow.SetValue(_T("attr"), m_dwAttributes); - if(m_setModifications[eMod_FileSize]) - rRow.SetValue(_T("size"), m_uhFileSize); - if(m_setModifications[eMod_TimeCreated]) - rRow.SetValue(_T("time_created"), m_ftCreation.Get().ToUInt64()); - if(m_setModifications[eMod_TimeLastWrite]) - rRow.SetValue(_T("time_last_write"), m_ftLastWrite.Get().ToUInt64()); - if(m_setModifications[eMod_TimeLastAccess]) - rRow.SetValue(_T("time_last_access"), m_ftLastAccess.Get().ToUInt64()); - if(m_setModifications[eMod_Flags]) - rRow.SetValue(_T("flags"), m_uiFlags); + void TFileInfo::Store(const ISerializerContainerPtr& spContainer) const + { + if (m_setModifications.any()) + { + ISerializerRowData& rRow = spContainer->GetRow(m_oidObjectID, m_setModifications[eMod_Added]); - m_setModifications.reset(); + if (m_setModifications[eMod_Path]) + rRow.SetValue(_T("rel_path"), m_pathFile); + if (m_setModifications[eMod_BasePath]) + rRow.SetValue(_T("base_path_id"), m_spBasePathData.Get()->GetObjectID()); + if (m_setModifications[eMod_Attributes]) + rRow.SetValue(_T("attr"), m_dwAttributes); + if (m_setModifications[eMod_FileSize]) + rRow.SetValue(_T("size"), m_uhFileSize); + if (m_setModifications[eMod_TimeCreated]) + rRow.SetValue(_T("time_created"), m_ftCreation.Get().ToUInt64()); + if (m_setModifications[eMod_TimeLastWrite]) + rRow.SetValue(_T("time_last_write"), m_ftLastWrite.Get().ToUInt64()); + if (m_setModifications[eMod_TimeLastAccess]) + rRow.SetValue(_T("time_last_access"), m_ftLastAccess.Get().ToUInt64()); + if (m_setModifications[eMod_Flags]) + rRow.SetValue(_T("flags"), m_uiFlags); + + m_setModifications.reset(); + } } -} -void TFileInfo::InitColumns(IColumnsDefinition& rColumns) -{ - rColumns.AddColumn(_T("id"), ColumnType::value); - rColumns.AddColumn(_T("rel_path"), IColumnsDefinition::eType_path); - rColumns.AddColumn(_T("base_path_id"), ColumnType::value); - rColumns.AddColumn(_T("attr"), IColumnsDefinition::eType_ulong); - rColumns.AddColumn(_T("size"), IColumnsDefinition::eType_ulonglong); - rColumns.AddColumn(_T("time_created"), IColumnsDefinition::eType_ulonglong); - rColumns.AddColumn(_T("time_last_write"), IColumnsDefinition::eType_ulonglong); - rColumns.AddColumn(_T("time_last_access"), IColumnsDefinition::eType_ulonglong); - rColumns.AddColumn(_T("flags"), IColumnsDefinition::eType_uint); -} + void TFileInfo::InitColumns(IColumnsDefinition& rColumns) + { + rColumns.AddColumn(_T("id"), ColumnType::value); + rColumns.AddColumn(_T("rel_path"), IColumnsDefinition::eType_path); + rColumns.AddColumn(_T("base_path_id"), ColumnType::value); + rColumns.AddColumn(_T("attr"), IColumnsDefinition::eType_ulong); + rColumns.AddColumn(_T("size"), IColumnsDefinition::eType_ulonglong); + rColumns.AddColumn(_T("time_created"), IColumnsDefinition::eType_ulonglong); + rColumns.AddColumn(_T("time_last_write"), IColumnsDefinition::eType_ulonglong); + rColumns.AddColumn(_T("time_last_access"), IColumnsDefinition::eType_ulonglong); + rColumns.AddColumn(_T("flags"), IColumnsDefinition::eType_uint); + } -void TFileInfo::Load(const ISerializerRowReaderPtr& spRowReader, const TBasePathDataContainerPtr& spSrcContainer) -{ - size_t stBaseObjectID = 0; - unsigned long long ullTime = 0; - spRowReader->GetValue(_T("id"), m_oidObjectID); - spRowReader->GetValue(_T("rel_path"), m_pathFile.Modify()); - spRowReader->GetValue(_T("base_path_id"), stBaseObjectID); - spRowReader->GetValue(_T("attr"), m_dwAttributes.Modify()); - spRowReader->GetValue(_T("size"), m_uhFileSize.Modify()); + void TFileInfo::Load(const ISerializerRowReaderPtr& spRowReader, const TBasePathDataContainerPtr& spSrcContainer) + { + size_t stBaseObjectID = 0; + unsigned long long ullTime = 0; + spRowReader->GetValue(_T("id"), m_oidObjectID); + spRowReader->GetValue(_T("rel_path"), m_pathFile.Modify()); + spRowReader->GetValue(_T("base_path_id"), stBaseObjectID); + spRowReader->GetValue(_T("attr"), m_dwAttributes.Modify()); + spRowReader->GetValue(_T("size"), m_uhFileSize.Modify()); - spRowReader->GetValue(_T("time_created"), ullTime); - m_ftCreation.Modify().FromUInt64(ullTime); + spRowReader->GetValue(_T("time_created"), ullTime); + m_ftCreation.Modify().FromUInt64(ullTime); - spRowReader->GetValue(_T("time_last_write"), ullTime); - m_ftLastWrite.Modify().FromUInt64(ullTime); + spRowReader->GetValue(_T("time_last_write"), ullTime); + m_ftLastWrite.Modify().FromUInt64(ullTime); - spRowReader->GetValue(_T("time_last_access"), ullTime); - m_ftLastAccess.Modify().FromUInt64(ullTime); + spRowReader->GetValue(_T("time_last_access"), ullTime); + m_ftLastAccess.Modify().FromUInt64(ullTime); - spRowReader->GetValue(_T("flags"), m_uiFlags.Modify()); + spRowReader->GetValue(_T("flags"), m_uiFlags.Modify()); - m_spBasePathData = spSrcContainer->FindByID(stBaseObjectID); + m_spBasePathData = spSrcContainer->FindByID(stBaseObjectID); - m_setModifications.reset(); -} + m_setModifications.reset(); + } -object_id_t TFileInfo::GetObjectID() const -{ - return m_oidObjectID; -} + object_id_t TFileInfo::GetObjectID() const + { + return m_oidObjectID; + } -void TFileInfo::SetObjectID(object_id_t oidObjectID) -{ - m_oidObjectID = oidObjectID; + void TFileInfo::SetObjectID(object_id_t oidObjectID) + { + m_oidObjectID = oidObjectID; + } } - -END_CHCORE_NAMESPACE Index: src/libchcore/TFileInfo.h =================================================================== diff -u -N -ra44714d5c7ec0f50a376f4d0ea919ee5a224f834 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TFileInfo.h (.../TFileInfo.h) (revision a44714d5c7ec0f50a376f4d0ea919ee5a224f834) +++ src/libchcore/TFileInfo.h (.../TFileInfo.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -29,117 +29,119 @@ #include "TSharedModificationTracker.h" #include "TFileTime.h" -BEGIN_CHCORE_NAMESPACE - -// CFileInfo flags - -class LIBCHCORE_API TFileInfo +namespace chcore { -public: - enum EFlags + class LIBCHCORE_API TFileInfo { - // flag stating that file has been processed (used to determine if file can be deleted at the end of copying) - eFlag_Processed = 1, - }; + public: + enum EFlags + { + // flag stating that file has been processed (used to determine if file can be deleted at the end of copying) + eFlag_Processed = 1, + }; -public: - TFileInfo(); - TFileInfo(const TFileInfo& rSrc); - ~TFileInfo(); + public: + TFileInfo(); + TFileInfo(const TFileInfo& rSrc); + TFileInfo(const TBasePathDataPtr& spBasePathData, const TSmartPath& rpathFile, + DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, FILETIME ftLastAccess, FILETIME ftLastWrite, + uint_t uiFlags); + ~TFileInfo(); - TFileInfo& operator=(const TFileInfo& rSrc); + TFileInfo& operator=(const TFileInfo& rSrc); - // operators - bool operator==(const TFileInfo& rInfo) const; + // operators + bool operator==(const TFileInfo& rInfo) const; - // with base path - void Init(const TBasePathDataPtr& spBasePathData, const TSmartPath& rpathFile, - DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, FILETIME ftLastAccess, FILETIME ftLastWrite, - uint_t uiFlags); + // with base path + void Init(const TBasePathDataPtr& spBasePathData, const TSmartPath& rpathFile, + DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, FILETIME ftLastAccess, FILETIME ftLastWrite, + uint_t uiFlags); - // without base path - void Init(const TSmartPath& rpathFile, DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, - FILETIME ftLastAccess, FILETIME ftLastWrite, uint_t uiFlags); + // without base path + void Init(const TSmartPath& rpathFile, DWORD dwAttributes, ULONGLONG uhFileSize, FILETIME ftCreation, + FILETIME ftLastAccess, FILETIME ftLastWrite, uint_t uiFlags); - // unique object id - object_id_t GetObjectID() const; - void SetObjectID(object_id_t oidObjectID); + // unique object id + object_id_t GetObjectID() const; + void SetObjectID(object_id_t oidObjectID); - // parent object - TBasePathDataPtr GetBasePathData() const; - void SetParentObject(const TBasePathDataPtr& spBasePathData); - object_id_t GetSrcObjectID() const; + // parent object + TBasePathDataPtr GetBasePathData() const; + void SetParentObject(const TBasePathDataPtr& spBasePathData); + object_id_t GetSrcObjectID() const; - // file path - const TSmartPath& GetFilePath() const; // returns path with m_pathFile (probably not full) - TSmartPath GetFullFilePath() const; // returns full path - void SetFilePath(const TSmartPath& tPath); + // file path + const TSmartPath& GetFilePath() const; // returns path with m_pathFile (probably not full) + TSmartPath GetFullFilePath() const; // returns full path + void SetFilePath(const TSmartPath& tPath); - // file size - ULONGLONG GetLength64() const; - void SetLength64(ULONGLONG uhSize); + // file size + ULONGLONG GetLength64() const; + void SetLength64(ULONGLONG uhSize); - // file times - const TFileTime& GetCreationTime() const; - const TFileTime& GetLastAccessTime() const; - const TFileTime& GetLastWriteTime() const; + // file times + void SetFileTimes(const TFileTime& rCreation, const TFileTime& rLastAccess, const TFileTime& rLastWrite); + const TFileTime& GetCreationTime() const; + const TFileTime& GetLastAccessTime() const; + const TFileTime& GetLastWriteTime() const; - // attributes - DWORD GetAttributes() const; - bool IsDirectory() const; - bool IsArchived() const; - bool IsReadOnly() const; - bool IsCompressed() const; - bool IsSystem() const; - bool IsHidden() const; - bool IsTemporary() const; - bool IsNormal() const; + // attributes + DWORD GetAttributes() const; + void SetAttributes(DWORD dwAttributes); + bool IsDirectory() const; + bool IsArchived() const; + bool IsReadOnly() const; + bool IsCompressed() const; + bool IsSystem() const; + bool IsHidden() const; + bool IsTemporary() const; + bool IsNormal() const; - void MarkAsProcessed(bool bProcessed); - bool IsProcessed() const; + void MarkAsProcessed(bool bProcessed); + bool IsProcessed() const; - void Store(const ISerializerContainerPtr& spContainer) const; - static void InitColumns(IColumnsDefinition& rColumns); - void Load(const ISerializerRowReaderPtr& spRowReader, const TBasePathDataContainerPtr& spSrcContainer); + void Store(const ISerializerContainerPtr& spContainer) const; + static void InitColumns(IColumnsDefinition& rColumns); + void Load(const ISerializerRowReaderPtr& spRowReader, const TBasePathDataContainerPtr& spSrcContainer); -private: - enum EModifications - { - eMod_None = 0, - eMod_Added, - eMod_Path, - eMod_BasePath, - eMod_Attributes, - eMod_FileSize, - eMod_TimeCreated, - eMod_TimeLastAccess, - eMod_TimeLastWrite, - eMod_Flags, + private: + enum EModifications + { + eMod_None = 0, + eMod_Added, + eMod_Path, + eMod_BasePath, + eMod_Attributes, + eMod_FileSize, + eMod_TimeCreated, + eMod_TimeLastAccess, + eMod_TimeLastWrite, + eMod_Flags, - // do not use - must be the last value in this enum - eMod_Last - }; + // do not use - must be the last value in this enum + eMod_Last + }; #pragma warning(push) #pragma warning(disable: 4251) - typedef std::bitset Bitset; - mutable Bitset m_setModifications; + typedef std::bitset Bitset; + mutable Bitset m_setModifications; - object_id_t m_oidObjectID; + object_id_t m_oidObjectID; - TSharedModificationTracker m_pathFile; - TSharedModificationTracker m_spBasePathData; - TSharedModificationTracker m_dwAttributes; // attributes - TSharedModificationTracker m_uhFileSize; - TSharedModificationTracker m_ftCreation; - TSharedModificationTracker m_ftLastAccess; - TSharedModificationTracker m_ftLastWrite; - TSharedModificationTracker m_uiFlags; + TSharedModificationTracker m_pathFile; + TSharedModificationTracker m_spBasePathData; + TSharedModificationTracker m_dwAttributes; // attributes + TSharedModificationTracker m_uhFileSize; + TSharedModificationTracker m_ftCreation; + TSharedModificationTracker m_ftLastAccess; + TSharedModificationTracker m_ftLastWrite; + TSharedModificationTracker m_uiFlags; #pragma warning(pop) -}; + }; -typedef boost::shared_ptr TFileInfoPtr; + typedef boost::shared_ptr TFileInfoPtr; +} -END_CHCORE_NAMESPACE - #endif Index: src/libchcore/TLocalFilesystem.cpp =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TLocalFilesystem.cpp (.../TLocalFilesystem.cpp) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/TLocalFilesystem.cpp (.../TLocalFilesystem.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -203,9 +203,9 @@ return std::shared_ptr(new TLocalFilesystemFind(pathDir, pathMask)); } -IFilesystemFilePtr TLocalFilesystem::CreateFileObject() +IFilesystemFilePtr TLocalFilesystem::CreateFileObject(const TSmartPath& pathFile) { - return std::shared_ptr(new TLocalFilesystemFile()); + return std::shared_ptr(new TLocalFilesystemFile(pathFile)); } TSmartPath TLocalFilesystem::PrependPathExtensionIfNeeded(const TSmartPath& pathInput) Index: src/libchcore/TLocalFilesystem.h =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TLocalFilesystem.h (.../TLocalFilesystem.h) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/TLocalFilesystem.h (.../TLocalFilesystem.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -57,7 +57,7 @@ virtual bool FastMove(const TSmartPath& pathSource, const TSmartPath& pathDestination) override; virtual IFilesystemFindPtr CreateFinderObject(const TSmartPath& pathDir, const TSmartPath& pathMask) override; - virtual IFilesystemFilePtr CreateFileObject() override; + virtual IFilesystemFilePtr CreateFileObject(const TSmartPath& pathFile) override; virtual EPathsRelation GetPathsRelation(const TSmartPath& pathFirst, const TSmartPath& pathSecond) override; Index: src/libchcore/TLocalFilesystemFile.cpp =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TLocalFilesystemFile.cpp (.../TLocalFilesystemFile.cpp) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/TLocalFilesystemFile.cpp (.../TLocalFilesystemFile.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -26,196 +26,191 @@ #include "RoundingFunctions.h" #include "TLocalFilesystem.h" -BEGIN_CHCORE_NAMESPACE - -// compile-time check - ensure the buffer granularity used for transfers are bigger than expected sector size -static_assert(TLocalFilesystemFile::MaxSectorSize <= TBufferSizes::BufferGranularity, "Buffer granularity must be equal to or bigger than the max sector size"); - -TLocalFilesystemFile::TLocalFilesystemFile() : - m_hFile(INVALID_HANDLE_VALUE), - m_pathFile(), - m_bNoBuffering(false) +namespace chcore { -} + // compile-time check - ensure the buffer granularity used for transfers are bigger than expected sector size + static_assert(TLocalFilesystemFile::MaxSectorSize <= TBufferSizes::BufferGranularity, "Buffer granularity must be equal to or bigger than the max sector size"); -TLocalFilesystemFile::~TLocalFilesystemFile() -{ - Close(); -} + TLocalFilesystemFile::TLocalFilesystemFile(const TSmartPath& pathFile) : + m_pathFile(TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile)), + m_hFile(INVALID_HANDLE_VALUE), + m_bNoBuffering(false) + { + if (pathFile.IsEmpty()) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + } -DWORD TLocalFilesystemFile::GetFlagsAndAttributes(bool bNoBuffering) const -{ - return FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING /*| FILE_FLAG_WRITE_THROUGH*/ : 0); -} + TLocalFilesystemFile::~TLocalFilesystemFile() + { + Close(); + } -bool TLocalFilesystemFile::OpenExistingForReading(const TSmartPath& pathFile, bool bNoBuffering) -{ - Close(); + DWORD TLocalFilesystemFile::GetFlagsAndAttributes(bool bNoBuffering) const + { + return FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN | (bNoBuffering ? FILE_FLAG_NO_BUFFERING /*| FILE_FLAG_WRITE_THROUGH*/ : 0); + } - m_pathFile = TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile); - m_hFile = ::CreateFile(m_pathFile.ToString(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, GetFlagsAndAttributes(bNoBuffering), NULL); - if (m_hFile == INVALID_HANDLE_VALUE) - return false; + bool TLocalFilesystemFile::OpenExistingForReading(bool bNoBuffering) + { + Close(); - m_bNoBuffering = bNoBuffering; - return true; -} + m_hFile = ::CreateFile(m_pathFile.ToString(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, GetFlagsAndAttributes(bNoBuffering), NULL); + if (m_hFile == INVALID_HANDLE_VALUE) + return false; -bool TLocalFilesystemFile::CreateNewForWriting(const TSmartPath& pathFile, bool bNoBuffering) -{ - Close(); + m_bNoBuffering = bNoBuffering; + return true; + } - m_pathFile = TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile); - m_hFile = ::CreateFile(m_pathFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, GetFlagsAndAttributes(bNoBuffering), NULL); - if (m_hFile == INVALID_HANDLE_VALUE) - return false; + bool TLocalFilesystemFile::CreateNewForWriting(bool bNoBuffering) + { + Close(); - m_bNoBuffering = bNoBuffering; - return true; -} + m_hFile = ::CreateFile(m_pathFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, GetFlagsAndAttributes(bNoBuffering), NULL); + if (m_hFile == INVALID_HANDLE_VALUE) + return false; -bool TLocalFilesystemFile::OpenExistingForWriting(const TSmartPath& pathFile, bool bNoBuffering) -{ - Close(); + m_bNoBuffering = bNoBuffering; + return true; + } - m_pathFile = TLocalFilesystem::PrependPathExtensionIfNeeded(pathFile); - m_hFile = CreateFile(m_pathFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, GetFlagsAndAttributes(bNoBuffering), NULL); - if (m_hFile == INVALID_HANDLE_VALUE) - return false; + bool TLocalFilesystemFile::OpenExistingForWriting(bool bNoBuffering) + { + Close(); - m_bNoBuffering = bNoBuffering; - return true; -} + m_hFile = CreateFile(m_pathFile.ToString(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, GetFlagsAndAttributes(bNoBuffering), NULL); + if (m_hFile == INVALID_HANDLE_VALUE) + return false; -bool TLocalFilesystemFile::SetFilePointer(long long llNewPos, DWORD dwMoveMethod) -{ - if (!IsOpen()) - return false; + m_bNoBuffering = bNoBuffering; + return true; + } - LARGE_INTEGER li = { 0, 0 }; - LARGE_INTEGER liNew = { 0, 0 }; + bool TLocalFilesystemFile::Truncate(long long llNewSize) + { + if (!IsOpen()) + return false; - li.QuadPart = llNewPos; + LARGE_INTEGER li = { 0, 0 }; + LARGE_INTEGER liNew = { 0, 0 }; - return SetFilePointerEx(m_hFile, li, &liNew, dwMoveMethod) != FALSE; -} + li.QuadPart = llNewSize; -bool TLocalFilesystemFile::SetEndOfFile() -{ - if (!IsOpen()) - return false; + if (!SetFilePointerEx(m_hFile, li, &liNew, FILE_BEGIN)) + return false; - return ::SetEndOfFile(m_hFile) != FALSE; -} + return ::SetEndOfFile(m_hFile) != FALSE; + } -bool TLocalFilesystemFile::ReadFile(TOverlappedDataBuffer& rBuffer) -{ - if (!IsOpen()) - THROW_CORE_EXCEPTION(eErr_InternalProblem); - - ATLTRACE(_T("Reading %lu bytes\n"), rBuffer.GetRequestedDataSize()); - if (!::ReadFileEx(m_hFile, rBuffer.GetBufferPtr(), rBuffer.GetRequestedDataSize(), &rBuffer, OverlappedReadCompleted)) + bool TLocalFilesystemFile::ReadFile(TOverlappedDataBuffer& rBuffer) { - DWORD dwLastError = GetLastError(); - switch (dwLastError) - { - case ERROR_IO_PENDING: - return true; + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); - case ERROR_HANDLE_EOF: + ATLTRACE(_T("Reading %lu bytes\n"), rBuffer.GetRequestedDataSize()); + if (!::ReadFileEx(m_hFile, rBuffer.GetBufferPtr(), rBuffer.GetRequestedDataSize(), &rBuffer, OverlappedReadCompleted)) { - rBuffer.SetBytesTransferred(0); - rBuffer.SetStatusCode(0); - rBuffer.SetErrorCode(ERROR_SUCCESS); - rBuffer.SetLastPart(true); + DWORD dwLastError = GetLastError(); + switch (dwLastError) + { + case ERROR_IO_PENDING: + return true; - rBuffer.RequeueAsFull(); // basically the same as OverlappedReadCompleted + case ERROR_HANDLE_EOF: + { + rBuffer.SetBytesTransferred(0); + rBuffer.SetStatusCode(0); + rBuffer.SetErrorCode(ERROR_SUCCESS); + rBuffer.SetLastPart(true); - return true; - } - } + rBuffer.RequeueAsFull(); // basically the same as OverlappedReadCompleted - return false; + return true; + } + } + + return false; + } + return true; } - return true; -} -bool TLocalFilesystemFile::WriteFile(TOverlappedDataBuffer& rBuffer) -{ - if (!IsOpen()) - THROW_CORE_EXCEPTION(eErr_InternalProblem); + bool TLocalFilesystemFile::WriteFile(TOverlappedDataBuffer& rBuffer) + { + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); - DWORD dwToWrite = boost::numeric_cast(rBuffer.GetRealDataSize()); + DWORD dwToWrite = boost::numeric_cast(rBuffer.GetRealDataSize()); - if (m_bNoBuffering && rBuffer.IsLastPart()) - dwToWrite = RoundUp(dwToWrite, MaxSectorSize); + if (m_bNoBuffering && rBuffer.IsLastPart()) + dwToWrite = RoundUp(dwToWrite, MaxSectorSize); - ATLTRACE(_T("Writing %lu bytes\n"), dwToWrite); - if (!::WriteFileEx(m_hFile, rBuffer.GetBufferPtr(), dwToWrite, &rBuffer, OverlappedWriteCompleted)) - { - if (GetLastError() == ERROR_IO_PENDING) - return true; - return false; + ATLTRACE(_T("Writing %lu bytes\n"), dwToWrite); + if (!::WriteFileEx(m_hFile, rBuffer.GetBufferPtr(), dwToWrite, &rBuffer, OverlappedWriteCompleted)) + { + if (GetLastError() == ERROR_IO_PENDING) + return true; + return false; + } + + return true; } - return true; -} - -bool TLocalFilesystemFile::FinalizeFile(TOverlappedDataBuffer& rBuffer) -{ - if (!IsOpen()) - THROW_CORE_EXCEPTION(eErr_InternalProblem); - - if (m_bNoBuffering && rBuffer.IsLastPart()) + bool TLocalFilesystemFile::FinalizeFile(TOverlappedDataBuffer& rBuffer) { - DWORD dwToWrite = boost::numeric_cast(rBuffer.GetRealDataSize()); - DWORD dwReallyWritten = RoundUp(dwToWrite, MaxSectorSize); + if (!IsOpen()) + THROW_CORE_EXCEPTION(eErr_InternalProblem); - ATLTRACE(_T("Finalize file - size diff: written: %I64u, required: %I64u\n"), dwReallyWritten, dwToWrite); - - if (dwToWrite != dwReallyWritten) + if (m_bNoBuffering && rBuffer.IsLastPart()) { - unsigned long long ullNewFileSize = rBuffer.GetFilePosition() + dwToWrite; // new size + DWORD dwToWrite = boost::numeric_cast(rBuffer.GetRealDataSize()); + DWORD dwReallyWritten = RoundUp(dwToWrite, MaxSectorSize); - if (!OpenExistingForWriting(m_pathFile, false)) - return false; + ATLTRACE(_T("Finalize file - size diff: written: %I64u, required: %I64u\n"), dwReallyWritten, dwToWrite); - //seek - ATLTRACE(_T("Truncating file to %I64u bytes\n"), ullNewFileSize); - if (!SetFilePointer(ullNewFileSize, FILE_BEGIN)) - return false; + if (dwToWrite != dwReallyWritten) + { + unsigned long long ullNewFileSize = rBuffer.GetFilePosition() + dwToWrite; // new size - //set eof - if (!SetEndOfFile()) - return false; + if (!OpenExistingForWriting(false)) + return false; + + //seek + ATLTRACE(_T("Truncating file to %I64u bytes\n"), ullNewFileSize); + if (!Truncate(ullNewFileSize)) + return false; + } } + + return true; } - return true; -} + void TLocalFilesystemFile::Close() + { + if (m_hFile != INVALID_HANDLE_VALUE) + ::CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } -void TLocalFilesystemFile::Close() -{ - if (m_hFile != INVALID_HANDLE_VALUE) - ::CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; -} + unsigned long long TLocalFilesystemFile::GetFileSize() const + { + if (!IsOpen()) + return 0; -unsigned long long TLocalFilesystemFile::GetFileSize() const -{ - if (!IsOpen()) - return 0; + BY_HANDLE_FILE_INFORMATION bhfi; - BY_HANDLE_FILE_INFORMATION bhfi; + if (!::GetFileInformationByHandle(m_hFile, &bhfi)) + return 0; - if (!::GetFileInformationByHandle(m_hFile, &bhfi)) - return 0; + ULARGE_INTEGER uli; + uli.HighPart = bhfi.nFileSizeHigh; + uli.LowPart = bhfi.nFileSizeLow; - ULARGE_INTEGER uli; - uli.HighPart = bhfi.nFileSizeHigh; - uli.LowPart = bhfi.nFileSizeLow; + return uli.QuadPart; + } - return uli.QuadPart; -} + TSmartPath TLocalFilesystemFile::GetFilePath() const + { + return m_pathFile; + } -END_CHCORE_NAMESPACE +} Index: src/libchcore/TLocalFilesystemFile.h =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TLocalFilesystemFile.h (.../TLocalFilesystemFile.h) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/TLocalFilesystemFile.h (.../TLocalFilesystemFile.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -24,41 +24,40 @@ #include "TOverlappedDataBuffer.h" #include "IFilesystemFile.h" -BEGIN_CHCORE_NAMESPACE - -class LIBCHCORE_API TLocalFilesystemFile : public IFilesystemFile +namespace chcore { -public: - virtual ~TLocalFilesystemFile(); + class LIBCHCORE_API TLocalFilesystemFile : public IFilesystemFile + { + public: + virtual ~TLocalFilesystemFile(); - virtual bool OpenExistingForReading(const TSmartPath& pathFile, bool bNoBuffering) override; - virtual bool CreateNewForWriting(const TSmartPath& pathFile, bool bNoBuffering) override; - virtual bool OpenExistingForWriting(const TSmartPath& pathFile, bool bNoBuffering) override; + virtual bool OpenExistingForReading(bool bNoBuffering) override; + virtual bool CreateNewForWriting(bool bNoBuffering) override; + virtual bool OpenExistingForWriting(bool bNoBuffering) override; - virtual bool SetFilePointer(long long llNewPos, DWORD dwMoveMethod) override; - virtual bool SetEndOfFile() override; + virtual bool Truncate(long long llNewSize) override; - virtual bool ReadFile(TOverlappedDataBuffer& rBuffer) override; - virtual bool WriteFile(TOverlappedDataBuffer& rBuffer) override; - virtual bool FinalizeFile(TOverlappedDataBuffer& rBuffer) override; + virtual bool ReadFile(TOverlappedDataBuffer& rBuffer) override; + virtual bool WriteFile(TOverlappedDataBuffer& rBuffer) override; + virtual bool FinalizeFile(TOverlappedDataBuffer& rBuffer) override; - virtual bool IsOpen() const override { return m_hFile != INVALID_HANDLE_VALUE; } - virtual unsigned long long GetFileSize() const override; + virtual bool IsOpen() const override { return m_hFile != INVALID_HANDLE_VALUE; } + virtual unsigned long long GetFileSize() const override; + virtual TSmartPath GetFilePath() const override; - virtual void Close() override; + virtual void Close() override; -private: - TLocalFilesystemFile(); - DWORD GetFlagsAndAttributes(bool bNoBuffering) const; + private: + TLocalFilesystemFile(const TSmartPath& pathFile); + DWORD GetFlagsAndAttributes(bool bNoBuffering) const; -private: - TSmartPath m_pathFile; - HANDLE m_hFile; - bool m_bNoBuffering; + private: + TSmartPath m_pathFile; + HANDLE m_hFile; + bool m_bNoBuffering; - friend class TLocalFilesystem; -}; + friend class TLocalFilesystem; + }; +} -END_CHCORE_NAMESPACE - #endif Index: src/libchcore/TPath.cpp =================================================================== diff -u -N -r11b0a299be97bc3afaa633d6522c17b214ba3b79 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TPath.cpp (.../TPath.cpp) (revision 11b0a299be97bc3afaa633d6522c17b214ba3b79) +++ src/libchcore/TPath.cpp (.../TPath.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -31,878 +31,904 @@ #include "TPathContainer.h" #include "TStringArray.h" -BEGIN_CHCORE_NAMESPACE - +namespace chcore +{ #define DEFAULT_PATH_SEPARATOR _T("\\") -// ============================================================================ -/// TSmartPath::TSmartPath -/// @date 2009/11/29 -/// -/// @brief Constructs an empty path. -// ============================================================================ -TSmartPath::TSmartPath() : - m_strPath() -{ -} + // ============================================================================ + /// TSmartPath::TSmartPath + /// @date 2009/11/29 + /// + /// @brief Constructs an empty path. + // ============================================================================ + TSmartPath::TSmartPath() : + m_strPath() + { + } -// ============================================================================ -/// TSmartPath::TSmartPath -/// @date 2009/11/29 -/// -/// @brief Constructs path object from another path object. -/// @param[in] spPath - reference to another path object. -// ============================================================================ -TSmartPath::TSmartPath(const TSmartPath& spPath) : - m_strPath(spPath.m_strPath) -{ -} + // ============================================================================ + /// TSmartPath::TSmartPath + /// @date 2009/11/29 + /// + /// @brief Constructs path object from another path object. + /// @param[in] spPath - reference to another path object. + // ============================================================================ + TSmartPath::TSmartPath(const TSmartPath& spPath) : + m_strPath(spPath.m_strPath) + { + } -// ============================================================================ -/// TSmartPath::~TSmartPath -/// @date 2009/11/29 -/// -/// @brief -/// @return -// ============================================================================ -TSmartPath::~TSmartPath() -{ - Clear(); -} + // ============================================================================ + /// TSmartPath::~TSmartPath + /// @date 2009/11/29 + /// + /// @brief + /// @return + // ============================================================================ + TSmartPath::~TSmartPath() + { + Clear(); + } -// ============================================================================ -/// TSmartPath::Clear -/// @date 2009/11/29 -/// -/// @brief Clears this object. -// ============================================================================ -void TSmartPath::Clear() throw() -{ - m_strPath.Clear(); -} + // ============================================================================ + /// TSmartPath::Clear + /// @date 2009/11/29 + /// + /// @brief Clears this object. + // ============================================================================ + void TSmartPath::Clear() throw() + { + m_strPath.Clear(); + } -TSmartPath TSmartPath::AppendCopy(const TSmartPath& pathToAppend, bool bEnsurePathSeparatorExists) const -{ - TSmartPath pathNew(*this); - pathNew.Append(pathToAppend, bEnsurePathSeparatorExists); + TSmartPath TSmartPath::AppendCopy(const TSmartPath& pathToAppend, bool bEnsurePathSeparatorExists) const + { + TSmartPath pathNew(*this); + pathNew.Append(pathToAppend, bEnsurePathSeparatorExists); - return pathNew; -} + return pathNew; + } -TSmartPath& TSmartPath::Append(const TSmartPath& pathToAppend, bool bEnsurePathSeparatorExists) -{ - // if there is no path inside rPath, then there is no point in doing anything - if(!pathToAppend.m_strPath.IsEmpty()) + TSmartPath& TSmartPath::Append(const TSmartPath& pathToAppend, bool bEnsurePathSeparatorExists) { - // if this path is empty, then optimize by just assigning the input path to this one - if(m_strPath.IsEmpty()) - *this = pathToAppend; - else + // if there is no path inside rPath, then there is no point in doing anything + if (!pathToAppend.m_strPath.IsEmpty()) { - if(bEnsurePathSeparatorExists) + // if this path is empty, then optimize by just assigning the input path to this one + if (m_strPath.IsEmpty()) + *this = pathToAppend; + else { - // detect separators - bool bThisEndsWithSeparator = EndsWithSeparator(); - bool bInStartsWithSeparator = pathToAppend.StartsWithSeparator(); + if (bEnsurePathSeparatorExists) + { + // detect separators + bool bThisEndsWithSeparator = EndsWithSeparator(); + bool bInStartsWithSeparator = pathToAppend.StartsWithSeparator(); - if(!bThisEndsWithSeparator && !bInStartsWithSeparator) - m_strPath += _T("\\") + pathToAppend.m_strPath; - else if(bThisEndsWithSeparator ^ bInStartsWithSeparator) - m_strPath += pathToAppend.m_strPath; + if (!bThisEndsWithSeparator && !bInStartsWithSeparator) + m_strPath += _T("\\") + pathToAppend.m_strPath; + else if (bThisEndsWithSeparator ^ bInStartsWithSeparator) + m_strPath += pathToAppend.m_strPath; + else + { + m_strPath.Delete(m_strPath.GetLength() - 1, 1); + m_strPath += pathToAppend.m_strPath; + } + } else - { - m_strPath.Delete(m_strPath.GetLength() - 1, 1); m_strPath += pathToAppend.m_strPath; - } } - else - m_strPath += pathToAppend.m_strPath; } + + return *this; } - return *this; -} + // ============================================================================ + /// TSmartPath::operator= + /// @date 2009/11/29 + /// + /// @brief Assigns a path from other path object. + /// @param[in] spPath - path object from which we want to get path. + /// @return Reference to this object. + // ============================================================================ + TSmartPath& TSmartPath::operator=(const TSmartPath& spPath) + { + if (this != &spPath) + { + Clear(); + m_strPath = spPath.m_strPath; + } -// ============================================================================ -/// TSmartPath::operator= -/// @date 2009/11/29 -/// -/// @brief Assigns a path from other path object. -/// @param[in] spPath - path object from which we want to get path. -/// @return Reference to this object. -// ============================================================================ -TSmartPath& TSmartPath::operator=(const TSmartPath& spPath) -{ - if(this != &spPath) + return *this; + } + + // ============================================================================ + /// TSmartPath::operator== + /// @date 2009/11/29 + /// + /// @brief Compares paths (case sensitive). + /// @param[in] rPath - path to compare this object to. + /// @return True if equal, false otherwise. + // ============================================================================ + bool TSmartPath::operator==(const TSmartPath& rPath) const { - Clear(); - m_strPath = spPath.m_strPath; + return Compare(rPath) == 0; } - return *this; -} -// ============================================================================ -/// TSmartPath::operator== -/// @date 2009/11/29 -/// -/// @brief Compares paths (case sensitive). -/// @param[in] rPath - path to compare this object to. -/// @return True if equal, false otherwise. -// ============================================================================ -bool TSmartPath::operator==(const TSmartPath& rPath) const -{ - return Compare(rPath) == 0; -} + bool TSmartPath::operator!=(const TSmartPath& rPath) const + { + return Compare(rPath) != 0; + } + // ============================================================================ + /// TSmartPath::operator< + /// @date 2009/11/29 + /// + /// @brief Compares paths (case sensitive). + /// @param[in] rPath - input path to compare. + /// @return True if this object is less than rPath, false otherwise. + // ============================================================================ + bool TSmartPath::operator<(const TSmartPath& rPath) const + { + return Compare(rPath) < 0; + } -bool TSmartPath::operator!=(const TSmartPath& rPath) const -{ - return Compare(rPath) != 0; -} + // ============================================================================ + /// TSmartPath::operator> + /// @date 2009/11/29 + /// + /// @brief Compares paths (case sensitive). + /// @param[in] rPath - input path to compare. + /// @return True if this object is less than rPath, false otherwise. + // ============================================================================ + bool TSmartPath::operator>(const TSmartPath& rPath) const + { + return Compare(rPath) > 0; + } -// ============================================================================ -/// TSmartPath::operator< -/// @date 2009/11/29 -/// -/// @brief Compares paths (case sensitive). -/// @param[in] rPath - input path to compare. -/// @return True if this object is less than rPath, false otherwise. -// ============================================================================ -bool TSmartPath::operator<(const TSmartPath& rPath) const -{ - return Compare(rPath) < 0; -} + // ============================================================================ + /// TSmartPath::operator+ + /// @date 2009/11/29 + /// + /// @brief Concatenates two paths, returns the result. + /// @param[in] rPath - path to concatenate. + /// @return New path object with the results of concatenation. + // ============================================================================ + TSmartPath TSmartPath::operator+(const TSmartPath& rPath) const + { + return AppendCopy(rPath, true); + } -// ============================================================================ -/// TSmartPath::operator> -/// @date 2009/11/29 -/// -/// @brief Compares paths (case sensitive). -/// @param[in] rPath - input path to compare. -/// @return True if this object is less than rPath, false otherwise. -// ============================================================================ -bool TSmartPath::operator>(const TSmartPath& rPath) const -{ - return Compare(rPath) > 0; -} + // ============================================================================ + /// TSmartPath::operator+= + /// @date 2009/11/29 + /// + /// @brief Concatenates provided path to our own. + /// @param[in] rPath - path to concatenate. + /// @return Reference to this object. + // ============================================================================ + TSmartPath& TSmartPath::operator+=(const TSmartPath& rPath) + { + return Append(rPath, true); + } -// ============================================================================ -/// TSmartPath::operator+ -/// @date 2009/11/29 -/// -/// @brief Concatenates two paths, returns the result. -/// @param[in] rPath - path to concatenate. -/// @return New path object with the results of concatenation. -// ============================================================================ -TSmartPath TSmartPath::operator+(const TSmartPath& rPath) const -{ - return AppendCopy(rPath, true); -} + // ============================================================================ + /// TSmartPath::FromString + /// @date 2010/10/12 + /// + /// @brief Initializes this path object with path contained in string. + /// @param[in] pszPath - string containing path. + // ============================================================================ + void TSmartPath::FromString(const wchar_t* pszPath) + { + if (!pszPath) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); -// ============================================================================ -/// TSmartPath::operator+= -/// @date 2009/11/29 -/// -/// @brief Concatenates provided path to our own. -/// @param[in] rPath - path to concatenate. -/// @return Reference to this object. -// ============================================================================ -TSmartPath& TSmartPath::operator+=(const TSmartPath& rPath) -{ - return Append(rPath, true); -} + m_strPath = pszPath; + } -// ============================================================================ -/// TSmartPath::FromString -/// @date 2010/10/12 -/// -/// @brief Initializes this path object with path contained in string. -/// @param[in] pszPath - string containing path. -// ============================================================================ -void TSmartPath::FromString(const wchar_t* pszPath) -{ - if(!pszPath) - THROW_CORE_EXCEPTION(eErr_InvalidArgument); + // ============================================================================ + /// TSmartPath::FromString + /// @date 2010/10/12 + /// + /// @brief Initializes this path object with path contained in string. + /// @param[in] strPath - string containing path. + // ============================================================================ + void TSmartPath::FromString(const TString& strPath) + { + m_strPath = strPath; + } - m_strPath = pszPath; -} + // ============================================================================ + /// TSmartPath::ToString + /// @date 2010/10/12 + /// + /// @brief Retrieves the pointer to a string containing path. + /// @return Pointer to the string containing path. + // ============================================================================ + const wchar_t* TSmartPath::ToString() const + { + return m_strPath.c_str(); + } -// ============================================================================ -/// TSmartPath::FromString -/// @date 2010/10/12 -/// -/// @brief Initializes this path object with path contained in string. -/// @param[in] strPath - string containing path. -// ============================================================================ -void TSmartPath::FromString(const TString& strPath) -{ - m_strPath = strPath; -} + // ============================================================================ + /// TSmartPath::ToString + /// @date 2010/10/12 + /// + /// @brief Retrieves the string containing path. + /// @return String containing path. + // ============================================================================ + TString TSmartPath::ToWString() const + { + return m_strPath; + } -// ============================================================================ -/// TSmartPath::ToString -/// @date 2010/10/12 -/// -/// @brief Retrieves the pointer to a string containing path. -/// @return Pointer to the string containing path. -// ============================================================================ -const wchar_t* TSmartPath::ToString() const -{ - return m_strPath.c_str(); -} + // ============================================================================ + /// TSmartPath::Compare + /// @date 2009/11/29 + /// + /// @brief Compares paths. + /// @param[in] rPath - path to compare to. + /// @return Result of the comparison. + // ============================================================================ + int TSmartPath::Compare(const TSmartPath& rPath, bool bCaseSensitive) const + { + if (bCaseSensitive) + return m_strPath.Compare(rPath.m_strPath); + else + return m_strPath.CompareNoCase(rPath.m_strPath); + } -// ============================================================================ -/// TSmartPath::ToString -/// @date 2010/10/12 -/// -/// @brief Retrieves the string containing path. -/// @return String containing path. -// ============================================================================ -TString TSmartPath::ToWString() const -{ - return m_strPath; -} + // ============================================================================ + /// TSmartPath::SplitPath + /// @date 2011/04/05 + /// + /// @brief Splits path to components. + /// @param[in] vComponents - receives the split path. + // ============================================================================ + void TSmartPath::SplitPath(TPathContainer& vComponents) const + { + vComponents.Clear(); -// ============================================================================ -/// TSmartPath::Compare -/// @date 2009/11/29 -/// -/// @brief Compares paths. -/// @param[in] rPath - path to compare to. -/// @return Result of the comparison. -// ============================================================================ -int TSmartPath::Compare(const TSmartPath& rPath, bool bCaseSensitive) const -{ - if(bCaseSensitive) - return m_strPath.Compare(rPath.m_strPath); - else - return m_strPath.CompareNoCase(rPath.m_strPath); -} + if (IsNetworkPath()) + { + // server name first + vComponents.Add(GetServerName()); -// ============================================================================ -/// TSmartPath::SplitPath -/// @date 2011/04/05 -/// -/// @brief Splits path to components. -/// @param[in] vComponents - receives the split path. -// ============================================================================ -void TSmartPath::SplitPath(TPathContainer& vComponents) const -{ - vComponents.Clear(); + // now the split directories + TPathContainer vDirSplit; + TSmartPath spDir = GetFileDir(); + spDir.SplitPath(vDirSplit); - if(IsNetworkPath()) - { - // server name first - vComponents.Add(GetServerName()); + vComponents.Append(vDirSplit); - // now the split directories - TPathContainer vDirSplit; - TSmartPath spDir = GetFileDir(); - spDir.SplitPath(vDirSplit); + // and file name last + vComponents.Add(GetFileName()); + } + else + { + TStringArray vStrings; + m_strPath.Split(_T("\\/"), vStrings); - vComponents.Append(vDirSplit); + for (size_t stIndex = 0; stIndex < vStrings.GetCount(); ++stIndex) + { + const TString& strComponent = vStrings.GetAt(stIndex); + if (!strComponent.IsEmpty()) + vComponents.Add(PathFromWString(strComponent)); + } + } + } - // and file name last - vComponents.Add(GetFileName()); + // ============================================================================ + /// TSmartPath::IsChildOf + /// @date 2009/11/29 + /// + /// @brief Checks if this path starts with the path specified as parameter. + /// @param[in] rPath - path to check this one against. + /// @return True if this path starts with the provided one, false otherwise. + // ============================================================================ + bool TSmartPath::IsChildOf(const TSmartPath& rPath, bool bCaseSensitive) const + { + if (bCaseSensitive) + return m_strPath.StartsWith(rPath.m_strPath.c_str()); + else + return m_strPath.StartsWithNoCase(rPath.m_strPath.c_str()); } - else + + // ============================================================================ + /// TSmartPath::MakeRelativePath + /// @date 2010/10/12 + /// + /// @brief Converts this path to be relative to the reference, base path. + /// @param[in] rReferenceBasePath - Path which will be base path to this relative path. + /// @param[in] bCaseSensitive - Compare path with case sensitivity on/off. + /// @return True if conversion to relative path succeeded, false otherwise. + // ============================================================================ + bool TSmartPath::MakeRelativePath(const TSmartPath& rReferenceBasePath, bool bCaseSensitive) { - TStringArray vStrings; - m_strPath.Split(_T("\\/"), vStrings); + bool bStartsWith = false; + if (bCaseSensitive) + bStartsWith = m_strPath.StartsWith(rReferenceBasePath.m_strPath.c_str()); + else + bStartsWith = m_strPath.StartsWithNoCase(rReferenceBasePath.m_strPath.c_str()); - for(size_t stIndex = 0; stIndex < vStrings.GetCount(); ++stIndex) + if (bStartsWith) { - const TString& strComponent = vStrings.GetAt(stIndex); - if(!strComponent.IsEmpty()) - vComponents.Add(PathFromWString(strComponent)); + m_strPath.Delete(0, rReferenceBasePath.m_strPath.GetLength()); + return true; } + else + return false; } -} -// ============================================================================ -/// TSmartPath::IsChildOf -/// @date 2009/11/29 -/// -/// @brief Checks if this path starts with the path specified as parameter. -/// @param[in] rPath - path to check this one against. -/// @return True if this path starts with the provided one, false otherwise. -// ============================================================================ -bool TSmartPath::IsChildOf(const TSmartPath& rPath, bool bCaseSensitive) const -{ - if(bCaseSensitive) - return m_strPath.StartsWith(rPath.m_strPath.c_str()); - else - return m_strPath.StartsWithNoCase(rPath.m_strPath.c_str()); -} + bool TSmartPath::MakeAbsolutePath(const TSmartPath& rReferenceBasePath) + { + if (!IsRelativePath()) + return false; -// ============================================================================ -/// TSmartPath::MakeRelativePath -/// @date 2010/10/12 -/// -/// @brief Converts this path to be relative to the reference, base path. -/// @param[in] rReferenceBasePath - Path which will be base path to this relative path. -/// @param[in] bCaseSensitive - Compare path with case sensitivity on/off. -/// @return True if conversion to relative path succeeded, false otherwise. -// ============================================================================ -bool TSmartPath::MakeRelativePath(const TSmartPath& rReferenceBasePath, bool bCaseSensitive) -{ - bool bStartsWith = false; - if(bCaseSensitive) - bStartsWith = m_strPath.StartsWith(rReferenceBasePath.m_strPath.c_str()); - else - bStartsWith = m_strPath.StartsWithNoCase(rReferenceBasePath.m_strPath.c_str()); + bool bHasSeparator = rReferenceBasePath.EndsWithSeparator(); + if (!bHasSeparator) + PrependSeparatorIfDoesNotExist(); + else + StripSeparatorAtFront(); - if(bStartsWith) - { - m_strPath.Delete(0, rReferenceBasePath.m_strPath.GetLength()); + m_strPath = rReferenceBasePath.ToString() + m_strPath; + return true; } - else - return false; -} -bool TSmartPath::MakeAbsolutePath(const TSmartPath& rReferenceBasePath) -{ - if(!IsRelativePath()) - return false; + // ============================================================================ + /// TSmartPath::AppendIfNotExists + /// @date 2009/11/29 + /// + /// @brief Appends a specified suffix if not present. + /// @param[in] pszPostfix - string to check against. + // ============================================================================ + void TSmartPath::AppendIfNotExists(const wchar_t* pszPostfix, bool bCaseSensitive) + { + BOOST_ASSERT(pszPostfix); + if (!pszPostfix) + return; - bool bHasSeparator = rReferenceBasePath.EndsWithSeparator(); - if(!bHasSeparator) - PrependSeparatorIfDoesNotExist(); - else - StripSeparatorAtFront(); + bool bEndsWith = false; + if (bCaseSensitive) + bEndsWith = m_strPath.EndsWith(pszPostfix); + else + bEndsWith = m_strPath.EndsWithNoCase(pszPostfix); - m_strPath = rReferenceBasePath.ToString() + m_strPath; + if (!bEndsWith) + m_strPath += pszPostfix; + } - return true; -} + // ============================================================================ + /// TSmartPath::CutIfExists + /// @date 2010/10/07 + /// + /// @brief Cuts a specified suffix if present. + /// @param[in] pszPostfix - string to check against. + // ============================================================================ + void TSmartPath::CutIfExists(const wchar_t* pszPostfix, bool bCaseSensitive) + { + BOOST_ASSERT(pszPostfix); + if (!pszPostfix) + return; -// ============================================================================ -/// TSmartPath::AppendIfNotExists -/// @date 2009/11/29 -/// -/// @brief Appends a specified suffix if not present. -/// @param[in] pszPostfix - string to check against. -// ============================================================================ -void TSmartPath::AppendIfNotExists(const wchar_t* pszPostfix, bool bCaseSensitive) -{ - BOOST_ASSERT(pszPostfix); - if(!pszPostfix) - return; + bool bEndsWith = false; + if (bCaseSensitive) + bEndsWith = m_strPath.EndsWith(pszPostfix); + else + bEndsWith = m_strPath.EndsWithNoCase(pszPostfix); - bool bEndsWith = false; - if(bCaseSensitive) - bEndsWith = m_strPath.EndsWith(pszPostfix); - else - bEndsWith = m_strPath.EndsWithNoCase(pszPostfix); + if (bEndsWith) + m_strPath.Delete(m_strPath.GetLength() - _tcslen(pszPostfix), m_strPath.GetLength() - _tcslen(pszPostfix)); + } - if(!bEndsWith) - m_strPath += pszPostfix; -} + // ============================================================================ + /// TSmartPath::IsNetworkPath + /// @date 2010/10/17 + /// + /// @brief Checks if the path is network one (\\server_name...) + /// @return True if it is, false otherwise. + // ============================================================================ + bool TSmartPath::IsNetworkPath() const + { + return (m_strPath.GetLength() > 2 && IsSeparator(m_strPath.GetAt(0)) && IsSeparator(m_strPath.GetAt(1))); // "\\server_name" + } -// ============================================================================ -/// TSmartPath::CutIfExists -/// @date 2010/10/07 -/// -/// @brief Cuts a specified suffix if present. -/// @param[in] pszPostfix - string to check against. -// ============================================================================ -void TSmartPath::CutIfExists(const wchar_t* pszPostfix, bool bCaseSensitive) -{ - BOOST_ASSERT(pszPostfix); - if(!pszPostfix) - return; + // ============================================================================ + /// TSmartPath::IsDrive + /// @date 2011/04/05 + /// + /// @brief Checks if this path contains only drive specification (i.e. c:) + /// @return True if it is, false otherwise. + // ============================================================================ + bool TSmartPath::IsDrive() const + { + return (m_strPath.GetLength() == 2 && m_strPath.GetAt(1) == _T(':')); + } - bool bEndsWith = false; - if(bCaseSensitive) - bEndsWith = m_strPath.EndsWith(pszPostfix); - else - bEndsWith = m_strPath.EndsWithNoCase(pszPostfix); + // ============================================================================ + /// TSmartPath::HasDrive + /// @date 2010/10/16 + /// + /// @brief Checks if path has a drive component. + /// @return True if it has, false otherwise. + // ============================================================================ + bool TSmartPath::HasDrive() const + { + return (m_strPath.GetLength() >= 2 && m_strPath.GetAt(1) == _T(':')); + } - if(bEndsWith) - m_strPath.Delete(m_strPath.GetLength() - _tcslen(pszPostfix), m_strPath.GetLength() - _tcslen(pszPostfix)); -} + // ============================================================================ + /// TSmartPath::GetDrive + /// @date 2010/10/16 + /// + /// @brief Retrieves drive from path. + /// @return Path with drive, empty if drive does not exist. + // ============================================================================ + TSmartPath TSmartPath::GetDrive() const + { + if (m_strPath.GetLength() >= 2 && m_strPath.GetAt(1) == _T(':')) + { + if (m_strPath.GetLength() == 2) + return *this; + else + return PathFromWString(m_strPath.Left(2)); // c: for c:\windows\test.cpp + } -// ============================================================================ -/// TSmartPath::IsNetworkPath -/// @date 2010/10/17 -/// -/// @brief Checks if the path is network one (\\server_name...) -/// @return True if it is, false otherwise. -// ============================================================================ -bool TSmartPath::IsNetworkPath() const -{ - return (m_strPath.GetLength() > 2 && IsSeparator(m_strPath.GetAt(0)) && IsSeparator(m_strPath.GetAt(1))); // "\\server_name" -} + return TSmartPath(); + } -// ============================================================================ -/// TSmartPath::IsDrive -/// @date 2011/04/05 -/// -/// @brief Checks if this path contains only drive specification (i.e. c:) -/// @return True if it is, false otherwise. -// ============================================================================ -bool TSmartPath::IsDrive() const -{ - return (m_strPath.GetLength() == 2 && m_strPath.GetAt(1) == _T(':')); -} + // ============================================================================ + /// TSmartPath::GetDriveLetter + /// @date 2011/07/17 + /// + /// @brief Retrieves drive letter from path. + /// @return Drive letter or zero in case path does not have drive. + // ============================================================================ + wchar_t TSmartPath::GetDriveLetter() const + { + if (m_strPath.GetLength() >= 2 && m_strPath.GetAt(1) == _T(':')) + { + wchar_t wchDrive = m_strPath.GetAt(0); + if (wchDrive >= L'a' && wchDrive <= L'z') + wchDrive = L'A' + wchDrive - L'a'; + return wchDrive; + } -// ============================================================================ -/// TSmartPath::HasDrive -/// @date 2010/10/16 -/// -/// @brief Checks if path has a drive component. -/// @return True if it has, false otherwise. -// ============================================================================ -bool TSmartPath::HasDrive() const -{ - return (m_strPath.GetLength() >= 2 && m_strPath.GetAt(1) == _T(':')); -} + return L'\0'; + } -// ============================================================================ -/// TSmartPath::GetDrive -/// @date 2010/10/16 -/// -/// @brief Retrieves drive from path. -/// @return Path with drive, empty if drive does not exist. -// ============================================================================ -TSmartPath TSmartPath::GetDrive() const -{ - if(m_strPath.GetLength() >= 2 && m_strPath.GetAt(1) == _T(':')) + // ============================================================================ + /// TSmartPath::IsServerName + /// @date 2011/04/05 + /// + /// @brief Checks if this path contains only the server specification (i.e. \\server - witn no ending backslash) + /// @return True is this path contains only server specification. + // ============================================================================ + bool TSmartPath::IsServerName() const { - if(m_strPath.GetLength() == 2) - return *this; - else - return PathFromWString(m_strPath.Left(2)); // c: for c:\windows\test.cpp + return (m_strPath.GetLength() > 2 && // must have at least 3 characters... + IsSeparator(m_strPath.GetAt(0)) && IsSeparator(m_strPath.GetAt(1)) && // ... the first two of which are separators... + std::isalnum(m_strPath.GetAt(2)) && // ... followed by at least one alphanumeric character... + m_strPath.FindFirstOf(_T("\\/"), 3) == TString::npos); // ... with no additional separators (so \\abc is true, \\abc\ is not). } - return TSmartPath(); -} + // ============================================================================ + /// TSmartPath::HasServerName + /// @date 2010/10/17 + /// + /// @brief + /// @return + // ============================================================================ + bool TSmartPath::HasServerName() const + { + return (m_strPath.GetLength() > 2 && IsSeparator(m_strPath.GetAt(0)) && IsSeparator(m_strPath.GetAt(1)) && std::isalnum(m_strPath.GetAt(2))); + } -// ============================================================================ -/// TSmartPath::GetDriveLetter -/// @date 2011/07/17 -/// -/// @brief Retrieves drive letter from path. -/// @return Drive letter or zero in case path does not have drive. -// ============================================================================ -wchar_t TSmartPath::GetDriveLetter() const -{ - if(m_strPath.GetLength() >= 2 && m_strPath.GetAt(1) == _T(':')) + // ============================================================================ + /// TSmartPath::GetServerName + /// @date 2010/10/17 + /// + /// @brief Retrieves server name from path (if network path). + /// @return Path containing server name (with prepended \\) + // ============================================================================ + TSmartPath TSmartPath::GetServerName() const { - wchar_t wchDrive = m_strPath.GetAt(0); - if(wchDrive >= L'a' && wchDrive <= L'z') - wchDrive = L'A' + wchDrive - L'a'; - return wchDrive; + TString wstrPath; + if (m_strPath.GetLength() > 2 && IsSeparator(m_strPath.GetAt(0)) && IsSeparator(m_strPath.GetAt(1)) && std::isalnum(m_strPath.GetAt(2))) + { + size_t stEndPos = m_strPath.FindFirstOf(_T("\\/"), 2); + if (stEndPos == TString::npos) + wstrPath = m_strPath; + else + wstrPath = m_strPath.Left(stEndPos); + return PathFromWString(wstrPath); + } + + return TSmartPath(); } - return L'\0'; -} + // ============================================================================ + /// TSmartPath::HasFileRoot + /// @date 2010/10/17 + /// + /// @brief Checks if this path has a file root part. + /// @return True if it has, false otherwise. + // ============================================================================ + bool TSmartPath::HasFileRoot() const + { + size_t stIndex = m_strPath.FindLastOf(_T("\\/")); + return (stIndex != TString::npos); + } -// ============================================================================ -/// TSmartPath::IsServerName -/// @date 2011/04/05 -/// -/// @brief Checks if this path contains only the server specification (i.e. \\server - witn no ending backslash) -/// @return True is this path contains only server specification. -// ============================================================================ -bool TSmartPath::IsServerName() const -{ - return (m_strPath.GetLength() > 2 && // must have at least 3 characters... - IsSeparator(m_strPath.GetAt(0)) && IsSeparator(m_strPath.GetAt(1)) && // ... the first two of which are separators... - std::isalnum(m_strPath.GetAt(2)) && // ... followed by at least one alphanumeric character... - m_strPath.FindFirstOf(_T("\\/"), 3) == TString::npos); // ... with no additional separators (so \\abc is true, \\abc\ is not). -} + // ============================================================================ + /// TSmartPath::GetFileRoot + /// @date 2010/10/17 + /// + /// @brief Retrieves the root of the file. + /// @return File root as path, empty path if does not exist. + // ============================================================================ + TSmartPath TSmartPath::GetFileRoot() const + { + size_t stIndex = m_strPath.FindLastOf(_T("\\/")); + if (stIndex != TString::npos) + return PathFromWString(m_strPath.Left(stIndex + 1)); -// ============================================================================ -/// TSmartPath::HasServerName -/// @date 2010/10/17 -/// -/// @brief -/// @return -// ============================================================================ -bool TSmartPath::HasServerName() const -{ - return (m_strPath.GetLength() > 2 && IsSeparator(m_strPath.GetAt(0)) && IsSeparator(m_strPath.GetAt(1)) && std::isalnum(m_strPath.GetAt(2))); -} + return TSmartPath(); + } -// ============================================================================ -/// TSmartPath::GetServerName -/// @date 2010/10/17 -/// -/// @brief Retrieves server name from path (if network path). -/// @return Path containing server name (with prepended \\) -// ============================================================================ -TSmartPath TSmartPath::GetServerName() const -{ - TString wstrPath; - if(m_strPath.GetLength() > 2 && IsSeparator(m_strPath.GetAt(0)) && IsSeparator(m_strPath.GetAt(1)) && std::isalnum(m_strPath.GetAt(2))) + // ============================================================================ + /// TSmartPath::HasFileDir + /// @date 2010/10/16 + /// + /// @brief Checks if path contains directory specification. + /// @return True if it contains one, false otherwise. + // ============================================================================ + bool TSmartPath::HasFileDir() const { - size_t stEndPos = m_strPath.FindFirstOf(_T("\\/"), 2); - if(stEndPos == TString::npos) - wstrPath = m_strPath; + size_t stStart = 0; + if (IsNetworkPath()) + stStart = m_strPath.FindFirstOf(_T("/\\"), 2); else - wstrPath = m_strPath.Left(stEndPos); - return PathFromWString(wstrPath); + stStart = m_strPath.FindFirstOf(_T("/\\")); + + size_t stEnd = m_strPath.FindLastOf(_T("/\\")); + return (stStart != TString::npos && stEnd >= stStart); } - return TSmartPath(); -} + // ============================================================================ + /// TSmartPath::GetFileDir + /// @date 2010/10/16 + /// + /// @brief Retrieves the directory specification from path. + /// @return Directory specification, empty path if not found. + // ============================================================================ + TSmartPath TSmartPath::GetFileDir() const + { + size_t stStart = 0; + if (IsNetworkPath()) + stStart = m_strPath.FindFirstOf(_T("/\\"), 2); + else if (HasDrive()) + stStart = m_strPath.FindFirstOf(_T("/\\")); + else + stStart = 0; -// ============================================================================ -/// TSmartPath::HasFileRoot -/// @date 2010/10/17 -/// -/// @brief Checks if this path has a file root part. -/// @return True if it has, false otherwise. -// ============================================================================ -bool TSmartPath::HasFileRoot() const -{ - size_t stIndex = m_strPath.FindLastOf(_T("\\/")); - return (stIndex != TString::npos); -} + size_t stEnd = m_strPath.FindLastOf(_T("/\\")); + if (stStart != TString::npos && stEnd >= stStart) + return PathFromWString(m_strPath.MidRange(stStart, stEnd + 1)); -// ============================================================================ -/// TSmartPath::GetFileRoot -/// @date 2010/10/17 -/// -/// @brief Retrieves the root of the file. -/// @return File root as path, empty path if does not exist. -// ============================================================================ -TSmartPath TSmartPath::GetFileRoot() const -{ - size_t stIndex = m_strPath.FindLastOf(_T("\\/")); - if(stIndex != TString::npos) - return PathFromWString(m_strPath.Left(stIndex + 1)); + return TSmartPath(); + } - return TSmartPath(); -} + // ============================================================================ + /// TSmartPath::HasFileTitle + /// @date 2010/10/16 + /// + /// @brief Checks if the path has file title part. + /// @return True if it has one, false otherwise. + // ============================================================================ + bool TSmartPath::HasFileTitle() const + { + size_t stStart = m_strPath.FindLastOf(_T("/\\")); + size_t stEnd = m_strPath.FindLastOf(_T(".")); + if ((stStart == TString::npos && stEnd == TString::npos)) + return !IsEmpty(); + if (stStart == TString::npos) // if does not exist, start from beginning + stStart = 0; + if (stEnd == TString::npos || stEnd < stStart) // if does not exist or we have ".\\", use up to the end + stEnd = m_strPath.GetLength(); -// ============================================================================ -/// TSmartPath::HasFileDir -/// @date 2010/10/16 -/// -/// @brief Checks if path contains directory specification. -/// @return True if it contains one, false otherwise. -// ============================================================================ -bool TSmartPath::HasFileDir() const -{ - size_t stStart = 0; - if(IsNetworkPath()) - stStart = m_strPath.FindFirstOf(_T("/\\"), 2); - else - stStart = m_strPath.FindFirstOf(_T("/\\")); + return stEnd > stStart + 1; + } - size_t stEnd = m_strPath.FindLastOf(_T("/\\")); - return (stStart != TString::npos && stEnd >= stStart); -} + // ============================================================================ + /// TSmartPath::GetFileTitle + /// @date 2010/10/16 + /// + /// @brief Retrieves file title from path. + /// @return File title. Empty if does not exist. + // ============================================================================ + TSmartPath TSmartPath::GetFileTitle() const + { + size_t stStart = m_strPath.FindLastOf(_T("/\\")); + size_t stEnd = m_strPath.FindLastOf(_T(".")); + if ((stStart == TString::npos && stEnd == TString::npos)) + return *this; + if (stStart == TString::npos) // if does not exist, start from beginning + stStart = 0; + else + ++stStart; + if (stEnd == TString::npos || stEnd < stStart) // if does not exist or we have ".\\", use up to the end + stEnd = m_strPath.GetLength(); -// ============================================================================ -/// TSmartPath::GetFileDir -/// @date 2010/10/16 -/// -/// @brief Retrieves the directory specification from path. -/// @return Directory specification, empty path if not found. -// ============================================================================ -TSmartPath TSmartPath::GetFileDir() const -{ - size_t stStart = 0; - if(IsNetworkPath()) - stStart = m_strPath.FindFirstOf(_T("/\\"), 2); - else if(HasDrive()) - stStart = m_strPath.FindFirstOf(_T("/\\")); - else - stStart = 0; + return PathFromWString(m_strPath.MidRange(stStart, stEnd)); + } - size_t stEnd = m_strPath.FindLastOf(_T("/\\")); - if(stStart != TString::npos && stEnd >= stStart) - return PathFromWString(m_strPath.MidRange(stStart, stEnd + 1)); + // ============================================================================ + /// TSmartPath::HasExtension + /// @date 2010/10/16 + /// + /// @brief Checks if this path has a file extension. + /// @return True if it has, false otherwise. + // ============================================================================ + bool TSmartPath::HasExtension() const + { + size_t stIndex = m_strPath.FindLastOf(_T("\\/.")); - return TSmartPath(); -} + return stIndex != TString::npos && (m_strPath.GetAt(stIndex) == _T('.')); + } -// ============================================================================ -/// TSmartPath::HasFileTitle -/// @date 2010/10/16 -/// -/// @brief Checks if the path has file title part. -/// @return True if it has one, false otherwise. -// ============================================================================ -bool TSmartPath::HasFileTitle() const -{ - size_t stStart = m_strPath.FindLastOf(_T("/\\")); - size_t stEnd = m_strPath.FindLastOf(_T(".")); - if((stStart == TString::npos && stEnd == TString::npos)) - return !IsEmpty(); - if(stStart == TString::npos) // if does not exist, start from beginning - stStart = 0; - if(stEnd == TString::npos || stEnd < stStart) // if does not exist or we have ".\\", use up to the end - stEnd = m_strPath.GetLength(); + // ============================================================================ + /// TSmartPath::GetExtension + /// @date 2010/10/16 + /// + /// @brief Retrieves file extension from this path. + /// @return Extension part or empty if does not exist. + // ============================================================================ + TSmartPath TSmartPath::GetExtension() const + { + size_t stIndex = m_strPath.FindLastOf(_T("\\/.")); - return stEnd > stStart + 1; -} + if (stIndex != TString::npos && m_strPath.GetAt(stIndex) == _T('.')) + return PathFromWString(m_strPath.MidRange(stIndex, m_strPath.GetLength())); // ".txt" for "c:\windows\test.txt" -// ============================================================================ -/// TSmartPath::GetFileTitle -/// @date 2010/10/16 -/// -/// @brief Retrieves file title from path. -/// @return File title. Empty if does not exist. -// ============================================================================ -TSmartPath TSmartPath::GetFileTitle() const -{ - size_t stStart = m_strPath.FindLastOf(_T("/\\")); - size_t stEnd = m_strPath.FindLastOf(_T(".")); - if((stStart == TString::npos && stEnd == TString::npos)) - return *this; - if(stStart == TString::npos) // if does not exist, start from beginning - stStart = 0; - else - ++stStart; - if(stEnd == TString::npos || stEnd < stStart) // if does not exist or we have ".\\", use up to the end - stEnd = m_strPath.GetLength(); + return TSmartPath(); + } - return PathFromWString(m_strPath.MidRange(stStart, stEnd)); -} + // ============================================================================ + /// TSmartPath::HasFileName + /// @date 2010/10/16 + /// + /// @brief Checks if this path contains filename part. + /// @return True if filename exists, false otherwise. + // ============================================================================ + bool TSmartPath::HasFileName() const + { + size_t stIndex = m_strPath.FindLastOf(_T("\\/")); + if (stIndex == TString::npos) // no path separator? + return true; + else + return (stIndex != TString::npos && stIndex != m_strPath.GetLength() - 1); + } -// ============================================================================ -/// TSmartPath::HasExtension -/// @date 2010/10/16 -/// -/// @brief Checks if this path has a file extension. -/// @return True if it has, false otherwise. -// ============================================================================ -bool TSmartPath::HasExtension() const -{ - size_t stIndex = m_strPath.FindLastOf(_T("\\/.")); + // ============================================================================ + /// TSmartPath::GetFileName + /// @date 2010/10/16 + /// + /// @brief Retrieves filename part of this path. + /// @return Filename, or empty if does not exist. + // ============================================================================ + TSmartPath TSmartPath::GetFileName() const + { + size_t stIndex = m_strPath.FindLastOf(_T("\\/")); + if (stIndex != TString::npos) + return PathFromWString(m_strPath.MidRange(stIndex + 1, m_strPath.GetLength())); // "test.txt" for "c:\windows\test.txt" + else + return *this; + } - return stIndex != TString::npos && (m_strPath.GetAt(stIndex) == _T('.')); -} + // ============================================================================ + /// TSmartPath::DeleteFileName + /// @date 2010/10/17 + /// + /// @brief Deletes the filename part of this path if exists. + // ============================================================================ + void TSmartPath::DeleteFileName() + { + size_t stIndex = m_strPath.FindLastOf(_T("\\/")); + if (stIndex != TString::npos) + m_strPath.Delete(stIndex + 1, m_strPath.GetLength() - stIndex - 1); // "test.txt" for "c:\windows\test.txt" + else + { + // no path separator inside - everything in this path is a filename + Clear(); + } + } -// ============================================================================ -/// TSmartPath::GetExtension -/// @date 2010/10/16 -/// -/// @brief Retrieves file extension from this path. -/// @return Extension part or empty if does not exist. -// ============================================================================ -TSmartPath TSmartPath::GetExtension() const -{ - size_t stIndex = m_strPath.FindLastOf(_T("\\/.")); + TSmartPath TSmartPath::GetParent() const + { + if (IsServerName() || IsDrive()) + return TSmartPath(); - if(stIndex != TString::npos && m_strPath.GetAt(stIndex) == _T('.')) - return PathFromWString(m_strPath.MidRange(stIndex, m_strPath.GetLength())); // ".txt" for "c:\windows\test.txt" + TSmartPath pathResult(*this); - return TSmartPath(); -} + if (pathResult.EndsWithSeparator()) + { + pathResult.StripSeparatorAtEnd(); + if (pathResult.IsDrive() || pathResult.IsServerName()) + return pathResult; + } -// ============================================================================ -/// TSmartPath::HasFileName -/// @date 2010/10/16 -/// -/// @brief Checks if this path contains filename part. -/// @return True if filename exists, false otherwise. -// ============================================================================ -bool TSmartPath::HasFileName() const -{ - size_t stIndex = m_strPath.FindLastOf(_T("\\/")); - if(stIndex == TString::npos) // no path separator? - return true; - else - return (stIndex != TString::npos && stIndex != m_strPath.GetLength() - 1); -} + pathResult.DeleteFileName(); -// ============================================================================ -/// TSmartPath::GetFileName -/// @date 2010/10/16 -/// -/// @brief Retrieves filename part of this path. -/// @return Filename, or empty if does not exist. -// ============================================================================ -TSmartPath TSmartPath::GetFileName() const -{ - size_t stIndex = m_strPath.FindLastOf(_T("\\/")); - if(stIndex != TString::npos) - return PathFromWString(m_strPath.MidRange(stIndex + 1, m_strPath.GetLength())); // "test.txt" for "c:\windows\test.txt" - else - return *this; -} + return pathResult; + } -// ============================================================================ -/// TSmartPath::DeleteFileName -/// @date 2010/10/17 -/// -/// @brief Deletes the filename part of this path if exists. -// ============================================================================ -void TSmartPath::DeleteFileName() -{ - size_t stIndex = m_strPath.FindLastOf(_T("\\/")); - if(stIndex != TString::npos) - m_strPath.Delete(stIndex + 1, m_strPath.GetLength() - stIndex - 1); // "test.txt" for "c:\windows\test.txt" - else + // ============================================================================ + /// TSmartPath::EndsWithSeparator + /// @date 2010/10/16 + /// + /// @brief Checks if path end with a path separator (/ or \) + /// @return True if path ends with separator, false otherwise. + // ============================================================================ + bool TSmartPath::EndsWithSeparator() const { - // no path separator inside - everything in this path is a filename - Clear(); + size_t stThisSize = m_strPath.GetLength(); + if (stThisSize > 0) + { + wchar_t wchLastChar = m_strPath.GetAt(stThisSize - 1); + return (wchLastChar == _T('\\') || wchLastChar == _T('/')); + } + + return false; } -} -// ============================================================================ -/// TSmartPath::EndsWithSeparator -/// @date 2010/10/16 -/// -/// @brief Checks if path end with a path separator (/ or \) -/// @return True if path ends with separator, false otherwise. -// ============================================================================ -bool TSmartPath::EndsWithSeparator() const -{ - size_t stThisSize = m_strPath.GetLength(); - if(stThisSize > 0) + // ============================================================================ + /// TSmartPath::AppendSeparatorIfDoesNotExist + /// @date 2010/10/16 + /// + /// @brief Appends separator to this path if does not exist already. + // ============================================================================ + void TSmartPath::AppendSeparatorIfDoesNotExist() { - wchar_t wchLastChar = m_strPath.GetAt(stThisSize - 1); - return (wchLastChar == _T('\\') || wchLastChar == _T('/')); + if (!EndsWithSeparator()) + m_strPath += _T("\\"); } - return false; -} + // ============================================================================ + /// TSmartPath::StripSeparatorAtEnd + /// @date 2010/10/17 + /// + /// @brief Strips separator at the end of path if exists. + // ============================================================================ + void TSmartPath::StripSeparatorAtEnd() + { + if (EndsWithSeparator()) + m_strPath.Delete(m_strPath.GetLength() - 1, 1); + } -// ============================================================================ -/// TSmartPath::AppendSeparatorIfDoesNotExist -/// @date 2010/10/16 -/// -/// @brief Appends separator to this path if does not exist already. -// ============================================================================ -void TSmartPath::AppendSeparatorIfDoesNotExist() -{ - if(!EndsWithSeparator()) - m_strPath += _T("\\"); -} + // ============================================================================ + /// TSmartPath::StartsWithSeparator + /// @date 2010/10/16 + /// + /// @brief Checks if path starts with a separator. + /// @return True if path starts with separator, false otherwise. + // ============================================================================ + bool TSmartPath::StartsWithSeparator() const + { + wchar_t wchLastChar = 0; + if (m_strPath.GetLength() > 0) + wchLastChar = m_strPath.GetAt(0); -// ============================================================================ -/// TSmartPath::StripSeparatorAtEnd -/// @date 2010/10/17 -/// -/// @brief Strips separator at the end of path if exists. -// ============================================================================ -void TSmartPath::StripSeparatorAtEnd() -{ - if(EndsWithSeparator()) - m_strPath.Delete(m_strPath.GetLength() - 1, 1); -} + return (wchLastChar == _T('\\') || wchLastChar == _T('/')); + } -// ============================================================================ -/// TSmartPath::StartsWithSeparator -/// @date 2010/10/16 -/// -/// @brief Checks if path starts with a separator. -/// @return True if path starts with separator, false otherwise. -// ============================================================================ -bool TSmartPath::StartsWithSeparator() const -{ - wchar_t wchLastChar = 0; - if(m_strPath.GetLength() > 0) - wchLastChar = m_strPath.GetAt(0); + // ============================================================================ + /// TSmartPath::PrependSeparatorIfDoesNotExist + /// @date 2010/10/17 + /// + /// @brief Prepends a separator to this path if not exist already. + // ============================================================================ + void TSmartPath::PrependSeparatorIfDoesNotExist() + { + if (!StartsWithSeparator()) + m_strPath = _T("\\") + m_strPath; + } - return (wchLastChar == _T('\\') || wchLastChar == _T('/')); -} + // ============================================================================ + /// TSmartPath::StripSeparatorAtFront + /// @date 2010/10/17 + /// + /// @brief Strips separator at the front of this path (if exists). + // ============================================================================ + void TSmartPath::StripSeparatorAtFront() + { + if (StartsWithSeparator()) + m_strPath.Delete(0, 1); + } -// ============================================================================ -/// TSmartPath::PrependSeparatorIfDoesNotExist -/// @date 2010/10/17 -/// -/// @brief Prepends a separator to this path if not exist already. -// ============================================================================ -void TSmartPath::PrependSeparatorIfDoesNotExist() -{ - if(!StartsWithSeparator()) - m_strPath = _T("\\") + m_strPath; -} + // ============================================================================ + /// TSmartPath::IsEmpty + /// @date 2010/10/07 + /// + /// @brief Prepares the path to be written to. + // ============================================================================ + bool TSmartPath::IsEmpty() const + { + return m_strPath.IsEmpty(); + } -// ============================================================================ -/// TSmartPath::StripSeparatorAtFront -/// @date 2010/10/17 -/// -/// @brief Strips separator at the front of this path (if exists). -// ============================================================================ -void TSmartPath::StripSeparatorAtFront() -{ - if(StartsWithSeparator()) - m_strPath.Delete(0, 1); -} + // ============================================================================ + /// TSmartPath::GetLength + /// @date 2011/04/05 + /// + /// @brief Retrieves path length in characters. + /// @return Path length. + // ============================================================================ + size_t TSmartPath::GetLength() const + { + return m_strPath.GetLength(); + } -// ============================================================================ -/// TSmartPath::IsEmpty -/// @date 2010/10/07 -/// -/// @brief Prepares the path to be written to. -// ============================================================================ -bool TSmartPath::IsEmpty() const -{ - return m_strPath.IsEmpty(); -} + // ============================================================================ + /// TSmartPath::IsSeparator + /// @date 2010/10/17 + /// + /// @brief Checks if the character is a separator. + /// @param[in] wchSeparator - Character to be checked. + /// @return True if it is a separator, false otherwise. + // ============================================================================ + bool TSmartPath::IsSeparator(wchar_t wchSeparator) + { + return (wchSeparator == _T('\\') || wchSeparator == _T('/')); + } -// ============================================================================ -/// TSmartPath::GetLength -/// @date 2011/04/05 -/// -/// @brief Retrieves path length in characters. -/// @return Path length. -// ============================================================================ -size_t TSmartPath::GetLength() const -{ - return m_strPath.GetLength(); -} + bool TSmartPath::IsRelativePath() const + { + return !HasDrive() && !HasServerName(); + } -// ============================================================================ -/// TSmartPath::IsSeparator -/// @date 2010/10/17 -/// -/// @brief Checks if the character is a separator. -/// @param[in] wchSeparator - Character to be checked. -/// @return True if it is a separator, false otherwise. -// ============================================================================ -bool TSmartPath::IsSeparator(wchar_t wchSeparator) -{ - return (wchSeparator == _T('\\') || wchSeparator == _T('/')); -} + bool TSmartPath::StartsWith(const TSmartPath& rPath, bool bCaseSensitive) + { + if(bCaseSensitive) + return m_strPath.StartsWith(rPath.m_strPath.c_str()); -bool TSmartPath::IsRelativePath() const -{ - return !HasDrive() && !HasServerName(); -} + return m_strPath.StartsWithNoCase(rPath.m_strPath.c_str()); + } -// ============================================================================ -/// PathFromString -/// @date 2010/10/12 -/// -/// @brief Creates a path object from string. -/// @param[in] pszPath - string containing path. -/// @return New path object. -// ============================================================================ -TSmartPath PathFromString(const wchar_t* pszPath) -{ - if(!pszPath) - THROW(_T("Invalid pointer"), 0, 0, 0); + // ============================================================================ + /// PathFromString + /// @date 2010/10/12 + /// + /// @brief Creates a path object from string. + /// @param[in] pszPath - string containing path. + /// @return New path object. + // ============================================================================ + TSmartPath PathFromString(const wchar_t* pszPath) + { + if (!pszPath) + THROW(_T("Invalid pointer"), 0, 0, 0); - TSmartPath spPath; - spPath.FromString(pszPath); - return spPath; -} + TSmartPath spPath; + spPath.FromString(pszPath); + return spPath; + } -// ============================================================================ -/// PathFromWString -/// @date 2010/10/12 -/// -/// @brief Creates a path object from string. -/// @param[in] pszPath - string containing path. -/// @return New path object. -// ============================================================================ -TSmartPath PathFromWString(const TString& strPath) -{ - TSmartPath spPath; - spPath.FromString(strPath); - return spPath; + // ============================================================================ + /// PathFromWString + /// @date 2010/10/12 + /// + /// @brief Creates a path object from string. + /// @param[in] pszPath - string containing path. + /// @return New path object. + // ============================================================================ + TSmartPath PathFromWString(const TString& strPath) + { + TSmartPath spPath; + spPath.FromString(strPath); + return spPath; + } } - -END_CHCORE_NAMESPACE Index: src/libchcore/TPath.h =================================================================== diff -u -N -r7b830c34855c8aaa81aac2c6e0ca0fa6bae95e66 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TPath.h (.../TPath.h) (revision 7b830c34855c8aaa81aac2c6e0ca0fa6bae95e66) +++ src/libchcore/TPath.h (.../TPath.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -100,8 +100,10 @@ bool HasFileName() const; // test.txt for c:\windows\test.txt TSmartPath GetFileName() const; // test.txt for c:\windows\test.txt - void DeleteFileName(); // test.txt for c:\windows\test.txt + void DeleteFileName(); // c:\windows\ for c:\windows\test.txt + TSmartPath GetParent() const; + bool EndsWithSeparator() const; void AppendSeparatorIfDoesNotExist(); void StripSeparatorAtEnd(); @@ -110,6 +112,8 @@ void PrependSeparatorIfDoesNotExist(); void StripSeparatorAtFront(); + bool StartsWith(const TSmartPath& rPath, bool bCaseSensitive = DefaultCaseSensitivity); + bool IsEmpty() const; size_t GetLength() const; Index: src/libchcore/TSubTaskCopyMove.cpp =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/TSubTaskCopyMove.cpp (.../TSubTaskCopyMove.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -272,8 +272,8 @@ const TConfig& rConfig = GetContext().GetConfig(); IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem(); - IFilesystemFilePtr fileSrc = spFilesystem->CreateFileObject(); - IFilesystemFilePtr fileDst = spFilesystem->CreateFileObject(); + IFilesystemFilePtr fileSrc = spFilesystem->CreateFileObject(pData->spSrcFile->GetFullFilePath()); + IFilesystemFilePtr fileDst = spFilesystem->CreateFileObject(pData->pathDstFile); TString strFormat; TSubTaskBase::ESubOperationResult eResult = TSubTaskBase::eSubResult_Continue; @@ -315,7 +315,9 @@ pData->dbBuffer.GetEventReadPossibleHandle() }; + // #bug: always starting at the beginning of file instead of the position that OpenSrcAndDstFilesFB set the files to unsigned long long ullNextReadPos = 0; + bool bStopProcessing = false; while(!bStopProcessing) { @@ -524,7 +526,7 @@ bSkip = false; // first open the source file and handle any failures - TSubTaskCopyMove::ESubOperationResult eResult = OpenSourceFileFB(spFeedbackHandler, spFileSrc, pData->spSrcFile->GetFullFilePath(), bNoBuffer); + TSubTaskCopyMove::ESubOperationResult eResult = OpenSourceFileFB(spFeedbackHandler, spFileSrc, bNoBuffer); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; else if(!spFileSrc->IsOpen()) @@ -578,7 +580,7 @@ { // open destination file for case, when we start operation on this file (i.e. it is not resume of the // old operation) - eResult = OpenDestinationFileFB(spFeedbackHandler, spFileDst, pData->pathDstFile, bNoBuffer, pData->spSrcFile, ullSeekTo, bDstFileFreshlyCreated); + eResult = OpenDestinationFileFB(spFeedbackHandler, spFileDst, bNoBuffer, pData->spSrcFile, ullSeekTo, bDstFileFreshlyCreated); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; else if(!spFileDst->IsOpen()) @@ -596,7 +598,7 @@ else { // we are resuming previous operation - eResult = OpenExistingDestinationFileFB(spFeedbackHandler, spFileDst, pData->pathDstFile, bNoBuffer); + eResult = OpenExistingDestinationFileFB(spFeedbackHandler, spFileDst, bNoBuffer); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; else if(!spFileDst->IsOpen()) @@ -624,40 +626,9 @@ } // seek to the position where copying will start - if(ullSeekTo != 0) // src and dst files exists, requested resume at the specified index + ULONGLONG ullMove = (bNoBuffer ? RoundDown(ullSeekTo, IFilesystemFile::MaxSectorSize) : ullSeekTo);; + if(ullMove != 0) // src and dst files exists, requested resume at the specified index { - // try to move file pointers to the end - ULONGLONG ullMove = (bNoBuffer ? RoundDown(ullSeekTo, IFilesystemFile::MaxSectorSize) : ullSeekTo); - - eResult = SetFilePointerFB(spFeedbackHandler, spFileSrc, ullMove, pData->spSrcFile->GetFullFilePath(), bSkip); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; - else if(bSkip) - { - unsigned long long ullDiff = pData->spSrcFile->GetLength64() - ullProcessedSize; - - m_tSubTaskStats.IncreaseProcessedSize(ullDiff); - m_tSubTaskStats.IncreaseCurrentItemProcessedSize(ullDiff); - - pData->bProcessed = false; - return TSubTaskBase::eSubResult_Continue; - } - - eResult = SetFilePointerFB(spFeedbackHandler, spFileDst, ullMove, pData->pathDstFile, bSkip); - if(eResult != TSubTaskBase::eSubResult_Continue) - return eResult; - else if(bSkip) - { - // with either first or second seek we got 'skip' answer... - unsigned long long ullDiff = pData->spSrcFile->GetLength64() - ullProcessedSize; - - m_tSubTaskStats.IncreaseProcessedSize(ullDiff); - m_tSubTaskStats.IncreaseCurrentItemProcessedSize(ullDiff); - - pData->bProcessed = false; - return TSubTaskBase::eSubResult_Continue; - } - // adjust the stats for the difference between what was already processed and what will now be considered processed if (ullMove > ullProcessedSize) { @@ -677,7 +648,7 @@ if(!bDstFileFreshlyCreated) { // if destination file was opened (as opposed to newly created) - eResult = SetEndOfFileFB(spFeedbackHandler, spFileDst, pData->pathDstFile, bSkip); + eResult = TruncateFileFB(spFeedbackHandler, spFileDst, ullMove, pData->pathDstFile, bSkip); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; else if(bSkip) @@ -725,28 +696,23 @@ return false; // buffer did not need adjusting } -TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenSourceFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& spFileSrc, - const TSmartPath& spPathToOpen, bool bNoBuffering) +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenSourceFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileSrc, bool bNoBuffering) { icpf::log_file& rLog = GetContext().GetLog(); - BOOST_ASSERT(!spPathToOpen.IsEmpty()); - if(spPathToOpen.IsEmpty()) - THROW_CORE_EXCEPTION(eErr_InvalidArgument); - bool bRetry = false; - spFileSrc->Close(); + fileSrc->Close(); do { bRetry = false; - if(!spFileSrc->OpenExistingForReading(spPathToOpen, bNoBuffering)) + if(!fileSrc->OpenExistingForReading(bNoBuffering)) { DWORD dwLastError = GetLastError(); - EFeedbackResult frResult = spFeedbackHandler->FileError(spPathToOpen.ToWString(), TString(), EFileError::eCreateError, dwLastError); + EFeedbackResult frResult = spFeedbackHandler->FileError(fileSrc->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); switch(frResult) { case EFeedbackResult::eResult_Skip: @@ -757,7 +723,7 @@ // log TString strFormat = _T("Cancel request [error %errno] while opening source file %path (OpenSourceFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), spPathToOpen.ToString()); + strFormat.Replace(_T("%path"), fileSrc->GetFilePath().ToString()); rLog.loge(strFormat.c_str()); return TSubTaskBase::eSubResult_CancelRequest; @@ -771,7 +737,7 @@ // log TString strFormat = _T("Retrying [error %errno] to open source file %path (OpenSourceFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), spPathToOpen.ToString()); + strFormat.Replace(_T("%path"), fileSrc->GetFilePath().ToString()); rLog.loge(strFormat.c_str()); bRetry = true; @@ -789,8 +755,7 @@ return TSubTaskBase::eSubResult_Continue; } -TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenDestinationFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& spFileDst, - const TSmartPath& pathDstFile, bool bNoBuffering, const TFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated) +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenDestinationFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileDst, bool bNoBuffering, const TFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated) { icpf::log_file& rLog = GetContext().GetLog(); IFilesystemPtr spFilesystem = GetContext().GetLocalFilesystem(); @@ -800,23 +765,23 @@ ullSeekTo = 0; bFreshlyCreated = true; - spFileDst->Close(); + fileDst->Close(); do { bRetry = false; - if(!spFileDst->CreateNewForWriting(pathDstFile, bNoBuffering)) + if(!fileDst->CreateNewForWriting(bNoBuffering)) { DWORD dwLastError = GetLastError(); if(dwLastError == ERROR_FILE_EXISTS) { bFreshlyCreated = false; // pass it to the specialized method - TSubTaskBase::ESubOperationResult eResult = OpenExistingDestinationFileFB(spFeedbackHandler, spFileDst, pathDstFile, bNoBuffering); + TSubTaskBase::ESubOperationResult eResult = OpenExistingDestinationFileFB(spFeedbackHandler, fileDst, bNoBuffering); if(eResult != TSubTaskBase::eSubResult_Continue) return eResult; - else if(!spFileDst->IsOpen()) + else if(!fileDst->IsOpen()) return TSubTaskBase::eSubResult_Continue; // read info about the existing destination file, @@ -825,7 +790,7 @@ // reading parameters using opened handle; need to be tested in the future TFileInfoPtr spDstFileInfo(boost::make_shared()); - if(!spFilesystem->GetFileInfo(pathDstFile, spDstFileInfo)) + if(!spFilesystem->GetFileInfo(fileDst->GetFilePath(), spDstFileInfo)) THROW_CORE_EXCEPTION_WIN32(eErr_CannotGetFileInfo, GetLastError()); // src and dst files are the same @@ -847,7 +812,7 @@ { // log TString strFormat = _T("Cancel request while checking result of dialog before opening source file %path (CustomCopyFileFB)"); - strFormat.Replace(_T("%path"), pathDstFile.ToString()); + strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); rLog.logi(strFormat.c_str()); return TSubTaskBase::eSubResult_CancelRequest; @@ -862,15 +827,15 @@ } else { - EFeedbackResult frResult = spFeedbackHandler->FileError(pathDstFile.ToWString(), TString(), EFileError::eCreateError, dwLastError); + EFeedbackResult frResult = spFeedbackHandler->FileError(fileDst->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); switch(frResult) { case EFeedbackResult::eResult_Retry: { // log TString strFormat = _T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), pathDstFile.ToString()); + strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); rLog.loge(strFormat.c_str()); bRetry = true; @@ -882,7 +847,7 @@ // log TString strFormat = _T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), pathDstFile.ToString()); + strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); rLog.loge(strFormat.c_str()); return TSubTaskBase::eSubResult_CancelRequest; @@ -906,32 +871,31 @@ return TSubTaskBase::eSubResult_Continue; } -TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenExistingDestinationFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& spFileDst, - const TSmartPath& pathDstFile, bool bNoBuffering) +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::OpenExistingDestinationFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileDst, bool bNoBuffering) { icpf::log_file& rLog = GetContext().GetLog(); bool bRetry = false; - spFileDst->Close(); + fileDst->Close(); do { bRetry = false; - if(!spFileDst->OpenExistingForWriting(pathDstFile, bNoBuffering)) + if(!fileDst->OpenExistingForWriting(bNoBuffering)) { DWORD dwLastError = GetLastError(); - EFeedbackResult frResult = spFeedbackHandler->FileError(pathDstFile.ToWString(), TString(), EFileError::eCreateError, dwLastError); + EFeedbackResult frResult = spFeedbackHandler->FileError(fileDst->GetFilePath().ToWString(), TString(), EFileError::eCreateError, dwLastError); switch (frResult) { case EFeedbackResult::eResult_Retry: { // log TString strFormat = _T("Retrying [error %errno] to open destination file %path (CustomCopyFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_t("%path"), pathDstFile.ToString()); + strFormat.Replace(_t("%path"), fileDst->GetFilePath().ToString()); rLog.loge(strFormat.c_str()); bRetry = true; @@ -943,7 +907,7 @@ // log TString strFormat = _T("Cancel request [error %errno] while opening destination file %path (CustomCopyFileFB)"); strFormat.Replace(_T("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_T("%path"), pathDstFile.ToString()); + strFormat.Replace(_T("%path"), fileDst->GetFilePath().ToString()); rLog.loge(strFormat.c_str()); return TSubTaskBase::eSubResult_CancelRequest; @@ -966,57 +930,7 @@ return TSubTaskBase::eSubResult_Continue; } -TSubTaskBase::ESubOperationResult TSubTaskCopyMove::SetFilePointerFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& spFile, - long long llDistance, const TSmartPath& pathFile, bool& bSkip) -{ - icpf::log_file& rLog = GetContext().GetLog(); - - bSkip = false; - bool bRetry = false; - do - { - bRetry = false; - - if(!spFile->SetFilePointer(llDistance, FILE_BEGIN)) - { - DWORD dwLastError = GetLastError(); - - // log - TString strFormat = _T("Error %errno while moving file pointer of %path to %pos"); - strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); - strFormat.Replace(_t("%path"), pathFile.ToString()); - strFormat.Replace(_t("%pos"), boost::lexical_cast(llDistance).c_str()); - rLog.loge(strFormat.c_str()); - - EFeedbackResult frResult = spFeedbackHandler->FileError(pathFile.ToWString(), TString(), EFileError::eSeekError, dwLastError); - switch(frResult) - { - case EFeedbackResult::eResult_Cancel: - return TSubTaskBase::eSubResult_CancelRequest; - - case EFeedbackResult::eResult_Retry: - bRetry = true; - break; - - case EFeedbackResult::eResult_Pause: - return TSubTaskBase::eSubResult_PauseRequest; - - case EFeedbackResult::eResult_Skip: - bSkip = true; - return TSubTaskBase::eSubResult_Continue; - - default: - BOOST_ASSERT(FALSE); // unknown result - THROW_CORE_EXCEPTION(eErr_UnhandledCase); - } - } - } - while(bRetry); - - return TSubTaskBase::eSubResult_Continue; -} - -TSubTaskBase::ESubOperationResult TSubTaskCopyMove::SetEndOfFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& spFile, +TSubTaskBase::ESubOperationResult TSubTaskCopyMove::TruncateFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& spFile, long long llNewSize, const TSmartPath& pathFile, bool& bSkip) { icpf::log_file& rLog = GetContext().GetLog(); @@ -1026,12 +940,12 @@ bool bRetry = false; do { - if(!spFile->SetEndOfFile()) + if(!spFile->Truncate(llNewSize)) { // log DWORD dwLastError = GetLastError(); - TString strFormat = _T("Error %errno while setting size of file %path to 0"); + TString strFormat = _T("Error %errno while truncating file %path to 0"); strFormat.Replace(_t("%errno"), boost::lexical_cast(dwLastError).c_str()); strFormat.Replace(_t("%path"), pathFile.ToString()); rLog.loge(strFormat.c_str()); Index: src/libchcore/TSubTaskCopyMove.h =================================================================== diff -u -N -r9ebcc7abf1e0e70f0db2d08b2691351a26ef259b -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision 9ebcc7abf1e0e70f0db2d08b2691351a26ef259b) +++ src/libchcore/TSubTaskCopyMove.h (.../TSubTaskCopyMove.h) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -67,17 +67,12 @@ ESubOperationResult OpenSrcAndDstFilesFB(const IFeedbackHandlerPtr& spFeedbackHandler, CUSTOM_COPY_PARAMS* pData, const IFilesystemFilePtr& spFileSrc, const IFilesystemFilePtr& spFileDst, bool bNoBuffer, bool& bSkip); - ESubOperationResult OpenSourceFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileSrc, - const TSmartPath& spPathToOpen, bool bNoBuffering); - ESubOperationResult OpenDestinationFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileDst, - const TSmartPath& pathDstFile, bool bNoBuffering, const TFileInfoPtr& spSrcFileInfo, + ESubOperationResult OpenSourceFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileSrc, bool bNoBuffering); + ESubOperationResult OpenDestinationFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileDst, bool bNoBuffering, const TFileInfoPtr& spSrcFileInfo, unsigned long long& ullSeekTo, bool& bFreshlyCreated); - ESubOperationResult OpenExistingDestinationFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileDst, - const TSmartPath& pathDstFilePath, bool bNoBuffering); + ESubOperationResult OpenExistingDestinationFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& fileDst, bool bNoBuffering); - ESubOperationResult SetFilePointerFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& file, - long long llDistance, const TSmartPath& pathFile, bool& bSkip); - ESubOperationResult SetEndOfFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& file, + ESubOperationResult TruncateFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& file, long long llNewSize, const TSmartPath& pathFile, bool& bSkip); ESubOperationResult ReadFileFB(const IFeedbackHandlerPtr& spFeedbackHandler, const IFilesystemFilePtr& file, Index: src/libchcore/Tests/TestsTSmartPath.cpp =================================================================== diff -u -N -ra44714d5c7ec0f50a376f4d0ea919ee5a224f834 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/Tests/TestsTSmartPath.cpp (.../TestsTSmartPath.cpp) (revision a44714d5c7ec0f50a376f4d0ea919ee5a224f834) +++ src/libchcore/Tests/TestsTSmartPath.cpp (.../TestsTSmartPath.cpp) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -1106,3 +1106,148 @@ path.FromString(_T("some path")); EXPECT_EQ(9, path.GetLength()); } + +/////////////////////////////////////////////////////////////////////////////// +TEST(TSmartPathTests, GetParent_FilePath) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\test.txt"); + + EXPECT_STREQ(L"c:\\windows\\", path.GetParent().ToString()); +} + +TEST(TSmartPathTests, GetParent_DirPath) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\"); + + EXPECT_STREQ(L"c:\\", path.GetParent().ToString()); +} + +TEST(TSmartPathTests, GetParent_NetFilePath) +{ + TSmartPath path; + path.FromString(L"\\\\SomeServer\\windows\\test.txt"); + + EXPECT_STREQ(L"\\\\SomeServer\\windows\\", path.GetParent().ToString()); +} + +TEST(TSmartPathTests, GetParent_NetDirPath) +{ + TSmartPath path; + path.FromString(L"\\\\SomeServer\\windows\\"); + + EXPECT_STREQ(L"\\\\SomeServer\\", path.GetParent().ToString()); +} + +TEST(TSmartPathTests, GetParent_ServerNameRootDir) +{ + TSmartPath path; + path.FromString(L"\\\\SomeServer\\"); + + EXPECT_STREQ(L"\\\\SomeServer", path.GetParent().ToString()); +} + +TEST(TSmartPathTests, GetParent_DiskRootDir) +{ + TSmartPath path; + path.FromString(L"c:\\"); + + EXPECT_STREQ(L"c:", path.GetParent().ToString()); +} + +TEST(TSmartPathTests, GetParent_ServerName) +{ + TSmartPath path; + path.FromString(L"\\\\SomeServer"); + + EXPECT_STREQ(L"", path.GetParent().ToString()); +} + +TEST(TSmartPathTests, GetParent_Disk) +{ + TSmartPath path; + path.FromString(L"c:"); + + EXPECT_STREQ(L"", path.GetParent().ToString()); +} + +TEST(TSmartPathTests, StartsWith_SameCase_Positive) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_TRUE(path.StartsWith(PathFromString(L"c:\\windows"))); +} + +TEST(TSmartPathTests, StartsWith_NoCase_SameCase_Positive) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_TRUE(path.StartsWith(PathFromString(L"c:\\windows"), false)); +} + +TEST(TSmartPathTests, StartsWith_NoCase_DiffCase_Positive) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_TRUE(path.StartsWith(PathFromString(L"c:\\Windows"), false)); +} + +TEST(TSmartPathTests, StartsWith_CaseSensitive_SameCase_Positive) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_TRUE(path.StartsWith(PathFromString(L"c:\\windows"), true)); +} + +TEST(TSmartPathTests, StartsWith_CaseSensitive_DiffCase_Positive) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_FALSE(path.StartsWith(PathFromString(L"c:\\Windows"), true)); +} + +TEST(TSmartPathTests, StartsWith_SameCase_Negative) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_FALSE(path.StartsWith(PathFromString(L"\\windows"))); +} + +TEST(TSmartPathTests, StartsWith_NoCase_SameCase_Negative) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_FALSE(path.StartsWith(PathFromString(L"\\windows"), false)); +} + +TEST(TSmartPathTests, StartsWith_NoCase_DiffCase_Negative) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_FALSE(path.StartsWith(PathFromString(L"\\Windows"), false)); +} + +TEST(TSmartPathTests, StartsWith_CaseSensitive_SameCase_Negative) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_FALSE(path.StartsWith(PathFromString(L"\\windows"), true)); +} + +TEST(TSmartPathTests, StartsWith_CaseSensitive_DiffCase_Negative) +{ + TSmartPath path; + path.FromString(L"c:\\windows\\file.txt"); + + EXPECT_FALSE(path.StartsWith(PathFromString(L"\\Windows"), true)); +} Index: src/libchcore/libchcore.vc140.vcxproj =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/libchcore.vc140.vcxproj (.../libchcore.vc140.vcxproj) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/libchcore.vc140.vcxproj (.../libchcore.vc140.vcxproj) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -523,6 +523,7 @@ + @@ -753,6 +754,7 @@ + Index: src/libchcore/libchcore.vc140.vcxproj.filters =================================================================== diff -u -N -r5efb534fc5440a7ab779d2514a00486ecb58e845 -r27c262eb9cae55720e10f4886af6b5a82cb94fe9 --- src/libchcore/libchcore.vc140.vcxproj.filters (.../libchcore.vc140.vcxproj.filters) (revision 5efb534fc5440a7ab779d2514a00486ecb58e845) +++ src/libchcore/libchcore.vc140.vcxproj.filters (.../libchcore.vc140.vcxproj.filters) (revision 27c262eb9cae55720e10f4886af6b5a82cb94fe9) @@ -437,6 +437,9 @@ Source Files\Tools + + Source Files\Filesystems\Fake + @@ -811,5 +814,8 @@ Tests + + Source Files\Filesystems\Fake + \ No newline at end of file