1 /////////////////////////////////////////////////////////////////////////////
2 // WinMerge: an interactive diff/merge utility
3 // Copyright (C) 1997-2000 Thingamahoochie Software
5 // SPDX-License-Identifier: GPL-2.0-or-later
6 /////////////////////////////////////////////////////////////////////////////
8 * @file DiffContext.cpp
10 * @brief Implementation of CDiffContext
14 #include "DiffContext.h"
15 #include <Poco/ScopedLock.h>
16 #include "CompareOptions.h"
17 #include "VersionInfo.h"
19 #include "codepage_detect.h"
20 #include "DiffItemList.h"
21 #include "IAbortable.h"
22 #include "DiffWrapper.h"
25 using Poco::FastMutex;
27 //////////////////////////////////////////////////////////////////////
28 // Construction/Destruction
29 //////////////////////////////////////////////////////////////////////
32 * @brief Construct CDiffContext.
34 * @param [in] pszLeft Initial left-side path.
35 * @param [in] pszRight Initial right-side path.
36 * @param [in] compareMethod Main compare method for this compare.
38 CDiffContext::CDiffContext(const PathContext & paths, int compareMethod)
39 : m_piFilterGlobal(nullptr)
40 , m_piPluginInfos(nullptr)
41 , m_nCompMethod(compareMethod)
42 , m_bIgnoreSmallTimeDiff(false)
43 , m_pCompareStats(nullptr)
44 , m_piAbortable(nullptr)
45 , m_bStopAfterFirstDiff(false)
46 , m_pFilterList(nullptr)
47 , m_pSubstitutionList(nullptr)
48 , m_pContentCompareOptions(nullptr)
49 , m_pQuickCompareOptions(nullptr)
51 , m_bPluginsEnabled(false)
53 , m_bWalkUniques(true)
54 , m_bIgnoreReparsePoints(false)
55 , m_bIgnoreCodepage(false)
56 , m_iGuessEncodingType(0)
57 , m_nQuickCompareLimit(0)
58 , m_nBinaryCompareLimit(0)
59 , m_bEnableImageCompare(false)
60 , m_dColorDistanceThreshold(0.0)
63 for (index = 0; index < paths.GetSize(); index++)
64 m_paths.SetPath(index, paths[index]);
70 CDiffContext::~CDiffContext()
75 * @brief Update info in item in result list from disk.
76 * This function updates result list item's file information from actual
77 * file in the disk. This updates info like date, size and attributes.
78 * @param [in] diffpos DIFFITEM to update.
79 * @param [in] nIndex index to update
81 void CDiffContext::UpdateStatusFromDisk(DIFFITEM *diffpos, int nIndex)
83 DIFFITEM &di = GetDiffRefAt(diffpos);
84 di.diffFileInfo[nIndex].ClearPartial();
85 if (di.diffcode.exists(nIndex))
86 UpdateInfoFromDiskHalf(di, nIndex);
90 * @brief Update file information from disk for DIFFITEM.
91 * This function updates DIFFITEM's file information from actual file in
92 * the disk. This updates info like date, size and attributes.
93 * @param [in, out] di DIFFITEM to update.
94 * @param [in] nIndex index to update
95 * @return true if file exists
97 bool CDiffContext::UpdateInfoFromDiskHalf(DIFFITEM &di, int nIndex)
99 String filepath = paths::ConcatPath(paths::ConcatPath(m_paths[nIndex], di.diffFileInfo[nIndex].path), di.diffFileInfo[nIndex].filename);
100 DiffFileInfo & dfi = di.diffFileInfo[nIndex];
101 if (!dfi.Update(filepath))
103 UpdateVersion(di, nIndex);
104 dfi.encoding = GuessCodepageEncoding(filepath, m_iGuessEncodingType);
109 * @brief Determine if file is one to have a version information.
110 * This function determines if the given file has a version information
111 * attached into it in resource. This is done by comparing file extension to
112 * list of known filename extensions usually to have a version information.
113 * @param [in] ext Extension to check.
114 * @return true if extension has version info, false otherwise.
116 static bool CheckFileForVersion(const String& ext)
118 String lower_ext = strutils::makelower(ext);
119 if (lower_ext == _T(".exe") || lower_ext == _T(".dll") || lower_ext == _T(".sys") ||
120 lower_ext == _T(".drv") || lower_ext == _T(".ocx") || lower_ext == _T(".cpl") ||
121 lower_ext == _T(".scr") || lower_ext == _T(".lang"))
129 * @brief Load file version from disk.
130 * Update fileversion for given item and side from disk. Note that versions
131 * are read from only some filetypes. See CheckFileForVersion() function
132 * for list of files to check versions.
133 * @param [in,out] di DIFFITEM to update.
134 * @param [in] bLeft If true left-side file is updated, right-side otherwise.
136 void CDiffContext::UpdateVersion(DIFFITEM &di, int nIndex) const
138 DiffFileInfo & dfi = di.diffFileInfo[nIndex];
139 // Check only binary files
140 dfi.version.SetFileVersionNone();
142 if (di.diffcode.isDirectory())
146 if (!di.diffcode.exists(nIndex))
148 String ext = paths::FindExtension(di.diffFileInfo[nIndex].filename);
149 if (!CheckFileForVersion(ext))
151 spath = di.getFilepath(nIndex, GetNormalizedPath(nIndex));
152 spath = paths::ConcatPath(spath, di.diffFileInfo[nIndex].filename);
154 // Get version info if it exists
155 CVersionInfo ver(spath.c_str());
158 if (ver.GetFixedFileVersion(verMS, verLS))
159 dfi.version.SetFileVersion(verMS, verLS);
163 * @brief Create compare-method specific compare options class.
164 * This function creates a compare options class that is specific for
165 * main compare method. Compare options class is initialized from
166 * given set of options.
167 * @param [in] compareMethod Selected compare method.
168 * @param [in] options Initial set of compare options.
169 * @return true if creation succeeds.
171 bool CDiffContext::CreateCompareOptions(int compareMethod, const DIFFOPTIONS & options)
173 m_pContentCompareOptions.reset();
174 m_pQuickCompareOptions.reset();
175 m_pOptions.reset(new DIFFOPTIONS);
176 if (m_pOptions != nullptr)
177 std::memcpy(m_pOptions.get(), &options, sizeof(DIFFOPTIONS));
181 m_nCompMethod = compareMethod;
182 if (GetCompareOptions(m_nCompMethod) == nullptr)
184 // For Date and Date+Size compare `nullptr` is ok since they don't have actual
186 if (m_nCompMethod == CMP_DATE || m_nCompMethod == CMP_DATE_SIZE ||
187 m_nCompMethod == CMP_SIZE)
198 * @brief Get compare-type specific compare options.
199 * This function returns per-compare method options. The compare options
200 * returned are converted from general options to match options for specific
201 * comapare type. Not all compare options in general set are available for
202 * some other compare type. And some options can have different values.
203 * @param [in] compareMethod Compare method used.
204 * @return Compare options class.
206 CompareOptions * CDiffContext::GetCompareOptions(int compareMethod)
208 FastMutex::ScopedLock lock(m_mutex);
209 CompareOptions *pCompareOptions = nullptr;
211 // Otherwise we have to create new options
212 switch (compareMethod)
215 if (m_pContentCompareOptions != nullptr)
216 return m_pContentCompareOptions.get();
217 m_pContentCompareOptions.reset(pCompareOptions = new DiffutilsOptions());
220 case CMP_QUICK_CONTENT:
221 if (m_pQuickCompareOptions != nullptr)
222 return m_pQuickCompareOptions.get();
223 m_pQuickCompareOptions.reset(pCompareOptions = new QuickCompareOptions());
228 if (pCompareOptions != nullptr)
229 pCompareOptions->SetFromDiffOptions(*m_pOptions);
231 return pCompareOptions;
234 /** @brief Forward call to retrieve plugin info (winds up in DirDoc) */
235 void CDiffContext::FetchPluginInfos(const String& filteredFilenames,
236 PackingInfo ** infoUnpacker, PrediffingInfo ** infoPrediffer)
238 assert(m_piPluginInfos != nullptr);
239 m_piPluginInfos->FetchPluginInfos(filteredFilenames, infoUnpacker, infoPrediffer);
243 * @brief Check if user has requested aborting the compare.
244 * @return true if user has requested abort, false otherwise.
246 bool CDiffContext::ShouldAbort() const
248 return m_piAbortable!=nullptr && m_piAbortable->ShouldAbort();