OSDN Git Service

autoit.cpp - Macros >> User 1 ..... Variable >> User 2 (#749) (2)
[winmerge-jp/winmerge-jp.git] / Src / DiffContext.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 //    WinMerge:  an interactive diff/merge utility
3 //    Copyright (C) 1997-2000  Thingamahoochie Software
4 //    Author: Dean Grimm
5 //    SPDX-License-Identifier: GPL-2.0-or-later
6 /////////////////////////////////////////////////////////////////////////////
7 /**
8  *  @file DiffContext.cpp
9  *
10  *  @brief Implementation of CDiffContext
11  */ 
12
13 #include "pch.h"
14 #include "DiffContext.h"
15 #include <Poco/ScopedLock.h>
16 #include "CompareOptions.h"
17 #include "VersionInfo.h"
18 #include "paths.h"
19 #include "codepage_detect.h"
20 #include "DiffItemList.h"
21 #include "IAbortable.h"
22 #include "DiffWrapper.h"
23 #include "DebugNew.h"
24
25 using Poco::FastMutex;
26
27 //////////////////////////////////////////////////////////////////////
28 // Construction/Destruction
29 //////////////////////////////////////////////////////////////////////
30
31 /**
32  * @brief Construct CDiffContext.
33  *
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.
37  */
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)
50 , m_pOptions(nullptr)
51 , m_bPluginsEnabled(false)
52 , m_bRecursive(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)
61 {
62         int index;
63         for (index = 0; index < paths.GetSize(); index++)
64                 m_paths.SetPath(index, paths[index]);
65 }
66
67 /**
68  * @brief Destructor.
69  */
70 CDiffContext::~CDiffContext()
71 {
72 }
73
74 /**
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 
80  */
81 void CDiffContext::UpdateStatusFromDisk(DIFFITEM *diffpos, int nIndex)
82 {
83         DIFFITEM &di = GetDiffRefAt(diffpos);
84         di.diffFileInfo[nIndex].ClearPartial();
85         if (di.diffcode.exists(nIndex))
86                 UpdateInfoFromDiskHalf(di, nIndex);
87 }
88
89 /**
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
96  */
97 bool CDiffContext::UpdateInfoFromDiskHalf(DIFFITEM &di, int nIndex)
98 {
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))
102                 return false;
103         UpdateVersion(di, nIndex);
104         dfi.encoding = GuessCodepageEncoding(filepath, m_iGuessEncodingType);
105         return true;
106 }
107
108 /**
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.
115  */
116 static bool CheckFileForVersion(const String& ext)
117 {
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"))
122         {
123                 return true;
124         }
125         return false;
126 }
127
128 /**
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.
135  */
136 void CDiffContext::UpdateVersion(DIFFITEM &di, int nIndex) const
137 {
138         DiffFileInfo & dfi = di.diffFileInfo[nIndex];
139         // Check only binary files
140         dfi.version.SetFileVersionNone();
141
142         if (di.diffcode.isDirectory())
143                 return;
144         
145         String spath;
146         if (!di.diffcode.exists(nIndex))
147                 return;
148         String ext = paths::FindExtension(di.diffFileInfo[nIndex].filename);
149         if (!CheckFileForVersion(ext))
150                 return;
151         spath = di.getFilepath(nIndex, GetNormalizedPath(nIndex));
152         spath = paths::ConcatPath(spath, di.diffFileInfo[nIndex].filename);
153         
154         // Get version info if it exists
155         CVersionInfo ver(spath.c_str());
156         unsigned verMS = 0;
157         unsigned verLS = 0;
158         if (ver.GetFixedFileVersion(verMS, verLS))
159                 dfi.version.SetFileVersion(verMS, verLS);
160 }
161
162 /**
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.
170  */
171 bool CDiffContext::CreateCompareOptions(int compareMethod, const DIFFOPTIONS & options)
172 {
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));
178         else
179                 return false;
180
181         m_nCompMethod = compareMethod;
182         if (GetCompareOptions(m_nCompMethod) == nullptr)
183         {
184                 // For Date and Date+Size compare `nullptr` is ok since they don't have actual
185                 // compare options.
186                 if (m_nCompMethod == CMP_DATE || m_nCompMethod == CMP_DATE_SIZE ||
187                         m_nCompMethod == CMP_SIZE)
188                 {
189                         return true;
190                 }
191                 else
192                         return false;
193         }
194         return true;
195 }
196
197 /**
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.
205  */
206 CompareOptions * CDiffContext::GetCompareOptions(int compareMethod)
207 {
208         FastMutex::ScopedLock lock(m_mutex);
209         CompareOptions *pCompareOptions = nullptr;
210
211         // Otherwise we have to create new options
212         switch (compareMethod)
213         {
214         case CMP_CONTENT:
215                 if (m_pContentCompareOptions != nullptr)
216                         return m_pContentCompareOptions.get();
217                 m_pContentCompareOptions.reset(pCompareOptions = new DiffutilsOptions());
218                 break;
219
220         case CMP_QUICK_CONTENT:
221                 if (m_pQuickCompareOptions != nullptr)
222                         return m_pQuickCompareOptions.get();
223                 m_pQuickCompareOptions.reset(pCompareOptions = new QuickCompareOptions());
224                 break;
225         }
226
227
228         if (pCompareOptions != nullptr)
229                 pCompareOptions->SetFromDiffOptions(*m_pOptions);
230
231         return pCompareOptions;
232 }
233
234 /** @brief Forward call to retrieve plugin info (winds up in DirDoc) */
235 void CDiffContext::FetchPluginInfos(const String& filteredFilenames,
236                 PackingInfo ** infoUnpacker, PrediffingInfo ** infoPrediffer)
237 {
238         assert(m_piPluginInfos != nullptr);
239         m_piPluginInfos->FetchPluginInfos(filteredFilenames, infoUnpacker, infoPrediffer);
240 }
241
242 /**
243  * @brief Check if user has requested aborting the compare.
244  * @return true if user has requested abort, false otherwise.
245  */
246 bool CDiffContext::ShouldAbort() const
247 {
248         return m_piAbortable!=nullptr && m_piAbortable->ShouldAbort();
249 }