OSDN Git Service

Merge with stable
authorsdottaka <sdottaka@users.sourceforge.net>
Tue, 17 Feb 2015 06:29:04 +0000 (15:29 +0900)
committersdottaka <sdottaka@users.sourceforge.net>
Tue, 17 Feb 2015 06:29:04 +0000 (15:29 +0900)
1  2 
Src/7zCommon.cpp
Src/DiffItem.h
Src/DirActions.cpp
Src/DirActions.h
Src/DirDoc.cpp
Src/DirDoc.h
Src/DirView.cpp
Src/DirViewColItems.cpp
Translations/WinMerge/English.pot

 -/////////////////////////////////////////////////////////////////////////////
 -//    WinMerge:  an interactive diff/merge utility
 -//    Copyright (C) 1997-2000  Thingamahoochie Software
 -//    Author: Dean Grimm
 -//
 -//    This program is free software; you can redistribute it and/or modify
 -//    it under the terms of the GNU General Public License as published by
 -//    the Free Software Foundation; either version 2 of the License, or
 -//    (at your option) any later version.
 -//
 -//    This program is distributed in the hope that it will be useful,
 -//    but WITHOUT ANY WARRANTY; without even the implied warranty of
 -//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 -//    GNU General Public License for more details.
 -//
 -//    You should have received a copy of the GNU General Public License
 -//    along with this program; if not, write to the Free Software
 -//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 -//
 -/////////////////////////////////////////////////////////////////////////////
 -
 -/* 7zCommon.cpp: Implement 7z related classes and functions
 - * Copyright (c) 2003 Jochen Tucht
 - *
 - * Remarks:   Different versions of 7-Zip are interfaced through specific
 - *                    versions of Merge7z (Merge7z311.dll, Merge7z312.dll, etc.)
 - *                    WinMerge can either use an installed copy of the 7-Zip software,
 - *                    or fallback to a local set of 7-Zip DLLs, which are to be included
 - *                    in the WinMerge binary distribution.
 - *
 - *                    Fallback policies are as follows:
 - *
 - *                    1. Detect 7-Zip version installed (XXX).
 - *                    2. If there is a Merge7zXXX.dll, be happy to use it
 - *                    3. Detect 7-Zip version from WinMerge distribution (YYY).
 - *                    4. If there is a Merge7zYYY.dll, be happy to use it.
 - *                    5. Sorry, no way.
 - *
 - *                    These rules can be customized by setting a registry variable
 - *                    *Merge7z/Enable* of type DWORD to one of the following values:
 - *
 - *                    0 - Entirely disable 7-Zip integration.
 - *                    1 - Use installed 7-Zip if present. Otherwise, use local 7-Zip.
 - *                    2 - Always use local 7-Zip.
 - *
 -
 -Please mind 2. a) of the GNU General Public License, and log your changes below.
 -
 -DATE:         BY:                                     DESCRIPTION:
 -==========    ==================      ================================================
 -2003-12-09    Jochen Tucht            Created
 -2003-12-16    Jochen Tucht            Properly generate .tar.gz and .tar.bz2
 -2003-12-16    Jochen Tucht            Obtain long path to temporary folder
 -2004-01-20    Jochen Tucht            Complain only once if Merge7z*.dll is missing
 -2004-01-25    Jochen Tucht            Fix bad default for OPENFILENAME::nFilterIndex
 -2004-03-15    Jochen Tucht            Fix Visual Studio 2003 build issue
 -2004-04-13    Jochen Tucht            Avoid StrNCat to get away with shlwapi 4.70
 -2004-08-25    Jochen Tucht            More explicit error message
 -2004-10-17    Jochen Tucht            Leave decision whether to recurse into folders
 -                                                              to enumerator (Mask.Recurse)
 -2004-11-03    Jochen Tucht            FIX [1048997] as proposed by Kimmo 2004-11-02
 -2005-01-15    Jochen Tucht            Read 7-Zip version from 7zip_pad.xml
 -                                                              Set Merge7z UI language if DllBuild_Merge7z >= 9
 -2005-01-22    Jochen Tucht            Better explain what's present/missing/outdated
 -2005-02-05    Jochen Tucht            Fall back to IDD_MERGE7ZMISMATCH template from
 -                                                              .exe if .lang file isn't up to date.
 -2005-02-26    Jochen Tucht            Add download link to error message
 -2005-02-26    Jochen Tucht            Use WinAPI to obtain ISO language/region codes
 -2005-02-27    Jochen Tucht            FIX [1152375]
 -2005-04-24    Kimmo Varis                     Don't use DiffContext exported from DirView
 -2005-06-08    Kimmo Varis                     Use DIFFITEM, not reference to it (hopefully only
 -                                                              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.
 -2005-08-20    Jochen Tucht            Option to guess archive format by signature
 -                                                              Map extensions through ExternalArchiveFormat.ini
 -2005-08-23    Jochen Tucht            Option to entirely disable 7-Zip integration
 -2007-01-04    Kimmo Varis                     Convert using COptionsMgr for options.
 -2007-06-16    Jochen Neubeck          FIX [1723263] "Zip --> Both" operation...
 -2007-12-22    Jochen Neubeck          Fix Merge7z UI lang for new translation system
 -                                                              Change recommended version of 7-Zip to 4.57
 -2010-05-16    Jochen Neubeck          Read 7-Zip version from 7z.dll (which has long
 -                                                              ago replaced the various format and codec DLLs)
 -                                                              Change recommended version of 7-Zip to 4.65
 -*/
 -
 -// ID line follows -- this is updated by SVN
 -// $Id: 7zCommon.cpp 7169 2010-05-16 14:44:19Z jtuc $
 -
 -#include "stdafx.h"
 -#include "7zCommon.h"
 -#include <afxinet.h>
 -#include <shlwapi.h>
 -#include <paths.h>
 -#include "OptionsDef.h"
 -#include "OptionsMgr.h"
 -#include "Merge.h"            // DirDocFilter theApp GetOptionsMgr()
 -#include "resource.h"
 -#include "DirDoc.h"
 -//#include "ExternalArchiveFormat.h"
 -#include "version.h"
 -#include "Environment.h"
 -#include "Merge7zFormatRegister.h"
 -
 -#ifdef _DEBUG
 -#define new DEBUG_NEW
 -#undef THIS_FILE
 -static char THIS_FILE[] = __FILE__;
 -#endif
 -
 -/**
 - * @brief Proxy for Merge7z
 - */
 -static __declspec(thread) Merge7z::Proxy m_Merge7z =
 -{
 -      { 0, 0, DllBuild_Merge7z, },
 -      "Merge7z%u%02u"DECORATE_U".dll",
 -      "Merge7z",
 -      NULL
 -};
 -
 -std::vector<Merge7z::Format *(*)(const String& path)> Merge7zFormatRegister::optionalFormats;
 -
 -bool IsArchiveFile(const String& pszFile)
 -{
 -      try {
 -              Merge7z::Format *piHandler = ArchiveGuessFormat(pszFile);
 -              if (piHandler)
 -                      return TRUE;
 -              else
 -                      return FALSE;
 -      }
 -      catch (CException *e)
 -      {
 -              e->Delete();
 -              return FALSE;
 -      }
 -      return FALSE;
 -}
 -
 -/**
 - * @brief Wrap Merge7z::GuessFormat() to allow for some customizing:
 - * - Check if 7-Zip integration is enabled.
 - * - Check for filename extension mappings.
 - */
 -Merge7z::Format *ArchiveGuessFormat(const String& path)
 -{
 -      if (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE) == 0)
 -              return NULL;
 -      if (paths_IsDirectory(path))
 -              return NULL;
 -      String path2(path);
 -      // Map extensions through ExternalArchiveFormat.ini
 -      static TCHAR null[] = _T("");
 -      static const TCHAR section[] = _T("extensions");
 -      String entry = paths_FindExtension(path);
 -      TCHAR value[20];
 -      static LPCTSTR filename = NULL;
 -      if (filename == NULL)
 -      {
 -              TCHAR cPath[INTERNET_MAX_PATH_LENGTH];
 -              DWORD cchPath = SearchPath(NULL, _T("ExternalArchiveFormat.ini"), NULL,
 -                      INTERNET_MAX_PATH_LENGTH, cPath, NULL);
 -              filename = cchPath && cchPath < INTERNET_MAX_PATH_LENGTH ? StrDup(cPath) : null;
 -      }
 -      if (*filename &&
 -              GetPrivateProfileString(section, entry.c_str(), null, value, 20, filename) &&
 -              *value == '.')
 -      {
 -              // Remove end-of-line comments (in string returned from GetPrivateProfileString)
 -              // that is, remove semicolon & whatever follows it
 -              if (LPTSTR p = StrChr(value, ';'))
 -              {
 -                      *p = '\0';
 -                      StrTrim(value, _T(" \t"));
 -              }
 -              path2 = value;
 -      }
 -
 -      // PATCH [ 1229867 ] RFE [ 1205516 ], RFE [ 887948 ], and other issues
 -      // command line integration portion is not yet applied
 -      // so following code not yet valid, so temporarily commented out
 -      // Look for command line tool first
 -      /*Merge7z::Format *pFormat;
 -      if (CExternalArchiveFormat::GuessFormat(path, pFormat))
 -      {
 -              return pFormat;
 -      }*/
 -      // Default to Merge7z*.dll
 -
 -      try
 -      {
 -              Merge7z::Format *pFormat = m_Merge7z->GuessFormat(path2.c_str());
 -              if (!pFormat)
 -                      pFormat = Merge7zFormatRegister::GuessFormat(path2);
 -              return pFormat;
 -      }
 -      catch (...)
 -      {
 -              Merge7z::Format *pFormat = Merge7zFormatRegister::GuessFormat(path2);
 -              if (pFormat)
 -                      return pFormat;
 -              throw;
 -      }
 -}
 -
 -/**
 - * @brief Self-initializing raw C character buffer class.
 - */
 -template<class TYPE, size_t SIZE> struct CRawString
 -{
 -      enum { Size = SIZE };
 -      TYPE Data[SIZE];
 -      CRawString()
 -      {
 -              Data[0] = 0;
 -      }
 -};
 -
 -/**
 - * @brief Exception class for more explicit error message.
 - */
 -class C7ZipMismatchException : public CException
 -{
 -public:
 -      C7ZipMismatchException(DWORD dwVer7zInstalled, DWORD dwVer7zLocal, CException *pCause)
 -      {
 -              m_dwVer7zInstalled = dwVer7zInstalled;
 -              m_dwVer7zLocal = dwVer7zLocal;
 -              m_pCause = pCause;
 -      }
 -      ~C7ZipMismatchException()
 -      {
 -              if (m_pCause)
 -                      m_pCause->Delete();
 -      }
 -      virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0);
 -protected:
 -      DWORD m_dwVer7zInstalled;
 -      DWORD m_dwVer7zLocal;
 -      CException *m_pCause;
 -      BOOL m_bShowAllways;
 -      static const DWORD m_dwVer7zRecommended;
 -      static const TCHAR m_strRegistryKey[];
 -      static const TCHAR m_strDownloadURL[];
 -      static INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
 -      static DWORD FormatVersion(LPTSTR, LPTSTR, DWORD);
 -};
 -
 -/**
 - * @brief Recommended version of 7-Zip.
 - */
 -const DWORD C7ZipMismatchException::m_dwVer7zRecommended = DWORD MAKELONG(65,4);
 -
 -/**
 - * @brief Registry key for C7ZipMismatchException's ReportError() popup.
 - */
 -const TCHAR C7ZipMismatchException::m_strRegistryKey[] = _T("7ZipMismatch");
 -
 -/**
 - * @brief Download URL for C7ZipMismatchException's ReportError() popup.
 - */
 -const TCHAR C7ZipMismatchException::m_strDownloadURL[] = _T("https://sourceforge.net/project/showfiles.php?group_id=13216&package_id=143957");
 -
 -/**
 - * @brief Retrieve build number of given DLL.
 - */
 -static DWORD NTAPI GetDllBuild(LPCTSTR cPath)
 -{
 -      HMODULE hModule = LoadLibrary(cPath);
 -      DLLVERSIONINFO dvi;
 -      dvi.cbSize = sizeof dvi;
 -      dvi.dwBuildNumber = ~0UL;
 -      if (hModule)
 -      {
 -              dvi.dwBuildNumber = 0UL;
 -              DLLGETVERSIONPROC DllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hModule, "DllGetVersion");
 -              if (DllGetVersion)
 -              {
 -                      DllGetVersion(&dvi);
 -              }
 -              FreeLibrary(hModule);
 -      }
 -      return dvi.dwBuildNumber;
 -}
 -
 -/**
 - * @brief Format Merge7z version number and plugin name, and retrieve DllBuild.
 - */
 -DWORD C7ZipMismatchException::FormatVersion(LPTSTR pcVersion, LPTSTR pcPluginName, DWORD dwVersion)
 -{
 -      *pcVersion = '\0';
 -      *pcPluginName = '\0';
 -      if (dwVersion)
 -      {
 -              wsprintf
 -              (
 -                      pcVersion, _T("%u.%02u"),
 -                      UINT HIWORD(dwVersion),
 -                      UINT LOWORD(dwVersion)
 -              );
 -              wsprintf
 -              (
 -                      pcPluginName,
 -                      sizeof(TCHAR) == 1 ? _T("Merge7z%u%02u.dll") : _T("Merge7z%u%02uU.dll"),
 -                      UINT HIWORD(dwVersion),
 -                      UINT LOWORD(dwVersion)
 -              );
 -      }
 -      return GetDllBuild(pcPluginName);
 -}
 -
 -/**
 - * @brief Populate ListBox with names/revisions of DLLs matching given pattern.
 - */
 -static void NTAPI DlgDirListDLLs(HWND hWnd, LPTSTR cPattern, int nIDListBox)
 -{
 -      HDC hDC = GetDC(hWnd);
 -      HFONT hFont = (HFONT)SendDlgItemMessage(hWnd, nIDListBox, WM_GETFONT, 0, 0);
 -      int cxView = (int)SendDlgItemMessage(hWnd, nIDListBox, LB_GETHORIZONTALEXTENT, 0, 0) - 8;
 -      HGDIOBJ hObject = SelectObject(hDC, hFont);
 -      WIN32_FIND_DATA ff;
 -      HANDLE h = FindFirstFile(cPattern, &ff);
 -      if (h != INVALID_HANDLE_VALUE)
 -      {
 -              do
 -              {
 -                      PathRemoveFileSpec(cPattern);
 -                      PathAppend(cPattern, ff.cFileName);
 -                      wsprintf(ff.cFileName, _T(" (dllbuild %04u)"), GetDllBuild(cPattern));
 -                      lstrcat(cPattern, ff.cFileName);
 -                      int cxText = (int)(WORD)GetTabbedTextExtent(hDC, cPattern, lstrlen(cPattern), 0, 0);
 -                      if (cxView < cxText)
 -                              cxView = cxText;
 -                      SendDlgItemMessage(hWnd, nIDListBox, LB_ADDSTRING, 0, (LPARAM)cPattern);
 -              } while (FindNextFile(h, &ff));
 -              FindClose(h);
 -      }
 -      SelectObject(hDC, hObject);
 -      ReleaseDC(hWnd, hDC);
 -      SendDlgItemMessage(hWnd, nIDListBox, LB_SETHORIZONTALEXTENT, cxView + 8, 0);
 -}
 -
 -/**
 - * @brief OwnerDraw states from recent SDK.
 - */
 -#define ODS_NOACCEL         0x0100
 -#define ODS_NOFOCUSRECT     0x0200
 -
 -/**
 - * @brief WM_DRAWITEM notification handlers.
 - */
 -struct CDrawItemStruct : DRAWITEMSTRUCT
 -{
 -      typedef CDrawItemStruct *From;
 -      void DrawWebLinkButton();
 -};
 -
 -void CDrawItemStruct::DrawWebLinkButton()
 -{
 -      CRawString<TCHAR,INTERNET_MAX_PATH_LENGTH> cText;
 -      int cchText = ::GetWindowText(hwndItem, cText.Data, cText.Size);
 -      COLORREF clrText = RGB(0,0,255);
 -      if (::GetWindowLong(hwndItem, GWL_STYLE) & BS_LEFTTEXT)
 -      {
 -              clrText = RGB(128,0,128);
 -      }
 -      RECT rcText = rcItem;
 -      ::DrawText(hDC, cText.Data, cchText, &rcText, DT_LEFT|DT_CALCRECT);
 -      ::OffsetRect(&rcText, 1, 0);
 -      rcItem.right = rcText.right + 1;
 -      rcItem.bottom = rcText.bottom + 1;
 -      switch (itemAction)
 -      {
 -      case ODA_DRAWENTIRE:
 -              ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcItem, 0, 0, 0);
 -              ::SetBkMode(hDC, TRANSPARENT);
 -              ::SetTextColor(hDC, clrText);
 -              ::DrawText(hDC, cText.Data, cchText, &rcText, DT_LEFT);
 -              rcText.top = rcText.bottom - 1;
 -              ::SetBkColor(hDC, clrText);
 -              ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcText, 0, 0, 0);
 -              if (itemState & ODS_FOCUS)
 -              {
 -              case ODA_FOCUS:
 -                      if (!(itemState & ODS_NOFOCUSRECT))
 -                      {
 -                              ::SetTextColor(hDC, 0);
 -                              ::SetBkColor(hDC, RGB(255,255,255));
 -                              ::SetBkMode(hDC, OPAQUE);
 -                              DrawFocusRect(hDC, &rcItem);
 -                      }
 -              }
 -              break;
 -      }
 -}
 -
 -/**
 - * @brief Load a cursor from COMCTL32.DLL.
 - */
 -HCURSOR NTAPI CommCtrl_LoadCursor(LPCTSTR lpCursorName)
 -{
 -      HMODULE hModule = GetModuleHandle(_T("COMCTL32.DLL"));
 -      return hModule ? LoadCursor(hModule, lpCursorName) : NULL;
 -}
 -
 -/**
 - * @brief DLGPROC for C7ZipMismatchException's ReportError() popup.
 - */
 -INT_PTR CALLBACK C7ZipMismatchException::DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 -{
 -      switch (uMsg)
 -      {
 -              case WM_INITDIALOG:
 -              {
 -                      theApp.TranslateDialog(hWnd);
 -                      if (GetDlgItem(hWnd, 9001) == NULL)
 -                      {
 -                              // Dialog template isn't up to date. Give it a second chance.
 -                              EndDialog(hWnd, -1);
 -                              return FALSE;
 -                      }
 -                      C7ZipMismatchException *pThis = (C7ZipMismatchException *)lParam;
 -                      CRawString<TCHAR,2600> cText;
 -                      CRawString<TCHAR,80> cPresent, cMissing, cOutdated, cNone, cPlugin;
 -                      if (pThis->m_pCause)
 -                      {
 -                              pThis->m_pCause->GetErrorMessage(cText.Data, cText.Size);
 -                              SetDlgItemText(hWnd, 107, cText.Data);
 -                      }
 -                      else
 -                      {
 -                              GetDlgItemText(hWnd, 107, cText.Data, cText.Size);
 -                              switch (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE))
 -                              {
 -                              case 0:
 -                                      lstrcat(cText.Data, theApp.LoadString(IDS_MERGE7Z_ENABLE_0).c_str());
 -                                      break;
 -                              case 2:
 -                                      lstrcat(cText.Data, theApp.LoadString(IDS_MERGE7Z_ENABLE_2).c_str());
 -                                      break;
 -                              }
 -                              SetDlgItemText(hWnd, 107, cText.Data);
 -                      }
 -                      GetDlgItemText(hWnd, 112, cPresent.Data, cPresent.Size);
 -                      GetDlgItemText(hWnd, 122, cMissing.Data, cMissing.Size);
 -                      GetDlgItemText(hWnd, 132, cOutdated.Data, cOutdated.Size);
 -                      GetDlgItemText(hWnd, 120, cNone.Data, cNone.Size);
 -                      GetDlgItemText(hWnd, 102, cPlugin.Data, cPlugin.Size);
 -                      wsprintf(cText.Data, cPlugin.Data, DllBuild_Merge7z);
 -                      SetDlgItemText(hWnd, 102, cText.Data);
 -                      SetDlgItemText
 -                      (
 -                              hWnd, 109,
 -                              (
 -                                      pThis->m_dwVer7zRecommended == pThis->m_dwVer7zInstalled
 -                              ||      pThis->m_dwVer7zRecommended == pThis->m_dwVer7zLocal
 -                              ) ? cPresent.Data : cMissing.Data
 -                      );
 -                      DWORD dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zRecommended);
 -                      SetDlgItemText(hWnd, 110, *cText.Data ? cText.Data : cNone.Data);
 -                      SetDlgItemText(hWnd, 111, cPlugin.Data);
 -                      SetDlgItemText(hWnd, 112, *cPlugin.Data == '\0' ? cPlugin.Data :
 -                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);
 -                      dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zInstalled);
 -                      SetDlgItemText(hWnd, 120, *cText.Data ? cText.Data : cNone.Data);
 -                      SetDlgItemText(hWnd, 121, cPlugin.Data);
 -                      SetDlgItemText(hWnd, 122, *cPlugin.Data == '\0' ? cPlugin.Data :
 -                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);
 -                      dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zLocal);
 -                      SetDlgItemText(hWnd, 130, *cText.Data ? cText.Data : cNone.Data);
 -                      SetDlgItemText(hWnd, 131, cPlugin.Data);
 -                      SetDlgItemText(hWnd, 132, *cPlugin.Data == '\0' ? cPlugin.Data :
 -                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);
 -                      GetModuleFileName(0, cText.Data, MAX_PATH);
 -                      PathRemoveFileSpec(cText.Data);
 -                      PathAppend(cText.Data, _T("Merge7z*.dll"));
 -                      DlgDirListDLLs(hWnd, cText.Data, 105);
 -                      if (DWORD cchPath = GetEnvironmentVariable(_T("path"), 0, 0))
 -                      {
 -                              static const TCHAR cSep[] = _T(";");
 -                              LPTSTR pchPath = new TCHAR[cchPath];
 -                              GetEnvironmentVariable(_T("PATH"), pchPath, cchPath);
 -                              LPTSTR pchItem = pchPath;
 -                              while (int cchItem = StrCSpn(pchItem += StrSpn(pchItem, cSep), cSep))
 -                              {
 -                                      if (cchItem < MAX_PATH)
 -                                      {
 -                                              CopyMemory(cText.Data, pchItem, cchItem*sizeof*pchItem);
 -                                              cText.Data[cchItem] = 0;
 -                                              PathAppend(cText.Data, _T("Merge7z*.dll"));
 -                                              DlgDirListDLLs(hWnd, cText.Data, 105);
 -                                      }
 -                                      pchItem += cchItem;
 -                              }
 -                              delete[] pchPath;
 -                      }
 -                      if (SendDlgItemMessage(hWnd, 105, LB_GETCOUNT, 0, 0) == 0)
 -                      {
 -                              SendDlgItemMessage(hWnd, 105, LB_ADDSTRING, 0, (LPARAM) cNone.Data);
 -                      }
 -                      HICON hIcon = LoadIcon(0, IDI_EXCLAMATION);
 -                      SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
 -                      SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
 -                      if (pThis->m_bShowAllways)
 -                      {
 -                              ShowWindow(GetDlgItem(hWnd, 106), SW_HIDE);
 -                      }
 -              } return TRUE;
 -              case WM_DRAWITEM:
 -              {
 -                      switch (wParam)
 -                      {
 -                      case 108:
 -                              CDrawItemStruct::From(lParam)->DrawWebLinkButton();
 -                              break;
 -                      }
 -              } return TRUE;
 -              case WM_SETCURSOR:
 -              {
 -                      HCURSOR hCursor = 0;
 -                      switch (GetDlgCtrlID((HWND)wParam))
 -                      {
 -                      case 108:
 -                              hCursor = CommCtrl_LoadCursor(MAKEINTRESOURCE(108));
 -                              break;
 -                      }
 -                      if (hCursor)
 -                      {
 -                              SetCursor(hCursor);
 -                              SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1);
 -                              return TRUE;
 -                      }
 -              } return FALSE;
 -              case WM_COMMAND:
 -              {
 -                      switch (wParam)
 -                      {
 -                              case IDOK:
 -                              case IDCANCEL:
 -                              {
 -                                      LRESULT nDontShowAgain = SendDlgItemMessage(hWnd, 106, BM_GETCHECK, 0, 0);
 -                                      EndDialog(hWnd, MAKEWORD(IDOK, nDontShowAgain));
 -                              } break;
 -                              case 108:
 -                              {
 -                                      HINSTANCE h = ShellExecute(hWnd, _T("open"), m_strDownloadURL, 0, 0, SW_SHOWNORMAL);
 -                                      if ((UINT)h > 32)
 -                                      {
 -                                              LONG lStyle = ::GetWindowLong((HWND)lParam, GWL_STYLE);
 -                                              ::SetWindowLong((HWND)lParam, GWL_STYLE, lStyle|BS_LEFTTEXT);
 -                                              ::InvalidateRect((HWND)lParam, 0, TRUE);
 -                                      }
 -                                      else
 -                                      {
 -                                              MessageBeep(0);
 -                                      }
 -                              } break;
 -                      }
 -              } return TRUE;
 -      }
 -      return FALSE;
 -}
 -
 -/**
 - * @brief Tell user what went wrong and how she can help.
 - */
 -int C7ZipMismatchException::ReportError(UINT nType, UINT nMessageID)
 -{
 -      UINT_PTR response = -1;
 -      m_bShowAllways = nMessageID;
 -      if (!m_bShowAllways)
 -      {
 -              // Suppress error message in case 7-Zip is not installed.
 -              response =
 -              (
 -                      m_dwVer7zInstalled || m_dwVer7zLocal
 -              ?       (INT_PTR)(int)theApp.GetProfileInt(REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, -1)
 -              :       IDOK
 -              );
 -      }
 -      if (response == -1)
 -      {
 -              HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();
 -              response = DialogBoxParam(AfxGetResourceHandle(), MAKEINTRESOURCE(IDD_MERGE7ZMISMATCH), hwndOwner, DlgProc, (LPARAM)this);
 -              if (response == -1)
 -              {
 -                      response = DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_MERGE7ZMISMATCH), hwndOwner, DlgProc, (LPARAM)this);
 -                      ASSERT(response != -1);
 -              }
 -              if (HIBYTE(response) == 1)
 -              {
 -                      theApp.WriteProfileInt(REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, response = int LOBYTE(response));
 -              }
 -      }
 -      return response;
 -}
 -
 -/**
 - * @brief Check whether archive support is available.
 - */
 -int NTAPI HasZipSupport()
 -{
 -      static int HasZipSupport = -1;
 -      if (HasZipSupport == -1)
 -      {
 -              try
 -              {
 -                      m_Merge7z.operator->();
 -                      HasZipSupport = 1;
 -              }
 -              catch (CException *e)
 -              {
 -                      e->Delete();
 -                      HasZipSupport = 0;
 -              }
 -      }
 -      return HasZipSupport;
 -}
 -
 -/**
 - * @brief Tell user why archive support is not available.
 - */
 -void NTAPI Recall7ZipMismatchError()
 -{
 -      try
 -      {
 -              m_Merge7z.operator->();
 -      }
 -      catch (CException *e)
 -      {
 -              e->ReportError(MB_ICONEXCLAMATION, TRUE);
 -              e->Delete();
 -      }
 -}
 -
 -/**
 - * @brief Delete head of temp path context list, and return its parent context.
 - */
 -CTempPathContext *CTempPathContext::DeleteHead()
 -{
 -      CTempPathContext *pParent = m_pParent;
 -      delete this;
 -      return pParent;
 -}
 -
 -BOOL NTAPI IsMerge7zEnabled()
 -{
 -      return AfxGetApp()->GetProfileInt(_T("Merge7z"), _T("Enable"), 0);
 -}
 -
 -/**
 - * @brief Return installed or local version of 7-Zip.
 - */
 -DWORD NTAPI VersionOf7z(BOOL bLocal)
 -{
 -      TCHAR path[MAX_PATH];
 -      if (bLocal)
 -      {
 -              GetModuleFileName(0, path, sizeof path/sizeof*path);
 -              PathRemoveFileSpec(path);
 -      }
 -      else
 -      {
 -              static const TCHAR szSubKey[] = _T("Software\\7-Zip");
 -              static const TCHAR szValue[] = _T("Path");
 -              DWORD type = 0;
 -              DWORD size = sizeof path;
 -              SHGetValue(HKEY_LOCAL_MACHINE, szSubKey, szValue, &type, path, &size);
 -      }
 -      PathAppend(path, _T("7z.dll"));
 -      unsigned versionMS = 0;
 -      unsigned versionLS = 0;
 -      CVersionInfo(path).GetFixedFileVersion(versionMS, versionLS);
 -      return versionMS;
 -}
 -
 -/**
 - * @brief Access dll functions through proxy.
 - */
 -interface Merge7z *Merge7z::Proxy::operator->()
 -{
 -      // As long as the Merge7z*.DLL has not yet been loaded, Merge7z
 -      // [0] points to the name of the DLL (with placeholders for 7-
 -      // Zip major and minor version numbers). Once the DLL has been
 -      // loaded successfully, Merge7z[0] is set to NULL, causing the
 -      // if to fail on subsequent calls.
 -
 -      if (const char *format = Merge7z[0])
 -      {
 -              // Merge7z has not yet been loaded
 -
 -              char name[MAX_PATH];
 -              DWORD flags = ~0;
 -              CException *pCause = NULL;
 -              switch (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE))
 -              {
 -              case 1: //Use installed 7-Zip if present. Otherwise, use local 7-Zip.
 -                      if (DWORD ver = VersionOf7z(FALSE))
 -                      {
 -                              flags = Initialize::Default;
 -                              try
 -                              {
 -                                      wsprintfA(name, format, UINT HIWORD(ver), UINT LOWORD(ver));
 -                                      Merge7z[0] = name;
 -                                      stub.Load();
 -                                      break;
 -                              }
 -                              catch (CException *e)
 -                              {
 -                                      Merge7z[0] = format;
 -                                      pCause = e;
 -                              }
 -                      }
 -              case 2: //Always use local 7-Zip.
 -                      if (DWORD ver = VersionOf7z(TRUE))
 -                      {
 -                              flags = Initialize::Default | Initialize::Local7z;
 -                              try
 -                              {
 -                                      wsprintfA(name, format, UINT HIWORD(ver), UINT LOWORD(ver));
 -                                      Merge7z[0] = name;
 -                                      stub.Load();
 -                                      break;
 -                              }
 -                              catch (CException *e)
 -                              {
 -                                      Merge7z[0] = format;
 -                                      if (pCause) pCause->Delete();
 -                                      pCause = e;
 -                              }
 -                      }
 -              default:
 -                      throw new C7ZipMismatchException
 -                      (
 -                              VersionOf7z(FALSE),
 -                              VersionOf7z(TRUE),
 -                              pCause
 -                      );
 -              }
 -              LANGID wLangID = (LANGID)GetThreadLocale();
 -              flags |= wLangID << 16;
 -              if (GetOptionsMgr()->GetBool(OPT_ARCHIVE_PROBETYPE))
 -              {
 -                      flags |= Initialize::GuessFormatBySignature | Initialize::GuessFormatByExtension;
 -              }
 -              if (Merge7z[1])
 -                      ((interface Merge7z *)Merge7z[1])->Initialize(flags);
 -      }
 -      return ((interface Merge7z *)Merge7z[1]);
 -}
 -
 -/**
 - * @brief Tell Merge7z we are going to enumerate just 1 item.
 - */
 -UINT SingleItemEnumerator::Open()
 -{
 -      return 1;
 -}
 -
 -/**
 - * @brief Pass information about the item to Merge7z.
 - */
 -Merge7z::Envelope *SingleItemEnumerator::Enum(Item &item)
 -{
 -      item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.Recurse;
 -      item.Name = Name;
 -      item.FullPath = FullPath;
 -      return 0;
 -}
 -
 -/**
 - * @brief SingleFileEnumerator constructor.
 - */
 -SingleItemEnumerator::SingleItemEnumerator(LPCTSTR path, LPCTSTR FullPath, LPCTSTR Name)
 -: FullPath(FullPath)
 -, Name(Name)
 -{
 -}
 -
 -/**
 - * @brief Construct a CDirView::DirItemEnumerator.
 - *
 - * Argument *nFlags* controls operation as follows:
 - * LVNI_ALL:          Enumerate all items.
 - * LVNI_SELECTED:     Enumerate selected items only.
 - * Original:          Set folder prefix for first iteration to "original"
 - * Altered:                   Set folder prefix for second iteration to "altered"
 - * BalanceFolders:    Ensure that all nonempty folders on either side have a
 - *                                    corresponding folder on the other side, even if it is
 - *                                    empty (DirScan doesn't recurse into folders which
 - *                                    appear only on one side).
 - * DiffsOnly:         Enumerate diffs only.
 - */
 -CDirView::DirItemEnumerator::DirItemEnumerator(CDirView *pView, int nFlags)
 -: m_pView(pView)
 -, m_nFlags(nFlags)
 -{
 -      if (m_nFlags & Original)
 -      {
 -              m_rgFolderPrefix.push_back(_T("original"));
 -      }
 -      if (m_nFlags & Altered)
 -      {
 -              m_rgFolderPrefix.push_back(_T("altered"));
 -      }
 -      if (m_nFlags & BalanceFolders)
 -      {
 -              // Collect implied folders
 -              for (UINT i = Open() ; i-- ; )
 -              {
 -                      const DIFFITEM &di = Next();
 -                      if ((m_nFlags & DiffsOnly) && !m_pView->IsItemNavigableDiff(di))
 -                      {
 -                              continue;
 -                      }
 -                      if (m_bRight) 
 -                      {
 -                              // Enumerating items on right side
 -                              if (!di.diffcode.isSideFirstOnly())
 -                              {
 -                                      // Item is present on right side, i.e. folder is implied
 -                                      m_rgImpliedFoldersRight[di.diffFileInfo[1].path.get()] = PVOID(1);
 -                              }
 -                      }
 -                      else
 -                      {
 -                              // Enumerating items on left side
 -                              if (!di.diffcode.isSideSecondOnly())
 -                              {
 -                                      // Item is present on left side, i.e. folder is implied
 -                                      m_rgImpliedFoldersLeft[di.diffFileInfo[0].path.get()] = PVOID(1);
 -                              }
 -                      }
 -              }
 -      }
 -}
 -
 -/**
 - * @brief Initialize enumerator, return number of items to be enumerated.
 - */
 -UINT CDirView::DirItemEnumerator::Open()
 -{
 -      m_nIndex = -1;
 -      m_curFolderPrefix = m_rgFolderPrefix.begin();
 -      m_bRight = (m_nFlags & Right) != 0;
 -      size_t nrgFolderPrefix = m_rgFolderPrefix.size();
 -      if (nrgFolderPrefix)
 -      {
 -              m_strFolderPrefix = *m_curFolderPrefix++;
 -      }
 -      else
 -      {
 -              nrgFolderPrefix = 1;
 -      }
 -      return
 -      (
 -              m_nFlags & LVNI_SELECTED
 -      ?       pView(m_pView)->GetSelectedCount()
 -      :       pView(m_pView)->GetItemCount()
 -      ) * nrgFolderPrefix;
 -}
 -
 -/**
 - * @brief Return next item.
 - */
 -const DIFFITEM &CDirView::DirItemEnumerator::Next()
 -{
 -      enum {nMask = LVNI_FOCUSED|LVNI_SELECTED|LVNI_CUT|LVNI_DROPHILITED};
 -      while ((m_nIndex = pView(m_pView)->GetNextItem(m_nIndex, m_nFlags & nMask)) == -1)
 -      {
 -              m_strFolderPrefix = *m_curFolderPrefix++;
 -              m_bRight = TRUE;
 -      }
 -      return m_pView->GetDiffItem(m_nIndex);
 -}
 -
 -/**
 - * @brief Pass information about an item to Merge7z.
 - *
 - * Information is passed through struct Merge7z::DirItemEnumerator::Item.
 - * The *mask* member denotes which of the other members contain valid data.
 - * If *mask* is zero upon return, which will be the case if Enum() decides to
 - * leave the struct untouched, Merge7z will ignore the item.
 - * If Enum() allocates temporary storage for string members, it must also
 - * allocate an Envelope, providing a Free() method to free the temporary
 - * storage, along with the Envelope itself. The Envelope pointer is passed to
 - * Merge7z as the return value of the function. It is not meant to be a success
 - * indicator, so if no temporary storage is required, it is perfectly alright
 - * to return NULL.
 - */
 -Merge7z::Envelope *CDirView::DirItemEnumerator::Enum(Item &item)
 -{
 -      CDirDoc * pDoc = m_pView->GetDocument();
 -      const DIFFITEM &di = Next();
 -
 -      if ((m_nFlags & DiffsOnly) && !m_pView->IsItemNavigableDiff(di))
 -      {
 -              return 0;
 -      }
 -
 -      bool isSideFirst = di.diffcode.isSideFirstOnly();
 -      bool isSideSecond = di.diffcode.isSideSecondOnly();
 -
 -      Envelope *envelope = new Envelope;
 -
 -      const String &sFilename = m_bRight ? di.diffFileInfo[1].filename : di.diffFileInfo[0].filename;
 -      const String &sSubdir = m_bRight ? di.diffFileInfo[1].path : di.diffFileInfo[0].path;
 -      envelope->Name = sFilename;
 -      if (sSubdir.length())
 -      {
 -              envelope->Name.insert(0, _T("\\"));
 -              envelope->Name.insert(0, sSubdir);
 -      }
 -      envelope->FullPath = sFilename;
 -      envelope->FullPath.insert(0, _T("\\"));
 -      envelope->FullPath.insert(0, m_bRight ?
 -      di.getFilepath(1, pDoc->GetBasePath(1)) :
 -      di.getFilepath(0, pDoc->GetBasePath(0)));
 -
 -      UINT32 Recurse = item.Mask.Recurse;
 -
 -      if (m_nFlags & BalanceFolders)
 -      {
 -              if (m_bRight)
 -              {
 -                      // Enumerating items on right side
 -                      if (isSideFirst)
 -                      {
 -                              // Item is missing on right side
 -                              PVOID &implied = m_rgImpliedFoldersRight[di.diffFileInfo[0].path.get()];
 -                              if (!implied)
 -                              {
 -                                      // Folder is not implied by some other file, and has
 -                                      // not been enumerated so far, so enumerate it now!
 -                                      envelope->Name = di.diffFileInfo[0].path;
 -                                      envelope->FullPath = di.getFilepath(0, pDoc->GetBasePath(0));
 -                                      implied = PVOID(2); // Don't enumerate same folder twice!
 -                                      isSideFirst = false;
 -                                      Recurse = 0;
 -                              }
 -                      }
 -              }
 -              else
 -              {
 -                      // Enumerating items on left side
 -                      if (isSideSecond)
 -                      {
 -                              // Item is missing on left side
 -                              PVOID &implied = m_rgImpliedFoldersLeft[di.diffFileInfo[1].path.get()];
 -                              if (!implied)
 -                              {
 -                                      // Folder is not implied by some other file, and has
 -                                      // not been enumerated so far, so enumerate it now!
 -                                      envelope->Name = di.diffFileInfo[1].path;
 -                                      envelope->FullPath = di.getFilepath(1, pDoc->GetBasePath(1));
 -                                      implied = PVOID(2); // Don't enumerate same folder twice!
 -                                      isSideSecond = false;
 -                                      Recurse = 0;
 -                              }
 -                      }
 -              }
 -      }
 -
 -      if (m_bRight ? isSideFirst : isSideSecond)
 -      {
 -              return envelope;
 -      }
 -
 -      if (m_strFolderPrefix.length())
 -      {
 -              if (envelope->Name.length())
 -                      envelope->Name.insert(0, _T("\\"));
 -              envelope->Name.insert(0, m_strFolderPrefix);
 -      }
 -
 -      item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.CheckIfPresent|Recurse;
 -      item.Name = envelope->Name.c_str();
 -      item.FullPath = envelope->FullPath.c_str();
 -      return envelope;
 -}
 -
 -/**
 - * @brief Apply appropriate handlers from left to right.
 - */
 -bool CDirView::DirItemEnumerator::MultiStepCompressArchive(LPCTSTR path)
 -{
 -      DeleteFile(path);
 -      Merge7z::Format *piHandler = ArchiveGuessFormat(path);
 -      if (piHandler)
 -      {
 -              HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();
 -              CString pathIntermediate;
 -              SysFreeString(Assign(pathIntermediate, piHandler->GetDefaultName(hwndOwner, path)));
 -              String pathPrepend = path;
 -              pathPrepend.resize(pathPrepend.rfind('\\') + 1);
 -              pathIntermediate.Insert(0, pathPrepend.c_str());
 -              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.
 - */
 -void CDirView::DirItemEnumerator::CompressArchive(LPCTSTR path)
 -{
 -      String strPath;
 -      if (path == 0)
 -      {
 -              // No path given, so prompt for path!
 -              static const TCHAR _T_Merge7z[] = _T("Merge7z");
 -              static const TCHAR _T_FilterIndex[] = _T("FilterIndex");
 -              // 7z311 can only write 7z, zip, and tar(.gz|.bz2) archives, so don't
 -              // offer other formats here!
 -              static const TCHAR _T_Filter[]
 -              (
 -                      _T("7z|*.7z|")
 -                      //_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("|")
 -              );
 -              String strFilter; // = CExternalArchiveFormat::GetOpenFileFilterString();
 -              strFilter.insert(0, _T_Filter);
 -              strFilter += _T("|");
 -              CFileDialog dlg
 -              (
 -                      FALSE,
 -                      0,
 -                      0,
 -                      OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN,
 -                      strFilter.c_str()
 -              );
 -              dlg.m_ofn.nFilterIndex = AfxGetApp()->GetProfileInt(_T_Merge7z, _T_FilterIndex, 1);
 -              // Use extension from current filter as default extension:
 -              if (int i = dlg.m_ofn.nFilterIndex)
 -              {
 -                      dlg.m_ofn.lpstrDefExt = dlg.m_ofn.lpstrFilter;
 -                      while (*dlg.m_ofn.lpstrDefExt && --i)
 -                      {
 -                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 1;
 -                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 1;
 -                      }
 -                      if (*dlg.m_ofn.lpstrDefExt)
 -                      {
 -                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 3;
 -                      }
 -              }
 -              if (dlg.DoModal() == IDOK)
 -              {
 -                      strPath = dlg.GetPathName();
 -                      path = strPath.c_str();
 -                      AfxGetApp()->WriteProfileInt(_T_Merge7z, _T_FilterIndex, dlg.m_ofn.nFilterIndex);
 -              }
 -      }
 -      if (path && !MultiStepCompressArchive(path))
 -      {
 -              LangMessageBox(IDS_UNKNOWN_ARCHIVE_FORMAT, MB_ICONEXCLAMATION);
 -      }
 -}
 -
 -/**
 - * @brief Collect files for SHFileOperation
 - */
 -void CDirView::DirItemEnumerator::CollectFiles(String &strBuffer)
 -{
 -      CDirDoc *pDoc = m_pView->GetDocument();
 -      const String sLeftRootPath = pDoc->GetBasePath(0);
 -      const String sRightRootPath = pDoc->GetBasePath(1);
 -      UINT i;
 -      int cchBuffer = 0;
 -      for (i = Open() ; i-- ; )
 -      {
 -              const DIFFITEM &di = Next();
 -              if (m_bRight ? m_pView->IsItemOpenableOnRightWith(di) : m_pView->IsItemOpenableOnLeftWith(di))
 -              {
 -                      cchBuffer +=
 -                      (
 -                              m_bRight ? di.getFilepath(1, sLeftRootPath) : di.getFilepath(0, sRightRootPath)
 -                      ).length() + (m_bRight ? di.diffFileInfo[1].filename : di.diffFileInfo[0].filename).get().length() + 2;
 -              }
 -      }
 -      strBuffer.resize(cchBuffer + 1);
 -      LPTSTR pchBuffer = &strBuffer[0];
 -      for (i = Open() ; i-- ; )
 -      {
 -              const DIFFITEM &di = Next();
 -              if (m_bRight ? m_pView->IsItemOpenableOnRightWith(di) : m_pView->IsItemOpenableOnLeftWith(di))
 -              {
 -                      pchBuffer += wsprintf
 -                      (
 -                              pchBuffer,
 -                              _T("%s\\%s"),
 -                              m_bRight ? di.getFilepath(1, sLeftRootPath).c_str() : di.getFilepath(0, sRightRootPath).c_str(),
 -                              m_bRight ? di.diffFileInfo[1].filename.get().c_str() : di.diffFileInfo[0].filename.get().c_str()
 -                      ) + 1;
 -              }
 -      }
 -      ASSERT(pchBuffer - &strBuffer[0] == cchBuffer);
 -}
 -
 -DecompressResult DecompressArchive(HWND hWnd, const PathContext& files)
 -{
 -      DecompressResult res(files, NULL, IS_EXISTING_DIR);
 -      try
 -      {
 -              String path;
 -              USES_CONVERSION;
 -              // Handle archives using 7-zip
 -              Merge7z::Format *piHandler;
 -              if (piHandler = ArchiveGuessFormat(res.files[0].c_str()))
 -              {
 -                      res.pTempPathContext = new CTempPathContext;
 -                      path = env_GetTempChildPath();
 -                      for (int index = 0; index < res.files.GetSize(); index++)
 -                              res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];
 -                      if (res.files.GetSize() == 2 && res.files[0] == res.files[1])
 -                              res.files[1].erase();
 -                      do
 -                      {
 -                              if (FAILED(piHandler->DeCompressArchive(hWnd, res.files[0].c_str(), path.c_str())))
 -                                      break;
 -                              if (res.files[0].find(path) == 0)
 -                              {
 -                                      VERIFY(::DeleteFile(res.files[0].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[0].c_str())), false));
 -                              }
 -                              BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[0].c_str());
 -                              res.files[0] = OLE2T(pTmp);
 -                              SysFreeString(pTmp);
 -                              res.files[0].insert(0, _T("\\"));
 -                              res.files[0].insert(0, path);
 -                      } while (piHandler = ArchiveGuessFormat(res.files[0].c_str()));
 -                      res.files[0] = path;
 -              }
 -              if (!res.files[1].empty() && (piHandler = ArchiveGuessFormat(res.files[1].c_str())))
 -              {
 -                      if (!res.pTempPathContext)
 -                      {
 -                              res.pTempPathContext = new CTempPathContext;
 -                              for (int index = 0; index < res.files.GetSize(); index++)
 -                                      res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];
 -                      }
 -                      path = env_GetTempChildPath();
 -                      do
 -                      {
 -                              if (FAILED(piHandler->DeCompressArchive(hWnd, res.files[1].c_str(), path.c_str())))
 -                                      break;;
 -                              if (res.files[1].find(path) == 0)
 -                              {
 -                                      VERIFY(::DeleteFile(res.files[1].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[1].c_str())), false));
 -                              }
 -                              BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[1].c_str());
 -                              res.files[1] = OLE2T(pTmp);
 -                              SysFreeString(pTmp);
 -                              res.files[1].insert(0, _T("\\"));
 -                              res.files[1].insert(0, path);
 -                      } while (piHandler = ArchiveGuessFormat(res.files[1].c_str()));
 -                      res.files[1] = path;
 -              }
 -              if (res.files.GetSize() > 2 && (piHandler = ArchiveGuessFormat(res.files[2].c_str())))
 -              {
 -                      if (!res.pTempPathContext)
 -                      {
 -                              res.pTempPathContext = new CTempPathContext;
 -                              for (int index = 0; index < res.files.GetSize(); index++)
 -                                      res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];
 -                      }
 -                      path = env_GetTempChildPath();
 -                      do
 -                      {
 -                              if (FAILED(piHandler->DeCompressArchive(hWnd, res.files[2].c_str(), path.c_str())))
 -                                      break;;
 -                              if (res.files[2].find(path) == 0)
 -                              {
 -                                      VERIFY(::DeleteFile(res.files[2].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[2].c_str())), false));
 -                              }
 -                              BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[1].c_str());
 -                              res.files[2] = OLE2T(pTmp);
 -                              SysFreeString(pTmp);
 -                              res.files[2].insert(0, _T("\\"));
 -                              res.files[2].insert(0, path);
 -                      } while (piHandler = ArchiveGuessFormat(res.files[2].c_str()));
 -                      res.files[2] = path;
 -              }
 -              if (res.files[1].empty())
 -              {
 -                      // assume Perry style patch
 -                      res.files[1] = path;
 -                      res.files[0] += _T("\\ORIGINAL");
 -                      res.files[1] += _T("\\ALTERED");
 -                      if (!PathFileExists(res.files[0].c_str()) || !PathFileExists(res.files[1].c_str()))
 -                      {
 -                              // not a Perry style patch: diff with itself...
 -                              res.files[0] = res.files[1] = path;
 -                      }
 -                      else
 -                      {
 -                              res.pTempPathContext->m_strDisplayRoot[0] += _T("\\ORIGINAL");
 -                              res.pTempPathContext->m_strDisplayRoot[1] += _T("\\ALTERED");
 -                      }
 -              }
 -      }
 -      catch (CException *e)
 -      {
 -              e->ReportError(MB_ICONSTOP);
 -              e->Delete();
 -      }
 -      return res;
 -}
 -
 +/////////////////////////////////////////////////////////////////////////////\r
 +//    WinMerge:  an interactive diff/merge utility\r
 +//    Copyright (C) 1997-2000  Thingamahoochie Software\r
 +//    Author: Dean Grimm\r
 +//\r
 +//    This program is free software; you can redistribute it and/or modify\r
 +//    it under the terms of the GNU General Public License as published by\r
 +//    the Free Software Foundation; either version 2 of the License, or\r
 +//    (at your option) any later version.\r
 +//\r
 +//    This program is distributed in the hope that it will be useful,\r
 +//    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
 +//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
 +//    GNU General Public License for more details.\r
 +//\r
 +//    You should have received a copy of the GNU General Public License\r
 +//    along with this program; if not, write to the Free Software\r
 +//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
 +//\r
 +/////////////////////////////////////////////////////////////////////////////\r
 +\r
 +/* 7zCommon.cpp: Implement 7z related classes and functions\r
 + * Copyright (c) 2003 Jochen Tucht\r
 + *\r
 + * Remarks:   Different versions of 7-Zip are interfaced through specific\r
 + *                    versions of Merge7z (Merge7z311.dll, Merge7z312.dll, etc.)\r
 + *                    WinMerge can either use an installed copy of the 7-Zip software,\r
 + *                    or fallback to a local set of 7-Zip DLLs, which are to be included\r
 + *                    in the WinMerge binary distribution.\r
 + *\r
 + *                    Fallback policies are as follows:\r
 + *\r
 + *                    1. Detect 7-Zip version installed (XXX).\r
 + *                    2. If there is a Merge7zXXX.dll, be happy to use it\r
 + *                    3. Detect 7-Zip version from WinMerge distribution (YYY).\r
 + *                    4. If there is a Merge7zYYY.dll, be happy to use it.\r
 + *                    5. Sorry, no way.\r
 + *\r
 + *                    These rules can be customized by setting a registry variable\r
 + *                    *Merge7z/Enable* of type DWORD to one of the following values:\r
 + *\r
 + *                    0 - Entirely disable 7-Zip integration.\r
 + *                    1 - Use installed 7-Zip if present. Otherwise, use local 7-Zip.\r
 + *                    2 - Always use local 7-Zip.\r
 + *\r
 +\r
 +Please mind 2. a) of the GNU General Public License, and log your changes below.\r
 +\r
 +DATE:         BY:                                     DESCRIPTION:\r
 +==========    ==================      ================================================\r
 +2003-12-09    Jochen Tucht            Created\r
 +2003-12-16    Jochen Tucht            Properly generate .tar.gz and .tar.bz2\r
 +2003-12-16    Jochen Tucht            Obtain long path to temporary folder\r
 +2004-01-20    Jochen Tucht            Complain only once if Merge7z*.dll is missing\r
 +2004-01-25    Jochen Tucht            Fix bad default for OPENFILENAME::nFilterIndex\r
 +2004-03-15    Jochen Tucht            Fix Visual Studio 2003 build issue\r
 +2004-04-13    Jochen Tucht            Avoid StrNCat to get away with shlwapi 4.70\r
 +2004-08-25    Jochen Tucht            More explicit error message\r
 +2004-10-17    Jochen Tucht            Leave decision whether to recurse into folders\r
 +                                                              to enumerator (Mask.Recurse)\r
 +2004-11-03    Jochen Tucht            FIX [1048997] as proposed by Kimmo 2004-11-02\r
 +2005-01-15    Jochen Tucht            Read 7-Zip version from 7zip_pad.xml\r
 +                                                              Set Merge7z UI language if DllBuild_Merge7z >= 9\r
 +2005-01-22    Jochen Tucht            Better explain what's present/missing/outdated\r
 +2005-02-05    Jochen Tucht            Fall back to IDD_MERGE7ZMISMATCH template from\r
 +                                                              .exe if .lang file isn't up to date.\r
 +2005-02-26    Jochen Tucht            Add download link to error message\r
 +2005-02-26    Jochen Tucht            Use WinAPI to obtain ISO language/region codes\r
 +2005-02-27    Jochen Tucht            FIX [1152375]\r
 +2005-04-24    Kimmo Varis                     Don't use DiffContext exported from DirView\r
 +2005-06-08    Kimmo Varis                     Use DIFFITEM, not reference to it (hopefully only\r
 +                                                              temporarily, to sort out new directory compare)\r
 +2005-06-22    Jochen Tucht            Change recommended version of 7-Zip to 4.20\r
 +                                                              Remove noise from Nagbox\r
 +2005-07-03    Jochen Tucht            DIFFITEM has changed due to RFE [ 1205516 ]\r
 +2005-07-04    Jochen Tucht            New global ArchiveGuessFormat() checks for\r
 +                                                              formats to be handled by external command line\r
 +                                                              tools. These take precedence over Merge7z\r
 +                                                              internal handlers.\r
 +2005-07-05    Jochen Tucht            Move to Merge7z::Format::GetDefaultName() to\r
 +                                                              build intermediate filenames for multi-step\r
 +                                                              compression.\r
 +2005-07-15    Jochen Tucht            Remove external command line tool integration\r
 +                                                              for now. Rethink about it after 2.4 branch.\r
 +2005-08-20    Jochen Tucht            Option to guess archive format by signature\r
 +                                                              Map extensions through ExternalArchiveFormat.ini\r
 +2005-08-23    Jochen Tucht            Option to entirely disable 7-Zip integration\r
 +2007-01-04    Kimmo Varis                     Convert using COptionsMgr for options.\r
 +2007-06-16    Jochen Neubeck          FIX [1723263] "Zip --> Both" operation...\r
 +2007-12-22    Jochen Neubeck          Fix Merge7z UI lang for new translation system\r
 +                                                              Change recommended version of 7-Zip to 4.57\r
 +2010-05-16    Jochen Neubeck          Read 7-Zip version from 7z.dll (which has long\r
 +                                                              ago replaced the various format and codec DLLs)\r
 +                                                              Change recommended version of 7-Zip to 4.65\r
 +*/\r
 +\r
 +// ID line follows -- this is updated by SVN\r
 +// $Id: 7zCommon.cpp 7169 2010-05-16 14:44:19Z jtuc $\r
 +\r
 +#include "stdafx.h"\r
 +#include "7zCommon.h"\r
 +#include <afxinet.h>\r
 +#include <shlwapi.h>\r
 +#include "OptionsDef.h"\r
 +#include "OptionsMgr.h"\r
 +#include "Merge.h"            // DirDocFilter theApp GetOptionsMgr()\r
 +#include "resource.h"\r
 +#include "DirView.h"\r
 +#include "DirDoc.h"\r
 +#include "DirActions.h"\r
 +//#include "ExternalArchiveFormat.h"\r
 +#include "version.h"\r
 +#include "paths.h"\r
 +#include "Environment.h"\r
 +#include "Merge7zFormatRegister.h"\r
 +\r
 +#ifdef _DEBUG\r
 +#define new DEBUG_NEW\r
 +#undef THIS_FILE\r
 +static char THIS_FILE[] = __FILE__;\r
 +#endif\r
 +\r
 +/**\r
 + * @brief Proxy for Merge7z\r
 + */\r
 +static __declspec(thread) Merge7z::Proxy m_Merge7z =\r
 +{\r
 +      { 0, 0, DllBuild_Merge7z, },\r
 +      "Merge7z%u%02u"DECORATE_U".dll",\r
 +      "Merge7z",\r
 +      NULL\r
 +};\r
 +\r
 +std::vector<Merge7z::Format *(*)(const String& path)> Merge7zFormatRegister::optionalFormats;\r
 +\r
 +/**\r
 + * @brief assign BSTR to String, and return BSTR for optional SysFreeString()\r
 + */\r
 +inline BSTR Assign(CString &dst, BSTR src)\r
 +{\r
 +      dst = src;\r
 +      return src;\r
 +}\r
 +\r
 +bool IsArchiveFile(const String& pszFile)\r
 +{\r
 +      try {\r
 +              Merge7z::Format *piHandler = ArchiveGuessFormat(pszFile);\r
 +              if (piHandler)\r
 +                      return TRUE;\r
 +              else\r
 +                      return FALSE;\r
 +      }\r
 +      catch (CException *e)\r
 +      {\r
 +              e->Delete();\r
 +              return FALSE;\r
 +      }\r
 +      return FALSE;\r
 +}\r
 +\r
 +/**\r
 + * @brief Wrap Merge7z::GuessFormat() to allow for some customizing:\r
 + * - Check if 7-Zip integration is enabled.\r
 + * - Check for filename extension mappings.\r
 + */\r
 +Merge7z::Format *ArchiveGuessFormat(const String& path)\r
 +{\r
 +      if (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE) == 0)\r
 +              return NULL;\r
 +      if (paths_IsDirectory(path))\r
 +              return NULL;\r
 +      String path2(path);\r
 +      // Map extensions through ExternalArchiveFormat.ini\r
 +      static TCHAR null[] = _T("");\r
 +      static const TCHAR section[] = _T("extensions");\r
 +      String entry = paths_FindExtension(path);\r
 +      TCHAR value[20];\r
 +      static LPCTSTR filename = NULL;\r
 +      if (filename == NULL)\r
 +      {\r
 +              TCHAR cPath[INTERNET_MAX_PATH_LENGTH];\r
 +              DWORD cchPath = SearchPath(NULL, _T("ExternalArchiveFormat.ini"), NULL,\r
 +                      INTERNET_MAX_PATH_LENGTH, cPath, NULL);\r
 +              filename = cchPath && cchPath < INTERNET_MAX_PATH_LENGTH ? StrDup(cPath) : null;\r
 +      }\r
 +      if (*filename &&\r
 +              GetPrivateProfileString(section, entry.c_str(), null, value, 20, filename) &&\r
 +              *value == '.')\r
 +      {\r
 +              // Remove end-of-line comments (in string returned from GetPrivateProfileString)\r
 +              // that is, remove semicolon & whatever follows it\r
 +              if (LPTSTR p = StrChr(value, ';'))\r
 +              {\r
 +                      *p = '\0';\r
 +                      StrTrim(value, _T(" \t"));\r
 +              }\r
 +              path2 = value;\r
 +      }\r
 +\r
 +      // PATCH [ 1229867 ] RFE [ 1205516 ], RFE [ 887948 ], and other issues\r
 +      // command line integration portion is not yet applied\r
 +      // so following code not yet valid, so temporarily commented out\r
 +      // Look for command line tool first\r
 +      /*Merge7z::Format *pFormat;\r
 +      if (CExternalArchiveFormat::GuessFormat(path, pFormat))\r
 +      {\r
 +              return pFormat;\r
 +      }*/\r
 +      // Default to Merge7z*.dll\r
 +\r
 +      try\r
 +      {\r
 +              Merge7z::Format *pFormat = m_Merge7z->GuessFormat(path2.c_str());\r
 +              if (!pFormat)\r
 +                      pFormat = Merge7zFormatRegister::GuessFormat(path2);\r
 +              return pFormat;\r
 +      }\r
 +      catch (...)\r
 +      {\r
 +              Merge7z::Format *pFormat = Merge7zFormatRegister::GuessFormat(path2);\r
 +              if (pFormat)\r
 +                      return pFormat;\r
 +              throw;\r
 +      }\r
 +}\r
 +\r
 +/**\r
 + * @brief Self-initializing raw C character buffer class.\r
 + */\r
 +template<class TYPE, size_t SIZE> struct CRawString\r
 +{\r
 +      enum { Size = SIZE };\r
 +      TYPE Data[SIZE];\r
 +      CRawString()\r
 +      {\r
 +              Data[0] = 0;\r
 +      }\r
 +};\r
 +\r
 +/**\r
 + * @brief Exception class for more explicit error message.\r
 + */\r
 +class C7ZipMismatchException : public CException\r
 +{\r
 +public:\r
 +      C7ZipMismatchException(DWORD dwVer7zInstalled, DWORD dwVer7zLocal, CException *pCause)\r
 +      {\r
 +              m_dwVer7zInstalled = dwVer7zInstalled;\r
 +              m_dwVer7zLocal = dwVer7zLocal;\r
 +              m_pCause = pCause;\r
 +      }\r
 +      ~C7ZipMismatchException()\r
 +      {\r
 +              if (m_pCause)\r
 +                      m_pCause->Delete();\r
 +      }\r
 +      virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0);\r
 +protected:\r
 +      DWORD m_dwVer7zInstalled;\r
 +      DWORD m_dwVer7zLocal;\r
 +      CException *m_pCause;\r
 +      BOOL m_bShowAllways;\r
 +      static const DWORD m_dwVer7zRecommended;\r
 +      static const TCHAR m_strRegistryKey[];\r
 +      static const TCHAR m_strDownloadURL[];\r
 +      static INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);\r
 +      static DWORD FormatVersion(LPTSTR, LPTSTR, DWORD);\r
 +};\r
 +\r
 +/**\r
 + * @brief Recommended version of 7-Zip.\r
 + */\r
 +const DWORD C7ZipMismatchException::m_dwVer7zRecommended = DWORD MAKELONG(65,4);\r
 +\r
 +/**\r
 + * @brief Registry key for C7ZipMismatchException's ReportError() popup.\r
 + */\r
 +const TCHAR C7ZipMismatchException::m_strRegistryKey[] = _T("7ZipMismatch");\r
 +\r
 +/**\r
 + * @brief Download URL for C7ZipMismatchException's ReportError() popup.\r
 + */\r
 +const TCHAR C7ZipMismatchException::m_strDownloadURL[] = _T("https://sourceforge.net/project/showfiles.php?group_id=13216&package_id=143957");\r
 +\r
 +/**\r
 + * @brief Retrieve build number of given DLL.\r
 + */\r
 +static DWORD NTAPI GetDllBuild(LPCTSTR cPath)\r
 +{\r
 +      HMODULE hModule = LoadLibrary(cPath);\r
 +      DLLVERSIONINFO dvi;\r
 +      dvi.cbSize = sizeof dvi;\r
 +      dvi.dwBuildNumber = ~0UL;\r
 +      if (hModule)\r
 +      {\r
 +              dvi.dwBuildNumber = 0UL;\r
 +              DLLGETVERSIONPROC DllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hModule, "DllGetVersion");\r
 +              if (DllGetVersion)\r
 +              {\r
 +                      DllGetVersion(&dvi);\r
 +              }\r
 +              FreeLibrary(hModule);\r
 +      }\r
 +      return dvi.dwBuildNumber;\r
 +}\r
 +\r
 +/**\r
 + * @brief Format Merge7z version number and plugin name, and retrieve DllBuild.\r
 + */\r
 +DWORD C7ZipMismatchException::FormatVersion(LPTSTR pcVersion, LPTSTR pcPluginName, DWORD dwVersion)\r
 +{\r
 +      *pcVersion = '\0';\r
 +      *pcPluginName = '\0';\r
 +      if (dwVersion)\r
 +      {\r
 +              wsprintf\r
 +              (\r
 +                      pcVersion, _T("%u.%02u"),\r
 +                      UINT HIWORD(dwVersion),\r
 +                      UINT LOWORD(dwVersion)\r
 +              );\r
 +              wsprintf\r
 +              (\r
 +                      pcPluginName,\r
 +                      sizeof(TCHAR) == 1 ? _T("Merge7z%u%02u.dll") : _T("Merge7z%u%02uU.dll"),\r
 +                      UINT HIWORD(dwVersion),\r
 +                      UINT LOWORD(dwVersion)\r
 +              );\r
 +      }\r
 +      return GetDllBuild(pcPluginName);\r
 +}\r
 +\r
 +/**\r
 + * @brief Populate ListBox with names/revisions of DLLs matching given pattern.\r
 + */\r
 +static void NTAPI DlgDirListDLLs(HWND hWnd, LPTSTR cPattern, int nIDListBox)\r
 +{\r
 +      HDC hDC = GetDC(hWnd);\r
 +      HFONT hFont = (HFONT)SendDlgItemMessage(hWnd, nIDListBox, WM_GETFONT, 0, 0);\r
 +      int cxView = (int)SendDlgItemMessage(hWnd, nIDListBox, LB_GETHORIZONTALEXTENT, 0, 0) - 8;\r
 +      HGDIOBJ hObject = SelectObject(hDC, hFont);\r
 +      WIN32_FIND_DATA ff;\r
 +      HANDLE h = FindFirstFile(cPattern, &ff);\r
 +      if (h != INVALID_HANDLE_VALUE)\r
 +      {\r
 +              do\r
 +              {\r
 +                      PathRemoveFileSpec(cPattern);\r
 +                      PathAppend(cPattern, ff.cFileName);\r
 +                      wsprintf(ff.cFileName, _T(" (dllbuild %04u)"), GetDllBuild(cPattern));\r
 +                      lstrcat(cPattern, ff.cFileName);\r
 +                      int cxText = (int)(WORD)GetTabbedTextExtent(hDC, cPattern, lstrlen(cPattern), 0, 0);\r
 +                      if (cxView < cxText)\r
 +                              cxView = cxText;\r
 +                      SendDlgItemMessage(hWnd, nIDListBox, LB_ADDSTRING, 0, (LPARAM)cPattern);\r
 +              } while (FindNextFile(h, &ff));\r
 +              FindClose(h);\r
 +      }\r
 +      SelectObject(hDC, hObject);\r
 +      ReleaseDC(hWnd, hDC);\r
 +      SendDlgItemMessage(hWnd, nIDListBox, LB_SETHORIZONTALEXTENT, cxView + 8, 0);\r
 +}\r
 +\r
 +/**\r
 + * @brief OwnerDraw states from recent SDK.\r
 + */\r
 +#define ODS_NOACCEL         0x0100\r
 +#define ODS_NOFOCUSRECT     0x0200\r
 +\r
 +/**\r
 + * @brief WM_DRAWITEM notification handlers.\r
 + */\r
 +struct CDrawItemStruct : DRAWITEMSTRUCT\r
 +{\r
 +      typedef CDrawItemStruct *From;\r
 +      void DrawWebLinkButton();\r
 +};\r
 +\r
 +void CDrawItemStruct::DrawWebLinkButton()\r
 +{\r
 +      CRawString<TCHAR,INTERNET_MAX_PATH_LENGTH> cText;\r
 +      int cchText = ::GetWindowText(hwndItem, cText.Data, cText.Size);\r
 +      COLORREF clrText = RGB(0,0,255);\r
 +      if (::GetWindowLong(hwndItem, GWL_STYLE) & BS_LEFTTEXT)\r
 +      {\r
 +              clrText = RGB(128,0,128);\r
 +      }\r
 +      RECT rcText = rcItem;\r
 +      ::DrawText(hDC, cText.Data, cchText, &rcText, DT_LEFT|DT_CALCRECT);\r
 +      ::OffsetRect(&rcText, 1, 0);\r
 +      rcItem.right = rcText.right + 1;\r
 +      rcItem.bottom = rcText.bottom + 1;\r
 +      switch (itemAction)\r
 +      {\r
 +      case ODA_DRAWENTIRE:\r
 +              ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcItem, 0, 0, 0);\r
 +              ::SetBkMode(hDC, TRANSPARENT);\r
 +              ::SetTextColor(hDC, clrText);\r
 +              ::DrawText(hDC, cText.Data, cchText, &rcText, DT_LEFT);\r
 +              rcText.top = rcText.bottom - 1;\r
 +              ::SetBkColor(hDC, clrText);\r
 +              ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rcText, 0, 0, 0);\r
 +              if (itemState & ODS_FOCUS)\r
 +              {\r
 +              case ODA_FOCUS:\r
 +                      if (!(itemState & ODS_NOFOCUSRECT))\r
 +                      {\r
 +                              ::SetTextColor(hDC, 0);\r
 +                              ::SetBkColor(hDC, RGB(255,255,255));\r
 +                              ::SetBkMode(hDC, OPAQUE);\r
 +                              DrawFocusRect(hDC, &rcItem);\r
 +                      }\r
 +              }\r
 +              break;\r
 +      }\r
 +}\r
 +\r
 +/**\r
 + * @brief Load a cursor from COMCTL32.DLL.\r
 + */\r
 +HCURSOR NTAPI CommCtrl_LoadCursor(LPCTSTR lpCursorName)\r
 +{\r
 +      HMODULE hModule = GetModuleHandle(_T("COMCTL32.DLL"));\r
 +      return hModule ? LoadCursor(hModule, lpCursorName) : NULL;\r
 +}\r
 +\r
 +/**\r
 + * @brief DLGPROC for C7ZipMismatchException's ReportError() popup.\r
 + */\r
 +INT_PTR CALLBACK C7ZipMismatchException::DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
 +{\r
 +      switch (uMsg)\r
 +      {\r
 +              case WM_INITDIALOG:\r
 +              {\r
 +                      theApp.TranslateDialog(hWnd);\r
 +                      if (GetDlgItem(hWnd, 9001) == NULL)\r
 +                      {\r
 +                              // Dialog template isn't up to date. Give it a second chance.\r
 +                              EndDialog(hWnd, -1);\r
 +                              return FALSE;\r
 +                      }\r
 +                      C7ZipMismatchException *pThis = (C7ZipMismatchException *)lParam;\r
 +                      CRawString<TCHAR,2600> cText;\r
 +                      CRawString<TCHAR,80> cPresent, cMissing, cOutdated, cNone, cPlugin;\r
 +                      if (pThis->m_pCause)\r
 +                      {\r
 +                              pThis->m_pCause->GetErrorMessage(cText.Data, cText.Size);\r
 +                              SetDlgItemText(hWnd, 107, cText.Data);\r
 +                      }\r
 +                      else\r
 +                      {\r
 +                              GetDlgItemText(hWnd, 107, cText.Data, cText.Size);\r
 +                              switch (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE))\r
 +                              {\r
 +                              case 0:\r
 +                                      lstrcat(cText.Data, _("\nNote: 7-Zip integration is disabled in WinMerge settings.").c_str());\r
 +                                      break;\r
 +                              case 2:\r
 +                                      lstrcat(cText.Data, _("\nNote: 7-Zip integration is restricted to standalone operation in WinMerge settings.").c_str());\r
 +                                      break;\r
 +                              }\r
 +                              SetDlgItemText(hWnd, 107, cText.Data);\r
 +                      }\r
 +                      GetDlgItemText(hWnd, 112, cPresent.Data, cPresent.Size);\r
 +                      GetDlgItemText(hWnd, 122, cMissing.Data, cMissing.Size);\r
 +                      GetDlgItemText(hWnd, 132, cOutdated.Data, cOutdated.Size);\r
 +                      GetDlgItemText(hWnd, 120, cNone.Data, cNone.Size);\r
 +                      GetDlgItemText(hWnd, 102, cPlugin.Data, cPlugin.Size);\r
 +                      wsprintf(cText.Data, cPlugin.Data, DllBuild_Merge7z);\r
 +                      SetDlgItemText(hWnd, 102, cText.Data);\r
 +                      SetDlgItemText\r
 +                      (\r
 +                              hWnd, 109,\r
 +                              (\r
 +                                      pThis->m_dwVer7zRecommended == pThis->m_dwVer7zInstalled\r
 +                              ||      pThis->m_dwVer7zRecommended == pThis->m_dwVer7zLocal\r
 +                              ) ? cPresent.Data : cMissing.Data\r
 +                      );\r
 +                      DWORD dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zRecommended);\r
 +                      SetDlgItemText(hWnd, 110, *cText.Data ? cText.Data : cNone.Data);\r
 +                      SetDlgItemText(hWnd, 111, cPlugin.Data);\r
 +                      SetDlgItemText(hWnd, 112, *cPlugin.Data == '\0' ? cPlugin.Data :\r
 +                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);\r
 +                      dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zInstalled);\r
 +                      SetDlgItemText(hWnd, 120, *cText.Data ? cText.Data : cNone.Data);\r
 +                      SetDlgItemText(hWnd, 121, cPlugin.Data);\r
 +                      SetDlgItemText(hWnd, 122, *cPlugin.Data == '\0' ? cPlugin.Data :\r
 +                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);\r
 +                      dwDllBuild = FormatVersion(cText.Data, cPlugin.Data, pThis->m_dwVer7zLocal);\r
 +                      SetDlgItemText(hWnd, 130, *cText.Data ? cText.Data : cNone.Data);\r
 +                      SetDlgItemText(hWnd, 131, cPlugin.Data);\r
 +                      SetDlgItemText(hWnd, 132, *cPlugin.Data == '\0' ? cPlugin.Data :\r
 +                              dwDllBuild == ~0 ? cMissing.Data : dwDllBuild < DllBuild_Merge7z ? cOutdated.Data : cPresent.Data);\r
 +                      GetModuleFileName(0, cText.Data, MAX_PATH);\r
 +                      PathRemoveFileSpec(cText.Data);\r
 +                      PathAppend(cText.Data, _T("Merge7z*.dll"));\r
 +                      DlgDirListDLLs(hWnd, cText.Data, 105);\r
 +                      if (DWORD cchPath = GetEnvironmentVariable(_T("path"), 0, 0))\r
 +                      {\r
 +                              static const TCHAR cSep[] = _T(";");\r
 +                              LPTSTR pchPath = new TCHAR[cchPath];\r
 +                              GetEnvironmentVariable(_T("PATH"), pchPath, cchPath);\r
 +                              LPTSTR pchItem = pchPath;\r
 +                              while (int cchItem = StrCSpn(pchItem += StrSpn(pchItem, cSep), cSep))\r
 +                              {\r
 +                                      if (cchItem < MAX_PATH)\r
 +                                      {\r
 +                                              CopyMemory(cText.Data, pchItem, cchItem*sizeof*pchItem);\r
 +                                              cText.Data[cchItem] = 0;\r
 +                                              PathAppend(cText.Data, _T("Merge7z*.dll"));\r
 +                                              DlgDirListDLLs(hWnd, cText.Data, 105);\r
 +                                      }\r
 +                                      pchItem += cchItem;\r
 +                              }\r
 +                              delete[] pchPath;\r
 +                      }\r
 +                      if (SendDlgItemMessage(hWnd, 105, LB_GETCOUNT, 0, 0) == 0)\r
 +                      {\r
 +                              SendDlgItemMessage(hWnd, 105, LB_ADDSTRING, 0, (LPARAM) cNone.Data);\r
 +                      }\r
 +                      HICON hIcon = LoadIcon(0, IDI_EXCLAMATION);\r
 +                      SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon);\r
 +                      SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);\r
 +                      if (pThis->m_bShowAllways)\r
 +                      {\r
 +                              ShowWindow(GetDlgItem(hWnd, 106), SW_HIDE);\r
 +                      }\r
 +              } return TRUE;\r
 +              case WM_DRAWITEM:\r
 +              {\r
 +                      switch (wParam)\r
 +                      {\r
 +                      case 108:\r
 +                              CDrawItemStruct::From(lParam)->DrawWebLinkButton();\r
 +                              break;\r
 +                      }\r
 +              } return TRUE;\r
 +              case WM_SETCURSOR:\r
 +              {\r
 +                      HCURSOR hCursor = 0;\r
 +                      switch (GetDlgCtrlID((HWND)wParam))\r
 +                      {\r
 +                      case 108:\r
 +                              hCursor = CommCtrl_LoadCursor(MAKEINTRESOURCE(108));\r
 +                              break;\r
 +                      }\r
 +                      if (hCursor)\r
 +                      {\r
 +                              SetCursor(hCursor);\r
 +                              SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1);\r
 +                              return TRUE;\r
 +                      }\r
 +              } return FALSE;\r
 +              case WM_COMMAND:\r
 +              {\r
 +                      switch (wParam)\r
 +                      {\r
 +                              case IDOK:\r
 +                              case IDCANCEL:\r
 +                              {\r
 +                                      LRESULT nDontShowAgain = SendDlgItemMessage(hWnd, 106, BM_GETCHECK, 0, 0);\r
 +                                      EndDialog(hWnd, MAKEWORD(IDOK, nDontShowAgain));\r
 +                              } break;\r
 +                              case 108:\r
 +                              {\r
 +                                      HINSTANCE h = ShellExecute(hWnd, _T("open"), m_strDownloadURL, 0, 0, SW_SHOWNORMAL);\r
 +                                      if ((UINT)h > 32)\r
 +                                      {\r
 +                                              LONG lStyle = ::GetWindowLong((HWND)lParam, GWL_STYLE);\r
 +                                              ::SetWindowLong((HWND)lParam, GWL_STYLE, lStyle|BS_LEFTTEXT);\r
 +                                              ::InvalidateRect((HWND)lParam, 0, TRUE);\r
 +                                      }\r
 +                                      else\r
 +                                      {\r
 +                                              MessageBeep(0);\r
 +                                      }\r
 +                              } break;\r
 +                      }\r
 +              } return TRUE;\r
 +      }\r
 +      return FALSE;\r
 +}\r
 +\r
 +/**\r
 + * @brief Tell user what went wrong and how she can help.\r
 + */\r
 +int C7ZipMismatchException::ReportError(UINT nType, UINT nMessageID)\r
 +{\r
 +      UINT_PTR response = -1;\r
 +      m_bShowAllways = nMessageID;\r
 +      if (!m_bShowAllways)\r
 +      {\r
 +              // Suppress error message in case 7-Zip is not installed.\r
 +              response =\r
 +              (\r
 +                      m_dwVer7zInstalled || m_dwVer7zLocal\r
 +              ?       (INT_PTR)(int)theApp.GetProfileInt(REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, -1)\r
 +              :       IDOK\r
 +              );\r
 +      }\r
 +      if (response == -1)\r
 +      {\r
 +              HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();\r
 +              response = DialogBoxParam(AfxGetResourceHandle(), MAKEINTRESOURCE(IDD_MERGE7ZMISMATCH), hwndOwner, DlgProc, (LPARAM)this);\r
 +              if (response == -1)\r
 +              {\r
 +                      response = DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_MERGE7ZMISMATCH), hwndOwner, DlgProc, (LPARAM)this);\r
 +                      ASSERT(response != -1);\r
 +              }\r
 +              if (HIBYTE(response) == 1)\r
 +              {\r
 +                      theApp.WriteProfileInt(REGISTRY_SECTION_MESSAGEBOX, m_strRegistryKey, response = int LOBYTE(response));\r
 +              }\r
 +      }\r
 +      return response;\r
 +}\r
 +\r
 +/**\r
 + * @brief Check whether archive support is available.\r
 + */\r
 +int NTAPI HasZipSupport()\r
 +{\r
 +      static int HasZipSupport = -1;\r
 +      if (HasZipSupport == -1)\r
 +      {\r
 +              try\r
 +              {\r
 +                      m_Merge7z.operator->();\r
 +                      HasZipSupport = 1;\r
 +              }\r
 +              catch (CException *e)\r
 +              {\r
 +                      e->Delete();\r
 +                      HasZipSupport = 0;\r
 +              }\r
 +      }\r
 +      return HasZipSupport;\r
 +}\r
 +\r
 +/**\r
 + * @brief Tell user why archive support is not available.\r
 + */\r
 +void NTAPI Recall7ZipMismatchError()\r
 +{\r
 +      try\r
 +      {\r
 +              m_Merge7z.operator->();\r
 +      }\r
 +      catch (CException *e)\r
 +      {\r
 +              e->ReportError(MB_ICONEXCLAMATION, TRUE);\r
 +              e->Delete();\r
 +      }\r
 +}\r
 +\r
 +/**\r
 + * @brief Delete head of temp path context list, and return its parent context.\r
 + */\r
 +CTempPathContext *CTempPathContext::DeleteHead()\r
 +{\r
 +      CTempPathContext *pParent = m_pParent;\r
 +      delete this;\r
 +      return pParent;\r
 +}\r
 +\r
 +BOOL NTAPI IsMerge7zEnabled()\r
 +{\r
 +      return AfxGetApp()->GetProfileInt(_T("Merge7z"), _T("Enable"), 0);\r
 +}\r
 +\r
 +/**\r
 + * @brief Return installed or local version of 7-Zip.\r
 + */\r
 +DWORD NTAPI VersionOf7z(BOOL bLocal)\r
 +{\r
 +      TCHAR path[MAX_PATH];\r
 +      if (bLocal)\r
 +      {\r
 +              GetModuleFileName(0, path, sizeof path/sizeof*path);\r
 +              PathRemoveFileSpec(path);\r
 +      }\r
 +      else\r
 +      {\r
 +              static const TCHAR szSubKey[] = _T("Software\\7-Zip");\r
 +              static const TCHAR szValue[] = _T("Path");\r
 +              DWORD type = 0;\r
 +              DWORD size = sizeof path;\r
 +              SHGetValue(HKEY_LOCAL_MACHINE, szSubKey, szValue, &type, path, &size);\r
 +      }\r
 +      PathAppend(path, _T("7z.dll"));\r
 +      unsigned versionMS = 0;\r
 +      unsigned versionLS = 0;\r
 +      CVersionInfo(path).GetFixedFileVersion(versionMS, versionLS);\r
 +      return versionMS;\r
 +}\r
 +\r
 +/**\r
 + * @brief Access dll functions through proxy.\r
 + */\r
 +interface Merge7z *Merge7z::Proxy::operator->()\r
 +{\r
 +      // As long as the Merge7z*.DLL has not yet been loaded, Merge7z\r
 +      // [0] points to the name of the DLL (with placeholders for 7-\r
 +      // Zip major and minor version numbers). Once the DLL has been\r
 +      // loaded successfully, Merge7z[0] is set to NULL, causing the\r
 +      // if to fail on subsequent calls.\r
 +\r
 +      if (const char *format = Merge7z[0])\r
 +      {\r
 +              // Merge7z has not yet been loaded\r
 +\r
 +              char name[MAX_PATH];\r
 +              DWORD flags = ~0;\r
 +              CException *pCause = NULL;\r
 +              switch (GetOptionsMgr()->GetInt(OPT_ARCHIVE_ENABLE))\r
 +              {\r
 +              case 1: //Use installed 7-Zip if present. Otherwise, use local 7-Zip.\r
 +                      if (DWORD ver = VersionOf7z(FALSE))\r
 +                      {\r
 +                              flags = Initialize::Default;\r
 +                              try\r
 +                              {\r
 +                                      wsprintfA(name, format, UINT HIWORD(ver), UINT LOWORD(ver));\r
 +                                      Merge7z[0] = name;\r
 +                                      stub.Load();\r
 +                                      break;\r
 +                              }\r
 +                              catch (CException *e)\r
 +                              {\r
 +                                      Merge7z[0] = format;\r
 +                                      pCause = e;\r
 +                              }\r
 +                      }\r
 +              case 2: //Always use local 7-Zip.\r
 +                      if (DWORD ver = VersionOf7z(TRUE))\r
 +                      {\r
 +                              flags = Initialize::Default | Initialize::Local7z;\r
 +                              try\r
 +                              {\r
 +                                      wsprintfA(name, format, UINT HIWORD(ver), UINT LOWORD(ver));\r
 +                                      Merge7z[0] = name;\r
 +                                      stub.Load();\r
 +                                      break;\r
 +                              }\r
 +                              catch (CException *e)\r
 +                              {\r
 +                                      Merge7z[0] = format;\r
 +                                      if (pCause) pCause->Delete();\r
 +                                      pCause = e;\r
 +                              }\r
 +                      }\r
 +              default:\r
 +                      throw new C7ZipMismatchException\r
 +                      (\r
 +                              VersionOf7z(FALSE),\r
 +                              VersionOf7z(TRUE),\r
 +                              pCause\r
 +                      );\r
 +              }\r
 +              LANGID wLangID = (LANGID)GetThreadLocale();\r
 +              flags |= wLangID << 16;\r
 +              if (GetOptionsMgr()->GetBool(OPT_ARCHIVE_PROBETYPE))\r
 +              {\r
 +                      flags |= Initialize::GuessFormatBySignature | Initialize::GuessFormatByExtension;\r
 +              }\r
 +              if (Merge7z[1])\r
 +                      ((interface Merge7z *)Merge7z[1])->Initialize(flags);\r
 +      }\r
 +      return ((interface Merge7z *)Merge7z[1]);\r
 +}\r
 +\r
 +/**\r
 + * @brief Tell Merge7z we are going to enumerate just 1 item.\r
 + */\r
 +UINT SingleItemEnumerator::Open()\r
 +{\r
 +      return 1;\r
 +}\r
 +\r
 +/**\r
 + * @brief Pass information about the item to Merge7z.\r
 + */\r
 +Merge7z::Envelope *SingleItemEnumerator::Enum(Item &item)\r
 +{\r
 +      item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.Recurse;\r
 +      item.Name = Name;\r
 +      item.FullPath = FullPath;\r
 +      return 0;\r
 +}\r
 +\r
 +/**\r
 + * @brief SingleFileEnumerator constructor.\r
 + */\r
 +SingleItemEnumerator::SingleItemEnumerator(LPCTSTR path, LPCTSTR FullPath, LPCTSTR Name)\r
 +: FullPath(FullPath)\r
 +, Name(Name)\r
 +{\r
 +}\r
 +\r
 +/**\r
 + * @brief Construct a DirItemEnumerator.\r
 + *\r
 + * Argument *nFlags* controls operation as follows:\r
 + * LVNI_ALL:          Enumerate all items.\r
 + * LVNI_SELECTED:     Enumerate selected items only.\r
 + * Original:          Set folder prefix for first iteration to "original"\r
 + * Altered:                   Set folder prefix for second iteration to "altered"\r
 + * BalanceFolders:    Ensure that all nonempty folders on either side have a\r
 + *                                    corresponding folder on the other side, even if it is\r
 + *                                    empty (DirScan doesn't recurse into folders which\r
 + *                                    appear only on one side).\r
 + * DiffsOnly:         Enumerate diffs only.\r
 + */\r
 +DirItemEnumerator::DirItemEnumerator(CDirView *pView, int nFlags)\r
 +: m_pView(pView)\r
 +, m_nFlags(nFlags)\r
 +{\r
 +      if (m_nFlags & Original)\r
 +      {\r
 +              m_rgFolderPrefix.push_back(_T("original"));\r
 +      }\r
 +      if (m_nFlags & Altered)\r
 +      {\r
 +              m_rgFolderPrefix.push_back(_T("altered"));\r
 +      }\r
 +      if (m_nFlags & BalanceFolders)\r
 +      {\r
 +              const CDiffContext& ctxt = pView->GetDiffContext();\r
 +              // Collect implied folders\r
 +              for (UINT i = Open() ; i-- ; )\r
 +              {\r
 +                      const DIFFITEM &di = Next();\r
 +                      if ((m_nFlags & DiffsOnly) && !IsItemNavigableDiff(ctxt, di))\r
 +                      {\r
 +                              continue;\r
 +                      }\r
 +                      // Enumerating items\r
-                       if (di.diffcode.isExists(m_index))\r
++                      if (di.diffcode.exists(m_index))\r
 +                      {\r
 +                              // Item is present on right side, i.e. folder is implied\r
 +                              m_rgImpliedFolders[m_index][di.diffFileInfo[m_index].path.get()] = PVOID(1);\r
 +                      }\r
 +              }\r
 +      }\r
 +}\r
 +\r
 +/**\r
 + * @brief Initialize enumerator, return number of items to be enumerated.\r
 + */\r
 +UINT DirItemEnumerator::Open()\r
 +{\r
 +      m_nIndex = -1;\r
 +      m_curFolderPrefix = m_rgFolderPrefix.begin();\r
 +      m_index = (m_nFlags & Right) != 0 ? 1 : 0;\r
 +      size_t nrgFolderPrefix = m_rgFolderPrefix.size();\r
 +      if (nrgFolderPrefix)\r
 +      {\r
 +              m_strFolderPrefix = *m_curFolderPrefix++;\r
 +      }\r
 +      else\r
 +      {\r
 +              nrgFolderPrefix = 1;\r
 +      }\r
 +      return\r
 +      (\r
 +              m_nFlags & LVNI_SELECTED\r
 +      ?       pView(m_pView)->GetSelectedCount()\r
 +      :       pView(m_pView)->GetItemCount()\r
 +      ) * nrgFolderPrefix;\r
 +}\r
 +\r
 +/**\r
 + * @brief Return next item.\r
 + */\r
 +const DIFFITEM &DirItemEnumerator::Next()\r
 +{\r
 +      enum {nMask = LVNI_FOCUSED|LVNI_SELECTED|LVNI_CUT|LVNI_DROPHILITED};\r
 +      while ((m_nIndex = pView(m_pView)->GetNextItem(m_nIndex, m_nFlags & nMask)) == -1)\r
 +      {\r
 +              m_strFolderPrefix = *m_curFolderPrefix++;\r
 +              m_index = 1;\r
 +      }\r
 +      return m_pView->GetDiffItem(m_nIndex);\r
 +}\r
 +\r
 +/**\r
 + * @brief Pass information about an item to Merge7z.\r
 + *\r
 + * Information is passed through struct Merge7z::DirItemEnumerator::Item.\r
 + * The *mask* member denotes which of the other members contain valid data.\r
 + * If *mask* is zero upon return, which will be the case if Enum() decides to\r
 + * leave the struct untouched, Merge7z will ignore the item.\r
 + * If Enum() allocates temporary storage for string members, it must also\r
 + * allocate an Envelope, providing a Free() method to free the temporary\r
 + * storage, along with the Envelope itself. The Envelope pointer is passed to\r
 + * Merge7z as the return value of the function. It is not meant to be a success\r
 + * indicator, so if no temporary storage is required, it is perfectly alright\r
 + * to return NULL.\r
 + */\r
 +Merge7z::Envelope *DirItemEnumerator::Enum(Item &item)\r
 +{\r
 +      const CDiffContext& ctxt = m_pView->GetDiffContext();\r
 +      const DIFFITEM &di = Next();\r
 +\r
 +      if ((m_nFlags & DiffsOnly) && !IsItemNavigableDiff(ctxt, di))\r
 +      {\r
 +              return 0;\r
 +      }\r
 +\r
-       bool isSideOnly = !di.diffcode.isExists(m_index);\r
++      bool isSideOnly = !di.diffcode.exists(m_index);\r
 +\r
 +      Envelope *envelope = new Envelope;\r
 +\r
 +      const String &sFilename = di.diffFileInfo[m_index].filename;\r
 +      const String &sSubdir = di.diffFileInfo[m_index].path;\r
 +      if (sSubdir.length())\r
 +              envelope->Name = paths_ConcatPath(sSubdir, sFilename);\r
 +      else\r
 +              envelope->Name = sFilename;\r
 +      envelope->FullPath = paths_ConcatPath(\r
 +                      di.getFilepath(m_index, ctxt.GetNormalizedPath(m_index)),\r
 +                      sFilename);\r
 +\r
 +      UINT32 Recurse = item.Mask.Recurse;\r
 +\r
 +      if (m_nFlags & BalanceFolders)\r
 +      {\r
 +              // Enumerating items on right side\r
 +              if (isSideOnly)\r
 +              {\r
 +                      // Item is missing on right side\r
 +                      PVOID &implied = m_rgImpliedFolders[m_index][di.diffFileInfo[1-m_index].path.get()];\r
 +                      if (!implied)\r
 +                      {\r
 +                              // Folder is not implied by some other file, and has\r
 +                              // not been enumerated so far, so enumerate it now!\r
 +                              envelope->Name = di.diffFileInfo[1-m_index].path;\r
 +                              envelope->FullPath = di.getFilepath(1-m_index, ctxt.GetNormalizedPath(1-m_index));\r
 +                              implied = PVOID(2); // Don't enumerate same folder twice!\r
 +                              isSideOnly = false;\r
 +                              Recurse = 0;\r
 +                      }\r
 +              }\r
 +      }\r
 +\r
 +      if (isSideOnly)\r
 +      {\r
 +              return envelope;\r
 +      }\r
 +\r
 +      if (m_strFolderPrefix.length())\r
 +      {\r
 +              if (envelope->Name.length())\r
 +                      envelope->Name.insert(0, _T("\\"));\r
 +              envelope->Name.insert(0, m_strFolderPrefix);\r
 +      }\r
 +\r
 +      item.Mask.Item = item.Mask.Name|item.Mask.FullPath|item.Mask.CheckIfPresent|Recurse;\r
 +      item.Name = envelope->Name.c_str();\r
 +      item.FullPath = envelope->FullPath.c_str();\r
 +      return envelope;\r
 +}\r
 +\r
 +/**\r
 + * @brief Apply appropriate handlers from left to right.\r
 + */\r
 +bool DirItemEnumerator::MultiStepCompressArchive(LPCTSTR path)\r
 +{\r
 +      DeleteFile(path);\r
 +      Merge7z::Format *piHandler = ArchiveGuessFormat(path);\r
 +      if (piHandler)\r
 +      {\r
 +              HWND hwndOwner = CWnd::GetSafeOwner()->GetSafeHwnd();\r
 +              CString pathIntermediate;\r
 +              SysFreeString(Assign(pathIntermediate, piHandler->GetDefaultName(hwndOwner, path)));\r
 +              String pathPrepend = path;\r
 +              pathPrepend.resize(pathPrepend.rfind('\\') + 1);\r
 +              pathIntermediate.Insert(0, pathPrepend.c_str());\r
 +              bool bDone = MultiStepCompressArchive(pathIntermediate);\r
 +              if (bDone)\r
 +              {\r
 +                      piHandler->CompressArchive(hwndOwner, path,\r
 +                              &SingleItemEnumerator(path, pathIntermediate));\r
 +                      DeleteFile(pathIntermediate);\r
 +              }\r
 +              else\r
 +              {\r
 +                      piHandler->CompressArchive(hwndOwner, path, this);\r
 +              }\r
 +              return true;\r
 +      }\r
 +      return false;\r
 +}\r
 +\r
 +/**\r
 + * @brief Generate archive from DirView items.\r
 + */\r
 +void DirItemEnumerator::CompressArchive(LPCTSTR path)\r
 +{\r
 +      String strPath;\r
 +      if (path == 0)\r
 +      {\r
 +              // No path given, so prompt for path!\r
 +              static const TCHAR _T_Merge7z[] = _T("Merge7z");\r
 +              static const TCHAR _T_FilterIndex[] = _T("FilterIndex");\r
 +              // 7z311 can only write 7z, zip, and tar(.gz|.bz2) archives, so don't\r
 +              // offer other formats here!\r
 +              static const TCHAR _T_Filter[]\r
 +              (\r
 +                      _T("7z|*.7z|")\r
 +                      //_T("z|*.z|")\r
 +                      _T("zip|*.zip|")\r
 +                      _T("jar (zip)|*.jar|")\r
 +                      _T("ear (zip)|*.ear|")\r
 +                      _T("war (zip)|*.war|")\r
 +                      _T("xpi (zip)|*.xpi|")\r
 +                      //_T("rar|*.rar|")\r
 +                      _T("tar|*.tar|")\r
 +                      _T("tar.z|*.tar.z|")\r
 +                      _T("tar.gz|*.tar.gz|")\r
 +                      _T("tar.bz2|*.tar.bz2|")\r
 +                      //_T("tz|*.tz|")\r
 +                      _T("tgz|*.tgz|")\r
 +                      _T("tbz2|*.tbz2|")\r
 +                      //_T("lzh|*.lzh|")\r
 +                      //_T("cab|*.cab|")\r
 +                      //_T("arj|*.arj|")\r
 +                      //_T("deb|*.deb|")\r
 +                      //_T("rpm|*.rpm|")\r
 +                      //_T("cpio|*.cpio|")\r
 +                      //_T("|")\r
 +              );\r
 +              String strFilter; // = CExternalArchiveFormat::GetOpenFileFilterString();\r
 +              strFilter.insert(0, _T_Filter);\r
 +              strFilter += _T("|");\r
 +              CFileDialog dlg\r
 +              (\r
 +                      FALSE,\r
 +                      0,\r
 +                      0,\r
 +                      OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN,\r
 +                      strFilter.c_str()\r
 +              );\r
 +              dlg.m_ofn.nFilterIndex = AfxGetApp()->GetProfileInt(_T_Merge7z, _T_FilterIndex, 1);\r
 +              // Use extension from current filter as default extension:\r
 +              if (int i = dlg.m_ofn.nFilterIndex)\r
 +              {\r
 +                      dlg.m_ofn.lpstrDefExt = dlg.m_ofn.lpstrFilter;\r
 +                      while (*dlg.m_ofn.lpstrDefExt && --i)\r
 +                      {\r
 +                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 1;\r
 +                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 1;\r
 +                      }\r
 +                      if (*dlg.m_ofn.lpstrDefExt)\r
 +                      {\r
 +                              dlg.m_ofn.lpstrDefExt += lstrlen(dlg.m_ofn.lpstrDefExt) + 3;\r
 +                      }\r
 +              }\r
 +              if (dlg.DoModal() == IDOK)\r
 +              {\r
 +                      strPath = dlg.GetPathName();\r
 +                      path = strPath.c_str();\r
 +                      AfxGetApp()->WriteProfileInt(_T_Merge7z, _T_FilterIndex, dlg.m_ofn.nFilterIndex);\r
 +              }\r
 +      }\r
 +      if (path && !MultiStepCompressArchive(path))\r
 +      {\r
 +              LangMessageBox(IDS_UNKNOWN_ARCHIVE_FORMAT, MB_ICONEXCLAMATION);\r
 +      }\r
 +}\r
 +\r
 +\r
 +DecompressResult DecompressArchive(HWND hWnd, const PathContext& files)\r
 +{\r
 +      DecompressResult res(files, NULL, IS_EXISTING_DIR);\r
 +      try\r
 +      {\r
 +              String path;\r
 +              USES_CONVERSION;\r
 +              // Handle archives using 7-zip\r
 +              Merge7z::Format *piHandler;\r
 +              if (piHandler = ArchiveGuessFormat(res.files[0].c_str()))\r
 +              {\r
 +                      res.pTempPathContext = new CTempPathContext;\r
 +                      path = env_GetTempChildPath();\r
 +                      for (int index = 0; index < res.files.GetSize(); index++)\r
 +                              res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];\r
 +                      if (res.files.GetSize() == 2 && res.files[0] == res.files[1])\r
 +                              res.files[1].erase();\r
 +                      do\r
 +                      {\r
 +                              if (FAILED(piHandler->DeCompressArchive(hWnd, res.files[0].c_str(), path.c_str())))\r
 +                                      break;\r
 +                              if (res.files[0].find(path) == 0)\r
 +                              {\r
 +                                      VERIFY(::DeleteFile(res.files[0].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[0].c_str())), false));\r
 +                              }\r
 +                              BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[0].c_str());\r
 +                              res.files[0] = OLE2T(pTmp);\r
 +                              SysFreeString(pTmp);\r
 +                              res.files[0].insert(0, _T("\\"));\r
 +                              res.files[0].insert(0, path);\r
 +                      } while (piHandler = ArchiveGuessFormat(res.files[0].c_str()));\r
 +                      res.files[0] = path;\r
 +              }\r
 +              if (!res.files[1].empty() && (piHandler = ArchiveGuessFormat(res.files[1].c_str())))\r
 +              {\r
 +                      if (!res.pTempPathContext)\r
 +                      {\r
 +                              res.pTempPathContext = new CTempPathContext;\r
 +                              for (int index = 0; index < res.files.GetSize(); index++)\r
 +                                      res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];\r
 +                      }\r
 +                      path = env_GetTempChildPath();\r
 +                      do\r
 +                      {\r
 +                              if (FAILED(piHandler->DeCompressArchive(hWnd, res.files[1].c_str(), path.c_str())))\r
 +                                      break;;\r
 +                              if (res.files[1].find(path) == 0)\r
 +                              {\r
 +                                      VERIFY(::DeleteFile(res.files[1].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[1].c_str())), false));\r
 +                              }\r
 +                              BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[1].c_str());\r
 +                              res.files[1] = OLE2T(pTmp);\r
 +                              SysFreeString(pTmp);\r
 +                              res.files[1].insert(0, _T("\\"));\r
 +                              res.files[1].insert(0, path);\r
 +                      } while (piHandler = ArchiveGuessFormat(res.files[1].c_str()));\r
 +                      res.files[1] = path;\r
 +              }\r
 +              if (res.files.GetSize() > 2 && (piHandler = ArchiveGuessFormat(res.files[2].c_str())))\r
 +              {\r
 +                      if (!res.pTempPathContext)\r
 +                      {\r
 +                              res.pTempPathContext = new CTempPathContext;\r
 +                              for (int index = 0; index < res.files.GetSize(); index++)\r
 +                                      res.pTempPathContext->m_strDisplayRoot[index] = res.files[index];\r
 +                      }\r
 +                      path = env_GetTempChildPath();\r
 +                      do\r
 +                      {\r
 +                              if (FAILED(piHandler->DeCompressArchive(hWnd, res.files[2].c_str(), path.c_str())))\r
 +                                      break;;\r
 +                              if (res.files[2].find(path) == 0)\r
 +                              {\r
 +                                      VERIFY(::DeleteFile(res.files[2].c_str()) || (LogErrorString(string_format(_T("DeleteFile(%s) failed"), res.files[2].c_str())), false));\r
 +                              }\r
 +                              BSTR pTmp = piHandler->GetDefaultName(hWnd, res.files[1].c_str());\r
 +                              res.files[2] = OLE2T(pTmp);\r
 +                              SysFreeString(pTmp);\r
 +                              res.files[2].insert(0, _T("\\"));\r
 +                              res.files[2].insert(0, path);\r
 +                      } while (piHandler = ArchiveGuessFormat(res.files[2].c_str()));\r
 +                      res.files[2] = path;\r
 +              }\r
 +              if (res.files[1].empty())\r
 +              {\r
 +                      // assume Perry style patch\r
 +                      res.files[1] = path;\r
 +                      res.files[0] += _T("\\ORIGINAL");\r
 +                      res.files[1] += _T("\\ALTERED");\r
 +                      if (!PathFileExists(res.files[0].c_str()) || !PathFileExists(res.files[1].c_str()))\r
 +                      {\r
 +                              // not a Perry style patch: diff with itself...\r
 +                              res.files[0] = res.files[1] = path;\r
 +                      }\r
 +                      else\r
 +                      {\r
 +                              res.pTempPathContext->m_strDisplayRoot[0] += _T("\\ORIGINAL");\r
 +                              res.pTempPathContext->m_strDisplayRoot[1] += _T("\\ALTERED");\r
 +                      }\r
 +              }\r
 +      }\r
 +      catch (CException *e)\r
 +      {\r
 +              e->ReportError(MB_ICONSTOP);\r
 +              e->Delete();\r
 +      }\r
 +      return res;\r
 +}\r
 +\r
 +\r
diff --cc Src/DiffItem.h
Simple merge
@@@ -346,31 -1127,53 +346,31 @@@ bool IsItemCopyable(const DIFFITEM & di
        if (di.diffcode.isResultError()) return false;
        // can't copy same items
        if (di.diffcode.isResultSame()) return false;
 -      // impossible if only on left
 -      if (di.diffcode.isSideFirstOnly()) return false;
 -
 -      // everything else can be copied to left
 +      // impossible if not existing
-       if (!di.diffcode.isExists(index)) return false;
++      if (!di.diffcode.exists(index)) return false;
 +      // everything else can be copied to other side
        return true;
  }
 -/// is it possible to copy item to right ?
 -bool CDirView::IsItemCopyableToRight(const DIFFITEM & di) const
 -{
 -      // don't let them mess with error items
 -      if (di.diffcode.isResultError()) return false;
 -      // can't copy same items
 -      if (di.diffcode.isResultSame()) return false;
 -      // impossible if only on right
 -      if (di.diffcode.isSideSecondOnly()) return false;
  
 -      // everything else can be copied to right
 -      return true;
 -}
 -/// is it possible to delete left item ?
 -bool CDirView::IsItemDeletableOnLeft(const DIFFITEM & di) const
 +/// is it possible to delete item ?
 +bool IsItemDeletable(const DIFFITEM & di, int index)
  {
        // don't let them mess with error items
        if (di.diffcode.isResultError()) return false;
 -      // impossible if only on right
 -      if (di.diffcode.isSideSecondOnly()) return false;
 -      // everything else can be deleted on left
 +      // impossible if not existing
-       if (!di.diffcode.isExists(index)) return false;
++      if (!di.diffcode.exists(index)) return false;
 +      // everything else can be deleted
        return true;
  }
 -/// is it possible to delete right item ?
 -bool CDirView::IsItemDeletableOnRight(const DIFFITEM & di) const
 -{
 -      // don't let them mess with error items
 -      if (di.diffcode.isResultError()) return false;
 -      // impossible if only on right
 -      if (di.diffcode.isSideFirstOnly()) return false;
  
 -      // everything else can be deleted on right
 -      return true;
 -}
  /// is it possible to delete both items ?
 -bool CDirView::IsItemDeletableOnBoth(const DIFFITEM & di) const
 +bool IsItemDeletableOnBoth(const CDiffContext& ctxt, const DIFFITEM & di)
  {
        // don't let them mess with error items
        if (di.diffcode.isResultError()) return false;
        // impossible if only on right or left
 -      if (di.diffcode.isSideFirstOnly() || di.diffcode.isSideSecondOnly()) return false;
 +      for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
-               if (!di.diffcode.isExists(i)) return false;
++              if (!di.diffcode.exists(i)) return false;
  
        // everything else can be deleted on both
        return true;
@@@ -505,26 -1312,39 +505,26 @@@ bool AreItemsOpenable(const CDiffContex
  
        return false;
  }
 -/// is it possible to open left item ?
 -bool CDirView::IsItemOpenableOnLeft(const DIFFITEM & di) const
 +/// is it possible to open item ?
 +bool IsItemOpenableOn(const DIFFITEM & di, int index)
  {
 -      // impossible if only on right
 -      if (di.diffcode.isSideSecondOnly()) return false;
 +      // impossible if not existing
-       if (!di.diffcode.isExists(index)) return false;
++      if (!di.diffcode.exists(index)) return false;
  
        // everything else can be opened on right
        return true;
  }
 -/// is it possible to open right item ?
 -bool CDirView::IsItemOpenableOnRight(const DIFFITEM & di) const
 -{
 -      // impossible if only on left
 -      if (di.diffcode.isSideFirstOnly()) return false;
  
 -      // everything else can be opened on left
 -      return true;
 -}
  /// is it possible to open left ... item ?
 -bool CDirView::IsItemOpenableOnLeftWith(const DIFFITEM & di) const
 -{
 -      return (!di.diffcode.isDirectory() && IsItemOpenableOnLeft(di));
 -}
 -/// is it possible to open with ... right item ?
 -bool CDirView::IsItemOpenableOnRightWith(const DIFFITEM & di) const
 +bool IsItemOpenableOnWith(const DIFFITEM & di, int index)
  {
 -      return (!di.diffcode.isDirectory() && IsItemOpenableOnRight(di));
 +      return (!di.diffcode.isDirectory() && IsItemOpenableOn(di, index));
  }
  /// is it possible to copy to... left item?
 -bool CDirView::IsItemCopyableToOnLeft(const DIFFITEM & di) const
 +bool IsItemCopyableToOn(const DIFFITEM & di, int index)
  {
        // impossible if only on right
-       if (!di.diffcode.isExists(index)) return false;
 -      if (di.diffcode.isSideSecondOnly()) return false;
++      if (!di.diffcode.exists(index)) return false;
  
        // everything else can be copied to from left
        return true;
@@@ -543,374 -1359,69 +543,374 @@@ bool IsItemNavigableDiff(const CDiffCon
        return true;
  }
  
 -/// get the file names on both sides for first selected item
 -bool CDirView::GetSelectedFileNames(String& strLeft, String& strRight) const
 +bool IsItemExistAll(const CDiffContext& ctxt, const DIFFITEM & di)
  {
 -      int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
 -      if (sel == -1)
 +      // Not a valid diffitem, one of special items (e.g "..")
 +      if (di.diffcode.diffcode == 0)
                return false;
 -      GetItemFileNames(sel, strLeft, strRight);
 +      if (ctxt.GetCompareDirs() == 2)
 +              return di.diffcode.isSideBoth();
 +      else
 +              return di.diffcode.isSideAll();
 +}
 +
 +
 +/**
 + * @brief Determines if the user wants to see given item.
 + * This function determines what items to show and what items to hide. There
 + * are lots of combinations, but basically we check if menuitem is enabled or
 + * disabled and show/hide matching items. For non-recursive compare we never
 + * hide folders as that would disable user browsing into them. And we even
 + * don't really know if folders are identical or different as we haven't
 + * compared them.
 + * @param [in] di Item to check.
 + * @return true if item should be shown, false if not.
 + * @sa CDirDoc::Redisplay()
 + */
 +bool IsShowable(const CDiffContext& ctxt, const DIFFITEM & di, const DirViewFilterSettings& filter)
 +{
 +      if (di.customFlags1 & ViewCustomFlags::HIDDEN)
 +              return false;
 +
 +      if (di.diffcode.isResultFiltered())
 +      {
 +              // Treat SKIPPED as a 'super'-flag. If item is skipped and user
 +              // wants to see skipped items show item regardless of other flags
 +              return filter.show_skipped;
 +      }
 +
 +      if (di.diffcode.isDirectory())
 +      {
 +              // Subfolders in non-recursive compare can only be skipped or unique
 +              if (!ctxt.m_bRecursive)
 +              {
 +                      // left/right filters
 +                      if (di.diffcode.isSideFirstOnly() && !filter.show_unique_left)
 +                              return false;
 +                      if (di.diffcode.isSideSecondOnly() && !filter.show_unique_right)
 +                              return false;
 +
 +                      // result filters
 +                      if (di.diffcode.isResultError() && FALSE/* !GetMainFrame()->m_bShowErrors FIXME:*/)
 +                              return false;
 +              }
 +              else // recursive mode (including tree-mode)
 +              {
 +                      // left/right filters
 +                      if (di.diffcode.isSideFirstOnly() && !filter.show_unique_left)
 +                              return false;
 +                      if (di.diffcode.isSideSecondOnly() && !filter.show_unique_right)
 +                              return false;
 +
 +                      // ONLY filter folders by result (identical/different) for tree-view.
 +                      // In the tree-view we show subfolders with identical/different
 +                      // status. The flat view only shows files inside folders. So if we
 +                      // filter by status the files inside folder are filtered too and
 +                      // users see files appearing/disappearing without clear logic.          
 +                      if (filter.tree_mode)
 +                      {
 +                              // result filters
 +                              if (di.diffcode.isResultError() && FALSE/* !GetMainFrame()->m_bShowErrors FIXME:*/)
 +                                      return false;
 +
 +                              // result filters
 +                              if (di.diffcode.isResultSame() && !filter.show_identical)
 +                                      return false;
 +                              if (di.diffcode.isResultDiff() && !filter.show_different)
 +                                      return false;
 +                      }
 +              }
 +      }
 +      else
 +      {
 +              // left/right filters
 +              if (di.diffcode.isSideFirstOnly() && !filter.show_unique_left)
 +                      return false;
 +              if (di.diffcode.isSideSecondOnly() && !filter.show_unique_right)
 +                      return false;
 +
 +              // file type filters
 +              if (di.diffcode.isBin() && !filter.show_binaries)
 +                      return false;
 +
 +              // result filters
 +              if (di.diffcode.isResultSame() && !filter.show_identical)
 +                      return false;
 +              if (di.diffcode.isResultError() /* && !GetMainFrame()->m_bShowErrors FIXME:*/)
 +                      return false;
 +              if (di.diffcode.isResultDiff() && !filter.show_different)
 +                      return false;
 +      }
        return true;
  }
 -/// get file name on specified side for first selected item
 -String CDirView::GetSelectedFileName(SIDE_TYPE stype) const
 +
 +/**
 + * @brief Open one selected item.
 + * @param [in] pos1 Item position.
 + * @param [in,out] di1 Pointer to first diffitem.
 + * @param [in,out] di2 Pointer to second diffitem.
 + * @param [in,out] di3 Pointer to third diffitem.
 + * @param [out] paths First/Second/Third paths.
 + * @param [out] sel1 Item's selection index in listview.
 + * @param [in,out] isDir Is item folder?
 + * return false if there was error or item was completely processed.
 + */
 +bool GetOpenOneItem(const CDiffContext& ctxt, uintptr_t pos1, const DIFFITEM *pdi[3],
 +              PathContext & paths, int & sel1, bool & isdir, int nPane[3], String& errmsg)
  {
 -      String left, right;
 -      if (!GetSelectedFileNames(left, right)) return _T("");
 -      return stype==SIDE_LEFT ? left : right;
 +      pdi[0] = &ctxt.GetDiffAt(pos1);
 +      pdi[1] = pdi[0];
 +      pdi[2] = pdi[0];
 +
 +      paths = GetItemFileNames(ctxt, *pdi[0]);
 +
 +      for (int nIndex = 0; nIndex < paths.GetSize(); ++nIndex)
 +              nPane[nIndex] = nIndex;
 +
 +      if (pdi[0]->diffcode.isDirectory())
 +              isdir = true;
 +
-       if (isdir && (pdi[0]->diffcode.isExistsFirst() && pdi[1]->diffcode.isExistsSecond() && pdi[2]->diffcode.isExistsThird()))
++      if (isdir && (pdi[0]->diffcode.existsFirst() && pdi[1]->diffcode.existsSecond() && pdi[2]->diffcode.existsThird()))
 +      {
 +              // Check both folders exist. If either folder is missing that means
 +              // folder has been changed behind our back, so we just tell user to
 +              // refresh the compare.
 +              PATH_EXISTENCE path1Exists = paths_DoesPathExist(paths[0]);
 +              PATH_EXISTENCE path2Exists = paths_DoesPathExist(paths[1]);
 +              if (path1Exists != IS_EXISTING_DIR || path2Exists != IS_EXISTING_DIR)
 +              {
 +                      String invalid = path1Exists == IS_EXISTING_DIR ? paths[0] : paths[1];
 +                      errmsg = string_format_string1(
 +                              _("Operation aborted!\n\nFolder contents at disks has changed, path\n%1\nwas not found.\n\nPlease refresh the compare."),
 +                              invalid);
 +                      return false;
 +              }
 +      }
 +
 +      return true;
  }
 +
  /**
 - * @brief Get the file names on both sides for specified item.
 - * @note Return empty strings if item is special item.
 + * @brief Open two selected items.
 + * @param [in] pos1 First item position.
 + * @param [in] pos2 Second item position.
 + * @param [in,out] di1 Pointer to first diffitem.
 + * @param [in,out] di2 Pointer to second diffitem.
 + * @param [out] paths First/Second/Third paths.
 + * @param [out] sel1 First item's selection index in listview.
 + * @param [out] sel2 Second item's selection index in listview.
 + * @param [in,out] isDir Is item folder?
 + * return false if there was error or item was completely processed.
   */
 -void CDirView::GetItemFileNames(int sel, String& strLeft, String& strRight) const
 +bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, uintptr_t pos1, uintptr_t pos2, const DIFFITEM *pdi[3],
 +              PathContext & paths, int & sel1, int & sel2, bool & isDir, int nPane[3], String& errmsg)
  {
 -      UINT_PTR diffpos = GetItemKey(sel);
 -      if (diffpos == (UINT_PTR)SPECIAL_ITEM_POS)
 +      String pathLeft, pathRight;
 +
 +      // Two items selected, get their info
 +      pdi[0] = &ctxt.GetDiffAt(pos1);
 +      pdi[1] = &ctxt.GetDiffAt(pos2);
 +      nPane[0] = 0;
 +      nPane[1] = 1;
 +
 +      // Check for binary & side compatibility & file/dir compatibility
 +      if (!AreItemsOpenable(ctxt, selectionType, *pdi[0], *pdi[1]))
        {
 -              strLeft.erase();
 -              strRight.erase();
 +              return false;
        }
 -      else
 +
 +      String temp;
 +      switch (selectionType)
        {
 -              const DIFFITEM & di = GetDocument()->GetDiffByKey(diffpos);
 -              const String leftrelpath = di.diffFileInfo[0].GetFile();
 -              const String rightrelpath = di.diffFileInfo[1].GetFile();
 -              const String & leftpath = GetDocument()->GetBasePath(0);
 -              const String & rightpath = GetDocument()->GetBasePath(1);
 -              strLeft = paths_ConcatPath(leftpath, leftrelpath);
 -              strRight = paths_ConcatPath(rightpath, rightrelpath);
 +      case SELECTIONTYPE_NORMAL:
 +              // Ensure that di1 is on left (swap if needed)
 +              if (pdi[0]->diffcode.isSideSecondOnly() || (pdi[0]->diffcode.isSideBoth() &&
 +                              pdi[1]->diffcode.isSideFirstOnly()))
 +              {
 +                      std::swap(pdi[0], pdi[1]);
 +                      std::swap(sel1, sel2);
 +              }
 +              break;
 +      case SELECTIONTYPE_LEFT1LEFT2:
 +              nPane[0] = nPane[1] = 0;
 +              break;
 +      case SELECTIONTYPE_RIGHT1RIGHT2:
 +              nPane[0] = nPane[1] = 1;
 +              break;
 +      case SELECTIONTYPE_LEFT1RIGHT2:
 +              break;
 +      case SELECTIONTYPE_LEFT2RIGHT1:
 +              std::swap(pdi[0], pdi[1]);
 +              std::swap(sel1, sel2);
 +              break;
 +      }
 +
 +      PathContext files1, files2;
 +      files1 = GetItemFileNames(ctxt, *pdi[0]);
 +      files2 = GetItemFileNames(ctxt, *pdi[1]);
 +      paths.SetLeft(files1[nPane[0]]);
 +      paths.SetRight(files2[nPane[1]]);
 +
 +      if (pdi[0]->diffcode.isDirectory())
 +      {
 +              isDir = true;
 +              if (GetPairComparability(paths) != IS_EXISTING_DIR)
 +              {
 +                      errmsg = _("The selected folder is invalid.");
 +                      return false;
 +              }
        }
 +
 +      return true;
  }
  
  /**
 - * @brief Get the file names on both sides for specified item.
 - * @note Return empty strings if item is special item.
 + * @brief Open three selected items.
 + * @param [in] pos1 First item position.
 + * @param [in] pos2 Second item position.
 + * @param [in] pos3 Third item position.
 + * @param [in,out] di1 Pointer to first diffitem.
 + * @param [in,out] di2 Pointer to second diffitem.
 + * @param [in,out] di3 Pointer to third diffitem.
 + * @param [out] paths First/Second/Third paths.
 + * @param [out] sel1 First item's selection index in listview.
 + * @param [out] sel2 Second item's selection index in listview.
 + * @param [out] sel3 Third item's selection index in listview.
 + * @param [in,out] isDir Is item folder?
 + * return false if there was error or item was completely processed.
   */
 -void CDirView::GetItemFileNames(int sel, PathContext * paths) const
 +bool GetOpenThreeItems(const CDiffContext& ctxt, uintptr_t pos1, uintptr_t pos2, uintptr_t pos3, const DIFFITEM *pdi[3],
 +      PathContext & paths, int & sel1, int & sel2, int & sel3, bool & isDir, int nPane[3], String& errmsg)
  {
 -      String strPath[3];
 -      UINT_PTR diffpos = GetItemKey(sel);
 -      if (diffpos == SPECIAL_ITEM_POS)
 +      String pathLeft, pathMiddle, pathRight;
 +
 +      // FIXME:
 +      for (int nIndex = 0; nIndex < 3; ++nIndex)
 +              nPane[nIndex] = nIndex;
 +      if (!pos3)
        {
 -              for (int nIndex = 0; nIndex < GetDocument()->m_nDirs; nIndex++)
 -                      paths->SetPath(nIndex, _T(""));
 +              // Two items selected, get their info
 +              pdi[0] = &ctxt.GetDiffAt(pos1);
 +              pdi[1] = &ctxt.GetDiffAt(pos2);
 +
 +              // Check for binary & side compatibility & file/dir compatibility
 +              if (!::AreItemsOpenable(ctxt, *pdi[0], *pdi[1], *pdi[1]) && 
 +                      !::AreItemsOpenable(ctxt, *pdi[0], *pdi[0], *pdi[1]))
 +              {
 +                      return false;
 +              }
 +              // Ensure that pdi[0] is on left (swap if needed)
-               if (pdi[0]->diffcode.isExists(0) && pdi[0]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(2))
++              if (pdi[0]->diffcode.exists(0) && pdi[0]->diffcode.exists(1) && pdi[1]->diffcode.exists(2))
 +              {
 +                      pdi[2] = pdi[1];
 +                      pdi[1] = pdi[0];
 +                      sel3 = sel2;
 +                      sel2 = sel1;
 +              }
-               else if (pdi[0]->diffcode.isExists(0) && pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(1))
++              else if (pdi[0]->diffcode.exists(0) && pdi[0]->diffcode.exists(2) && pdi[1]->diffcode.exists(1))
 +              {
 +                      pdi[2] = pdi[0];
 +                      sel3 = sel1;
 +              }
-               else if (pdi[0]->diffcode.isExists(1) && pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(0))
++              else if (pdi[0]->diffcode.exists(1) && pdi[0]->diffcode.exists(2) && pdi[1]->diffcode.exists(0))
 +              {
 +                      std::swap(pdi[0], pdi[1]);
 +                      std::swap(sel1, sel2);
 +                      pdi[2] = pdi[1];
 +                      sel3 = sel2;
 +              }
-               else if (pdi[1]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(1) && pdi[0]->diffcode.isExists(2))
++              else if (pdi[1]->diffcode.exists(0) && pdi[1]->diffcode.exists(1) && pdi[0]->diffcode.exists(2))
 +              {
 +                      std::swap(pdi[0], pdi[1]);
 +                      std::swap(sel1, sel2);
 +                      pdi[2] = pdi[1];
 +                      pdi[1] = pdi[0];
 +                      sel3 = sel2;
 +                      sel2 = sel1;
 +              }
-               else if (pdi[1]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(2) && pdi[0]->diffcode.isExists(1))
++              else if (pdi[1]->diffcode.exists(0) && pdi[1]->diffcode.exists(2) && pdi[0]->diffcode.exists(1))
 +              {
 +                      std::swap(pdi[0], pdi[1]);
 +                      std::swap(sel1, sel2);
 +                      pdi[2] = pdi[0];
 +                      sel3 = sel1;
 +              }
-               else if (pdi[1]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(2) && pdi[0]->diffcode.isExists(0))
++              else if (pdi[1]->diffcode.exists(1) && pdi[1]->diffcode.exists(2) && pdi[0]->diffcode.exists(0))
 +              {
 +                      pdi[2] = pdi[1];
 +                      sel3 = sel2;
 +              }
        }
        else
        {
 -              const DIFFITEM & di = GetDocument()->GetDiffByKey(diffpos);
 -              for (int nIndex = 0; nIndex < GetDocument()->m_nDirs; nIndex++)
 +              // Three items selected, get their info
 +              pdi[0] = &ctxt.GetDiffAt(pos1);
 +              pdi[1] = &ctxt.GetDiffAt(pos2);
 +              pdi[2] = &ctxt.GetDiffAt(pos3);
 +
 +              // Check for binary & side compatibility & file/dir compatibility
 +              if (!::AreItemsOpenable(ctxt, *pdi[0], *pdi[1], *pdi[2]))
 +              {
 +                      return false;
 +              }
 +              // Ensure that pdi[0] is on left (swap if needed)
-               if (pdi[0]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(1) && pdi[2]->diffcode.isExists(2))
++              if (pdi[0]->diffcode.exists(0) && pdi[1]->diffcode.exists(1) && pdi[2]->diffcode.exists(2))
 +              {
 +              }
-               else if (pdi[0]->diffcode.isExists(0) && pdi[1]->diffcode.isExists(2) && pdi[2]->diffcode.isExists(1))
++              else if (pdi[0]->diffcode.exists(0) && pdi[1]->diffcode.exists(2) && pdi[2]->diffcode.exists(1))
                {
 -                      const String relpath = di.diffFileInfo[nIndex].GetFile();
 -                      const String & path = GetDocument()->GetBasePath(nIndex);
 -                      paths->SetPath(nIndex, paths_ConcatPath(path, relpath));
 +                      std::swap(pdi[1], pdi[2]);
 +                      std::swap(sel2, sel3);
                }
-               else if (pdi[0]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(0) && pdi[2]->diffcode.isExists(2))
++              else if (pdi[0]->diffcode.exists(1) && pdi[1]->diffcode.exists(0) && pdi[2]->diffcode.exists(2))
 +              {
 +                      std::swap(pdi[0], pdi[1]);
 +                      std::swap(sel1, sel2);
 +              }
-               else if (pdi[0]->diffcode.isExists(1) && pdi[1]->diffcode.isExists(2) && pdi[2]->diffcode.isExists(0))
++              else if (pdi[0]->diffcode.exists(1) && pdi[1]->diffcode.exists(2) && pdi[2]->diffcode.exists(0))
 +              {
 +                      std::swap(pdi[0], pdi[2]);
 +                      std::swap(sel1, sel3);
 +                      std::swap(pdi[1], pdi[2]);
 +                      std::swap(sel2, sel3);
 +              }
-               else if (pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(0) && pdi[2]->diffcode.isExists(1))
++              else if (pdi[0]->diffcode.exists(2) && pdi[1]->diffcode.exists(0) && pdi[2]->diffcode.exists(1))
 +              {
 +                      std::swap(pdi[0], pdi[1]);
 +                      std::swap(sel1, sel2);
 +                      std::swap(pdi[1], pdi[2]);
 +                      std::swap(sel2, sel3);
 +              }
-               else if (pdi[0]->diffcode.isExists(2) && pdi[1]->diffcode.isExists(1) && pdi[2]->diffcode.isExists(0))
++              else if (pdi[0]->diffcode.exists(2) && pdi[1]->diffcode.exists(1) && pdi[2]->diffcode.exists(0))
 +              {
 +                      std::swap(pdi[0], pdi[2]);
 +                      std::swap(sel1, sel3);
 +              }
 +      }
 +
 +      // Fill in pathLeft & & pathMiddle & pathRight
 +      PathContext pathsTemp = GetItemFileNames(ctxt, *pdi[0]);
 +      pathLeft = pathsTemp[0];
 +      pathsTemp = GetItemFileNames(ctxt, *pdi[1]);
 +      pathMiddle = pathsTemp[1];
 +      pathsTemp = GetItemFileNames(ctxt, *pdi[2]);
 +      pathRight = pathsTemp[2];
 +
 +      paths.SetLeft(pathLeft.c_str());
 +      paths.SetMiddle(pathMiddle.c_str());
 +      paths.SetRight(pathRight.c_str());
 +
 +      if (pdi[0]->diffcode.isDirectory())
 +      {
 +              isDir = true;
 +              if (GetPairComparability(paths) != IS_EXISTING_DIR)
 +              {
 +                      errmsg = _("The selected folder is invalid.");
 +                      return false;
 +              } 
        }
 +
 +      return true;
  }
  
  /**
@@@ -945,64 -1471,25 +945,64 @@@ PathContext GetItemFileNames(const CDif
  }
  
  /**
 - * @brief Apply specified setting for prediffing to all selected items
 + * @brief Return image index appropriate for this row
   */
 -void CDirView::ApplyPluginPrediffSetting(int newsetting)
 +int GetColImage(const CDiffContext&ctxt, const DIFFITEM & di)
  {
 -      // Unlike other group actions, here we don't build an action list
 -      // to execute; we just apply this change directly
 -      int sel=-1;
 -      String slFile, srFile;
 -      while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
 +      // Must return an image index into image list created above in OnInitDialog
 +      if (di.diffcode.isResultError())
 +              return DIFFIMG_ERROR;
 +      if (di.diffcode.isResultAbort())
 +              return DIFFIMG_ABORT;
 +      if (di.diffcode.isResultFiltered())
 +              return (di.diffcode.isDirectory() ? DIFFIMG_DIRSKIP : DIFFIMG_SKIP);
 +      if (di.diffcode.isSideFirstOnly())
 +              return (di.diffcode.isDirectory() ? DIFFIMG_LDIRUNIQUE : DIFFIMG_LUNIQUE);
 +      if (di.diffcode.isSideSecondOnly())
 +              return (ctxt.GetCompareDirs() < 3 ? 
 +                      (di.diffcode.isDirectory() ? DIFFIMG_RDIRUNIQUE : DIFFIMG_RUNIQUE) :
 +                      (di.diffcode.isDirectory() ? DIFFIMG_MDIRUNIQUE : DIFFIMG_MUNIQUE));
 +      if (di.diffcode.isSideThirdOnly())
 +              return (di.diffcode.isDirectory() ? DIFFIMG_RDIRUNIQUE : DIFFIMG_RUNIQUE);
 +      if (ctxt.GetCompareDirs() == 3)
 +      {
-               if (!di.diffcode.isExists(0))
++              if (!di.diffcode.exists(0))
 +                      return (di.diffcode.isDirectory() ? DIFFIMG_LDIRMISSING : DIFFIMG_LMISSING);
-               if (!di.diffcode.isExists(1))
++              if (!di.diffcode.exists(1))
 +                      return (di.diffcode.isDirectory() ? DIFFIMG_MDIRMISSING : DIFFIMG_MMISSING);
-               if (!di.diffcode.isExists(2))
++              if (!di.diffcode.exists(2))
 +                      return (di.diffcode.isDirectory() ? DIFFIMG_RDIRMISSING : DIFFIMG_RMISSING);
 +      }
 +      if (di.diffcode.isResultSame())
        {
 -              const DIFFITEM& di = GetDiffItem(sel);
 -              if (!di.diffcode.isDirectory() && !di.diffcode.isSideFirstOnly() &&
 -                      !di.diffcode.isSideSecondOnly())
 +              if (di.diffcode.isDirectory())
 +                      return DIFFIMG_DIRSAME;
 +              else
 +              {
 +                      if (di.diffcode.isText())
 +                              return DIFFIMG_TEXTSAME;
 +                      else if (di.diffcode.isBin())
 +                              return DIFFIMG_BINSAME;
 +                      else
 +                              return DIFFIMG_SAME;
 +              }
 +      }
 +      // diff
 +      if (di.diffcode.isResultDiff())
 +      {
 +              if (di.diffcode.isDirectory())
 +                      return DIFFIMG_DIRDIFF;
 +              else
                {
 -                      GetItemFileNames(sel, slFile, srFile);
 -                      String filteredFilenames = slFile + _T("|") + srFile;
 -                      GetDocument()->SetPluginPrediffSetting(filteredFilenames, newsetting);
 +                      if (di.diffcode.isText())
 +                              return DIFFIMG_TEXTDIFF;
 +                      else if (di.diffcode.isBin())
 +                              return DIFFIMG_BINDIFF;
 +                      else
 +                              return DIFFIMG_DIFF;
                }
        }
 +      return (di.diffcode.isDirectory() ? DIFFIMG_DIR : DIFFIMG_ABORT);
  }
  
  /**
index 1f6e732,0000000..4aa4167
mode 100644,000000..100644
--- /dev/null
@@@ -1,792 -1,0 +1,792 @@@
-               return (di.diffcode.diffcode != 0 && di.diffcode.isExists(SideToIndex(m_ctxt, src)));
 +#pragma once
 +
 +#include "UnicodeString.h"
 +#include "DiffContext.h"
 +#include "FileActionScript.h"
 +#include "paths.h"
 +#include "IntToIntMap.h"
 +#include <algorithm>
 +
 +struct DIFFITEM;
 +class CDiffContext;
 +class PathContext;
 +class PluginManager;
 +class FileActionScript;
 +class CTempPathContext;
 +
 +/**
 + * @brief Folder compare icon indexes.
 + * This enum defines indexes for imagelist used for folder compare icons.
 + * Note that this enum must be in synch with code in OnInitialUpdate() and
 + * GetColImage(). Also remember that icons are in resource file...
 + */
 +enum
 +{
 +      DIFFIMG_LUNIQUE,
 +      DIFFIMG_MUNIQUE,
 +      DIFFIMG_RUNIQUE,
 +      DIFFIMG_LMISSING,
 +      DIFFIMG_MMISSING,
 +      DIFFIMG_RMISSING,
 +      DIFFIMG_DIFF,
 +      DIFFIMG_SAME,
 +      DIFFIMG_BINSAME,
 +      DIFFIMG_BINDIFF,
 +      DIFFIMG_LDIRUNIQUE,
 +      DIFFIMG_MDIRUNIQUE,
 +      DIFFIMG_RDIRUNIQUE,
 +      DIFFIMG_LDIRMISSING,
 +      DIFFIMG_MDIRMISSING,
 +      DIFFIMG_RDIRMISSING,
 +      DIFFIMG_SKIP,
 +      DIFFIMG_DIRSKIP,
 +      DIFFIMG_DIRDIFF,
 +      DIFFIMG_DIRSAME,
 +      DIFFIMG_DIR,
 +      DIFFIMG_ERROR,
 +      DIFFIMG_DIRUP,
 +      DIFFIMG_DIRUP_DISABLE,
 +      DIFFIMG_ABORT,
 +      DIFFIMG_TEXTDIFF,
 +      DIFFIMG_TEXTSAME,
 +};
 +
 +typedef enum {
 +      SIDE_LEFT = 1,
 +      SIDE_MIDDLE,
 +      SIDE_RIGHT
 +} SIDE_TYPE;
 +
 +typedef enum {
 +      SELECTIONTYPE_NORMAL,
 +      SELECTIONTYPE_LEFT1LEFT2,
 +      SELECTIONTYPE_RIGHT1RIGHT2,
 +      SELECTIONTYPE_LEFT1RIGHT2,
 +      SELECTIONTYPE_LEFT2RIGHT1
 +} SELECTIONTYPE;
 +
 +typedef enum {
 +      UPDATEITEM_NONE,
 +      UPDATEITEM_UPDATE,
 +      UPDATEITEM_REMOVE
 +} UPDATEITEM_TYPE;
 +
 +struct ViewCustomFlags
 +{
 +      enum
 +      {
 +              // We use extra bits so that no valid values are 0
 +              // and each set of flags is in a different hex digit
 +              // to make debugging easier
 +              // These can always be packed down in the future
 +              INVALID_CODE = 0,
 +              VISIBILITY = 0x3, VISIBLE = 0x1, HIDDEN = 0x2, EXPANDED = 0x4
 +      };
 +};
 +
 +struct AllowUpwardDirectory
 +{
 +      enum ReturnCode
 +      {
 +              Never,
 +              No,
 +              ParentIsRegularPath,
 +              ParentIsTempPath
 +      };
 +};
 +
 +
 +struct DirViewFilterSettings
 +{
 +      template<class GetOptionBool>
 +      DirViewFilterSettings(GetOptionBool getoptbool)
 +      {
 +              show_skipped = getoptbool(OPT_SHOW_SKIPPED);
 +              show_unique_left = getoptbool(OPT_SHOW_UNIQUE_LEFT);
 +              show_unique_right = getoptbool(OPT_SHOW_UNIQUE_RIGHT);
 +              show_binaries = getoptbool(OPT_SHOW_BINARIES);
 +              show_identical = getoptbool(OPT_SHOW_IDENTICAL);
 +              show_different = getoptbool(OPT_SHOW_DIFFERENT);
 +              tree_mode = getoptbool(OPT_TREE_MODE);
 +      };
 +      bool show_skipped;
 +      bool show_unique_left;
 +      bool show_unique_right;
 +      bool show_binaries;
 +      bool show_identical;
 +      bool show_different;
 +      bool tree_mode;
 +};
 +
 +typedef std::map<String, bool> DirViewTreeState;
 +
 +String NumToStr(int n);
 +String FormatFilesAffectedString(int nFilesAffected, int nFilesTotal);
 +String FormatMenuItemString(SIDE_TYPE src, int count, int total);
 +String FormatMenuItemString(SIDE_TYPE src, SIDE_TYPE dst, int count, int total);
 +String FormatMenuItemStringBoth(int count, int total);
 +String FormatMenuItemString(const String& fmt1, const String& fmt2, int count, int total);
 +String FormatMenuItemStringTo(SIDE_TYPE src, int count, int total);
 +
 +void ConfirmActionList(const CDiffContext& ctxt, const FileActionScript & actionList);
 +UPDATEITEM_TYPE UpdateDiffAfterOperation(const FileActionItem & act, CDiffContext& ctxt, DIFFITEM &di);
 +
 +uintptr_t FindItemFromPaths(const CDiffContext& ctxt, const String& pathLeft, const String& pathRight);
 +
 +bool IsItemCopyable(const DIFFITEM & di, int index);
 +bool IsItemDeletable(const DIFFITEM & di, int index);
 +bool IsItemDeletableOnBoth(const CDiffContext& ctxt, const DIFFITEM & di);
 +bool IsItemOpenable(const CDiffContext& ctxt, const DIFFITEM & di, bool treemode);
 +bool AreItemsOpenable(const CDiffContext& ctxt, SELECTIONTYPE selectionType, const DIFFITEM & di1, const DIFFITEM & di2);
 +bool AreItemsOpenable(const CDiffContext& ctxt, const DIFFITEM & di1, const DIFFITEM & di2, const DIFFITEM & di3);
 +bool IsItemOpenableOn(const DIFFITEM & di, int index);
 +bool IsItemOpenableOnWith(const DIFFITEM & di, int index);
 +bool IsItemCopyableToOn(const DIFFITEM & di, int index);
 +bool IsItemNavigableDiff(const CDiffContext& ctxt, const DIFFITEM & di);
 +bool IsItemExistAll(const CDiffContext& ctxt, const DIFFITEM & di);
 +bool IsShowable(const CDiffContext& ctxt, const DIFFITEM & di, const DirViewFilterSettings& filter);
 +
 +bool GetOpenOneItem(const CDiffContext& ctxt, uintptr_t pos1, const DIFFITEM *pdi[3],
 +              PathContext &paths, int & sel1, bool & isDir, int nPane[3], String& errmsg);
 +bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, uintptr_t pos1, uintptr_t pos2, const DIFFITEM *pdi[3],
 +              PathContext &paths, int & sel1, int & sel2, bool & isDir, int nPane[3], String& errmsg);
 +bool GetOpenThreeItems(const CDiffContext& ctxt, uintptr_t pos1, uintptr_t pos2, uintptr_t pos3, const DIFFITEM *pdi[3],
 +              PathContext &paths, int & sel1, int & sel2, int & sel3, bool & isDir, int nPane[3], String& errmsg);
 +
 +void GetItemFileNames(const CDiffContext& ctxt, const DIFFITEM& di, String& strLeft, String& strRight);
 +PathContext GetItemFileNames(const CDiffContext& ctxt, const DIFFITEM& di);
 +String GetItemFileName(const CDiffContext& ctx, const DIFFITEM & di, int index);
 +int GetColImage(const CDiffContext&ctxt, const DIFFITEM & di);
 +
 +void SetDiffStatus(DIFFITEM& di, unsigned  diffcode, unsigned mask);
 +void SetDiffCompare(DIFFITEM& di, unsigned diffcode);
 +void SetDiffSide(DIFFITEM& di, unsigned diffcode);
 +void SetDiffCounts(DIFFITEM& di, unsigned diffs, unsigned ignored);
 +void SetItemViewFlag(DIFFITEM& di, unsigned flag, unsigned mask);
 +void SetItemViewFlag(CDiffContext& ctxt, unsigned flag, unsigned mask);
 +void MarkForRescan(DIFFITEM& di);
 +
 +bool RenameOnSameDir(const String& szOldFileName, const String& szNewFileName);
 +
 +void ExpandSubdirs(CDiffContext& ctxt, DIFFITEM& dip);
 +void ExpandAllSubdirs(CDiffContext &ctxt);
 +void CollapseAllSubdirs(CDiffContext &ctxt);
 +DirViewTreeState *SaveTreeState(const CDiffContext& ctxt);
 +void RestoreTreeState(CDiffContext &ctxt, DirViewTreeState *pTreeState);
 +
 +AllowUpwardDirectory::ReturnCode
 +CheckAllowUpwardDirectory(const CDiffContext& ctxt, const CTempPathContext *pTempPathContext, PathContext &pathsParent);
 +
 +inline int SideToIndex(const CDiffContext& ctxt, SIDE_TYPE stype)
 +{
 +      switch (stype)
 +      {
 +      case SIDE_MIDDLE: return ctxt.GetCompareDirs() == 3 ? 1 : -1;
 +      case SIDE_RIGHT: return ctxt.GetCompareDirs() - 1;
 +      default: return 0;
 +      }
 +}
 +
 +struct ConfirmationNeededException
 +{
 +      String m_caption;
 +      String m_question;
 +      String m_fromText;
 +      String m_toText;
 +      String m_fromPath;
 +      String m_toPath;
 +};
 +
 +struct ContentsChangedException
 +{
 +      ContentsChangedException(const String& failpath);
 +      String m_msg;
 +};
 +
 +struct DirActions
 +{
 +      typedef bool (DirActions::*method_type2)(const DIFFITEM& di) const;
 +      typedef FileActionScript *(DirActions::*method_type)(FileActionScript *, const std::pair<int, const DIFFITEM *> it) const;
 +
 +      DirActions(const CDiffContext& ctxt, const bool RO[], method_type func = NULL, method_type2 func2 = NULL) : 
 +              m_ctxt(ctxt), m_RO(RO), m_cur_method(func), m_cur_method2(func2) {}
 +
 +      template <SIDE_TYPE src, SIDE_TYPE dst>
 +      bool IsItemCopyableOnTo(const DIFFITEM& di) const
 +      {
 +              return (di.diffcode.diffcode != 0 && !m_RO[SideToIndex(m_ctxt, dst)] && ::IsItemCopyable(di, SideToIndex(m_ctxt, src)));
 +      }
 +
 +      template <SIDE_TYPE src>
 +      bool IsItemCopyableToOn(const DIFFITEM& di) const
 +      {
 +              return (di.diffcode.diffcode != 0 && ::IsItemCopyableToOn(di, SideToIndex(m_ctxt, src)));
 +      }
 +
 +      template <SIDE_TYPE src>
 +      bool IsItemMovableToOn(const DIFFITEM& di) const
 +      {
 +              const int idx = SideToIndex(m_ctxt, src);
 +              return (di.diffcode.diffcode != 0 && !m_RO[idx] && IsItemDeletable(di, idx) && ::IsItemCopyableToOn(di, idx));
 +      }
 +
 +      template <SIDE_TYPE src>
 +      bool IsItemDeletableOn(const DIFFITEM& di) const
 +      { 
 +              const int idx = SideToIndex(m_ctxt, src);
 +              return (di.diffcode.diffcode != 0 && !m_RO[idx] && IsItemDeletable(di, idx));
 +      }
 +      bool IsItemDeletableOnBoth(const DIFFITEM& di) const
 +      {
 +              if (di.diffcode.diffcode != 0)
 +              {
 +                      int i;
 +                      for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
 +                      {
 +                              if (m_RO[i] || !IsItemDeletable(di, i))
 +                                      break;
 +                      }
 +                      return (i == m_ctxt.GetCompareDirs());
 +              }
 +              return false;
 +      }
 +      bool IsItemDeletableOnEitherOrBoth(const DIFFITEM& di) const
 +      {
 +              if (di.diffcode.diffcode != 0)
 +              {
 +                      int i;
 +                      for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
 +                      {
 +                              if (!m_RO[i] && IsItemDeletable(di, i))
 +                                      break;
 +                      }
 +                      return (i < m_ctxt.GetCompareDirs());
 +              }
 +              return false;
 +      }
 +
 +      template <SIDE_TYPE src>
 +      bool IsItemOpenanbleOn(const DIFFITEM& di) const
 +      {
 +              return (di.diffcode.diffcode != 0 && IsItemOpenableOn(di, SideToIndex(m_ctxt, src)));
 +      }
 +
 +      template <SIDE_TYPE src>
 +      bool IsItemOpenanbleOnWith(const DIFFITEM& di) const
 +      {
 +              return (di.diffcode.diffcode != 0 && IsItemOpenableOnWith(di, SideToIndex(m_ctxt, src)));
 +      }
 +
 +      bool IsItemFile(const DIFFITEM& di) const
 +      {
 +              return (di.diffcode.diffcode != 0 && di.diffcode.isDirectory());
 +      }
 +
 +      template <SIDE_TYPE src>
 +      bool IsItemExist(const DIFFITEM& di) const
 +      {
-               return (di.diffcode.diffcode != 0 && di.diffcode.isExists(index) && di.diffFileInfo[index].IsEditableEncoding());
++              return (di.diffcode.diffcode != 0 && di.diffcode.exists(SideToIndex(m_ctxt, src)));
 +      }
 +
 +      template <SIDE_TYPE src>
 +      bool IsItemEditableEncoding(const DIFFITEM& di) const
 +      {
 +              const int index = SideToIndex(m_ctxt, src);
-               if (di.diffcode.isExists(index))
++              return (di.diffcode.diffcode != 0 && di.diffcode.exists(index) && di.diffFileInfo[index].IsEditableEncoding());
 +      }
 +
 +      bool IsItemNavigableDiff(const DIFFITEM& di) const
 +      {
 +              return ::IsItemNavigableDiff(m_ctxt, di);
 +      }
 +
 +      FileActionScript *CopyItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src, SIDE_TYPE dst) const
 +      {
 +              const DIFFITEM& di = *it.second;
 +              const int srcidx = SideToIndex(m_ctxt, src);
 +              const int dstidx = SideToIndex(m_ctxt, dst);
 +              if (di.diffcode.diffcode != 0 && !m_RO[dstidx] && IsItemCopyable(di, srcidx))
 +              {
 +                      FileActionItem act;
 +                      act.src  = GetItemFileName(m_ctxt, di, srcidx);
 +                      act.dest = GetItemFileName(m_ctxt, di, dstidx);
 +                      
 +                      // We must check that paths still exists
 +                      if (paths_DoesPathExist(act.src) == DOES_NOT_EXIST)
 +                              throw ContentsChangedException(act.src);
 +
 +                      act.context = it.first;
 +                      act.dirflag = di.diffcode.isDirectory();
 +                      act.atype = FileAction::ACT_COPY;
 +                      act.UIResult = FileActionItem::UI_SYNC;
 +                      act.UIOrigin = srcidx;
 +                      act.UIDestination = dstidx;
 +                      pscript->AddActionItem(act);
 +              }
 +              return pscript;
 +      }
 +
 +      template<SIDE_TYPE src, SIDE_TYPE to>
 +      FileActionScript *Copy(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
 +      {
 +              return CopyItem(pscript, it, src, to);
 +      }
 +
 +      FileActionScript *DeleteItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src) const
 +      {
 +              const DIFFITEM& di = *it.second;
 +              const int index = SideToIndex(m_ctxt, src);
 +              if (di.diffcode.diffcode != 0 && !m_RO[index] && IsItemDeletable(di, index))
 +              {
 +                      FileActionItem act;
 +                      act.src = GetItemFileName(m_ctxt, di, index);
 +
 +                      // We must check that path still exists
 +                      if (paths_DoesPathExist(act.src) == DOES_NOT_EXIST)
 +                              throw ContentsChangedException(act.src);
 +
 +                      act.context = it.first;
 +                      act.dirflag = di.diffcode.isDirectory();
 +                      act.atype = FileAction::ACT_DEL;
 +                      act.UIOrigin = index;
 +                      act.UIResult = FileActionItem::UI_DEL;
 +                      pscript->AddActionItem(act);
 +              }
 +              return pscript;
 +      }
 +
 +      template<SIDE_TYPE src>
 +      FileActionScript *DeleteOn(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
 +      {
 +              return DeleteItem(pscript, it, src);
 +      }
 +
 +      FileActionScript *DeleteOnBoth(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
 +      {
 +              const DIFFITEM& di = *it.second;
 +
 +              if (di.diffcode.diffcode != 0 && IsItemDeletableOnBoth(di) && 
 +                      (std::count(m_RO, m_RO + m_ctxt.GetCompareDirs(), true) == 0))
 +              {
 +                      for (int i = 0; i < m_ctxt.GetCompareDirs(); ++i)
 +                      {
 +                              FileActionItem act;
 +                              act.src = GetItemFileName(m_ctxt, di, i);
 +                              // We must first check that paths still exists
 +                              if (paths_DoesPathExist(act.src) == DOES_NOT_EXIST)
 +                                      throw ContentsChangedException(act.src);
 +                              act.context = it.first;
 +                              act.dirflag = di.diffcode.isDirectory();
 +                              act.atype = FileAction::ACT_DEL;
 +                              act.UIOrigin = i;
 +                              act.UIResult = FileActionItem::UI_DEL;
 +                              pscript->AddActionItem(act);
 +                      }
 +              }
 +              return pscript;
 +      }
 +
 +      FileActionScript *DeleteOnEitherOrBoth(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
 +      {
 +              const DIFFITEM& di = *it.second;
 +              if (di.diffcode.diffcode != 0)
 +              {
 +                      for (int i = 0; i < m_ctxt.GetCompareDirs(); ++i)
 +                      {
 +                              if (IsItemDeletable(di, i) && !m_RO[i])
 +                              {
 +                                      FileActionItem act;
 +                                      act.src = GetItemFileName(m_ctxt, di, i);
 +                                      act.UIResult = FileActionItem::UI_DEL;
 +                                      act.dirflag = di.diffcode.isDirectory();
 +                                      act.context = it.first;
 +                                      act.UIOrigin = i;
 +                                      act.atype = FileAction::ACT_DEL;
 +                                      pscript->AddActionItem(act);
 +                              }
 +                      }
 +              }
 +              return pscript;
 +      }
 +
 +      FileActionScript *CopyOrMoveItemTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, FileAction::ACT_TYPE atype, SIDE_TYPE src) const
 +      {
 +              const int index = SideToIndex(m_ctxt, src);
 +              const DIFFITEM& di = *it.second;
 +
 +              if (di.diffcode.diffcode != 0 && IsItemCopyable(di, index) && 
 +                      (atype == FileAction::ACT_MOVE ? (!m_RO[index] && IsItemDeletable(di, index)) : true))
 +              {
 +                      FileActionItem act;
 +                      act.src = GetItemFileName(m_ctxt, di, index);
 +                       
 +                      // We must check that path still exists
 +                      if (paths_DoesPathExist(act.src) == DOES_NOT_EXIST)
 +                              throw ContentsChangedException(act.src);
 +
 +                      act.dest = paths_ConcatPath(pscript->m_destBase, di.diffFileInfo[index].filename);
 +                      act.dirflag = di.diffcode.isDirectory();
 +                      act.context = it.first;
 +                      act.atype = atype;
 +                      act.UIResult = (atype == FileAction::ACT_COPY) ? FileActionItem::UI_DONT_CARE : FileActionItem::UI_DEL;
 +                      act.UIOrigin = index;
 +                      pscript->AddActionItem(act);
 +              }
 +              return pscript;
 +      }
 +
 +      template<SIDE_TYPE src>
 +      FileActionScript *CopyTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
 +      {
 +              return CopyOrMoveItemTo(pscript, it, FileAction::ACT_COPY, src);
 +      }
 +
 +      template<SIDE_TYPE src>
 +      FileActionScript *MoveTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
 +      {
 +              return CopyOrMoveItemTo(pscript, it, FileAction::ACT_MOVE, src);
 +      }
 +
 +      FileActionScript *operator()(FileActionScript *pscript, const std::pair<int, const DIFFITEM *> it) const
 +      {
 +              return ((*this).*m_cur_method)(pscript, it);
 +      }
 +
 +      bool operator()(const DIFFITEM & di) const
 +      {
 +              return ((*this).*m_cur_method2)(di);
 +      }
 +
 +      method_type m_cur_method;
 +      method_type2 m_cur_method2;
 +      const CDiffContext& m_ctxt;
 +      const bool *m_RO;
 +};
 +
 +struct Counts {
 +      Counts() : count(0), total(0) {}
 +      Counts(int c, int t): count(c), total(t) {}
 +      int count;
 +      int total;
 +};
 +
 +template<class InputIterator, class Predicate>
 +Counts Count(const InputIterator& begin, const InputIterator& end, const Predicate& pred) 
 +{
 +      int count = 0, total = 0;
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              if (pred(*it))
 +                      ++count;
 +              ++total;
 +      }
 +      return Counts(count, total);
 +}
 +
 +struct ContextMenuCounts {
 +      int nTotal; // total #items (includes files & directories, either side)
 +      int nCopyable[3];
 +      int nDeletable[3];
 +      int nDeletableOnBoth;
 +      int nOpenable[3];
 +      int nOpenableOnBoth;
 +      int nOpenableOnWith[3];
 +      int nDiffItems;
 +};
 +
 +template<class InputIterator>
 +ContextMenuCounts CountForContextMenu(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
 +{
 +      ContextMenuCounts counts = {0};
 +      int nDirs = ctxt.GetCompareDirs();
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
 +              if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
 +                      continue;
 +              int nOpenablePerItem = 0;
 +              for (int j = 0; j < nDirs; ++j)
 +              {
 +                      if (IsItemCopyable(di, j))
 +                              ++counts.nCopyable[j];
 +                      if (IsItemDeletable(di, j))
 +                              ++counts.nDeletable[j];         
 +                      if (IsItemOpenableOn(di, j))
 +                      {
 +                              ++nOpenablePerItem;
 +                              ++counts.nOpenable[j];
 +                      }
 +                      if (IsItemOpenableOnWith(di, j))
 +                              ++counts.nOpenableOnWith[j];
 +              }
 +              if (IsItemDeletableOnBoth(ctxt, di))
 +                      ++counts.nDeletableOnBoth;
 +
 +              if (IsItemNavigableDiff(ctxt, di))
 +                      ++counts.nDiffItems;
 +
 +              if (nOpenablePerItem == nDirs)
 +                      ++counts.nOpenableOnBoth;
 +
 +              ++counts.nTotal;
 +      }
 +      return counts;
 +}
 +
 +
 +/**
 + * @brief Rename selected item on both left and right sides.
 + *
 + * @param szNewItemName [in] New item name.
 + *
 + * @return true if at least one file was renamed successfully.
 + */
 +template<class InputIterator>
 +bool DoItemRename(InputIterator& it, const CDiffContext& ctxt, const String& szNewItemName)
 +{
 +      PathContext paths;
 +      int nDirs = ctxt.GetCompareDirs();
 +
 +      assert(it != InputIterator());
 +
 +      // We must check that paths still exists
 +      String failpath;
 +      DIFFITEM &di = *it;
 +      paths = ::GetItemFileNames(ctxt, di);
 +      for (int i = 0; i < paths.GetSize(); ++i)
 +      {
 +              if (paths_DoesPathExist(paths[i]) == DOES_NOT_EXIST)
 +                      throw ContentsChangedException(failpath);
 +      }
 +
 +      bool bRename[3] = {false};
 +      int index;
 +      for (index = 0; index < nDirs; index++)
 +      {
-               if (di.diffcode.isExists(index))
++              if (di.diffcode.exists(index))
 +                      bRename[index] = RenameOnSameDir(paths[index], szNewItemName);
 +      }
 +
 +      int nSuccessCount = 0;
 +      for (index = 0; index < nDirs; index++)
 +              nSuccessCount += bRename[index] ? 1 : 0;
 +
 +      if (nSuccessCount > 0)
 +      {
 +              for (index = 0; index < nDirs; index++)
 +              {
 +                      if (bRename[index])
 +                              di.diffFileInfo[index].filename = szNewItemName;
 +                      else
 +                              di.diffFileInfo[index].filename = _T("");
 +              }
 +      }
 +
 +      return (bRename[0] || bRename[1] || (nDirs > 2 && bRename[2]));
 +}
 +
 +template<class InputIterator, class OutputIterator>
 +OutputIterator CopyPathnames(const InputIterator& begin, const InputIterator& end, OutputIterator result, SIDE_TYPE stype, const CDiffContext& ctxt)
 +{
 +      const int index = SideToIndex(ctxt, stype);
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
-                       if (di.diffcode.isExists(i))
++              if (di.diffcode.exists(index))
 +              {
 +                      *result = GetItemFileName(ctxt, di, index);
 +                      ++result;
 +              }
 +      }
 +      return result;
 +}
 +
 +template<class InputIterator, class OutputIterator>
 +OutputIterator CopyBothPathnames(const InputIterator& begin, const InputIterator& end, OutputIterator result, const CDiffContext& ctxt)
 +{
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
 +              for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
 +              {
-                               if (di.diffcode.isExists(i))
++                      if (di.diffcode.exists(i))
 +                      {
 +                              *result = GetItemFileName(ctxt, di, i);
 +                              ++result;
 +                      }
 +              }
 +      }
 +      return result;
 +}
 +
 +template<class InputIterator, class OutputIterator>
 +OutputIterator CopyFilenames(const InputIterator& begin, const InputIterator& end, OutputIterator result)
 +{
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
 +              if (!di.diffcode.isDirectory())
 +              {
 +                      *result = di.diffFileInfo[0].filename;
 +                      ++result;
 +              }
 +      }
 +      return result;
 +}
 +
 +template<class InputIterator, class OutputIterator>
 +OutputIterator CopyPathnamesForDragAndDrop(const InputIterator& begin, const InputIterator& end, OutputIterator result, const CDiffContext& ctxt)
 +{
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
 +
 +              // check for special items (e.g not "..")
 +              if (di.diffcode.diffcode == 0)
 +                      continue;
 +
 +              if (!IsItemExistAll(ctxt, di) || di.diffcode.isResultDiff())
 +              {
 +                      for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
 +                      {
-                               if (di.diffcode.isExists(i))
++                              if (di.diffcode.exists(i))
 +                              {
 +                                      *result = GetItemFileName(ctxt, di, i);
 +                                      ++result;
 +                              }
 +                      }
 +              }
 +              else
 +              {
 +                      *result = GetItemFileName(ctxt, di, 0);
 +                      ++result;
 +              }
 +      }
 +      return result;
 +}
 +
 +template<class InputIterator, class BinaryFunction>
 +void ApplyFolderNameAndFileName(const InputIterator& begin, const InputIterator& end, SIDE_TYPE stype,
 +      const CDiffContext& ctxt, BinaryFunction func)
 +{
 +      int index = SideToIndex(ctxt, stype);
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
 +              if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
 +                      continue;
 +              String filename = di.diffFileInfo[index].filename;
 +              String currentDir = di.getFilepath(index, ctxt.GetNormalizedPath(index));
 +              func(currentDir, filename);
 +      }
 +}
 +
 +/**
 + * @brief Apply specified setting for prediffing to all selected items
 + */
 +template<class InputIterator>
 +void ApplyPluginPrediffSetting(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt, int newsetting)
 +{
 +      // Unlike other group actions, here we don't build an action list
 +      // to execute; we just apply this change directly
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
 +              if (!di.diffcode.isDirectory())
 +              {
 +                      String filteredFilenames;
 +                      for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
 +                      {
-                       if (di.diffcode.diffcode != 0 && di.diffcode.isExists(i))
++                              if (di.diffcode.exists(i))
 +                              {
 +                                      if (!filteredFilenames.empty()) filteredFilenames += _T("|");
 +                                      filteredFilenames += ::GetItemFileName(ctxt, di, i);
 +                              }
 +                      }
 +                      PackingInfo * infoUnpacker = 0;
 +                      PrediffingInfo * infoPrediffer = 0;
 +                      const_cast<CDiffContext&>(ctxt).FetchPluginInfos(filteredFilenames, &infoUnpacker, &infoPrediffer);
 +                      infoPrediffer->Initialize(newsetting);
 +              }
 +      }
 +}
 +
 +/**
 + * @brief Updates just before displaying plugin context view in list
 + */
 +template<class InputIterator>
 +std::pair<int, int> CountPredifferYesNo(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
 +{
 +      int nPredifferYes = 0;
 +      int nPredifferNo = 0;
 +
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
 +              if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
 +                      continue;
 +
 +              // note the prediffer flag for 'files present on both sides and not skipped'
 +              if (!di.diffcode.isDirectory() && !di.diffcode.isBin() && IsItemExistAll(ctxt, di)
 +                      && !di.diffcode.isResultFiltered())
 +              {
 +                      PathContext files = GetItemFileNames(ctxt, di);
 +                      String filteredFilenames = string_join(files.begin(), files.end(), _T("|"));
 +                      PackingInfo * unpacker;
 +                      PrediffingInfo * prediffer;
 +                      const_cast<CDiffContext&>(ctxt).FetchPluginInfos(filteredFilenames, &unpacker, &prediffer);
 +                      if (prediffer->bToBeScanned == 1 || prediffer->pluginName.empty() == false)
 +                              nPredifferYes ++;
 +                      else
 +                              nPredifferNo ++;
 +              }
 +      }
 +      return std::make_pair(nPredifferYes, nPredifferNo);
 +}
 +
 +template<class InputIterator>
 +IntToIntMap CountCodepages(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
 +{
 +      IntToIntMap map;
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              const DIFFITEM& di = *it;
 +              for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
 +              {
-                       if (affect[i] && di.diffcode.isExists(i) && di.diffFileInfo[i].IsEditableEncoding())
++                      if (di.diffcode.diffcode != 0 && di.diffcode.exists(i))
 +                              map.Increment(di.diffFileInfo[i].encoding.m_codepage);
 +              }
 +      }
 +      return map;
 +}
 +
 +template<class InputIterator>
 +void ApplyCodepage(const InputIterator& begin, const InputIterator& end, CDiffContext& ctxt, const bool affect[3], int nCodepage)
 +{
 +      for (InputIterator it = begin; it != end; ++it)
 +      {
 +              DIFFITEM& di = *it;
 +              if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
 +                      continue;
 +              if (di.diffcode.isDirectory())
 +                      continue;
 +
 +              for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
 +              {
 +                      // Does it exist on left? (ie, right or both)
++                      if (affect[i] && di.diffcode.exists(i) && di.diffFileInfo[i].IsEditableEncoding())
 +                      {
 +                              di.diffFileInfo[i].encoding.SetCodepage(nCodepage);
 +                      }
 +              }
 +      }
 +}
 +
 +/// get file name on specified side for first selected item
 +template<class InputIterator>
 +String GetSelectedFileName(InputIterator& it, SIDE_TYPE stype, const CDiffContext& ctxt)
 +{
 +      if (it == InputIterator())
 +              return _T("");
 +      return GetItemFileName(ctxt, *it, SideToIndex(ctxt, stype));
 +}
diff --cc Src/DirDoc.cpp
@@@ -328,18 -489,27 +326,17 @@@ CDirView * CDirDoc::GetMainView() cons
  }
  
  /**
 - * @brief Update in-memory diffitem status from disk.
 - * @param [in] diffPos POSITION of item in UI list.
 - * @param [in] idx index to update.
 - */
 -void CDirDoc::UpdateStatusFromDisk(uintptr_t diffPos, int idx)
 -{
 -      m_pCtxt->UpdateStatusFromDisk(diffPos, idx);
 -}
 -
 -/**
   * @brief Update in-memory diffitem status from disk and update view.
   * @param [in] diffPos POSITION of item in UI list.
-  * @param [in] bLeft If TRUE left-side item is updated.
-  * @param [in] bRight If TRUE right-side item is updated.
+  * @param [in] idx index to reload.
   * @note Do not call this function from DirView code! This function
   * calls slow DirView functions to get item position and to update GUI.
   * Use UpdateStatusFromDisk() function instead.
   */
- void CDirDoc::ReloadItemStatus(uintptr_t diffPos, int index)
+ void CDirDoc::ReloadItemStatus(uintptr_t diffPos, int idx)
  {
        // in case just copied (into existence) or modified
-       m_pCtxt->UpdateStatusFromDisk(diffPos, index);
 -      UpdateStatusFromDisk(diffPos, idx);
++      m_pCtxt->UpdateStatusFromDisk(diffPos, idx);
  
        int nIdx = m_pDirView->GetItemIndex(diffPos);
        if (nIdx != -1)
diff --cc Src/DirDoc.h
@@@ -97,9 -97,13 +97,9 @@@ public
        void CompareReady();
        void UpdateChangedItem(PathContext & paths,
                UINT nDiffs, UINT nTrivialDiffs, BOOL bIdentical);
 -      uintptr_t FindItemFromPaths(const String& pathLeft, const String& pathRight);
 -      void SetDiffSide(UINT diffcode, int idx);
 -      void SetDiffCompare(UINT diffcode, int idx);
        void UpdateResources();
        void InitStatusStrings();
-       void ReloadItemStatus(uintptr_t diffPos, int index);
 -      void UpdateStatusFromDisk(uintptr_t diffPos, int idx);
+       void ReloadItemStatus(uintptr_t diffPos, int idx);
        void Redisplay();
        virtual ~CDirDoc();
        void SetDirView( CDirView *newView ); // TODO Perry
diff --cc Src/DirView.cpp
@@@ -1341,15 -1802,15 +1341,15 @@@ void CDirView::OpenSelection(SELECTIONT
                {
                        theApp.m_strDescriptions[0].erase();
                        theApp.m_strDescriptions[1].erase();
-                       if (pdi[0] == pdi[1] && !pdi[0]->diffcode.isExists(0))
+                       if (pdi[0] == pdi[1] && !pdi[0]->diffcode.exists(0))
                        {
                                paths[0] = _T("");
 -                              theApp.m_strDescriptions[0] = theApp.LoadString(IDS_EMPTY_LEFT_FILE);
 +                              theApp.m_strDescriptions[0] = _("Untitled left");
                        }
-                       if (pdi[0] == pdi[1] && !pdi[0]->diffcode.isExists(1))
+                       if (pdi[0] == pdi[1] && !pdi[0]->diffcode.exists(1))
                        {
                                paths[1] = _T("");
 -                              theApp.m_strDescriptions[1] = theApp.LoadString(IDS_EMPTY_RIGHT_FILE);
 +                              theApp.m_strDescriptions[1] = _("Untitled right");
                        }
                }
                else
                        theApp.m_strDescriptions[0].erase();
                        theApp.m_strDescriptions[1].erase();
                        theApp.m_strDescriptions[2].erase();
-                       if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.isExists(0))
+                       if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.exists(0))
                        {
                                paths[0] = _T("");
 -                              theApp.m_strDescriptions[0] = theApp.LoadString(IDS_EMPTY_LEFT_FILE);
 +                              theApp.m_strDescriptions[0] = _("Untitled left");
                        }
-                       if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.isExists(1))
+                       if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.exists(1))
                        {
                                paths[1] = _T("");
 -                              theApp.m_strDescriptions[1] = theApp.LoadString(IDS_EMPTY_MIDDLE_FILE);
 +                              theApp.m_strDescriptions[1] = _("Untitled middle");
                        }
-                       if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.isExists(2))
+                       if (pdi[0] == pdi[1] && pdi[0] == pdi[2] && !pdi[0]->diffcode.exists(2))
                        {
                                paths[2] = _T("");
 -                              theApp.m_strDescriptions[2] = theApp.LoadString(IDS_EMPTY_RIGHT_FILE);
 +                              theApp.m_strDescriptions[2] = _("Untitled right");
                        }
                }
  
@@@ -2926,10 -3965,10 +2923,11 @@@ afx_msg void CDirView::OnEndLabelEdit(N
   */
  void CDirView::OnMarkedRescan()
  {
 -      UINT items = MarkSelectedForRescan();
 -      if (items > 0)
 +      std::for_each(SelBegin(), SelEnd(), MarkForRescan);
 +      if (std::distance(SelBegin(), SelEnd()) > 0)
        {
 -              m_pSavedTreeState.reset(SaveTreeState());
++              m_pSavedTreeState.reset(SaveTreeState(GetDiffContext()));
 +              GetDocument()->SetMarkedRescan();
                GetDocument()->Rescan();
        }
  }
@@@ -367,23 -313,23 +367,23 @@@ static String ColStatusGet(const CDiffC
        }
        else if (di.diffcode.isSideThirdOnly())
        {
 -              s = theApp.LoadString(IDS_RIGHT_ONLY_IN_FMT);
 -              string_replace(s, _T("%1"), di.getFilepath(2, pCtxt->GetNormalizedRight()));
 +              s = string_format_string1(_("Right only: %1"),
 +                              di.getFilepath(2, pCtxt->GetNormalizedRight()));
        }
-       else if (nDirs > 2 && !di.diffcode.isExistsFirst())
+       else if (nDirs > 2 && !di.diffcode.existsFirst())
        {
 -              s = theApp.LoadString(IDS_DOES_NOT_EXIST_IN_FMT);
 -              string_replace(s, _T("%1"), pCtxt->GetNormalizedLeft());
 +              s = string_format_string1(_("Does not exist in %1"),
 +                              pCtxt->GetNormalizedLeft());
        }
-       else if (nDirs > 2 && !di.diffcode.isExistsSecond())
+       else if (nDirs > 2 && !di.diffcode.existsSecond())
        {
 -              s = theApp.LoadString(IDS_DOES_NOT_EXIST_IN_FMT);
 -              string_replace(s, _T("%1"), pCtxt->GetNormalizedMiddle());
 +              s = string_format_string1(_("Does not exist in %1"),
 +                              pCtxt->GetNormalizedMiddle());
        }
-       else if (nDirs > 2 && !di.diffcode.isExistsThird())
+       else if (nDirs > 2 && !di.diffcode.existsThird())
        {
 -              s = theApp.LoadString(IDS_DOES_NOT_EXIST_IN_FMT);
 -              string_replace(s, _T("%1"), pCtxt->GetNormalizedRight());
 +              s = string_format_string1(_("Does not exist in %1"),
 +                              pCtxt->GetNormalizedRight());
        }
        else if (di.diffcode.isResultSame())
        {
@@@ -619,19 -565,19 +619,19 @@@ static String ColStatusAbbrGet(const CD
        }
        else if (di.diffcode.isSideThirdOnly())
        {
 -              id = IDS_RIGHTONLY;
 +              id = N_("Right Only");
        }
-       else if (nDirs > 2 && !di.diffcode.isExistsFirst())
+       else if (nDirs > 2 && !di.diffcode.existsFirst())
        {
 -              id = IDS_NOITEMLEFT;
 +              id = N_("No item in left");
        }
-       else if (nDirs > 2 && !di.diffcode.isExistsSecond())
+       else if (nDirs > 2 && !di.diffcode.existsSecond())
        {
 -              id = IDS_NOITEMMIDDLE;
 +              id = N_("No item in middle");
        }
-       else if (nDirs > 2 && !di.diffcode.isExistsThird())
+       else if (nDirs > 2 && !di.diffcode.existsThird())
        {
 -              id = IDS_NOITEMRIGHT;
 +              id = N_("No item in right");
        }
        else if (di.diffcode.isResultSame())
        {
@@@ -8,7 -8,7 +8,7 @@@ msgid "
  msgstr ""
  "Project-Id-Version: WinMerge\n"
  "Report-Msgid-Bugs-To: http://bugs.winmerge.org/\n"
- "POT-Creation-Date: 2015-02-13 21:36+0000\n"
 -"POT-Creation-Date: 2015-02-15 15:37+0000\n"
++"POT-Creation-Date: 2015-02-17 15:14+0000\n"
  "PO-Revision-Date: \n"
  "Last-Translator: \n"
  "Language-Team: English <winmerge-translate@lists.sourceforge.net>\n"