OSDN Git Service

Reduce compilation time (2)
[winmerge-jp/winmerge-jp.git] / Src / FolderCmp.cpp
1 /** 
2  * @file  FolderCmp.cpp
3  *
4  * @brief Implementation file for FolderCmp
5  */
6
7 #include "pch.h"
8 #include "diff.h"
9 #include "FolderCmp.h"
10 #include <cassert>
11 #include "Wrap_DiffUtils.h"
12 #include "ByteCompare.h"
13 #include "paths.h"
14 #include "FilterList.h"
15 #include "DiffContext.h"
16 #include "DiffList.h"
17 #include "DiffWrapper.h"
18 #include "FileTransform.h"
19 #include "codepage_detect.h"
20 #include "BinaryCompare.h"
21 #include "TimeSizeCompare.h"
22 #include "TFile.h"
23 #include "DebugNew.h"
24
25 using CompareEngines::ByteCompare;
26 using CompareEngines::BinaryCompare;
27 using CompareEngines::TimeSizeCompare;
28
29 static void GetComparePaths(CDiffContext * pCtxt, const DIFFITEM &di, PathContext & files);
30
31 FolderCmp::FolderCmp()
32 : m_pDiffUtilsEngine(nullptr)
33 , m_pByteCompare(nullptr)
34 , m_pBinaryCompare(nullptr)
35 , m_pTimeSizeCompare(nullptr)
36 , m_ndiffs(CDiffContext::DIFFS_UNKNOWN)
37 , m_ntrivialdiffs(CDiffContext::DIFFS_UNKNOWN)
38 {
39 }
40
41 FolderCmp::~FolderCmp()
42 {
43 }
44
45 bool FolderCmp::RunPlugins(CDiffContext * pCtxt, PluginsContext * plugCtxt, String &errStr)
46 {
47         // FIXME:
48         return true;
49 }
50
51 void FolderCmp::CleanupAfterPlugins(PluginsContext *plugCtxt)
52 {
53 }
54
55 /**
56  * @brief Prepare files (run plugins) & compare them, and return diffcode.
57  * This is function to compare two files in folder compare. It is not used in
58  * file compare.
59  * @param [in] pCtxt Pointer to compare context.
60  * @param [in, out] di Compared files with associated data.
61  * @return Compare result code.
62  */
63 int FolderCmp::prepAndCompareFiles(CDiffContext * pCtxt, DIFFITEM &di)
64 {
65         int nIndex;
66         int nCompMethod = pCtxt->GetCompareMethod();
67
68         unsigned code = DIFFCODE::FILE | DIFFCODE::CMPERR;
69
70         if (nCompMethod == CMP_CONTENT ||
71                 nCompMethod == CMP_QUICK_CONTENT)
72         {
73                 int nDirs = pCtxt->GetCompareDirs();
74
75                 // Reset text stats
76                 for (nIndex = 0; nIndex < nDirs; nIndex++)
77                         m_diffFileData.m_textStats[nIndex].clear();
78
79                 PathContext tFiles;
80                 GetComparePaths(pCtxt, di, tFiles);
81                 struct change *script10 = nullptr;
82                 struct change *script12 = nullptr;
83                 struct change *script02 = nullptr;
84                 FolderCmp diffdata10, diffdata12, diffdata02;
85                 String filepathUnpacked[3];
86                 String filepathTransformed[3];
87                 int codepage = 0;
88
89                 // For user chosen plugins, define bAutomaticUnpacker as false and use the chosen infoHandler
90                 // but how can we receive the infoHandler ? DirScan actually only 
91                 // returns info, but can not use file dependent information.
92
93                 // Transformation happens here
94                 // text used for automatic mode : plugin filter must match it
95                 String filteredFilenames = strutils::join(tFiles.begin(), tFiles.end(), _T("|"));
96
97                 PackingInfo * infoUnpacker = nullptr;
98                 PrediffingInfo * infoPrediffer = nullptr;
99
100                 // Get existing or new plugin infos
101                 if (pCtxt->m_piPluginInfos != nullptr)
102                         pCtxt->FetchPluginInfos(filteredFilenames, &infoUnpacker,
103                                         &infoPrediffer);
104
105                 FileTextEncoding encoding[3];
106                 bool bForceUTF8 = pCtxt->GetCompareOptions(nCompMethod)->m_bIgnoreCase;
107
108                 for (nIndex = 0; nIndex < nDirs; nIndex++)
109                 {
110                 // plugin may alter filepaths to temp copies (which we delete before returning in all cases)
111                         filepathUnpacked[nIndex] = tFiles[nIndex];
112
113                         //DiffFileData diffdata; //(filepathTransformed1, filepathTransformed2);
114                         // Invoke unpacking plugins
115                         if (infoUnpacker && strutils::compare_nocase(filepathUnpacked[nIndex], _T("NUL")) != 0)
116                         {
117                                 if (!FileTransform::Unpacking(infoUnpacker, filepathUnpacked[nIndex], filteredFilenames))
118                                         goto exitPrepAndCompare;
119
120                                 // we use the same plugins for both files, so they must be defined before second file
121                                 assert(!infoUnpacker->m_PluginOrPredifferMode != PLUGIN_MANUAL);
122                         }
123
124                         // As we keep handles open on unpacked files, Transform() may not delete them.
125                         // Unpacked files will be deleted at end of this function.
126                         filepathTransformed[nIndex] = filepathUnpacked[nIndex];
127
128                         encoding[nIndex] = GuessCodepageEncoding(filepathTransformed[nIndex], pCtxt->m_iGuessEncodingType);
129                         m_diffFileData.m_FileLocation[nIndex].encoding = encoding[nIndex];
130                 }
131
132                 if (!std::equal(encoding + 1, encoding + nDirs, encoding))
133                         bForceUTF8 = true;
134                 codepage = bForceUTF8 ? CP_UTF8 : (encoding[0].m_unicoding ? CP_UTF8 : encoding[0].m_codepage);
135                 for (nIndex = 0; nIndex < nDirs; nIndex++)
136                 {
137                 // Invoke prediff'ing plugins
138                         if (infoPrediffer && !m_diffFileData.Filepath_Transform(bForceUTF8, encoding[nIndex], filepathUnpacked[nIndex], filepathTransformed[nIndex], filteredFilenames, infoPrediffer))
139                                 goto exitPrepAndCompare;
140                 }
141
142                 // If options are binary equivalent, we could check for filesize
143                 // difference here, and bail out if files are clearly different
144                 // But, then we don't know if file is ascii or binary, and this
145                 // affects behavior (also, we don't have an icon for unknown type)
146
147                 // Actually compare the files
148                 // `diffutils_compare_files()` is a fairly thin front-end to GNU diffutils
149
150                 if (tFiles.GetSize() == 2)
151                 {
152                         m_diffFileData.SetDisplayFilepaths(tFiles[0], tFiles[1]); // store true names for diff utils patch file
153                         // This opens & fstats both files (if it succeeds)
154                         if (!m_diffFileData.OpenFiles(filepathTransformed[0], filepathTransformed[1]))
155                                 goto exitPrepAndCompare;
156                 }
157                 else
158                 {
159                         diffdata10.m_diffFileData.SetDisplayFilepaths(tFiles[1], tFiles[0]); // store true names for diff utils patch file
160                         diffdata12.m_diffFileData.SetDisplayFilepaths(tFiles[1], tFiles[2]); // store true names for diff utils patch file
161                         diffdata02.m_diffFileData.SetDisplayFilepaths(tFiles[0], tFiles[2]); // store true names for diff utils patch file
162
163                         if (!diffdata10.m_diffFileData.OpenFiles(filepathTransformed[1], filepathTransformed[0]))
164                                 goto exitPrepAndCompare;
165
166                         if (!diffdata12.m_diffFileData.OpenFiles(filepathTransformed[1], filepathTransformed[2]))
167                                 goto exitPrepAndCompare;
168
169                         if (!diffdata02.m_diffFileData.OpenFiles(filepathTransformed[0], filepathTransformed[2]))
170                                 goto exitPrepAndCompare;
171                 }
172
173                 // If either file is larger than limit compare files by quick contents
174                 // This allows us to (faster) compare big binary files
175                 if (nCompMethod == CMP_CONTENT && 
176                         (di.diffFileInfo[0].size > pCtxt->m_nQuickCompareLimit ||
177                         di.diffFileInfo[1].size > pCtxt->m_nQuickCompareLimit || 
178                         (nDirs > 2 && di.diffFileInfo[2].size > pCtxt->m_nQuickCompareLimit)))
179                 {
180                         nCompMethod = CMP_QUICK_CONTENT;
181                 }
182
183                 if (nCompMethod == CMP_CONTENT)
184                 {
185                         if (tFiles.GetSize() == 2)
186                         {
187                                 if (m_pDiffUtilsEngine == nullptr)
188                                         m_pDiffUtilsEngine.reset(new CompareEngines::DiffUtils());
189                                 m_pDiffUtilsEngine->SetCodepage(codepage);
190                                 bool success = m_pDiffUtilsEngine->SetCompareOptions(
191                                                 *pCtxt->GetCompareOptions(CMP_CONTENT));
192                                 if (success)
193                                 {
194                                         if (pCtxt->m_pFilterList != nullptr)
195                                                 m_pDiffUtilsEngine->SetFilterList(pCtxt->m_pFilterList.get());
196                                         else
197                                                 m_pDiffUtilsEngine->ClearFilterList();
198                                         m_pDiffUtilsEngine->SetFilterCommentsManager(pCtxt->m_pFilterCommentsManager);
199                                         m_pDiffUtilsEngine->SetFileData(2, m_diffFileData.m_inf);
200                                         code = m_pDiffUtilsEngine->diffutils_compare_files();
201                                         m_pDiffUtilsEngine->GetDiffCounts(m_ndiffs, m_ntrivialdiffs);
202                                         m_pDiffUtilsEngine->GetTextStats(0, &m_diffFileData.m_textStats[0]);
203                                         m_pDiffUtilsEngine->GetTextStats(1, &m_diffFileData.m_textStats[1]);
204                                 }
205                                 else
206                                         code = DIFFCODE::FILE | DIFFCODE::TEXT | DIFFCODE::CMPERR;
207
208                                 // If unique item, it was being compared to itself to determine encoding
209                                 // and the #diffs is invalid
210                                 if (di.diffcode.isSideSecondOnly() || di.diffcode.isSideFirstOnly())
211                                 {
212                                         m_ndiffs = CDiffContext::DIFFS_UNKNOWN;
213                                         m_ntrivialdiffs = CDiffContext::DIFFS_UNKNOWN;
214                                 }
215                         }
216                         else
217                         {
218                                 if (m_pDiffUtilsEngine == nullptr)
219                                         m_pDiffUtilsEngine.reset(new CompareEngines::DiffUtils());
220                                 m_pDiffUtilsEngine->SetCodepage(codepage);
221                                 bool success = m_pDiffUtilsEngine->SetCompareOptions(
222                                                 *pCtxt->GetCompareOptions(CMP_CONTENT));
223                                 if (success)
224                                 {
225                                         if (pCtxt->m_pFilterList != nullptr)
226                                                 m_pDiffUtilsEngine->SetFilterList(pCtxt->m_pFilterList.get());
227                                         else
228                                                 m_pDiffUtilsEngine->ClearFilterList();
229                                         m_pDiffUtilsEngine->SetFilterCommentsManager(pCtxt->m_pFilterCommentsManager);
230
231                                         bool bRet;
232                                         int bin_flag10 = 0, bin_flag12 = 0, bin_flag02 = 0;
233
234                                         m_pDiffUtilsEngine->SetFileData(2, diffdata10.m_diffFileData.m_inf);
235                                         bRet = m_pDiffUtilsEngine->Diff2Files(&script10, 0, &bin_flag10, false, nullptr);
236                                         m_pDiffUtilsEngine->GetTextStats(0, &m_diffFileData.m_textStats[1]);
237                                         m_pDiffUtilsEngine->GetTextStats(1, &m_diffFileData.m_textStats[0]);
238
239                                         m_pDiffUtilsEngine->SetFileData(2, diffdata12.m_diffFileData.m_inf);
240                                         bRet = m_pDiffUtilsEngine->Diff2Files(&script12, 0, &bin_flag12, false, nullptr);
241                                         m_pDiffUtilsEngine->GetTextStats(0, &m_diffFileData.m_textStats[1]);
242                                         m_pDiffUtilsEngine->GetTextStats(1, &m_diffFileData.m_textStats[2]);
243
244                                         m_pDiffUtilsEngine->SetFileData(2, diffdata02.m_diffFileData.m_inf);
245                                         bRet = m_pDiffUtilsEngine->Diff2Files(&script02, 0, &bin_flag02, false, nullptr);
246                                         m_pDiffUtilsEngine->GetTextStats(0, &m_diffFileData.m_textStats[0]);
247                                         m_pDiffUtilsEngine->GetTextStats(1, &m_diffFileData.m_textStats[2]);
248
249                                         code = DIFFCODE::FILE;
250
251                                         CDiffWrapper dw;
252                                         DiffList diffList;
253                                         DIFFSTATUS status;
254
255                                         diffList.Clear();
256                                         dw.SetCreateDiffList(&diffList);
257                                         dw.LoadWinMergeDiffsFromDiffUtilsScript3(
258                                                 script10, script12,
259                                                 diffdata10.m_diffFileData.m_inf, diffdata12.m_diffFileData.m_inf);
260                                         m_ndiffs = diffList.GetSignificantDiffs(); 
261                                         m_ntrivialdiffs = diffList.GetSize() - m_ndiffs;
262                                 
263                                         if (m_ndiffs > 0 || bin_flag10 < 0 || bin_flag12 < 0)
264                                                 code |= DIFFCODE::DIFF;
265                                         else
266                                                 code |= DIFFCODE::SAME;
267                                         if (bin_flag10 || bin_flag12)
268                                                 code |= DIFFCODE::BIN;
269                                         else
270                                                 code |= DIFFCODE::TEXT;
271
272                                         if ((code & DIFFCODE::COMPAREFLAGS) == DIFFCODE::DIFF)
273                                         {
274                                                 if ((code & DIFFCODE::TEXTFLAGS) == DIFFCODE::TEXT)
275                                                 {
276                                                         if (script12 == nullptr)
277                                                                 code |= DIFFCODE::DIFF1STONLY;
278                                                         else if (script02 == nullptr)
279                                                                 code |= DIFFCODE::DIFF2NDONLY;
280                                                         else if (script10 == nullptr)
281                                                                 code |= DIFFCODE::DIFF3RDONLY;
282                                                 }
283                                                 else
284                                                 {
285                                                         if (bin_flag12 > 0)
286                                                                 code |= DIFFCODE::DIFF1STONLY;
287                                                         else if (bin_flag02 > 0)
288                                                                 code |= DIFFCODE::DIFF2NDONLY;
289                                                         else if (bin_flag10 > 0)
290                                                                 code |= DIFFCODE::DIFF3RDONLY;
291                                                 }
292                                         }
293
294                                         // If unique item, it was being compared to itself to determine encoding
295                                         // and the #diffs is invalid
296                                         if (di.diffcode.isSideFirstOnly() || di.diffcode.isSideSecondOnly() || di.diffcode.isSideThirdOnly())
297                                         {
298                                                 m_ndiffs = CDiffContext::DIFFS_UNKNOWN;
299                                                 m_ntrivialdiffs = CDiffContext::DIFFS_UNKNOWN;
300                                         }
301
302                                         dw.FreeDiffUtilsScript(script10);
303                                         dw.FreeDiffUtilsScript(script12);
304                                         dw.FreeDiffUtilsScript(script02);
305                                 }
306                                 else
307                                         code = DIFFCODE::FILE | DIFFCODE::CMPERR;
308                         }
309
310                 }
311                 else if (nCompMethod == CMP_QUICK_CONTENT)
312                 {
313                         // use our own byte-by-byte compare
314                         if (tFiles.GetSize() == 2)
315                         {
316                                 if (m_pByteCompare == nullptr)
317                                         m_pByteCompare.reset(new ByteCompare());
318                                 bool success = m_pByteCompare->SetCompareOptions(
319                                         *pCtxt->GetCompareOptions(CMP_QUICK_CONTENT));
320         
321                                 if (success)
322                                 {
323                                         m_pByteCompare->SetAdditionalOptions(pCtxt->m_bStopAfterFirstDiff);
324                                         m_pByteCompare->SetAbortable(pCtxt->GetAbortable());
325                                         m_pByteCompare->SetFileData(2, m_diffFileData.m_inf);
326         
327                                         // use our own byte-by-byte compare
328                                         code = m_pByteCompare->CompareFiles(m_diffFileData.m_FileLocation);
329         
330                                         m_pByteCompare->GetTextStats(0, &m_diffFileData.m_textStats[0]);
331                                         m_pByteCompare->GetTextStats(1, &m_diffFileData.m_textStats[1]);
332                                 }
333                                 else
334                                         code = DIFFCODE::FILE | DIFFCODE::TEXT | DIFFCODE::CMPERR;
335         
336                                 // Quick contents doesn't know about diff counts
337                                 // Set to special value to indicate invalid
338                                 m_ndiffs = CDiffContext::DIFFS_UNKNOWN_QUICKCOMPARE;
339                                 m_ntrivialdiffs = CDiffContext::DIFFS_UNKNOWN_QUICKCOMPARE;
340                         }
341                         else
342                         {
343                                 if (m_pByteCompare == nullptr)
344                                         m_pByteCompare.reset(new ByteCompare());
345                                 bool success = m_pByteCompare->SetCompareOptions(
346                                         *pCtxt->GetCompareOptions(CMP_QUICK_CONTENT));
347         
348                                 if (success)
349                                 {
350                                         /* \93r\92\86 */
351                                         m_pByteCompare->SetAdditionalOptions(pCtxt->m_bStopAfterFirstDiff);
352                                         m_pByteCompare->SetAbortable(pCtxt->GetAbortable());
353
354                                         // 10
355                                         m_pByteCompare->SetFileData(2, diffdata10.m_diffFileData.m_inf);
356
357                                         // use our own byte-by-byte compare
358                                         int code10 = m_pByteCompare->CompareFiles(diffdata10.m_diffFileData.m_FileLocation);
359
360                                         m_pByteCompare->GetTextStats(0, &m_diffFileData.m_textStats[1]);
361                                         m_pByteCompare->GetTextStats(1, &m_diffFileData.m_textStats[0]);
362
363                                         // 12
364                                         m_pByteCompare->SetFileData(2, diffdata12.m_diffFileData.m_inf);
365
366                                         // use our own byte-by-byte compare
367                                         int code12 = m_pByteCompare->CompareFiles(diffdata12.m_diffFileData.m_FileLocation);
368
369                                         m_pByteCompare->GetTextStats(0, &m_diffFileData.m_textStats[1]);
370                                         m_pByteCompare->GetTextStats(1, &m_diffFileData.m_textStats[2]);
371
372                                         // 02
373                                         m_pByteCompare->SetFileData(2, diffdata02.m_diffFileData.m_inf);
374
375                                         // use our own byte-by-byte compare
376                                         int code02 = m_pByteCompare->CompareFiles(diffdata02.m_diffFileData.m_FileLocation);
377
378                                         m_pByteCompare->GetTextStats(0, &m_diffFileData.m_textStats[0]);
379                                         m_pByteCompare->GetTextStats(1, &m_diffFileData.m_textStats[2]);
380
381                                         code = DIFFCODE::FILE;
382                                         if (DIFFCODE::isResultError(code10) || DIFFCODE::isResultError(code12) || DIFFCODE::isResultError(code02))
383                                                 code |= DIFFCODE::CMPERR;
384                                         if ((code10 & DIFFCODE::COMPAREFLAGS) == DIFFCODE::DIFF || (code12 & DIFFCODE::COMPAREFLAGS) == DIFFCODE::DIFF)
385                                                 code |= DIFFCODE::DIFF;
386                                         else
387                                                 code |= DIFFCODE::SAME;
388                                         if ((code10 & DIFFCODE::TEXTFLAGS) == DIFFCODE::TEXT && 
389                                             (code12 & DIFFCODE::TEXTFLAGS) == DIFFCODE::TEXT)
390                                                 code |= DIFFCODE::TEXT;
391                                         else
392                                                 code |= DIFFCODE::BIN;
393                                         if ((code10 & DIFFCODE::TEXTFLAGS) == (DIFFCODE::BIN | DIFFCODE::BINSIDE1))
394                                                 code |= DIFFCODE::BINSIDE2;
395                                         if ((code10 & DIFFCODE::TEXTFLAGS) == (DIFFCODE::BIN | DIFFCODE::BINSIDE2))
396                                                 code |= DIFFCODE::BINSIDE1;
397                                         if ((code12 & DIFFCODE::TEXTFLAGS) == (DIFFCODE::BIN | DIFFCODE::BINSIDE2))
398                                                 code |= DIFFCODE::BINSIDE3;
399                                         if ((code & DIFFCODE::COMPAREFLAGS) == DIFFCODE::DIFF)
400                                         {
401                                                 if ((code12 & DIFFCODE::COMPAREFLAGS) == DIFFCODE::SAME)
402                                                         code |= DIFFCODE::DIFF1STONLY;
403                                                 else if ((code02 & DIFFCODE::COMPAREFLAGS) == DIFFCODE::SAME)
404                                                         code |= DIFFCODE::DIFF2NDONLY;
405                                                 else if ((code10 & DIFFCODE::COMPAREFLAGS) == DIFFCODE::SAME)
406                                                         code |= DIFFCODE::DIFF3RDONLY;
407                                         }
408                                 }
409                                 else
410                                         code = DIFFCODE::FILE | DIFFCODE::TEXT | DIFFCODE::CMPERR;
411         
412                                 // Quick contents doesn't know about diff counts
413                                 // Set to special value to indicate invalid
414                                 m_ndiffs = CDiffContext::DIFFS_UNKNOWN_QUICKCOMPARE;
415                                 m_ntrivialdiffs = CDiffContext::DIFFS_UNKNOWN_QUICKCOMPARE;
416                         }
417                 }
418 exitPrepAndCompare:
419                 m_diffFileData.Reset();
420                 diffdata10.m_diffFileData.Reset();
421                 diffdata12.m_diffFileData.Reset();
422                 diffdata02.m_diffFileData.Reset();
423                 
424                 // delete the temp files after comparison
425                 if (filepathTransformed[0] != filepathUnpacked[0])
426                         try { TFile(filepathTransformed[0]).remove(); } catch (...) { LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), filepathTransformed[0].c_str())); }
427                 if (filepathTransformed[1] != filepathUnpacked[1])
428                         try { TFile(filepathTransformed[1]).remove(); } catch (...) { LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), filepathTransformed[1].c_str())); }
429                 if (nDirs > 2 && filepathTransformed[2] != filepathUnpacked[2])
430                         try { TFile(filepathTransformed[2]).remove(); } catch (...) { LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), filepathTransformed[2].c_str())); }
431                 if (filepathUnpacked[0] != tFiles[0])
432                         try { TFile(filepathUnpacked[0]).remove(); } catch (...) { LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), filepathUnpacked[0].c_str())); }
433                 if (filepathUnpacked[1] != tFiles[1])
434                         try { TFile(filepathUnpacked[1]).remove(); } catch (...) { LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), filepathUnpacked[1].c_str())); }
435                 if (nDirs > 2 && filepathUnpacked[2] != tFiles[2])
436                         try { TFile(filepathUnpacked[2]).remove(); } catch (...) { LogErrorString(strutils::format(_T("DeleteFile(%s) failed"), filepathUnpacked[2].c_str())); }
437
438                 // When comparing empty file and nonexistent file, `DIFFCODE::SAME` flag is set to the variable `code`, so change the flag to `DIFFCODE::DIFF`
439                 // Also when disabling ignore codepage option and the encodings of files are not equal, change the flag to `DIFFCODE::DIFF even if  `DIFFCODE::SAME` flag is set to the variable `code`
440                 if (!di.diffcode.existAll() || (!pCtxt->m_bIgnoreCodepage && !std::equal(encoding + 1, encoding + nDirs, encoding)))
441                         code = (code & ~DIFFCODE::COMPAREFLAGS) | DIFFCODE::DIFF;
442         }
443         else if (nCompMethod == CMP_BINARY_CONTENT)
444         {
445                 if (m_pBinaryCompare == nullptr)
446                         m_pBinaryCompare.reset(new BinaryCompare());
447
448                 PathContext tFiles;
449                 GetComparePaths(pCtxt, di, tFiles);
450                 code = m_pBinaryCompare->CompareFiles(tFiles, di);
451         }
452         else if (nCompMethod == CMP_DATE || nCompMethod == CMP_DATE_SIZE || nCompMethod == CMP_SIZE)
453         {
454                 if (m_pTimeSizeCompare == nullptr)
455                         m_pTimeSizeCompare.reset(new TimeSizeCompare());
456
457                 m_pTimeSizeCompare->SetAdditionalOptions(pCtxt->m_bIgnoreSmallTimeDiff);
458                 code = m_pTimeSizeCompare->CompareFiles(nCompMethod, pCtxt->GetCompareDirs(), di);
459         }
460         else
461         {
462                 // Print error since we should have handled by date compare earlier
463                 throw "Invalid compare type, DiffFileData can't handle it";
464         }
465
466         return code;
467 }
468
469 /**
470  * @brief Get actual compared paths from DIFFITEM.
471  * @param [in] pCtx Pointer to compare context.
472  * @param [in] di DiffItem from which the paths are created.
473  * @param [out] left Gets the left compare path.
474  * @param [out] right Gets the right compare path.
475  * @note If item is unique, same path is returned for both.
476  */
477 void GetComparePaths(CDiffContext * pCtxt, const DIFFITEM &di, PathContext & tFiles)
478 {
479         int nDirs = pCtxt->GetCompareDirs();
480
481         tFiles.SetSize(nDirs);
482
483         for (int nIndex = 0; nIndex < nDirs; nIndex++)
484         {
485                 if (di.diffcode.exists(nIndex))
486                 {
487                         tFiles.SetPath(nIndex,
488                                 paths::ConcatPath(pCtxt->GetPath(nIndex), di.diffFileInfo[nIndex].GetFile()), false);
489                 }
490                 else
491                 {
492                         tFiles.SetPath(nIndex, _T("NUL"), false);
493                 }
494         }
495 }