OSDN Git Service

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