OSDN Git Service

2e4b6160f8b9897c1ca82487ccdd99cf0e40d6e2
[winmerge-jp/winmerge-jp.git] / Src / DiffWrapper.h
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** 
3  * @file  DiffWrapper.h
4  *
5  * @brief Declaration file for CDiffWrapper.
6  *
7  * @date  Created: 2003-08-22
8  */
9 #pragma once
10
11 #include <memory>
12 #include "diff.h"
13 #include "FileLocation.h"
14 #include "PathContext.h"
15 #include "CompareOptions.h"
16 #include "DiffList.h"
17 #include "UnicodeString.h"
18 #include "FileTransform.h"
19
20 class CDiffContext;
21 class PrediffingInfo;
22 struct DiffFileData;
23 class PathContext;
24 struct file_data;
25 class MovedLines;
26 class FilterList;
27 class SubstitutionList;
28 namespace CrystalLineParser { struct TextDefinition; };
29
30 /** @enum COMPARE_TYPE
31  * @brief Different foldercompare methods.
32  * These values are the foldercompare methods WinMerge supports.
33  */
34
35 /** @var CMP_CONTENT
36  * @brief Normal by content compare.
37  * This compare type is first, default and all-seeing compare type.
38  * diffutils is used for producing compare results. So all limitations
39  * of diffutils (like buffering) apply to this compare method. But this
40  * is also currently only compare method that produces difference lists
41  * we can use in file compare.
42  */
43
44 /** @var CMP_QUICK_CONTENT
45  * @brief Faster byte per byte -compare.
46  * This type of compare was a response for needing faster compare results
47  * in folder compare. It independent from diffutils, and fully customised
48  * for WinMerge. It basically does byte-per-byte compare, still implementing
49  * different whitespace ignore options.
50  *
51  * Optionally this compare type can be stopped when first difference is found.
52  * Which gets compare as fast as possible. But misses sometimes binary files
53  * if zero bytes aren't found before first difference. Also difference counts
54  * are not useful with that option.
55  */
56
57 /** @var CMP_DATE
58  * @brief Compare by modified date.
59  * This compare type was added after requests and realization that in some
60  * situations difference in file's timestamps is enough to judge them
61  * different. E.g. when modifying files in local machine, file timestamps
62  * are certainly different after modifying them. This method doesn't even
63  * open files for reading them. It only reads file's infos for timestamps
64  * and compares them.
65  *
66  * This is no doubt fastest way to compare files.
67  */
68
69 /** @var CMP_DATE_SIZE
70  * @brief Compare by date and then by size.
71  * This method is basically same than CMP_DATE, but it adds check for file
72  * sizes if timestamps are identical. This is because there are situations
73  * timestamps can't be trusted alone, especially with network shares. Adding
74  * checking for file sizes adds some more reliability for results with
75  * minimal increase in compare time.
76  */
77
78 /** @var CMP_SIZE
79  * @brief Compare by file size.
80  * This compare method compares file sizes. This isn't quite accurate method,
81  * other than it can detect files that certainly differ. But it can show lot of
82  * different files as identical too. Advantage is in some use cases where different
83  * size always means files are different. E.g. automatically created logs - when
84  * more data is added size increases.
85  */
86 enum COMPARE_TYPE
87 {
88         CMP_CONTENT = 0,
89         CMP_QUICK_CONTENT,
90         CMP_BINARY_CONTENT,
91         CMP_DATE,
92         CMP_DATE_SIZE,
93         CMP_SIZE,
94         CMP_IMAGE_CONTENT,
95 };
96
97 /**
98  * @brief Additional options for creating patch files
99  */
100 struct PATCHOPTIONS
101 {
102         enum output_style outputStyle; /**< Patch file style. */
103         int nContext; /**< Number of context lines. */
104         bool bAddCommandline; /**< Add diff-style commandline to patch file. */
105 };
106
107 enum class IDENTLEVEL {
108         ALL,
109         NONE,
110         EXCEPTLEFT,
111         EXCEPTMIDDLE,
112         EXCEPTRIGHT,
113 };
114 /**
115  * @brief Diffutils returns this statusdata about files compared
116  */
117 struct DIFFSTATUS
118 {
119         bool bMissingNL[3] {}; /**< file is missing EOL before EOF */
120         bool bBinaries = false; /**< Files are binaries */
121         IDENTLEVEL Identical = IDENTLEVEL::NONE; /**< diffutils said files are identical */
122         bool bPatchFileFailed = false; /**< Creating patch file failed */
123
124         DIFFSTATUS() {}
125         void MergeStatus(const DIFFSTATUS& other)
126         {
127                 if (Identical == IDENTLEVEL::ALL)
128                         Identical = other.Identical;
129                 else if (
130                          (Identical == IDENTLEVEL::EXCEPTLEFT   && other.Identical != IDENTLEVEL::EXCEPTLEFT) ||
131                          (Identical == IDENTLEVEL::EXCEPTRIGHT  && other.Identical != IDENTLEVEL::EXCEPTRIGHT) ||
132                          (Identical == IDENTLEVEL::EXCEPTMIDDLE && other.Identical != IDENTLEVEL::EXCEPTMIDDLE))
133                         Identical = IDENTLEVEL::NONE;
134                 if (other.bPatchFileFailed)
135                         bPatchFileFailed = true;
136                 if (other.bBinaries)
137                         bBinaries = true;
138                 std::copy_n(other.bMissingNL, 3, bMissingNL);
139         }
140 };
141
142 struct PostFilterContext
143 {
144         int nParsedLineEndLeft = -1;
145         int nParsedLineEndRight = -1;
146         unsigned dwCookieLeft = 0;
147         unsigned dwCookieRight = 0;
148 };
149
150 /**
151  * @brief Wrapper class for diffengine (diffutils and ByteComparator).
152  * Diffwappre class is used to run selected diffengine. For folder compare
153  * there are several methods (COMPARE_TYPE), but for file compare diffutils
154  * is used always. For file compare diffutils can output results to external
155  * DiffList or to patch file. Output type must be selected with member
156  * functions SetCreatePatchFile() and SetCreateDiffList().
157  */
158 class CDiffWrapper
159 {
160 public:
161         CDiffWrapper();
162         ~CDiffWrapper();
163         void SetCreatePatchFile(const String &filename);
164         void SetCreateDiffList(DiffList *diffList);
165         void GetOptions(DIFFOPTIONS *options) const;
166         void SetOptions(const DIFFOPTIONS *options);
167         void SetTextForAutomaticPrediff(const String &text);
168         void SetPrediffer(const PrediffingInfo * prediffer = nullptr);
169         void GetPrediffer(PrediffingInfo * prediffer) const;
170         void SetPatchOptions(const PATCHOPTIONS *options);
171         void SetDetectMovedBlocks(bool bDetectMovedBlocks);
172         bool GetDetectMovedBlocks() const { return (m_pMovedLines[0] != nullptr); }
173         void SetAppendFiles(bool bAppendFiles);
174         void SetPaths(const PathContext &files, bool tempPaths);
175         void SetAlternativePaths(const PathContext &altPaths);
176         bool RunFileDiff();
177         void GetDiffStatus(DIFFSTATUS *status) const;
178         void AddDiffRange(DiffList *pDiffList, unsigned begin0, unsigned end0, unsigned begin1, unsigned end1, OP_TYPE op);
179         void AddDiffRange(DiffList *pDiffList, DIFFRANGE &dr);
180         void FixLastDiffRange(int nFiles, int bufferLines[], bool bMissingNL[], bool bIgnoreBlankLines);
181         MovedLines * GetMovedLines(int index) { return m_pMovedLines[index].get(); }
182         void SetCompareFiles(const PathContext &originalFile);
183         void WritePatchFileHeader(enum output_style output_style, bool bAppendFiles);
184         void WritePatchFileTerminator(enum output_style output_style);
185         void SetFilterList(const String& filterStr);
186         void SetFilterList(const FilterList *pFilterList);
187         const SubstitutionList* GetIgnoredSubstitutionsList() const;
188         void SetIgnoredSubstitutionsList(std::shared_ptr<SubstitutionList> pIgnoredSubstitutionsList);
189         void SetFilterCommentsSourceDef(CrystalLineParser::TextDefinition *def) { m_pFilterCommentsDef = def; };
190         void SetFilterCommentsSourceDef(const String& ext);
191         void EnablePlugins(bool enable);
192         void PostFilter(PostFilterContext& ctxt, int LineNumberLeft, int QtyLinesLeft, int LineNumberRight,
193                 int QtyLinesRight, OP_TYPE &Op, const file_data *file_data_ary) const;
194
195 protected:
196         String FormatSwitchString() const;
197         bool Diff2Files(struct change ** diffs, DiffFileData *diffData,
198                 int * bin_status, int * bin_file) const;
199         void LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const file_data * inf);
200         void WritePatchFile(struct change * script, file_data * inf);
201 public:
202         void LoadWinMergeDiffsFromDiffUtilsScript3(
203                 struct change * script10, struct change * script12,
204                 const file_data * inf10, const file_data * inf12);
205         static void FreeDiffUtilsScript(struct change * & script);
206         bool RegExpFilter(int StartPos, int EndPos, const file_data * pinf) const;
207
208 private:
209         DiffutilsOptions m_options;
210         DIFFSTATUS m_status; /**< Status of last compare */
211         std::unique_ptr<FilterList> m_pFilterList; /**< List of linefilters. */
212         std::shared_ptr<SubstitutionList> m_pSubstitutionList;
213
214         PathContext m_files; /**< Full path to diff'ed file. */
215         PathContext m_alternativePaths; /**< file's alternative path (may be relative). */
216         PathContext m_originalFile; /**< file's original (NON-TEMP) path. */
217
218         String m_sPatchFile; /**< Full path to created patch file. */
219         bool m_bPathsAreTemp; /**< Are compared paths temporary? */
220         /// prediffer info are stored only for MergeDoc
221         std::unique_ptr<PrediffingInfo> m_infoPrediffer;
222         /// prediffer info are stored only for MergeDoc
223         String m_sToFindPrediffer;
224         bool m_bUseDiffList; /**< Are results returned in difflist? */
225         bool m_bCreatePatchFile; /**< Do we create a patch file? */
226         bool m_bAddCmdLine; /**< Do we add commandline to patch file? */
227         bool m_bAppendFiles; /**< Do we append to existing patch file? */
228         int m_nDiffs; /**< Difference count */
229         DiffList *m_pDiffList; /**< Pointer to external DiffList */
230         std::unique_ptr<MovedLines> m_pMovedLines[3];
231         CrystalLineParser::TextDefinition *m_pFilterCommentsDef; /**< Text definition for Comments filter  */
232         bool m_bPluginsEnabled; /**< Are plugins enabled? */
233 };
234
235 /**
236  * @brief Set text tested to find the prediffer automatically.
237  * Most probably a concatenated string of both filenames.
238  */
239 inline void CDiffWrapper::SetTextForAutomaticPrediff(const String &text)
240 {
241         m_sToFindPrediffer = text;
242 }
243
244 inline void CDiffWrapper::GetPrediffer(PrediffingInfo * prediffer) const
245 {
246         *prediffer = *m_infoPrediffer;
247 }
248
249 /**
250  * @brief Set plugins enabled/disabled.
251  * @param [in] enable if true plugins are enabled.
252  */
253 inline void CDiffWrapper::EnablePlugins(bool enable)
254 {
255         m_bPluginsEnabled = enable;
256 }
257
258 /**
259  * @brief Set source paths for original (NON-TEMP) diffing two files.
260  * Sets full paths to two (NON-TEMP) files we are diffing.
261  * @param [in] OriginalFile1 First file to compare "(NON-TEMP) file".
262  * @param [in] OriginalFile2 Second file to compare "(NON-TEMP) file".
263  */
264 inline void CDiffWrapper::SetCompareFiles(const PathContext &originalFile)
265 {
266         m_originalFile = originalFile;
267 }
268
269 /**
270  * @brief Set alternative paths for compared files.
271  * Sets alternative paths for diff'ed files. These alternative paths might not
272  * be real paths. For example when creating a patch file from folder compare
273  * we want to use relative paths.
274  * @param [in] altPaths Alternative file paths.
275  */
276 inline void CDiffWrapper::SetAlternativePaths(const PathContext &altPaths)
277 {
278         m_alternativePaths = altPaths;
279 }
280