OSDN Git Service

PATCH: [ 1229867 ] RFE [ 1205516 ], RFE [ 887948 ], and other issues (w/o command...
authorJochen Tucht <jtuc@users.sourceforge.net>
Fri, 15 Jul 2005 08:13:33 +0000 (08:13 +0000)
committerJochen Tucht <jtuc@users.sourceforge.net>
Fri, 15 Jul 2005 08:13:33 +0000 (08:13 +0000)
18 files changed:
Src/7zCommon.cpp
Src/7zCommon.h
Src/DiffContext.cpp
Src/DiffItem.cpp
Src/DiffItem.h
Src/DiffThread.cpp
Src/DiffWrapper.cpp
Src/DirActions.cpp
Src/DirDoc.cpp
Src/DirDoc.h
Src/DirScan.cpp
Src/DirScan.h
Src/DirView.cpp
Src/DirView.h
Src/DirViewColItems.cpp
Src/FileFilterHelper.h
Src/MainFrm.cpp
Src/MergeDoc.cpp

index b9ecc82..cdb441c 100644 (file)
@@ -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 <afxinet.h>
 #include <shlwapi.h>
@@ -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<TCHAR,4> 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;
 }
- //<winerror.h>
+
+/**
+ * @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;
                }
        }
index 8abfa06..f6393e6 100644 (file)
@@ -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()
index 5113ad9..d0aed12 100644 (file)
@@ -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) */
index 9090e0f..638aac1 100644 (file)
@@ -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;
 }
index 99dcbd5..79e9dd6 100644 (file)
@@ -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 */
 
index 2fdd08f..fa977d7 100644 (file)
@@ -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);
index ee054e5..1c71420 100644 (file)
@@ -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;
        }
 }
 
index 2257844..08a8b3a 100644 (file)
@@ -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
index dd54063..491de7e 100644 (file)
@@ -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);
        }       
 }
index c320a7c..7c9c419 100644 (file)
@@ -47,7 +47,7 @@ typedef CTypedPtrList<CPtrList, CMergeDoc *> 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}}
index dc1d135..f6a7e50 100644 (file)
@@ -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 (j<rightDirs.GetSize())
                        TRACE(_T("Candidate right: rightDirs[j]=%s\n"), (LPCTSTR)rightDirs[j].name);
-               if (i<leftDirs.GetSize() && (j==rightDirs.GetSize() || collstr(leftDirs[i].name, rightDirs[j].name, casesensitive)<0))
+               if (!bTreatDirAsEqual)
                {
-                       int nDiffCode = DIFFCODE::LEFT | DIFFCODE::DIR;
-
-                       // Advance left pointer over left-only entry, and then retest with new pointers
-                       AddToList(subdir, &leftDirs[i], 0, nDiffCode, pList, pCtxt);
-                       ++i;
-                       continue;
-               }
-               if (j<rightDirs.GetSize() && (i==leftDirs.GetSize() || collstr(leftDirs[i].name, rightDirs[j].name, casesensitive)>0))
-               {
-                       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 (i<leftDirs.GetSize() && (j==rightDirs.GetSize() || collstr(leftDirs[i].name, rightDirs[j].name, casesensitive)<0))
+                       {
+                               int nDiffCode = DIFFCODE::LEFT | DIFFCODE::DIR;
+                               AddToList(leftsubdir, rightsubdir, &leftDirs[i], 0, nDiffCode, pList, pCtxt);
+                               // Advance left pointer over left-only entry, and then retest with new pointers
+                               ++i;
+                               continue;
+                       }
+                       if (j<rightDirs.GetSize() && (i==leftDirs.GetSize() || collstr(leftDirs[i].name, rightDirs[j].name, casesensitive)>0))
+                       {
+                               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 (i<leftDirs.GetSize())
                {
                        ASSERT(j<rightDirs.GetSize());
-                       CString newsub = subprefix + leftDirs[i].name;
+                       if (!depth)
+                       {
+                               // 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
+                               const int nDiffCode = DIFFCODE::BOTH | DIFFCODE::DIR;
+                               AddToList(leftsubdir, rightsubdir, &leftDirs[i], &rightDirs[j], nDiffCode, pList, pCtxt);
+                       }
+                       else
                        {
-                               int nDiffCode = DIFFCODE::BOTH | DIFFCODE::DIR;
-                               if (!depth)
+                               // Recursive compare
+                               CString leftnewsub = leftsubprefix + leftDirs[i].name;
+                               // minimize memory footprint by having left/rightnewsub share CStringData if possible
+                               CString rightnewsub = OPTIMIZE_SHARE_CSTRINGDATA
+                               (
+                                       (LPCTSTR)leftsubprefix == (LPCTSTR)rightsubprefix
+                               &&      leftDirs[i].name == rightDirs[j].name ? leftnewsub :
+                               ) rightsubprefix + rightDirs[j].name;
+                               // 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(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<leftFiles.GetSize() && (j==rightFiles.GetSize() ||
                                collstr(leftFiles[i].name, rightFiles[j].name, casesensitive) < 0))
                {
-                       // Test against filter
-                       CString newsubfile = subprefix + leftFiles[i].name;
-                       int nDiffCode = DIFFCODE::LEFT | DIFFCODE::FILE;
-                       {
-                               AddToList(subdir, &leftFiles[i], 0, nDiffCode, pList, pCtxt);
-                       }
-
+                       const int nDiffCode = DIFFCODE::LEFT | DIFFCODE::FILE;
+                       AddToList(leftsubdir, rightsubdir, &leftFiles[i], 0, nDiffCode, pList, pCtxt);
                        // Advance left pointer over left-only entry, and then retest with new pointers
                        ++i;
                        continue;
@@ -203,12 +229,8 @@ int DirScan_GetItems(const PathContext &paths, const CString & subdir, DiffItemL
                if (j<rightFiles.GetSize() && (i==leftFiles.GetSize() ||
                                collstr(leftFiles[i].name, rightFiles[j].name, casesensitive) > 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 (i<leftFiles.GetSize())
                {
                        ASSERT(j<rightFiles.GetSize());
-                       CString newsubfile = subprefix + leftFiles[i].name;
-                       int nDiffCode = DIFFCODE::BOTH | DIFFCODE::FILE;
-
-                       AddToList(subdir, &leftFiles[i], &rightFiles[j], nDiffCode, pList, pCtxt);
-
+                       const int nDiffCode = DIFFCODE::BOTH | DIFFCODE::FILE;
+                       AddToList(leftsubdir, rightsubdir, &leftFiles[i], &rightFiles[j], nDiffCode, pList, pCtxt);
                        ++i;
                        ++j;
                        continue;
@@ -308,16 +327,14 @@ int DirScan_CompareItems(CDiffContext * pCtxt, IAbortable * piAbortable)
 void UpdateDiffItem(DIFFITEM & di, BOOL & bExists, CDiffContext *pCtxt)
 {
        struct _stat stats;
-       CString leftpath;
-       CString rightpath;
        BOOL bLeftExists = FALSE;
        BOOL bRightExists = FALSE;
 
        bExists = TRUE;
-       leftpath = di.getLeftFilepath(pCtxt->GetNormalizedLeft());
-       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);
index 15d1430..a09476f 100644 (file)
@@ -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);
index db34a09..3f8f2ee 100644 (file)
@@ -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");
                }
        }
index e6e929f..6f84ae2 100644 (file)
@@ -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);
index 05ba065..3946ad6 100644 (file)
@@ -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<const DIFFITEM*>(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<const CString*>(p);
-       if (r.IsEmpty())
-               return _T(".");
-       else
-               return r;
+       const DIFFITEM &di = *static_cast<const DIFFITEM*>(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<const DIFFITEM *>(p);
        const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(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<const DIFFITEM *>(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 },
index 155c303..79aba09 100644 (file)
@@ -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))
+               );
+       }
 };
 
 /**
index f79ebf2..c03a945 100644 (file)
@@ -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);
                }
index 8bcaed3..a116a16 100644 (file)
@@ -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;
        }