From ec84970e1813f906b0923a9c9edc0b57686f3023 Mon Sep 17 00:00:00 2001 From: Jochen Tucht Date: Fri, 15 Jul 2005 08:13:33 +0000 Subject: [PATCH] PATCH: [ 1229867 ] RFE [ 1205516 ], RFE [ 887948 ], and other issues (w/o command line tool integration) --- Src/7zCommon.cpp | 226 ++++++++++++++++++++++++++---------------------- Src/7zCommon.h | 33 +++---- Src/DiffContext.cpp | 24 +++-- Src/DiffItem.cpp | 12 +-- Src/DiffItem.h | 9 +- Src/DiffThread.cpp | 16 +++- Src/DiffWrapper.cpp | 34 +++----- Src/DirActions.cpp | 60 +++++-------- Src/DirDoc.cpp | 184 ++++++++++++++++++++++++++------------- Src/DirDoc.h | 18 +++- Src/DirScan.cpp | 194 +++++++++++++++++++++++------------------ Src/DirScan.h | 2 +- Src/DirView.cpp | 99 ++++++++------------- Src/DirView.h | 3 - Src/DirViewColItems.cpp | 57 ++++++++---- Src/FileFilterHelper.h | 16 ++++ Src/MainFrm.cpp | 123 ++++++++++++-------------- Src/MergeDoc.cpp | 6 ++ 18 files changed, 622 insertions(+), 494 deletions(-) diff --git a/Src/7zCommon.cpp b/Src/7zCommon.cpp index b9ecc82f3..cdb441c9e 100644 --- a/Src/7zCommon.cpp +++ b/Src/7zCommon.cpp @@ -68,6 +68,16 @@ DATE: BY: DESCRIPTION: temporarily, to sort out new directory compare) 2005/06/22 Jochen Tucht Change recommended version of 7-Zip to 4.20 Remove noise from Nagbox +2005/07/03 Jochen Tucht DIFFITEM has changed due to RFE [ 1205516 ] +2005/07/04 Jochen Tucht New global ArchiveGuessFormat() checks for + formats to be handled by external command line + tools. These take precedence over Merge7z + internal handlers. +2005/07/05 Jochen Tucht Move to Merge7z::Format::GetDefaultName() to + build intermediate filenames for multi-step + compression. +2005/07/15 Jochen Tucht Remove external command line tool integration + for now. Rethink about it after 2.4 branch. */ // RCS ID line follows -- this is updated by CVS @@ -79,6 +89,7 @@ DATE: BY: DESCRIPTION: #include "DirDoc.h" #include "MainFrm.h" #include "7zCommon.h" +//#include "ExternalArchiveFormat.h" #include "markdown.h" #include #include @@ -90,6 +101,18 @@ DATE: BY: DESCRIPTION: static char THIS_FILE[] = __FILE__; #endif +Merge7z::Format *ArchiveGuessFormat(LPCTSTR path) +{ + // Look for command line tool first + /*Merge7z::Format *pFormat; + if (CExternalArchiveFormat::GuessFormat(path, pFormat)) + { + return pFormat; + }*/ + // Default to Merge7z*.dll + return Merge7z->GuessFormat(path); +} + /** * @brief Self-initializing raw C character buffer class. */ @@ -506,38 +529,34 @@ void NTAPI Recall7ZipMismatchError() } /** - * @brief Recursively delete folder. + * @brief Construct path to a temporary folder for pOwner, and clear the folder. */ -void CTempPath::Clear() +CString NTAPI GetClearTempPath(LPVOID pOwner, LPCTSTR pchExt) { + CString strPath; + strPath.Format + ( + pOwner ? _T("%sWINMERGE.%08lX\\%08lX.%s") : _T("%sWINMERGE.%08lX"), + paths_GetTempPath(), GetCurrentProcessId(), pOwner, pchExt + ); // SHFileOperation expects a ZZ terminated list of paths! - LPTSTR pchPath = m_strPath.GetBufferSetLength(lstrlen(m_strPath) + 1); + int cchPath = strPath.GetLength(); + LPTSTR pchPath = strPath.GetBufferSetLength(cchPath + 1); SHFILEOPSTRUCT fileop = {0, FO_DELETE, pchPath, 0, FOF_NOCONFIRMATION|FOF_SILENT|FOF_NOERRORUI, 0, 0, 0}; SHFileOperation(&fileop); + strPath.ReleaseBuffer(cchPath); + return strPath; } /** - * @brief Prepare an additional sibling folder. + * @brief Delete head of temp path context list, and return its parent context. */ -void CTempPath::MakeSibling(LPCTSTR pchExt) +CTempPathContext *CTempPathContext::DeleteHead() { - LPTSTR pchPath = m_strPath.GetBuffer(lstrlen(m_strPath) + lstrlen(pchExt) + 1); - PathRenameExtension(pchPath, pchExt); - m_strPath.ReleaseBuffer(); - Clear(); -} - -/** - * @brief Prepare a temporary folder. - */ -CTempPath::CTempPath(LPVOID pOwner) -{ - m_strPath.Format - ( - pOwner ? _T("%sWINMERGE.%08lX\\%08lX") : _T("%sWINMERGE.%08lX"), - paths_GetTempPath(), GetCurrentProcessId(), pOwner - ); - Clear(); + CTempPathContext *pParent = m_pParent; + GetClearTempPath(this, _T("*")); + delete this; + return pParent; } /** @@ -591,26 +610,6 @@ BOOL CALLBACK FindNextResLang(HMODULE hModule, LPCTSTR lpType, LPCTSTR lpName, W } /** - * @brief Guess 7z language file name from language id. - */ -CString NTAPI LangFile7z() -{ - CString langFile; - if (HINSTANCE hinstLang = AfxGetResourceHandle()) - { - WORD wLangID = 0; - if (EnumResourceLanguages(hinstLang, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), FindNextResLang, (LPARAM)&wLangID) == 0) - { - CRawString sLng, sRgn; - GetLocaleInfo(wLangID, LOCALE_SISO639LANGNAME, sLng.Data, sLng.Size); - GetLocaleInfo(wLangID, LOCALE_SISO3166CTRYNAME, sRgn.Data, sRgn.Size); - langFile.Format(_T("%s-%s"), sLng.Data, sRgn.Data); - } - } - return langFile; -} - -/** * @brief Access dll functions through proxy. */ interface Merge7z *Merge7z::Proxy::operator->() @@ -664,10 +663,15 @@ interface Merge7z *Merge7z::Proxy::operator->() pCause ); } + if (HINSTANCE hinstLang = AfxGetResourceHandle()) + { + WORD wLangID = 0; + if (EnumResourceLanguages(hinstLang, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), FindNextResLang, (LPARAM)&wLangID) == 0) + { + flags |= wLangID << 16; + } + } ((interface Merge7z *)Merge7z[1])->Initialize(flags); -#if DllBuild_Merge7z >= 9 - ((interface Merge7z *)Merge7z[1])->LoadLang(LangFile7z()); -#endif } return ((interface Merge7z *)Merge7z[1]); } @@ -685,7 +689,7 @@ Merge7z::Proxy Merge7z = /** * @brief Tell Merge7z we are going to enumerate just 1 item. */ -UINT CompressSingleFile::Open() +UINT SingleItemEnumerator::Open() { return 1; } @@ -693,7 +697,7 @@ UINT CompressSingleFile::Open() /** * @brief Pass information about the item to Merge7z. */ -Merge7z::Envelope *CompressSingleFile::Enum(Item &item) +Merge7z::Envelope *SingleItemEnumerator::Enum(Item &item) { item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.Recurse; item.Name = Name; @@ -702,21 +706,12 @@ Merge7z::Envelope *CompressSingleFile::Enum(Item &item) } /** - * @brief CompressSingleFile constructor. Called like a function. + * @brief SingleFileEnumerator constructor. */ -CompressSingleFile::CompressSingleFile(LPCTSTR path, LPCTSTR FullPath, LPCTSTR Name) +SingleItemEnumerator::SingleItemEnumerator(LPCTSTR path, LPCTSTR FullPath, LPCTSTR Name) : FullPath(FullPath) , Name(Name) { - if (Merge7z::Format *piHandler = Merge7z->GuessFormat(path)) - { - HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd(); - piHandler->CompressArchive(hwndOwner, path, this); - } - else - { - AfxMessageBox(IDS_UNKNOWN_ARCHIVE_FORMAT, MB_ICONEXCLAMATION); - } } /** @@ -761,7 +756,7 @@ CDirView::DirItemEnumerator::DirItemEnumerator(CDirView *pView, int nFlags) if (!di.isSideLeft()) { // Item is present on right side, i.e. folder is implied - m_rgImpliedFoldersRight[di.sSubdir] = PVOID(1); + m_rgImpliedFoldersRight[di.sRightSubdir] = PVOID(1); } } else @@ -770,7 +765,7 @@ CDirView::DirItemEnumerator::DirItemEnumerator(CDirView *pView, int nFlags) if (!di.isSideRight()) { // Item is present on left side, i.e. folder is implied - m_rgImpliedFoldersLeft[di.sSubdir] = PVOID(1); + m_rgImpliedFoldersLeft[di.sLeftSubdir] = PVOID(1); } } } @@ -840,15 +835,20 @@ Merge7z::Envelope *CDirView::DirItemEnumerator::Enum(Item &item) return 0; } + bool isSideLeft = di.isSideLeft(); + bool isSideRight = di.isSideRight(); + Envelope *envelope = new Envelope; - envelope->Name = di.sfilename; - if (di.sSubdir.GetLength()) + const CString &sFilename = m_bRight ? di.sRightFilename : di.sLeftFilename; + const CString &sSubdir = m_bRight ? di.sRightSubdir : di.sLeftSubdir; + envelope->Name = sFilename; + if (sSubdir.GetLength()) { envelope->Name.Insert(0, '\\'); - envelope->Name.Insert(0, di.sSubdir); + envelope->Name.Insert(0, sSubdir); } - envelope->FullPath = di.sfilename; + envelope->FullPath = sFilename; envelope->FullPath.Insert(0, '\\'); envelope->FullPath.Insert(0, m_bRight ? di.getRightFilepath(pDoc->GetRightBasePath()) : @@ -859,39 +859,46 @@ Merge7z::Envelope *CDirView::DirItemEnumerator::Enum(Item &item) if (m_bRight) { // Enumerating items on right side - if (di.isSideLeft()) + if (isSideLeft) { // Item is missing on right side - PVOID &implied = m_rgImpliedFoldersRight[di.sSubdir]; + PVOID &implied = m_rgImpliedFoldersRight[di.sLeftSubdir]; if (!implied) { // Folder is not implied by some other file, and has // not been enumerated so far, so enumerate it now! - envelope->Name = di.sSubdir; + envelope->Name = di.sLeftSubdir; envelope->FullPath = di.getLeftFilepath(pDoc->GetLeftBasePath()); implied = PVOID(2); // Don't enumerate same folder twice! + isSideLeft = false; } } } else { // Enumerating items on left side - if (di.isSideRight()) + if (isSideRight) { // Item is missing on left side - PVOID &implied = m_rgImpliedFoldersLeft[di.sSubdir]; + PVOID &implied = m_rgImpliedFoldersLeft[di.sRightSubdir]; if (!implied) { // Folder is not implied by some other file, and has // not been enumerated so far, so enumerate it now! - envelope->Name = di.sSubdir; + envelope->Name = di.sRightSubdir; envelope->FullPath = di.getRightFilepath(pDoc->GetRightBasePath()); implied = PVOID(2); // Don't enumerate same folder twice! + isSideRight = false; } } } } + if (m_bRight ? isSideLeft : isSideRight) + { + return envelope; + } + if (m_strFolderPrefix.GetLength()) { envelope->Name.Insert(0, '\\'); @@ -903,7 +910,38 @@ Merge7z::Envelope *CDirView::DirItemEnumerator::Enum(Item &item) item.FullPath = envelope->FullPath; return envelope; } - // + +/** + * @brief Apply appropriate handlers from left to right. + */ +bool CDirView::DirItemEnumerator::MultiStepCompressArchive(LPCTSTR path) +{ + DeleteFile(path); + Merge7z::Format *piHandler = ArchiveGuessFormat(path); + if (piHandler) + { + HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd(); + CString pathIntermediate; + SysFreeString(Assign(pathIntermediate, piHandler->GetDefaultName(hwndOwner, path))); + CString pathPrepend = path; + pathPrepend.ReleaseBuffer(pathPrepend.ReverseFind('\\') + 1); + pathIntermediate.Insert(0, pathPrepend); + bool bDone = MultiStepCompressArchive(pathIntermediate); + if (bDone) + { + piHandler->CompressArchive(hwndOwner, path, + &SingleItemEnumerator(path, pathIntermediate)); + DeleteFile(pathIntermediate); + } + else + { + piHandler->CompressArchive(hwndOwner, path, this); + } + return true; + } + return false; +} + /** * @brief Generate archive from DirView items. */ @@ -923,18 +961,28 @@ void CDirView::DirItemEnumerator::CompressArchive(LPCTSTR path) //_T("z|*.z|") _T("zip|*.zip|") _T("jar (zip)|*.jar|") + _T("ear (zip)|*.ear|") + _T("war (zip)|*.war|") _T("xpi (zip)|*.xpi|") //_T("rar|*.rar|") _T("tar|*.tar|") + _T("tar.z|*.tar.z|") _T("tar.gz|*.tar.gz|") _T("tar.bz2|*.tar.bz2|") + //_T("tz|*.tz|") + _T("tgz|*.tgz|") + _T("tbz2|*.tbz2|") + //_T("lzh|*.lzh|") //_T("cab|*.cab|") //_T("arj|*.arj|") //_T("deb|*.deb|") //_T("rpm|*.rpm|") //_T("cpio|*.cpio|") - _T("|") + //_T("|") ); + CString strFilter; // = CExternalArchiveFormat::GetOpenFileFilterString(); + strFilter.Insert(0, _T_Filter); + strFilter += _T("|"); // Make CFileDialog static to preserve settings across invocations: static CFileDialog dlg ( @@ -942,7 +990,7 @@ void CDirView::DirItemEnumerator::CompressArchive(LPCTSTR path) 0, 0, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN, - _T_Filter + strFilter ); dlg.m_ofn.nFilterIndex = AfxGetApp()->GetProfileInt(_T_Merge7z, _T_FilterIndex, 1); // Use extension from current filter as default extension: @@ -965,33 +1013,9 @@ void CDirView::DirItemEnumerator::CompressArchive(LPCTSTR path) AfxGetApp()->WriteProfileInt(_T_Merge7z, _T_FilterIndex, dlg.m_ofn.nFilterIndex); } } - if (path) + if (path && !MultiStepCompressArchive(path)) { - LPCTSTR pathFinal = 0; - CString strPathIntermediate; - if (StrRStrI(path, 0, _T(".tar.")) == PathFindExtension(path) - 4) - { - // Extension is preceeded by .tar: - // - Keep full path in pathFinal for actual compression. - // - Cut off extension to produce an intermediate tar first. - strPathIntermediate = pathFinal = path; - path = strPathIntermediate.GetBufferSetLength(strPathIntermediate.ReverseFind('.')); - } - if (Merge7z::Format *piHandler = Merge7z->GuessFormat(path)) - { - HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd(); - piHandler->CompressArchive(hwndOwner, path, this); - } - else - { - AfxMessageBox(IDS_UNKNOWN_ARCHIVE_FORMAT, MB_ICONEXCLAMATION); - } - if (pathFinal) - { - // Compress the intermediate tar to pathFinal, then delete it. - CompressSingleFile(pathFinal, path); - DeleteFile(path); - } + AfxMessageBox(IDS_UNKNOWN_ARCHIVE_FORMAT, MB_ICONEXCLAMATION); } #ifdef _DEBUG afxDump << m_rgImpliedFoldersLeft; @@ -1017,7 +1041,7 @@ void CDirView::DirItemEnumerator::CollectFiles(CString &strBuffer) cchBuffer += ( m_bRight ? di.getRightFilepath(sLeftRootPath) : di.getLeftFilepath(sRightRootPath) - ).GetLength() + di.sfilename.GetLength() + 2; + ).GetLength() + (m_bRight ? di.sRightFilename : di.sLeftFilename).GetLength() + 2; } } LPTSTR pchBuffer = strBuffer.GetBufferSetLength(cchBuffer); @@ -1031,7 +1055,7 @@ void CDirView::DirItemEnumerator::CollectFiles(CString &strBuffer) pchBuffer, _T("%s\\%s"), m_bRight ? di.getRightFilepath(sLeftRootPath) : di.getLeftFilepath(sRightRootPath), - di.sfilename + m_bRight ? di.sRightFilename : di.sLeftFilename ) + 1; } } diff --git a/Src/7zCommon.h b/Src/7zCommon.h index 8abfa0631..f6393e6be 100644 --- a/Src/7zCommon.h +++ b/Src/7zCommon.h @@ -7,32 +7,35 @@ extern Merge7z::Proxy Merge7z; -class CTempPath +Merge7z::Format *ArchiveGuessFormat(LPCTSTR); + +CString NTAPI GetClearTempPath(LPVOID pOwner, LPCTSTR pchExt); + +/** + * @brief temp path context + */ +class CTempPathContext { - CString m_strPath; public: - operator LPCTSTR() - { - return m_strPath; - } - CTempPath(LPVOID); - void Clear(); - void MakeSibling(LPCTSTR); + CTempPathContext *m_pParent; + CString m_strLeftDisplayRoot; + CString m_strRightDisplayRoot; + CString m_strLeftRoot; + CString m_strRightRoot; + CTempPathContext *DeleteHead(); }; /** - * @brief Merge7z::DirItemEnumerator to compress a single file. - * - * Class has no extra leading C in its name because it is used like a function. + * @brief Merge7z::DirItemEnumerator to compress a single item. */ -class CompressSingleFile : public Merge7z::DirItemEnumerator +class SingleItemEnumerator : public Merge7z::DirItemEnumerator { LPCTSTR FullPath; LPCTSTR Name; public: virtual UINT Open(); virtual Merge7z::Envelope *Enum(Item &); - CompressSingleFile(LPCTSTR path, LPCTSTR FullPath, LPCTSTR Name = _T("")); + SingleItemEnumerator(LPCTSTR path, LPCTSTR FullPath, LPCTSTR Name = _T("")); }; /** @@ -62,6 +65,7 @@ private: CMapStringToPtr m_rgImpliedFoldersRight; // helper methods DIFFITEM Next(); + bool MultiStepCompressArchive(LPCTSTR); public: enum { @@ -83,7 +87,6 @@ int NTAPI HasZipSupport(); void NTAPI Recall7ZipMismatchError(); DWORD NTAPI VersionOf7z(BOOL bLocal = FALSE); -CString NTAPI LangFile7z(); /** * @brief assign BSTR to CString, and return BSTR for optional SysFreeString() diff --git a/Src/DiffContext.cpp b/Src/DiffContext.cpp index 5113ad924..d0aed1224 100644 --- a/Src/DiffContext.cpp +++ b/Src/DiffContext.cpp @@ -143,9 +143,12 @@ void CDiffContext::UpdateInfoFromDiskHalf(DIFFITEM & di, DiffFileInfo & dfi) { UpdateVersion(di, dfi); ASSERT(&dfi == &di.left || &dfi == &di.right); - CString spath = &dfi == &di.left ? di.getLeftFilepath(GetNormalizedLeft()) : - di.getRightFilepath(GetNormalizedRight()); - CString filepath = paths_ConcatPath(spath, di.sfilename); + CString filepath + ( + &dfi == &di.left + ? paths_ConcatPath(di.getLeftFilepath(GetNormalizedLeft()), di.sLeftFilename) + : paths_ConcatPath(di.getRightFilepath(GetNormalizedRight()), di.sRightFilename) + ); dfi.Update(filepath); GuessCodepageEncoding(filepath, &dfi.unicoding, &dfi.codepage, m_bGuessEncoding); } @@ -173,32 +176,35 @@ static bool CheckFileForVersion(LPCTSTR ext) void CDiffContext::UpdateVersion(DIFFITEM & di, DiffFileInfo & dfi) const { // Check only binary files - LPCTSTR ext = PathFindExtension(di.sfilename); dfi.version = _T(""); dfi.bVersionChecked = true; if (di.isDirectory()) return; - if (!CheckFileForVersion(ext)) - return; - CString spath; if (&dfi == &di.left) { if (di.isSideRight()) return; + LPCTSTR ext = PathFindExtension(di.sLeftFilename); + if (!CheckFileForVersion(ext)) + return; spath = di.getLeftFilepath(GetNormalizedLeft()); + spath = paths_ConcatPath(spath, di.sLeftFilename); } else { ASSERT(&dfi == &di.right); if (di.isSideLeft()) return; + LPCTSTR ext = PathFindExtension(di.sRightFilename); + if (!CheckFileForVersion(ext)) + return; spath = di.getRightFilepath(GetNormalizedRight()); + spath = paths_ConcatPath(spath, di.sRightFilename); } - CString filepath = paths_ConcatPath(spath, di.sfilename); - dfi.version = GetFixedFileVersion(filepath); + dfi.version = GetFixedFileVersion(spath); } /** @brief Forward call to retrieve plugin info (winds up in DirDoc) */ diff --git a/Src/DiffItem.cpp b/Src/DiffItem.cpp index 9090e0fe0..638aac1a2 100644 --- a/Src/DiffItem.cpp +++ b/Src/DiffItem.cpp @@ -22,11 +22,7 @@ CString DIFFITEM::getLeftFilepath(const CString &sLeftRoot) const CString sPath; if (!isSideRight()) { - sPath = sLeftRoot; - if (sSubdir.GetLength()) - { - sPath = paths_ConcatPath(sPath, sSubdir); - } + sPath = paths_ConcatPath(sLeftRoot, sLeftSubdir); } return sPath; } @@ -37,11 +33,7 @@ CString DIFFITEM::getRightFilepath(const CString &sRightRoot) const CString sPath; if (!isSideLeft()) { - sPath = sRightRoot; - if (sSubdir.GetLength()) - { - sPath = paths_ConcatPath(sPath, sSubdir); - } + sPath = paths_ConcatPath(sRightRoot, sRightSubdir); } return sPath; } diff --git a/Src/DiffItem.h b/Src/DiffItem.h index 99dcbd542..79e9dd6ea 100644 --- a/Src/DiffItem.h +++ b/Src/DiffItem.h @@ -34,8 +34,7 @@ struct DIFFCODE int diffcode; - DIFFCODE() : diffcode(0) { } - DIFFCODE(int diffcode) : diffcode(diffcode) { } + DIFFCODE(int diffcode = 0) : diffcode(diffcode) { } // file/directory bool isDirectory() const { return ((diffcode & DIFFCODE::DIRFLAG) == DIFFCODE::DIR); } @@ -79,8 +78,10 @@ struct DIFFITEM : DIFFCODE { DiffFileInfo left; /**< Fileinfo for left file */ DiffFileInfo right; /**< Fileinfo for right file */ - CString sfilename; /**< Filename (without path!) */ - CString sSubdir; //*< Common subdirectory from root of comparison */ + CString sLeftFilename; /**< Filename (without path!) */ + CString sRightFilename; /**< Filename (without path!) */ + CString sLeftSubdir; //*< Common subdirectory from root of comparison */ + CString sRightSubdir; //*< Common subdirectory from root of comparison */ int nsdiffs; /**< Amount of non-ignored differences */ int ndiffs; /**< Total amount of differences */ diff --git a/Src/DiffThread.cpp b/Src/DiffThread.cpp index 2fdd08f0f..fa977d7ca 100644 --- a/Src/DiffThread.cpp +++ b/Src/DiffThread.cpp @@ -198,7 +198,6 @@ UINT DiffThread(LPVOID lpParam) bool casesensitive = false; int depth = myStruct->bRecursive ? -1 : 0; - CString subdir; // blank to start at roots specified in diff context paths.SetLeft(myStruct->context->GetNormalizedLeft()); paths.SetRight(myStruct->context->GetNormalizedRight()); @@ -211,8 +210,19 @@ UINT DiffThread(LPVOID lpParam) else { myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_COLLECT); - DirScan_GetItems(paths, subdir, &itemList, casesensitive, depth, myStruct->context, myStruct->m_pAbortgate); - + CString subdir; // blank to start at roots specified in diff context +#ifdef _DEBUG + _CrtMemState memStateBefore; + _CrtMemState memStateAfter; + _CrtMemState memStateDiff; + _CrtMemCheckpoint(&memStateBefore); +#endif + DirScan_GetItems(paths, subdir, subdir, &itemList, casesensitive, depth, myStruct->context, myStruct->m_pAbortgate); +#ifdef _DEBUG + _CrtMemCheckpoint(&memStateAfter); + _CrtMemDifference(&memStateDiff, &memStateBefore, &memStateAfter); + _CrtMemDumpStatistics(&memStateDiff); +#endif myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_COMPARE); DirScan_CompareItems(itemList, myStruct->context, myStruct->m_pAbortgate); myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_READY); diff --git a/Src/DiffWrapper.cpp b/Src/DiffWrapper.cpp index ee054e53d..1c71420d2 100644 --- a/Src/DiffWrapper.cpp +++ b/Src/DiffWrapper.cpp @@ -1405,35 +1405,25 @@ void GetComparePaths(CDiffContext * pCtxt, const DIFFITEM &di, CString & left, C { static const TCHAR backslash[] = _T("\\"); - if (di.isSideLeft()) + if (!di.isSideRight()) { // Compare file to itself to detect encoding left = pCtxt->GetNormalizedLeft() + backslash; - if (!di.sSubdir.IsEmpty()) - left += di.sSubdir + backslash; - left += di.sfilename; - right = left; + if (!di.sLeftSubdir.IsEmpty()) + left += di.sLeftSubdir + backslash; + left += di.sLeftFilename; + if (di.isSideLeft()) + right = left; } - else if (di.isSideRight()) + if (!di.isSideLeft()) { // Compare file to itself to detect encoding right = pCtxt->GetNormalizedRight() + backslash; - if (!di.sSubdir.IsEmpty()) - right += di.sSubdir + backslash; - right += di.sfilename; - left = right; - } - else - { - left = pCtxt->GetNormalizedLeft() + backslash; - right = pCtxt->GetNormalizedRight() + backslash; - if (!di.sSubdir.IsEmpty()) - { - left += di.sSubdir + backslash; - right += di.sSubdir + backslash; - } - left += di.sfilename; - right += di.sfilename; + if (!di.sRightSubdir.IsEmpty()) + right += di.sRightSubdir + backslash; + right += di.sRightFilename; + if (di.isSideRight()) + left = right; } } diff --git a/Src/DirActions.cpp b/Src/DirActions.cpp index 2257844d9..08a8b3ac7 100644 --- a/Src/DirActions.cpp +++ b/Src/DirActions.cpp @@ -302,9 +302,9 @@ void CDirView::DoCopyLeftTo() { CString sFullDest(destPath); sFullDest += _T("\\"); - if (!di.sSubdir.IsEmpty()) - sFullDest += di.sSubdir + _T("\\"); - sFullDest += di.sfilename; + if (!di.sLeftSubdir.IsEmpty()) + sFullDest += di.sLeftSubdir + _T("\\"); + sFullDest += di.sLeftFilename; fileOp.AddDestFile(sFullDest); } GetItemFileNames(sel, slFile, srFile); @@ -355,9 +355,9 @@ void CDirView::DoCopyRightTo() { CString sFullDest(destPath); sFullDest += _T("\\"); - if (!di.sSubdir.IsEmpty()) - sFullDest += di.sSubdir + _T("\\"); - sFullDest += di.sfilename; + if (!di.sRightSubdir.IsEmpty()) + sFullDest += di.sRightSubdir + _T("\\"); + sFullDest += di.sRightFilename; fileOp.AddDestFile(sFullDest); } GetItemFileNames(sel, slFile, srFile); @@ -406,10 +406,10 @@ void CDirView::DoMoveLeftTo() sFullDest += _T("\\"); if (GetDocument()->GetRecursive()) { - if (!di.sSubdir.IsEmpty()) - sFullDest += di.sSubdir + _T("\\"); + if (!di.sLeftSubdir.IsEmpty()) + sFullDest += di.sLeftSubdir + _T("\\"); } - sFullDest += di.sfilename; + sFullDest += di.sLeftFilename; act.dest = sFullDest; GetItemFileNames(sel, slFile, srFile); @@ -459,10 +459,10 @@ void CDirView::DoMoveRightTo() sFullDest += _T("\\"); if (GetDocument()->GetRecursive()) { - if (!di.sSubdir.IsEmpty()) - sFullDest += di.sSubdir + _T("\\"); + if (!di.sRightSubdir.IsEmpty()) + sFullDest += di.sRightSubdir + _T("\\"); } - sFullDest += di.sfilename; + sFullDest += di.sRightFilename; act.dest = sFullDest; GetItemFileNames(sel, slFile, srFile); @@ -719,16 +719,16 @@ void CDirView::PerformActionList(ActionList & actionList) */ void CDirView::UpdateCopiedItems(ActionList & actionList) { + CDirDoc *pDoc = GetDocument(); while (actionList.GetCount()>0) { ActionList::action act = actionList.actions.RemoveHead(); POSITION diffpos = GetItemKey(act.idx); - const DIFFITEM & di = GetDocument()->GetDiffByKey(diffpos); + const DIFFITEM & di = pDoc->GetDiffByKey(diffpos); if (actionList.atype == ActionList::ACT_COPY) { // Copy files and folders - CDirDoc *pDoc = GetDocument(); pDoc->SetDiffSide(DIFFCODE::BOTH, act.idx); // Folders don't have compare flag set!! @@ -746,7 +746,6 @@ void CDirView::UpdateCopiedItems(ActionList & actionList) // Move files and folders // If unique item is moved, don't bother updating statuses, // just remove from list - CDirDoc *pDoc = GetDocument(); if (actionList.atype == ActionList::ACT_MOVE_LEFT) { if (di.isSideLeft()) @@ -776,7 +775,6 @@ void CDirView::UpdateCopiedItems(ActionList & actionList) // Delete files and folders // If both items or unique item is deleted, don't bother updating // statuses, just remove from list - CDirDoc *pDoc = GetDocument(); if (actionList.atype == ActionList::ACT_DEL_LEFT) { if (di.isSideLeft()) @@ -981,11 +979,12 @@ void CDirView::GetItemFileNames(int sel, CString& strLeft, CString& strRight) co else { const DIFFITEM & di = GetDocument()->GetDiffByKey(diffpos); - const CString relpath = paths_ConcatPath(di.sSubdir, di.sfilename); + const CString leftrelpath = paths_ConcatPath(di.sLeftSubdir, di.sLeftFilename); + const CString rightrelpath = paths_ConcatPath(di.sRightSubdir, di.sRightFilename); const CString & leftpath = GetDocument()->GetLeftBasePath(); const CString & rightpath = GetDocument()->GetRightBasePath(); - strLeft = paths_ConcatPath(leftpath, relpath); - strRight = paths_ConcatPath(rightpath, relpath); + strLeft = paths_ConcatPath(leftpath, leftrelpath); + strRight = paths_ConcatPath(rightpath, rightrelpath); } } @@ -995,24 +994,11 @@ void CDirView::GetItemFileNames(int sel, CString& strLeft, CString& strRight) co */ void CDirView::GetItemFileNames(int sel, PathContext * paths) const { - ASSERT(paths); - POSITION diffpos = GetItemKey(sel); - if (diffpos == (POSITION)SPECIAL_ITEM_POS) - { - paths->SetLeft(_T("")); - paths->SetRight(_T("")); - } - else - { - const DIFFITEM & di = GetDocument()->GetDiffByKey(diffpos); - const CString relpath = paths_ConcatPath(di.sSubdir, di.sfilename); - const CString & leftpath = GetDocument()->GetLeftBasePath(); - const CString & rightpath = GetDocument()->GetRightBasePath(); - CString strLeft = paths_ConcatPath(leftpath, relpath); - CString strRight = paths_ConcatPath(rightpath, relpath); - paths->SetLeft(strLeft); - paths->SetRight(strRight); - } + CString strLeft; + CString strRight; + GetItemFileNames(sel, strLeft, strRight); + paths->SetLeft(strLeft); + paths->SetRight(strRight); } /// Open selected file on specified side diff --git a/Src/DirDoc.cpp b/Src/DirDoc.cpp index dd5406339..491de7ec3 100644 --- a/Src/DirDoc.cpp +++ b/Src/DirDoc.cpp @@ -72,6 +72,8 @@ CDirDoc::CDirDoc() , m_statusCursor(NULL) , m_bReuseCloses(FALSE) , m_bMarkedRescan(FALSE) +, m_pTempPathContext(NULL) +, m_cchLeftRoot(0) { DIFFOPTIONS options = {0}; @@ -100,9 +102,11 @@ CDirDoc::~CDirDoc() CMergeDoc * pMergeDoc = m_MergeDocs.GetNext(pos); pMergeDoc->DirDocClosing(this); } - // Delete all temporary folders belonging to this document - CTempPath(this); + while (m_pTempPathContext) + { + m_pTempPathContext = m_pTempPathContext->DeleteHead(); + } } /** @@ -174,28 +178,55 @@ void CDirDoc::Serialize(CArchive& ar) * Previous compare context is first free'd. * @param [in] paths Paths to compare * @param [in] bRecursive If TRUE subdirectories are included to compare. - * @return TRUE if initialisation succeeds. */ -BOOL CDirDoc::InitCompare(const PathContext & paths, BOOL bRecursive) +void CDirDoc::InitCompare(const PathContext & paths, BOOL bRecursive, BOOL bInitRootLength, CTempPathContext *pTempPathContext) { - BOOL bRet = FALSE; - - if (m_pCtxt != NULL) - delete m_pCtxt; + // Anything that can go wrong here will yield an exception. + // Default implementation of operator new() never returns NULL. + delete m_pCtxt; if (m_pCompareStats == NULL) m_pCompareStats = new CompareStats(); m_pCtxt = new CDiffContext(paths.GetLeft(), paths.GetRight()); - - if (m_pCtxt != NULL && m_pCompareStats != NULL) + + if (pTempPathContext) + { + ApplyLeftDisplayRoot(pTempPathContext->m_strLeftDisplayRoot); + ApplyRightDisplayRoot(pTempPathContext->m_strRightDisplayRoot); + pTempPathContext->m_pParent = m_pTempPathContext; + m_pTempPathContext = pTempPathContext; + m_pTempPathContext->m_strLeftRoot = m_pCtxt->GetLeftPath(); + m_pTempPathContext->m_strRightRoot = m_pCtxt->GetRightPath(); + } + + if (bInitRootLength) { - m_bRecursive = bRecursive; - // All plugin management is done by our plugin manager - m_pCtxt->m_piPluginInfos = &m_pluginman; - bRet = TRUE; + m_cchLeftRoot = m_pCtxt->GetLeftPath().GetLength(); } - return bRet; + + m_bRecursive = bRecursive; + // All plugin management is done by our plugin manager + m_pCtxt->m_piPluginInfos = &m_pluginman; +} + +/** + * @brief Tell if user may use ".." and move to parents directory + * + * @return No : upward RESTRICTED + * ParentIsRegularPath : upward ENABLED + * ParentIsTempPath : upward ENABLED + */ +CDirDoc::AllowUpwardDirectory::ReturnCode CDirDoc::AllowUpwardDirectory() +{ + return + ( + GetLeftBasePath().GetLength() > m_cchLeftRoot + ? AllowUpwardDirectory::ParentIsRegularPath + : m_pTempPathContext && m_pTempPathContext->m_pParent + ? AllowUpwardDirectory::ParentIsTempPath + : AllowUpwardDirectory::No + ); } /** @@ -353,7 +384,7 @@ void CDirDoc::Redisplay() m_pDirView->SetRedraw(FALSE); // If non-recursive compare, add special item(s) - if (!m_bRecursive) + if (!m_bRecursive || m_pTempPathContext && m_pTempPathContext->m_pParent) cnt += m_pDirView->AddSpecialItems(); int alldiffs=0; @@ -478,7 +509,8 @@ POSITION CDirDoc::FindItemFromPaths(LPCTSTR pathLeft, LPCTSTR pathRight) if (path1 == current.getLeftFilepath(GetLeftBasePath()) && path2 == current.getRightFilepath(GetRightBasePath()) && - file1 == current.sfilename) + file1 == current.sLeftFilename && + file2 == current.sRightFilename) { return currentPos; } @@ -563,7 +595,7 @@ BOOL CDirDoc::ReusingDirDoc() // clear diff display ASSERT(m_pDirView); - m_pDirView->ReusingDirView(); + m_pDirView->DeleteAllDisplayItems(); // hide the floating state bar CDirFrame *pf = m_pDirView->GetParentFrame(); @@ -573,6 +605,11 @@ BOOL CDirDoc::ReusingDirDoc() delete m_pCtxt; m_pCtxt = NULL; + while (m_pTempPathContext) + { + m_pTempPathContext = m_pTempPathContext->DeleteHead(); + } + return TRUE; } @@ -744,7 +781,10 @@ void CDirDoc::UpdateHeaderPath(BOOL bLeft) if (!m_strLeftDesc.IsEmpty()) sText = m_strLeftDesc; else + { sText = m_pCtxt->GetLeftPath(); + ApplyLeftDisplayRoot(sText); + } nPane = 0; } else @@ -752,7 +792,10 @@ void CDirDoc::UpdateHeaderPath(BOOL bLeft) if (!m_strRightDesc.IsEmpty()) sText = m_strRightDesc; else + { sText = m_pCtxt->GetRightPath(); + ApplyRightDisplayRoot(sText); + } nPane = 1; } @@ -804,6 +847,30 @@ void CDirDoc::SetDescriptions(const CString &strLeftDesc, const CString &strRigh } /** + * @brief Replace internal root by display root (left) + */ +void CDirDoc::ApplyLeftDisplayRoot(CString &sText) +{ + if (m_pTempPathContext) + { + sText.Delete(0, m_pTempPathContext->m_strLeftRoot.GetLength()); + sText.Insert(0, m_pTempPathContext->m_strLeftDisplayRoot); + } +} + +/** + * @brief Replace internal root by display root (right) + */ +void CDirDoc::ApplyRightDisplayRoot(CString &sText) +{ + if (m_pTempPathContext) + { + sText.Delete(0, m_pTempPathContext->m_strRightRoot.GetLength()); + sText.Insert(0, m_pTempPathContext->m_strRightDisplayRoot); + } +} + +/** * @brief Store a plugin setting for specified file comparison */ void CDirDoc::SetPluginPrediffSetting(const CString & filteredFilenames, int newsetting) @@ -852,48 +919,45 @@ void CDirDoc::SetTitle(LPCTSTR lpszTitle) else { // PathCompactPath() supported in versions 4.71 and higher - if (GetDllVersion(_T("shlwapi.dll")) >= PACKVERSION(4,71)) - { - // Combine title from file/dir names - TCHAR *pszLeftFile; - TCHAR *pszRightFile; - CString sLeftFile; - CString sRightFile; - CRect rcClient; - CString strTitle; - const TCHAR strSeparator[] = _T(" - "); - CClientDC lDC(m_pDirView); - - m_pDirView->GetClientRect(&rcClient); - const DWORD width = rcClient.right / 3; - - sLeftFile = m_pCtxt->GetLeftPath(); - pszLeftFile = sLeftFile.GetBuffer(MAX_PATH); - - if (PathCompactPath(lDC.GetSafeHdc(), pszLeftFile, width)) - strTitle = pszLeftFile; - else - strTitle = m_pCtxt->GetLeftPath(); - - sLeftFile.ReleaseBuffer(); - strTitle += strSeparator; - - sRightFile = m_pCtxt->GetRightPath(); - pszRightFile = sRightFile.GetBuffer(MAX_PATH); - - if (PathCompactPath(lDC.GetSafeHdc(), pszRightFile, width)) - strTitle += pszRightFile; - else - strTitle += m_pCtxt->GetRightPath(); - sRightFile.ReleaseBuffer(); - - CDocument::SetTitle(strTitle); - } + // According to + // "http://members.ozemail.com.au/~geoffch/samples/win32/shell/shlwapi/functions/index.html", + // PathCompactPath() is supported since 4.70. Anyway, as we link to shlwapi import library, + // we wouldn't be running if any one of the functions we link to weren't implemented. This + // means there is no point in checking shlwapi.dll version here. + + // Combine title from file/dir names + TCHAR *pszLeftFile; + TCHAR *pszRightFile; + CString sLeftFile; + CString sRightFile; + CRect rcClient; + CString strTitle; + const TCHAR strSeparator[] = _T(" - "); + CClientDC lDC(m_pDirView); + + m_pDirView->GetClientRect(&rcClient); + const DWORD width = rcClient.right / 3; + + sLeftFile = m_pCtxt->GetLeftPath(); + pszLeftFile = sLeftFile.GetBuffer(MAX_PATH); + + if (PathCompactPath(lDC.GetSafeHdc(), pszLeftFile, width)) + strTitle = pszLeftFile; else - { - CString title; - VERIFY(title.LoadString(IDS_DIRECTORY_WINDOW_TITLE)); - CDocument::SetTitle(title); - } + strTitle = m_pCtxt->GetLeftPath(); + + sLeftFile.ReleaseBuffer(); + strTitle += strSeparator; + + sRightFile = m_pCtxt->GetRightPath(); + pszRightFile = sRightFile.GetBuffer(MAX_PATH); + + if (PathCompactPath(lDC.GetSafeHdc(), pszRightFile, width)) + strTitle += pszRightFile; + else + strTitle += m_pCtxt->GetRightPath(); + sRightFile.ReleaseBuffer(); + + CDocument::SetTitle(strTitle); } } diff --git a/Src/DirDoc.h b/Src/DirDoc.h index c320a7c8c..7c9c419c3 100644 --- a/Src/DirDoc.h +++ b/Src/DirDoc.h @@ -47,7 +47,7 @@ typedef CTypedPtrList MergeDocPtrList; class DirDocFilterGlobal; class DirDocFilterByExtension; class CustomStatusCursor; - +class CTempPathContext; ///////////////////////////////////////////////////////////////////////////// // CDirDoc document @@ -62,6 +62,7 @@ protected: // Attributes public: + CTempPathContext *m_pTempPathContext; // Operations public: BOOL CloseMergeDocs(); @@ -83,7 +84,7 @@ public: // Implementation public: - BOOL InitCompare(const PathContext & paths, BOOL bRecursive); + void InitCompare(const PathContext & paths, BOOL bRecursive, BOOL bSetRootLength, CTempPathContext *); void Rescan(); BOOL GetRecursive() { return m_bRecursive; } BOOL GetReadOnly(BOOL bLeft) const; @@ -111,6 +112,8 @@ public: void AbortCurrentScan(); bool IsCurrentScanAbortable() const; void SetDescriptions(const CString &strLeftDesc, const CString &strRightDesc); + void ApplyLeftDisplayRoot(CString &); + void ApplyRightDisplayRoot(CString &); void SetPluginPrediffSetting(const CString & filteredFilenames, int newsetting); void FetchPluginInfos(const CString& filteredFilenames, @@ -124,6 +127,16 @@ public: CString GetRightBasePath() const { return m_pCtxt->GetNormalizedRight(); } void RemoveDiffByKey(POSITION key) { m_pCtxt->RemoveDiff(key); } void SetMarkedRescan() {m_bMarkedRescan = TRUE; } + struct AllowUpwardDirectory + { + enum ReturnCode + { + No, + ParentIsRegularPath, + ParentIsTempPath + }; + }; + AllowUpwardDirectory::ReturnCode AllowUpwardDirectory(); protected: CDiffWrapper m_diffWrapper; @@ -149,6 +162,7 @@ private: PluginManager m_pluginman; BOOL m_bReuseCloses; /**< Are we closing because of reuse? */ BOOL m_bMarkedRescan; /**< If TRUE next rescan scans only marked items */ + int m_cchLeftRoot; /**< Don't go upward any further */ }; //{{AFX_INSERT_LOCATION}} diff --git a/Src/DirScan.cpp b/Src/DirScan.cpp index dc1d13586..f6a7e505e 100644 --- a/Src/DirScan.cpp +++ b/Src/DirScan.cpp @@ -53,7 +53,7 @@ static void Sort(fentryArray * dirs, bool casesensitive);; static int collstr(const CString & s1, const CString & s2, bool casesensitive); static void StoreDiffResult(DIFFITEM &di, CDiffContext * pCtxt, const DiffFileData * pDiffFileData); -static void AddToList(CString sDir, const fentry * lent, const fentry * rent, +static void AddToList(const CString & sLeftDir, const CString & sRightDir, const fentry * lent, const fentry * rent, int code, DiffItemList * pList, CDiffContext *pCtxt); static void UpdateDiffItem(DIFFITEM & di, BOOL & bExists, CDiffContext *pCtxt); @@ -62,6 +62,18 @@ typedef int (CString::*cmpmth)(LPCTSTR sz) const; /** @brief CALL_MEMBER_FN calls a method through a pointer to a method */ #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) +/** + * @brief Help minimize memory footprint by sharing CStringData if possible. + * + * Use OPTIMIZE_SHARE_CSTRINGDATA to conditionally include code that is merely + * intended to minimize memory footprint by having two CStrings share one + * CStringData if possible. The rule is that semantics must be identical + * regardless of whether OPTIMIZE_SHARE_CSTRINGDATA(X) expands to X or to + * nothing. If you suspect some bug to be related to this kind of optimization, + * then you can simply change OPTIMIZE_SHARE_CSTRINGDATA to expand to nothing, + * recompile, and see if bug disappears. + */ +#define OPTIMIZE_SHARE_CSTRINGDATA(X) X /** * @brief Collect file- and directory-names to list. @@ -75,19 +87,25 @@ typedef int (CString::*cmpmth)(LPCTSTR sz) const; * @param [in] piAbortable Interface allowing compare to be aborted * @return 1 normally, -1 if compare was aborted */ -int DirScan_GetItems(const PathContext &paths, const CString & subdir, DiffItemList *pList, +int DirScan_GetItems(const PathContext &paths, const CString & leftsubdir, const CString & rightsubdir, DiffItemList *pList, bool casesensitive, int depth, CDiffContext * pCtxt, IAbortable * piAbortable) { static const TCHAR backslash[] = _T("\\"); CString sLeftDir = paths.GetLeft(); CString sRightDir = paths.GetRight(); - CString subprefix; - if (!subdir.IsEmpty()) + CString leftsubprefix; + CString rightsubprefix; + if (!leftsubdir.IsEmpty()) { - sLeftDir += backslash + subdir; - sRightDir += backslash + subdir; - subprefix = subdir + backslash; + sLeftDir += backslash + leftsubdir; + sRightDir += backslash + rightsubdir; + leftsubprefix = leftsubdir + backslash; + // minimize memory footprint by having left/rightsubprefix share CStringData if possible + rightsubprefix = OPTIMIZE_SHARE_CSTRINGDATA + ( + (LPCTSTR)leftsubdir == (LPCTSTR)rightsubdir ? leftsubprefix : + ) rightsubdir + backslash; } fentryArray leftDirs, leftFiles, rightDirs, rightFiles; @@ -101,6 +119,15 @@ int DirScan_GetItems(const PathContext &paths, const CString & subdir, DiffItemL // Handle directories // i points to current directory in left list (leftDirs) // j points to current directory in right list (rightDirs) + + bool bTreatDirAsEqual + ( + leftDirs.GetSize() == 1 + && rightDirs.GetSize() == 1 + && leftFiles.GetSize() == 0 + && rightFiles.GetSize() == 0 + ); + int i=0, j=0; while (1) { @@ -111,57 +138,61 @@ int DirScan_GetItems(const PathContext &paths, const CString & subdir, DiffItemL TRACE(_T("Candidate left: leftDirs[i]=%s\n"), (LPCTSTR)leftDirs[i].name); if (j0)) - { - int nDiffCode = DIFFCODE::RIGHT | DIFFCODE::DIR; - - // Advance right pointer over right-only entry, and then retest with new pointers - AddToList(subdir, 0, &rightDirs[j], nDiffCode, pList, pCtxt); - ++j; - continue; + if (i0)) + { + int nDiffCode = DIFFCODE::RIGHT | DIFFCODE::DIR; + AddToList(leftsubdir, rightsubdir, 0, &rightDirs[j], nDiffCode, pList, pCtxt); + // Advance right pointer over right-only entry, and then retest with new pointers + ++j; + continue; + } } if (im_piFilterGlobal->includeDir(leftnewsub, rightnewsub)) { - // Non-recursive compare - // We are only interested about list of subdirectories to show - user can open them - // TODO: scan one level deeper to see if directories are identical/different - AddToList(subdir, &leftDirs[i], &rightDirs[j], nDiffCode, pList, pCtxt); + const int nDiffCode = DIFFCODE::BOTH | DIFFCODE::DIR | DIFFCODE::SKIPPED; + AddToList(leftsubdir, rightsubdir, &leftDirs[i], &rightDirs[j], nDiffCode, pList, pCtxt); } else { - // Recursive compare - // Test against filter so we don't include contents of filtered out directories - // Also this is only place we can test for both-sides directories in recursive compare - if (!pCtxt->m_piFilterGlobal->includeDir(newsub)) + // Scan recursively all subdirectories too, we are not adding folders + const int nDiffCode = DIFFCODE::BOTH | DIFFCODE::DIR | DIFFCODE::INCLUDED; + if (DirScan_GetItems(paths, leftnewsub, rightnewsub, pList, casesensitive, + depth - 1, pCtxt, piAbortable) == -1) { - nDiffCode |= DIFFCODE::SKIPPED; - AddToList(subdir, &leftDirs[i], &rightDirs[j], nDiffCode, pList, pCtxt); - } - else - { - // Scan recursively all subdirectories too, we are not adding folders - nDiffCode |= DIFFCODE::INCLUDED; - - if (DirScan_GetItems(paths, newsub, pList, casesensitive, - depth - 1, pCtxt, piAbortable) == -1) - { - return -1; - } + return -1; } } } @@ -189,13 +220,8 @@ int DirScan_GetItems(const PathContext &paths, const CString & subdir, DiffItemL if (i 0)) { - // Test against filter - CString newsubfile = subprefix + rightFiles[j].name; - int nDiffCode = DIFFCODE::RIGHT | DIFFCODE::FILE; - { - AddToList(subdir, 0, &rightFiles[j], nDiffCode, pList, pCtxt); - } + const int nDiffCode = DIFFCODE::RIGHT | DIFFCODE::FILE; + AddToList(leftsubdir, rightsubdir, 0, &rightFiles[j], nDiffCode, pList, pCtxt); // Advance right pointer over right-only entry, and then retest with new pointers ++j; continue; @@ -216,11 +238,8 @@ int DirScan_GetItems(const PathContext &paths, const CString & subdir, DiffItemL if (iGetNormalizedLeft()); - leftpath = paths_ConcatPath(leftpath, di.sfilename); - rightpath = di.getRightFilepath(pCtxt->GetNormalizedRight()); - rightpath = paths_ConcatPath(rightpath, di.sfilename); + CString leftpath = di.getLeftFilepath(pCtxt->GetNormalizedLeft()); + leftpath = paths_ConcatPath(leftpath, di.sLeftFilename); + CString rightpath = di.getRightFilepath(pCtxt->GetNormalizedRight()); + rightpath = paths_ConcatPath(rightpath, di.sRightFilename); // Re-check if left/right sides still exists (or are added) if (_tstat(leftpath, &stats) == 0) @@ -367,7 +384,7 @@ void CompareDiffItem(DIFFITEM di, CDiffContext * pCtxt) // 1. Test against filters if (di.isDirectory()) { - if (!pCtxt->m_piFilterGlobal->includeDir(di.sfilename)) + if (!pCtxt->m_piFilterGlobal->includeDir(di.sLeftFilename, di.sRightFilename)) di.diffcode |= DIFFCODE::SKIPPED; else di.diffcode |= DIFFCODE::INCLUDED; @@ -378,7 +395,7 @@ void CompareDiffItem(DIFFITEM di, CDiffContext * pCtxt) } else { - if (!pCtxt->m_piFilterGlobal->includeFile(di.sfilename)) + if (!pCtxt->m_piFilterGlobal->includeFile(di.sLeftFilename, di.sRightFilename)) di.diffcode |= DIFFCODE::SKIPPED; else di.diffcode |= DIFFCODE::INCLUDED; @@ -569,7 +586,7 @@ static void StoreDiffResult(DIFFITEM &di, CDiffContext * pCtxt, gLog.Write ( LOGLEVEL::LCOMPAREDATA, _T("name=<%s>, leftdir=<%s>, rightdir=<%s>, code=%d"), - (LPCTSTR)di.sfilename, (LPCTSTR)_T("di.left.spath"), (LPCTSTR)_T("di.right.spath"), di.diffcode + (LPCTSTR)di.sLeftFilename, (LPCTSTR)_T("di.left.spath"), (LPCTSTR)_T("di.right.spath"), di.diffcode ); pCtxt->AddDiff(di); } @@ -577,7 +594,7 @@ static void StoreDiffResult(DIFFITEM &di, CDiffContext * pCtxt, /** * @brief Add one compare item to list. */ -static void AddToList(CString sDir, const fentry * lent, const fentry * rent, +static void AddToList(const CString & sLeftDir, const CString & sRightDir, const fentry * lent, const fentry * rent, int code, DiffItemList * pList, CDiffContext *pCtxt) { // We must store both paths - we cannot get paths later @@ -585,38 +602,47 @@ static void AddToList(CString sDir, const fentry * lent, const fentry * rent, // change to identical DIFFITEM di; - di.left.unicoding = 0; - di.left.codepage = 0; - di.right.unicoding = 0; - di.right.codepage = 0; - if (!sDir.IsEmpty()) - di.sSubdir = sDir; + di.sLeftSubdir = sLeftDir; + di.sRightSubdir = sRightDir; if (lent) { - di.sfilename = lent->name; + di.sLeftFilename = lent->name; di.left.mtime = lent->mtime; di.left.ctime = lent->ctime; di.left.size = lent->size; di.left.flags.attributes = lent->attrs; } + else + { + // Don't break CDirView::DoCopyRightToLeft() + di.sLeftFilename = rent->name; + } if (rent) { - di.sfilename = rent->name; + di.sRightFilename = OPTIMIZE_SHARE_CSTRINGDATA + ( + di.sLeftFilename == rent->name ? di.sLeftFilename : + ) rent->name; di.right.mtime = rent->mtime; di.right.ctime = rent->ctime; di.right.size = rent->size; di.right.flags.attributes = rent->attrs; } + else + { + // Don't break CDirView::DoCopyLeftToRight() + di.sRightFilename = lent->name; + } di.diffcode = code; gLog.Write ( LOGLEVEL::LCOMPAREDATA, _T("name=<%s>, leftdir=<%s>, rightdir=<%s>, code=%d"), - (LPCTSTR)di.sfilename, (LPCTSTR)_T("di.left.spath"), (LPCTSTR)_T("di.right.spath"), code + (LPCTSTR)di.sLeftFilename, (LPCTSTR)_T("di.left.spath"), (LPCTSTR)_T("di.right.spath"), code ); pCtxt->m_pCompareStats->IncreaseTotalItems(); pList->AddDiff(di); diff --git a/Src/DirScan.h b/Src/DirScan.h index 15d1430d4..a09476f17 100644 --- a/Src/DirScan.h +++ b/Src/DirScan.h @@ -20,7 +20,7 @@ public: virtual bool ShouldAbort() = 0; }; -int DirScan_GetItems(const PathContext &paths, const CString & subdir, DiffItemList * pLst, +int DirScan_GetItems(const PathContext &paths, const CString & leftsubdir, const CString & rightsubdir, DiffItemList * pLst, bool casesensitive, int depth, CDiffContext * pCtxt, IAbortable * piAbortable); int DirScan_CompareItems(DiffItemList & list, CDiffContext * pCtxt, IAbortable * piAbortable); diff --git a/Src/DirView.cpp b/Src/DirView.cpp index db34a092f..3f8f2eec8 100644 --- a/Src/DirView.cpp +++ b/Src/DirView.cpp @@ -423,17 +423,6 @@ void CDirView::OnContextMenu(CWnd*, CPoint point) } /** - * @brief Return nearest ancestor which is not a child window - */ -static CWnd * GetNonChildAncestor(CWnd * w) -{ - CWnd* parent = w; - while (parent->GetStyle() & WS_CHILD) - parent = parent->GetParent(); - return parent; -} - -/** * @brief Format context menu string and disable item if it cannot be applied. */ static void NTAPI FormatContextMenu(BCMenu *pPopup, UINT uIDItem, int n1, int n2 = 0, int n3 = 0) @@ -544,9 +533,9 @@ void CDirView::ListContextMenu(CPoint point, int /*i*/) if (!di.isDirectory() && !di.isBin() && !di.isSideLeft() && !di.isSideRight() && !di.isResultFiltered()) { CString leftPath = di.getLeftFilepath(pDoc->GetLeftBasePath()) + - _T("\\") + di.sfilename; + _T("\\") + di.sLeftFilename; CString rightPath = di.getRightFilepath(pDoc->GetRightBasePath()) + - _T("\\") + di.sfilename; + _T("\\") + di.sRightFilename; CString filteredFilenames = leftPath + "|" + rightPath; PackingInfo * unpacker; PrediffingInfo * prediffer; @@ -815,16 +804,29 @@ void CDirView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) */ void CDirView::OpenParentDirectory() { - const CString & left = GetDocument()->GetLeftBasePath(); - const CString & right = GetDocument()->GetRightBasePath(); + CDirDoc *pDoc = GetDocument(); + const CString & left = pDoc->GetLeftBasePath(); + const CString & right = pDoc->GetRightBasePath(); CString leftParent = paths_GetParentPath(left); CString rightParent = paths_GetParentPath(right); if (paths_DoesPathExist(leftParent) == IS_EXISTING_DIR && - paths_DoesPathExist(rightParent) == IS_EXISTING_DIR && - AllowUpwardDirectory(left, right)) - mf->DoFileOpen(leftParent, rightParent, - FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, FALSE, GetDocument()); + paths_DoesPathExist(rightParent) == IS_EXISTING_DIR) // && + //(pDoc->AllowUpwardDirectory() || pDoc->m_pTempPathContext && pDoc->m_pTempPathContext->m_pParent)) + { + switch (pDoc->AllowUpwardDirectory()) + { + case CDirDoc::AllowUpwardDirectory::ParentIsRegularPath: + mf->DoFileOpen(leftParent, rightParent, + FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, pDoc->GetRecursive(), pDoc); + break; + case CDirDoc::AllowUpwardDirectory::ParentIsTempPath: + pDoc->m_pTempPathContext = pDoc->m_pTempPathContext->DeleteHead(); + mf->DoFileOpen(pDoc->m_pTempPathContext->m_strLeftRoot, pDoc->m_pTempPathContext->m_strRightRoot, + FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, pDoc->GetRecursive(), pDoc); + break; + } + } } /** @@ -855,6 +857,9 @@ void CDirView::OpenSelection(PackingInfo * infoUnpacker /*= NULL*/) DIFFITEM di = pDoc->GetDiffByKey((POSITION)diffpos); + PathContext paths; + GetItemFileNames(sel, &paths); + if (di.isDirectory() && (di.isSideLeft() == di.isSideRight())) { if (pDoc->GetRecursive()) @@ -863,15 +868,17 @@ void CDirView::OpenSelection(PackingInfo * infoUnpacker /*= NULL*/) { // Open subfolders if non-recursive compare // Don't add folders to MRU - CString left, right; - PathContext paths; - GetItemFileNames(sel, &paths); - mf->DoFileOpen(paths.GetLeft(), paths.GetRight(), FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, FALSE, pDoc); + mf->DoFileOpen(paths.GetLeft(), paths.GetRight(), FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, pDoc->GetRecursive(), pDoc); } break; } else if (di.isSideLeft() || di.isSideRight()) AfxMessageBox(IDS_FILEUNIQUE, MB_ICONINFORMATION); + else if (ArchiveGuessFormat(paths.GetLeft()) && ArchiveGuessFormat(paths.GetRight())) + { + // Open archives, not adding paths to MRU + mf->DoFileOpen(paths.GetLeft(), paths.GetRight(), FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, pDoc->GetRecursive(), pDoc); + } else if (di.isBin()) AfxMessageBox(IDS_FILEBINARY, MB_ICONSTOP); else @@ -887,8 +894,6 @@ void CDirView::OpenSelection(PackingInfo * infoUnpacker /*= NULL*/) BOOL bLeftRO = pDoc->GetReadOnly(TRUE); BOOL bRightRO = pDoc->GetReadOnly(FALSE); - PathContext paths; - GetItemFileNames(sel, &paths); mf->ShowMergeDoc(pDoc, paths.GetLeft(), paths.GetRight(), bLeftRO, bRightRO, di.left.codepage, di.right.codepage, @@ -1171,15 +1176,6 @@ void CDirView::DeleteAllDisplayItems() } /** - * @brief Prepare for reuse. - * - */ -void CDirView::ReusingDirView() -{ - DeleteAllDisplayItems(); -} - -/** * @brief Given key, get index of item which has it stored. * This function searches from list in UI. */ @@ -1962,7 +1958,7 @@ void CDirView::OnCtxtOpenWithUnpacker() if (sel != -1) { // let the user choose a handler - CSelectUnpackerDlg dlg(GetDiffItem(sel).sfilename, this); + CSelectUnpackerDlg dlg(GetDiffItem(sel).sLeftFilename, this); // create now a new infoUnpacker to initialize the manual/automatic flag PackingInfo infoUnpacker; dlg.SetInitialInfoHandler(&infoUnpacker); @@ -2101,7 +2097,7 @@ int CDirView::AddSpecialItems() if (paths_DoesPathExist(leftParent) == IS_EXISTING_DIR && paths_DoesPathExist(rightParent) == IS_EXISTING_DIR) { - BOOL bEnable = AllowUpwardDirectory(leftPath, rightPath); + BOOL bEnable = pDoc->AllowUpwardDirectory() != CDirDoc::AllowUpwardDirectory::No; //|| pDoc->m_pTempPathContext && pDoc->m_pTempPathContext->m_pParent; AddParentFolderItem(bEnable); retVal = 1; } @@ -2109,27 +2105,6 @@ int CDirView::AddSpecialItems() } /** - * @brief Tell if user may use ".." and move to parents directory - * - * @return TRUE : upward ENABLED : both paths have the same rightmost subdirectory, - * after we go upward, we may come back here with opening this subdirectory - * FALSE : upward RESTRICTED : both paths have a different rightmost subdirectory, - * the move can not be reversed (probably these are the original comparison directories) - */ -BOOL CDirView::AllowUpwardDirectory(const CString &leftPath, const CString &rightPath) -{ - int lastSegmentPos = leftPath.ReverseFind(_T('/')); - if (lastSegmentPos == -1 || leftPath.ReverseFind(_T('\\')) > lastSegmentPos) - lastSegmentPos = leftPath.ReverseFind(_T('\\')); - ASSERT (lastSegmentPos != -1); - lastSegmentPos ++; - - int nSegmentSize = leftPath.GetLength() - lastSegmentPos; - - return (leftPath.Right(nSegmentSize).CompareNoCase(rightPath.Right(nSegmentSize)) == 0); -} - -/** * @brief Add "Parent folder" ("..") item to directory view */ void CDirView::AddParentFolderItem(BOOL bEnable) @@ -2322,7 +2297,7 @@ void CDirView::OnCopyLeftPathnames() strPaths += di.getLeftFilepath(GetDocument()->GetLeftBasePath()); strPaths += _T("\\"); if (!di.isDirectory()) - strPaths += di.sfilename; + strPaths += di.sLeftFilename; strPaths += _T("\r\n"); } } @@ -2346,7 +2321,7 @@ void CDirView::OnCopyRightPathnames() strPaths += di. getRightFilepath(pDoc->GetRightBasePath()); strPaths += _T("\\"); if (!di.isDirectory()) - strPaths += di.sfilename; + strPaths += di.sRightFilename; strPaths += _T("\r\n"); } } @@ -2370,7 +2345,7 @@ void CDirView::OnCopyBothPathnames() strPaths += di.getLeftFilepath(pDoc->GetLeftBasePath()); strPaths += _T("\\"); if (!di.isDirectory()) - strPaths += di.sfilename; + strPaths += di.sLeftFilename; strPaths += _T("\r\n"); } @@ -2379,7 +2354,7 @@ void CDirView::OnCopyBothPathnames() strPaths += di. getRightFilepath(pDoc->GetRightBasePath()); strPaths += _T("\\"); if (!di.isDirectory()) - strPaths += di.sfilename; + strPaths += di.sRightFilename; strPaths += _T("\r\n"); } } @@ -2399,7 +2374,7 @@ void CDirView::OnCopyFilenames() const DIFFITEM& di = GetDiffItem(sel); if (!di.isDirectory()) { - strPaths += di.sfilename; + strPaths += di.sLeftFilename; strPaths += _T("\r\n"); } } diff --git a/Src/DirView.h b/Src/DirView.h index e6e929f91..6f84ae2e7 100644 --- a/Src/DirView.h +++ b/Src/DirView.h @@ -94,7 +94,6 @@ public: int GetItemIndex(DWORD key); // for populating list void DeleteAllDisplayItems(); - void ReusingDirView(); void SetColumnWidths(); void SortColumnsAppropriately(); @@ -104,7 +103,6 @@ public: //DIFFITEM GetNextSelectedInd(int &ind); DIFFITEM GetItemAt(int ind); int AddSpecialItems(); - BOOL AllowUpwardDirectory(const CString &leftPath, const CString &rightPath); void AddParentFolderItem(BOOL bEnable); void RefreshOptions(); @@ -238,7 +236,6 @@ protected: CMenu * m_pHeaderPopup; BOOL m_bEscCloses; /**< Cached value for option for ESC closing window */ CFont *m_pFont; /**< User-selected font */ - // Generated message map functions afx_msg void OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnContextMenu(CWnd*, CPoint point); diff --git a/Src/DirViewColItems.cpp b/Src/DirViewColItems.cpp index 05ba0655f..3946ad688 100644 --- a/Src/DirViewColItems.cpp +++ b/Src/DirViewColItems.cpp @@ -96,7 +96,13 @@ static int cmpfloat(double v1, double v2) static CString ColFileNameGet(const CDiffContext *, const void *p) //sfilename { const DIFFITEM &di = *static_cast(p); - return di.sfilename; + return + ( + di.sLeftFilename.IsEmpty() ? di.sRightFilename : + di.sRightFilename.IsEmpty() ? di.sLeftFilename : + di.sLeftFilename == di.sRightFilename ? di.sLeftFilename : + di.sLeftFilename + _T("|") + di.sRightFilename + ); } static CString ColNameGet(const CDiffContext *, const void *p) //sfilename { @@ -112,11 +118,30 @@ static CString ColExtGet(const CDiffContext *, const void *p) //sfilename } static CString ColPathGet(const CDiffContext *, const void *p) { - const CString &r = *static_cast(p); - if (r.IsEmpty()) - return _T("."); - else - return r; + const DIFFITEM &di = *static_cast(p); + CString s = di.sRightSubdir; + const CString &t = di.sLeftSubdir; + int i = 0, j = 0; + do + { + int i_ahead = s.Find('\\', i); + int j_ahead = t.Find('\\', j); + int length_s = (i_ahead != -1 ? i_ahead : s.GetLength()) - i; + int length_t = (j_ahead != -1 ? j_ahead : t.GetLength()) - j; + if (length_s != length_t || + !StrIsIntlEqual(FALSE, LPCTSTR(s) + i, LPCTSTR(t) + j, length_s)) + { + CString u(LPCTSTR(t) + j, length_t + 1); + u.SetAt(length_t, '|'); + s.Insert(i, u); + i_ahead += u.GetLength(); + } + i = i_ahead + 1; + j = j_ahead + 1; + } while (i && j); + if (s.IsEmpty()) + s = _T("."); + return s; } static CString ColStatusGet(const CDiffContext *pCtxt, const void *p) { @@ -302,18 +327,16 @@ static CString ColEncodingGet(const CDiffContext *, const void *p) * @name Functions to sort each type of column info. */ /* @{ */ -static int ColFileNameSort(const CDiffContext *, const void *p, const void *q) +static int ColFileNameSort(const CDiffContext *pCtxt, const void *p, const void *q) { const DIFFITEM &ldi = *static_cast(p); const DIFFITEM &rdi = *static_cast(q); - - if (ldi.isDirectory() && rdi.isDirectory()) - return ldi.sfilename.CompareNoCase(rdi.sfilename); - else if (ldi.isDirectory() && !rdi.isDirectory()) + if (ldi.isDirectory() && !rdi.isDirectory()) return -1; - else if (!ldi.isDirectory() && rdi.isDirectory()) + if (!ldi.isDirectory() && rdi.isDirectory()) return 1; - else return ldi.sfilename.CompareNoCase(rdi.sfilename); + return ColFileNameGet(pCtxt, p).CompareNoCase(ColFileNameGet(pCtxt, q)); + //return ldi.sLeftFilename.CompareNoCase(rdi.sLeftFilename); } static int ColNameSort(const CDiffContext *, const void *p, const void *q) { @@ -328,6 +351,10 @@ static int ColExtSort(const CDiffContext *pCtxt, const void *p, const void *q) return lstrcmpi(PathFindExtension(r), PathFindExtension(s)); //return ColExtGet(pCtxt, p).CompareNoCase(ColExtGet(pCtxt, q)); } +static int ColPathSort(const CDiffContext *pCtxt, const void *p, const void *q) +{ + return ColPathGet(pCtxt, p).CompareNoCase(ColPathGet(pCtxt, q)); +} static int ColStatusSort(const CDiffContext *, const void *p, const void *q) { const DIFFITEM &ldi = *static_cast(p); @@ -401,13 +428,13 @@ static int ColEncodingSort(const CDiffContext *, const void *p, const void *q) DirColInfo g_cols[] = { { _T("Name"), IDS_COLHDR_FILENAME, IDS_COLDESC_FILENAME, &ColFileNameGet, &ColFileNameSort, 0, 0, true, LVCFMT_LEFT }, - { _T("Path"), IDS_COLHDR_DIR, IDS_COLDESC_DIR, &ColPathGet, &ColNameSort, FIELD_OFFSET(DIFFITEM, sSubdir), 1, true, LVCFMT_LEFT }, + { _T("Path"), IDS_COLHDR_DIR, IDS_COLDESC_DIR, &ColPathGet, &ColPathSort, 0, 1, true, LVCFMT_LEFT }, { _T("Status"), IDS_COLHDR_RESULT, IDS_COLDESC_RESULT, &ColStatusGet, &ColStatusSort, 0, 2, true, LVCFMT_LEFT }, { _T("Lmtime"), IDS_COLHDR_LTIMEM, IDS_COLDESC_LTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, left.mtime), 3, false, LVCFMT_LEFT }, { _T("Rmtime"), IDS_COLHDR_RTIMEM, IDS_COLDESC_RTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, right.mtime), 4, false, LVCFMT_LEFT }, { _T("Lctime"), IDS_COLHDR_LTIMEC, IDS_COLDESC_LTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, left.ctime), -1, false, LVCFMT_LEFT }, { _T("Rctime"), IDS_COLHDR_RTIMEC, IDS_COLDESC_RTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, right.ctime), -1, false, LVCFMT_LEFT }, - { _T("Ext"), IDS_COLHDR_EXTENSION, IDS_COLDESC_EXTENSION, &ColExtGet, &ColExtSort, FIELD_OFFSET(DIFFITEM, sfilename), 5, true, LVCFMT_LEFT }, + { _T("Ext"), IDS_COLHDR_EXTENSION, IDS_COLDESC_EXTENSION, &ColExtGet, &ColExtSort, FIELD_OFFSET(DIFFITEM, sLeftFilename), 5, true, LVCFMT_LEFT }, { _T("Lsize"), IDS_COLHDR_LSIZE, IDS_COLDESC_LSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, left.size), -1, false, LVCFMT_RIGHT }, { _T("Rsize"), IDS_COLHDR_RSIZE, IDS_COLDESC_RSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, right.size), -1, false, LVCFMT_RIGHT }, { _T("Newer"), IDS_COLHDR_NEWER, IDS_COLDESC_NEWER, &ColNewerGet, &ColNewerSort, 0, -1, true, LVCFMT_LEFT }, diff --git a/Src/FileFilterHelper.h b/Src/FileFilterHelper.h index 155c30333..79aba09d4 100644 --- a/Src/FileFilterHelper.h +++ b/Src/FileFilterHelper.h @@ -62,6 +62,22 @@ class IDiffFilter public: virtual BOOL includeFile(LPCTSTR szFileName) = 0; virtual BOOL includeDir(LPCTSTR szDirName) = 0; + BOOL includeFile(LPCTSTR szFileName1, LPCTSTR szFileName2) + { + return + ( + (szFileName1[0] == '\0' || includeFile(szFileName1)) + && (szFileName2[0] == '\0' || includeFile(szFileName2)) + ); + } + BOOL includeDir(LPCTSTR szDirName1, LPCTSTR szDirName2) + { + return + ( + (szDirName1[0] == '\0' || includeDir(szDirName1)) + && (szDirName2[0] == '\0' || includeDir(szDirName2)) + ); + } }; /** diff --git a/Src/MainFrm.cpp b/Src/MainFrm.cpp index f79ebf202..c03a94533 100644 --- a/Src/MainFrm.cpp +++ b/Src/MainFrm.cpp @@ -225,7 +225,7 @@ CMainFrame::~CMainFrame() // destroy the reg expression list FreeRegExpList(); // Delete all temporary folders belonging to this process - CTempPath(0); + GetClearTempPath(NULL, NULL); delete m_pSyntaxColors; } @@ -1182,6 +1182,13 @@ void CMainFrame::OnOptions() BOOL CMainFrame::DoFileOpen(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL*/, DWORD dwLeftFlags /*=0*/, DWORD dwRightFlags /*=0*/, BOOL bRecurse /*=FALSE*/, CDirDoc *pDirDoc/*=NULL*/) { + // If the dirdoc we are supposed to use is busy doing a diff, bail out + if (IsComparing()) + return FALSE; + + if (pDirDoc && !pDirDoc->CloseMergeDocs()) + return FALSE; + CString strLeft(pszLeft); CString strRight(pszRight); PackingInfo infoUnpacker; @@ -1191,11 +1198,13 @@ BOOL CMainFrame::DoFileOpen(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL* BOOL bROLeft = dwLeftFlags & FFILEOPEN_READONLY; BOOL bRORight = dwRightFlags & FFILEOPEN_READONLY; - BOOL docNull; - - // If the dirdoc we are supposed to use is busy doing a diff, bail out - if (IsComparing()) - return FALSE; + // jtuc: docNull used to be uninitialized so you couldn't tell whether + // pDirDoc->ReusingDirDoc() would be called for passed-in pDirDoc. + // However, pDirDoc->ReusingDirDoc() kills temp path contexts, and I + // need to avoid that. This is why I'm initializing docNull to TRUE here. + // Note that call to pDirDoc->CloseMergeDocs() above preserves me from + // keeping orphaned MergeDocs in that case. + BOOL docNull = TRUE; // pop up dialog unless arguments exist (and are compatible) PATH_EXISTENCE pathsType = GetPairComparability(strLeft, strRight); @@ -1254,76 +1263,49 @@ BOOL CMainFrame::DoFileOpen(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL* bRecurse); } + CTempPathContext *pTempPathContext = NULL; try { // Handle archives using 7-zip - if (Merge7z::Format *piHandler = Merge7z->GuessFormat(strLeft)) + if (Merge7z::Format *piHandler = ArchiveGuessFormat(strLeft)) { + pTempPathContext = new CTempPathContext; + CString path = GetClearTempPath(pTempPathContext, _T("0")); + pTempPathContext->m_strLeftDisplayRoot = strLeft; + pTempPathContext->m_strRightDisplayRoot = strRight; pathsType = IS_EXISTING_DIR; - // Need DirDoc here to build temp path - if (!pDirDoc) - { - pDirDoc = GetDirDocToShow(&docNull); - } if (strRight == strLeft) { strRight.Empty(); } - CTempPath path = pDirDoc; do { if FAILED(piHandler->DeCompressArchive(m_hWnd, strLeft, path)) break; if (strLeft.Find(path) == 0) { - if (!::DeleteFile(strLeft)) - { - LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), - strLeft, GetSysError(GetLastError()))); - } - } - strLeft.Delete(0, strLeft.ReverseFind('\\')); - int dot = strLeft.ReverseFind('.'); - if (piHandler != &Merge7z->TarHandler && StrChr(_T("Tt"), strLeft[dot + 1])) - { - strLeft.GetBufferSetLength(dot + 2); - strLeft += _T("ar"); - } - else - { - strLeft.GetBufferSetLength(dot); + VERIFY(::DeleteFile(strLeft) || gLog::DeleteFileFailed(strLeft)); } + SysFreeString(Assign(strLeft, piHandler->GetDefaultName(m_hWnd, strLeft))); + strLeft.Insert(0, '\\'); strLeft.Insert(0, path); - } while (piHandler = Merge7z->GuessFormat(strLeft)); + } while (piHandler = ArchiveGuessFormat(strLeft)); strLeft = path; - if (Merge7z::Format *piHandler = Merge7z->GuessFormat(strRight)) + if (Merge7z::Format *piHandler = ArchiveGuessFormat(strRight)) { - path.MakeSibling(_T(".1")); + path = GetClearTempPath(pTempPathContext, _T("1")); do { if FAILED(piHandler->DeCompressArchive(m_hWnd, strRight, path)) break;; if (strRight.Find(path) == 0) { - if (!::DeleteFile(strRight)) - { - LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), - strRight, GetSysError(GetLastError()))); - } - } - strRight.Delete(0, strRight.ReverseFind('\\')); - int dot = strRight.ReverseFind('.'); - if (piHandler != &Merge7z->TarHandler && StrChr(_T("Tt"), strRight[dot + 1])) - { - strRight.GetBufferSetLength(dot + 2); - strRight += _T("ar"); - } - else - { - strRight.GetBufferSetLength(dot); + VERIFY(::DeleteFile(strRight) || gLog::DeleteFileFailed(strRight)); } + SysFreeString(Assign(strRight, piHandler->GetDefaultName(m_hWnd, strRight))); + strRight.Insert(0, '\\'); strRight.Insert(0, path); - } while (piHandler = Merge7z->GuessFormat(strRight)); + } while (piHandler = ArchiveGuessFormat(strRight)); strRight = path; } else if (strRight.IsEmpty()) @@ -1337,6 +1319,11 @@ BOOL CMainFrame::DoFileOpen(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL* // not a Perry style patch: diff with itself... strLeft = strRight = path; } + else + { + pTempPathContext->m_strLeftDisplayRoot += _T("\\ORIGINAL"); + pTempPathContext->m_strRightDisplayRoot += _T("\\ALTERED"); + } } } } @@ -1348,16 +1335,20 @@ BOOL CMainFrame::DoFileOpen(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL* // Determine if we want new a dirview open now that we know if it was // and archive. Don't open new dirview if we are comparing files. + BOOL bSetRootLenght = FALSE; if (!pDirDoc) { if (pathsType == IS_EXISTING_DIR) + { pDirDoc = GetDirDocToShow(&docNull); + bSetRootLenght = TRUE; + } else { pDirDoc = (CDirDoc*)theApp.m_pDirTemplate->CreateNewDocument(); docNull = TRUE; } - } + } if (!docNull) { @@ -1373,20 +1364,20 @@ BOOL CMainFrame::DoFileOpen(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL* if (pDirDoc) { PathContext paths(strLeft, strRight); - if (pDirDoc->InitCompare(paths, bRecurse)) - { - gLog.Write(LOGLEVEL::LNOTICE, _T("Open dirs: Left: %s\n\tRight: %s."), - strLeft, strRight); - - pDirDoc->SetReadOnly(TRUE, bROLeft); - pDirDoc->SetReadOnly(FALSE, bRORight); - pDirDoc->SetDescriptions(m_strLeftDesc, m_strRightDesc); - pDirDoc->SetTitle(NULL); - m_strLeftDesc.Empty(); - m_strRightDesc.Empty(); - - pDirDoc->Rescan(); - } + // Anything that can go wrong inside InitCompare() will yield an + // exception. There is no point in checking return value. + pDirDoc->InitCompare(paths, bRecurse, bSetRootLenght, pTempPathContext); + gLog.Write(LOGLEVEL::LNOTICE, _T("Open dirs: Left: %s\n\tRight: %s."), + strLeft, strRight); + + pDirDoc->SetReadOnly(TRUE, bROLeft); + pDirDoc->SetReadOnly(FALSE, bRORight); + pDirDoc->SetDescriptions(m_strLeftDesc, m_strRightDesc); + pDirDoc->SetTitle(NULL); + m_strLeftDesc.Empty(); + m_strRightDesc.Empty(); + + pDirDoc->Rescan(); } } else @@ -2176,10 +2167,10 @@ void CMainFrame::OnToolsGeneratePatch() CString leftFile = item.getLeftFilepath(pDoc->GetLeftBasePath()); if (!leftFile.IsEmpty()) - leftFile += _T("\\") + item.sfilename; + leftFile += _T("\\") + item.sLeftFilename; CString rightFile = item.getRightFilepath(pDoc->GetRightBasePath()); if (!rightFile.IsEmpty()) - rightFile += _T("\\") + item.sfilename; + rightFile += _T("\\") + item.sRightFilename; patcher.AddFiles(leftFile, rightFile); } diff --git a/Src/MergeDoc.cpp b/Src/MergeDoc.cpp index 8bcaed341..a116a16b3 100644 --- a/Src/MergeDoc.cpp +++ b/Src/MergeDoc.cpp @@ -2918,7 +2918,10 @@ void CMergeDoc::UpdateHeaderPath(BOOL bLeft) sText = m_strLeftDesc; } else + { sText = m_filePaths.GetLeft(); + m_pDirDoc->ApplyLeftDisplayRoot(sText); + } bChanges = m_ltBuf.IsModified(); nPane = 0; } @@ -2930,7 +2933,10 @@ void CMergeDoc::UpdateHeaderPath(BOOL bLeft) sText = m_strRightDesc; } else + { sText = m_filePaths.GetRight(); + m_pDirDoc->ApplyRightDisplayRoot(sText); + } bChanges = m_rtBuf.IsModified(); nPane = 1; } -- 2.11.0