#include "paths.h"
#include "FileTransform.h"
#include "codepage.h"
+#include "DiffItemList.h"
+#include "PathContext.h"
#ifdef _DEBUG
#define new DEBUG_NEW
typedef CArray<fentry, fentry&> fentryArray;
// Static functions (ie, functions only used locally)
+void CompareDiffItem(DIFFITEM di, CDiffContext * pCtxt);
static void LoadFiles(const CString & sDir, fentryArray * dirs, fentryArray * files);
void LoadAndSortFiles(const CString & sDir, fentryArray * dirs, fentryArray * files, bool casesensitive);
static void Sort(fentryArray * dirs, bool casesensitive);;
static int collstr(const CString & s1, const CString & s2, bool casesensitive);
-static void StoreDiffResult(const CString & sDir, const fentry * lent, const fentry *rent,
- int code, CDiffContext *, const DiffFileData * = 0);
+static void StoreDiffResult(DIFFITEM &di, CDiffContext * pCtxt,
+ const DiffFileData * pDiffFileData);
+static void AddToList(CString sDir, const fentry * lent, const fentry * rent,
+ int code, DiffItemList * pList);
/** @brief cmpmth is a typedef for a pointer to a method */
typedef int (CString::*cmpmth)(LPCTSTR sz) const;
/**
- * @brief Compare two directories and store results (via the context)
- *
- * Compare two directories & output all results found via calls to StoreDiffResult
- * base directories to compare are in the CDiffContext
- * and this call is responsible for diff'ing just the subdir specified
- * (ie, if subdir is empty, this is the base call)
- * return 1 normally, return -1 if aborting
+ * @brief Collect file- and directory-names to list.
+ *
+ * @param [in] paths Root paths of compare
+ * @param [in] subdir Current subdirectory under root paths
+ * @param [in,out] list List where found items are added
+ * @param [in] casesensitive Is filename compare casesensitive?
+ * @param [in] depth Levels of subdirectories to scan, -1 scans all
+ * @param [in] piAbortable Interface allowing compare to be aborted
+ * @return 1 normally, -1 if compare was aborted
*/
-int DirScan(const CString & subdir, CDiffContext * pCtxt, bool casesensitive,
- int depth, IAbortable * piAbortable)
+int DirScan_GetItems(const PathContext &paths, const CString & subdir, DiffItemList *pList,
+ bool casesensitive, int depth, IAbortable * piAbortable)
{
- //int (WINAPI *collstr)(LPCTSTR, LPCTSTR) = casesensitive ? lstrcmp : lstrcmpi;
static const TCHAR backslash[] = _T("\\");
- CString sLeftDir = pCtxt->GetNormalizedLeft();
- CString sRightDir = pCtxt->GetNormalizedRight();
+ CString sLeftDir = paths.GetLeft();
+ CString sRightDir = paths.GetRight();
CString subprefix;
if (!subdir.IsEmpty())
{
LoadAndSortFiles(sLeftDir, &leftDirs, &leftFiles, casesensitive);
LoadAndSortFiles(sRightDir, &rightDirs, &rightFiles, casesensitive);
- if (piAbortable && piAbortable->ShouldAbort()) return -1;
+ // Allow user to abort scanning
+ if (piAbortable && piAbortable->ShouldAbort())
+ return -1;
// Handle directories
// i points to current directory in left list (leftDirs)
TRACE(_T("Candidate right: rightDirs[j]=%s\n"), (LPCTSTR)rightDirs[j].name);
if (i<leftDirs.GetSize() && (j==rightDirs.GetSize() || collstr(leftDirs[i].name, rightDirs[j].name, casesensitive)<0))
{
- int nDiffCode = DIFFCODE::LEFT | DIFFCODE::DIR | DIFFCODE::INCLUDED;
-
- // Test against filter
- CString newsub = subprefix + leftDirs[i].name;
- if (!pCtxt->m_piFilterGlobal->includeDir(newsub))
- nDiffCode = DIFFCODE::LEFT | DIFFCODE::DIR | DIFFCODE::SKIPPED;
+ int nDiffCode = DIFFCODE::LEFT | DIFFCODE::DIR;
// Advance left pointer over left-only entry, and then retest with new pointers
- StoreDiffResult(subdir, &leftDirs[i], 0, nDiffCode, pCtxt);
+ AddToList(subdir, &leftDirs[i], 0, nDiffCode, pList);
++i;
continue;
}
{
int nDiffCode = DIFFCODE::RIGHT | DIFFCODE::DIR;
- // Test against filter
- CString newsub = subprefix + rightDirs[j].name;
- if (!pCtxt->m_piFilterGlobal->includeDir(newsub))
- nDiffCode = DIFFCODE::RIGHT | DIFFCODE::DIR | DIFFCODE::SKIPPED;
- else
- nDiffCode = DIFFCODE::RIGHT | DIFFCODE::DIR | DIFFCODE::INCLUDED;
-
// Advance right pointer over right-only entry, and then retest with new pointers
- StoreDiffResult(subdir, 0, &rightDirs[j], nDiffCode, pCtxt);
+ AddToList(subdir, 0, &rightDirs[j], nDiffCode, pList);
++j;
continue;
}
{
ASSERT(j<rightDirs.GetSize());
CString newsub = subprefix + leftDirs[i].name;
- if (!pCtxt->m_piFilterGlobal->includeDir(newsub))
- {
- int nDiffCode = DIFFCODE::BOTH | DIFFCODE::SKIPPED | DIFFCODE::DIR;
- StoreDiffResult(subdir, &leftDirs[i], &rightDirs[j], nDiffCode, pCtxt);
- }
- else
{
if (!depth)
{
// Non-recursive compare
// We are only interested about list of subdirectories to show - user can open them
// TODO: scan one level deeper to see if directories are identical/different
- int nDiffCode = DIFFCODE::BOTH | DIFFCODE::DIR | DIFFCODE::INCLUDED;
- StoreDiffResult(subdir, &leftDirs[i], &rightDirs[j], nDiffCode, pCtxt);
+ int nDiffCode = DIFFCODE::BOTH | DIFFCODE::DIR;
+ AddToList(subdir, &leftDirs[i], &rightDirs[j], nDiffCode, pList);
}
else
{
// Recursive compare
// Scan recursively all subdirectories too, we are not adding folders
- if (DirScan(newsub, pCtxt, casesensitive, depth-1, piAbortable) == -1)
+ if (DirScan_GetItems(paths, newsub, pList, casesensitive,
+ depth - 1, piAbortable) == -1)
+ {
return -1;
+ }
}
}
++i;
i=0, j=0;
while (1)
{
- if (piAbortable && piAbortable->ShouldAbort()) return -1;
+ if (piAbortable && piAbortable->ShouldAbort())
+ return -1;
// In debug mode, send current status to debug window
if (i<leftFiles.GetSize())
TRACE(_T("Candidate left: leftFiles[i]=%s\n"), (LPCTSTR)leftFiles[i].name);
if (j<rightFiles.GetSize())
TRACE(_T("Candidate right: rightFiles[j]=%s\n"), (LPCTSTR)rightFiles[j].name);
- if (i<leftFiles.GetSize() && (j==rightFiles.GetSize() || collstr(leftFiles[i].name, rightFiles[j].name, casesensitive)<0))
+
+ if (i<leftFiles.GetSize() && (j==rightFiles.GetSize() ||
+ collstr(leftFiles[i].name, rightFiles[j].name, casesensitive) < 0))
{
// Test against filter
CString newsubfile = subprefix + leftFiles[i].name;
int nDiffCode = DIFFCODE::LEFT | DIFFCODE::FILE;
- if (!pCtxt->m_piFilterGlobal->includeFile(newsubfile))
- {
- nDiffCode |= DIFFCODE::SKIPPED;
- StoreDiffResult(subdir, &leftFiles[i], 0, nDiffCode, pCtxt);
- }
- else if (pCtxt->m_nCompMethod != CMP_DATE)
{
- // Compare file to itself to detect encoding
- CString filepath = sLeftDir + backslash + leftFiles[i].name;
- DiffFileData diffdata;
- nDiffCode |= DIFFCODE::INCLUDED;
- diffdata.prepAndCompareTwoFiles(pCtxt, filepath, filepath);
- StoreDiffResult(subdir, &leftFiles[i], 0, nDiffCode, pCtxt, &diffdata);
- }
- else
- {
- nDiffCode |= DIFFCODE::INCLUDED;
- StoreDiffResult(subdir, &leftFiles[i], 0, nDiffCode, pCtxt);
+ AddToList(subdir, &leftFiles[i], 0, nDiffCode, pList);
}
+
// Advance left pointer over left-only entry, and then retest with new pointers
++i;
continue;
}
- if (j<rightFiles.GetSize() && (i==leftFiles.GetSize() || collstr(leftFiles[i].name, rightFiles[j].name, casesensitive)>0))
+ if (j<rightFiles.GetSize() && (i==leftFiles.GetSize() ||
+ collstr(leftFiles[i].name, rightFiles[j].name, casesensitive) > 0))
{
// Test against filter
CString newsubfile = subprefix + rightFiles[j].name;
int nDiffCode = DIFFCODE::RIGHT | DIFFCODE::FILE;
- if (!pCtxt->m_piFilterGlobal->includeFile(newsubfile))
- {
- nDiffCode |= DIFFCODE::SKIPPED;
- StoreDiffResult(subdir, 0, &rightFiles[j], nDiffCode, pCtxt);
- }
- else if (pCtxt->m_nCompMethod != CMP_DATE)
- {
- // Compare file to itself to detect encoding
- CString filepath = sRightDir + backslash + rightFiles[j].name;
- DiffFileData diffdata;
- nDiffCode |= DIFFCODE::INCLUDED;
- diffdata.prepAndCompareTwoFiles(pCtxt, filepath, filepath);
- StoreDiffResult(subdir, 0, &rightFiles[j], nDiffCode, pCtxt, &diffdata);
- }
- else
{
- nDiffCode |= DIFFCODE::INCLUDED;
- StoreDiffResult(subdir, 0, &rightFiles[j], nDiffCode, pCtxt);
+ AddToList(subdir, 0, &rightFiles[j], nDiffCode, pList);
}
// Advance right pointer over right-only entry, and then retest with new pointers
++j;
ASSERT(j<rightFiles.GetSize());
CString newsubfile = subprefix + leftFiles[i].name;
int nDiffCode = DIFFCODE::BOTH | DIFFCODE::FILE;
- if (!pCtxt->m_piFilterGlobal->includeFile(newsubfile))
- {
- nDiffCode |= DIFFCODE::SKIPPED;
- StoreDiffResult(subdir, &leftFiles[i], &rightFiles[j], nDiffCode, pCtxt);
- ++i;
- ++j;
- continue;
- }
- else
- nDiffCode |= DIFFCODE::INCLUDED;
- LPCTSTR leftname = leftFiles[i].name;
- LPCTSTR rightname = rightFiles[j].name;
+ AddToList(subdir, &leftFiles[i], &rightFiles[j], nDiffCode, pList);
- gLog.Write(_T("Comparing: n0=%s, n1=%s, d0=%s, d1=%s"),
- leftname, rightname, (LPCTSTR)sLeftDir, (LPCTSTR)sRightDir);
-
- if (pCtxt->m_nCompMethod == CMP_DATE)
- {
- // Compare by modified date
- __int64 nTimeDiff = leftFiles[i].mtime - rightFiles[j].mtime;
- // Compare absolute time difference (lose sign)
- nTimeDiff = (nTimeDiff > 0 ? nTimeDiff : -nTimeDiff);
- if (pCtxt->m_bIgnoreSmallTimeDiff)
- {
- // If option to ignore small timediffs (couple of seconds)
- // is set, decrease absolute difference by allowed diff
- nTimeDiff -= SmallTimeDiff;
- }
- if (nTimeDiff <= 0)
- nDiffCode |= DIFFCODE::TEXT | DIFFCODE::SAME;
- else
- nDiffCode |= DIFFCODE::TEXT | DIFFCODE::DIFF;
- // report result back to caller
- StoreDiffResult(subdir, &leftFiles[i], &rightFiles[j], nDiffCode, pCtxt);
- ++i;
- ++j;
- continue;
- }
- // Files to compare
- CString filepath1 = sLeftDir + backslash + leftname;
- CString filepath2 = sRightDir + backslash + rightname;
- // Really compare
- DiffFileData diffdata;
- nDiffCode |= diffdata.prepAndCompareTwoFiles(pCtxt, filepath1, filepath2);
- // report result back to caller
- StoreDiffResult(subdir, &leftFiles[i], &rightFiles[j], nDiffCode, pCtxt, &diffdata);
++i;
++j;
continue;
}
/**
+ * @brief Compare DiffItems in list and add results to compare context.
+ *
+ * @param list [in] List of items to compare
+ * @param pCtxt [in,out] Compare context: contains list where results are added.
+ * @param piAbortable [in] Interface allowing to abort compare
+ * @return 1 if compare finished, -1 if compare was aborted
+ */
+int DirScan_CompareItems(DiffItemList & list, CDiffContext * pCtxt, IAbortable * piAbortable)
+{
+ POSITION pos = list.GetFirstDiffPosition();
+
+ while (pos != NULL)
+ {
+ if (piAbortable && piAbortable->ShouldAbort())
+ return -1;
+
+ DIFFITEM di = list.GetNextDiffPosition(pos);
+ CompareDiffItem(di, pCtxt);
+ }
+ return 1;
+}
+
+/**
+ * @brief Compare two diffitems and add results to difflist in context.
+ *
+ * @param [in] di DiffItem to compare
+ * @param [in,out] pCtxt Compare context: contains difflist, encoding info etc.
+ */
+void CompareDiffItem(DIFFITEM di, CDiffContext * pCtxt)
+{
+ CString sLeftDir = pCtxt->GetNormalizedLeft();
+ CString sRightDir = pCtxt->GetNormalizedRight();
+ static const TCHAR backslash[] = _T("\\");
+
+ if (!di.sSubdir.IsEmpty())
+ {
+ sLeftDir += backslash + di.sSubdir;
+ sRightDir += backslash + di.sSubdir;
+ }
+
+ // 1. Test against filters
+ if (di.isDirectory())
+ {
+ if (!pCtxt->m_piFilterGlobal->includeDir(di.sfilename))
+ di.diffcode |= DIFFCODE::SKIPPED;
+ else
+ di.diffcode |= DIFFCODE::INCLUDED;
+
+ // Done for directories now
+ StoreDiffResult(di, pCtxt, NULL);
+ return;
+ }
+ else
+ {
+ if (!pCtxt->m_piFilterGlobal->includeFile(di.sfilename))
+ di.diffcode |= DIFFCODE::SKIPPED;
+ else
+ di.diffcode |= DIFFCODE::INCLUDED;
+ }
+
+ // Add unique files
+ if (di.isSideLeft())
+ {
+ if (pCtxt->m_nCompMethod != CMP_DATE)
+ {
+ // Compare file to itself to detect encoding
+ CString filepath = sRightDir + backslash + di.sfilename;
+ DiffFileData diffdata;
+ diffdata.prepAndCompareTwoFiles(pCtxt, filepath, filepath);
+ StoreDiffResult(di, pCtxt, &diffdata);
+ }
+ else
+ {
+ StoreDiffResult(di, pCtxt, NULL);
+ }
+ return;
+ }
+ else if (di.isSideRight())
+ {
+ if (pCtxt->m_nCompMethod != CMP_DATE)
+ {
+ // Compare file to itself to detect encoding
+ CString filepath = sLeftDir + backslash + di.sfilename;
+ DiffFileData diffdata;
+ diffdata.prepAndCompareTwoFiles(pCtxt, filepath, filepath);
+ StoreDiffResult(di, pCtxt, &diffdata);
+
+ }
+ else
+ {
+ StoreDiffResult(di, pCtxt, NULL);
+ }
+ return;
+ }
+ // Compare two files
+ else
+ {
+ /*LPCTSTR leftname = leftFiles[i].name;
+ LPCTSTR rightname = rightFiles[j].name;
+
+ gLog.Write(_T("Comparing: n0=%s, n1=%s, d0=%s, d1=%s"),
+ leftname, rightname, (LPCTSTR)sLeftDir, (LPCTSTR)sRightDir);
+ */
+
+ if (pCtxt->m_nCompMethod == CMP_DATE)
+ {
+ // Compare by modified date
+ __int64 nTimeDiff = di.left.mtime - di.right.mtime;
+ // Remove sign
+ nTimeDiff = (nTimeDiff > 0 ? nTimeDiff : -nTimeDiff);
+ if (pCtxt->m_bIgnoreSmallTimeDiff)
+ {
+ // If option to ignore small timediffs (couple of seconds)
+ // is set, decrease absolute difference by allowed diff
+ nTimeDiff -= SmallTimeDiff;
+ }
+ if (nTimeDiff <= 0)
+ di.diffcode |= DIFFCODE::TEXT | DIFFCODE::SAME;
+ else
+ di.diffcode |= DIFFCODE::TEXT | DIFFCODE::DIFF;
+ // report result back to caller
+ StoreDiffResult(di, pCtxt, NULL);
+ return;
+ }
+ // Files to compare
+ CString filepath1 = sLeftDir + backslash + di.sfilename;
+ CString filepath2 = sRightDir + backslash + di.sfilename;
+ // Really compare
+ DiffFileData diffdata;
+ di.diffcode |= diffdata.prepAndCompareTwoFiles(pCtxt, filepath1, filepath2);
+ // report result back to caller
+ StoreDiffResult(di, pCtxt, &diffdata);
+ }
+
+ return;
+}
+
+/**
* @brief Load arrays with all directories & files in specified dir
*/
void LoadAndSortFiles(const CString & sDir, fentryArray * dirs, fentryArray * files, bool casesensitive)
/**
* @brief Send one file or directory result back through the diff context
*/
-static void StoreDiffResult(const CString & sDir, const fentry * lent, const fentry * rent,
- int code, CDiffContext * pCtxt, const DiffFileData * pDiffFileData)
+static void StoreDiffResult(DIFFITEM &di, CDiffContext * pCtxt,
+ const DiffFileData * pDiffFileData)
+{
+ if (pDiffFileData)
+ {
+ di.nsdiffs = pDiffFileData->m_ndiffs - pDiffFileData->m_ntrivialdiffs;
+ di.ndiffs = pDiffFileData->m_ndiffs;
+
+ if (!di.isSideLeft())
+ {
+ di.right.unicoding = pDiffFileData->m_sFilepath[1].unicoding;
+ di.right.codepage = pDiffFileData->m_sFilepath[1].codepage;
+ }
+
+ if (!di.isSideRight())
+ {
+ di.left.unicoding = pDiffFileData->m_sFilepath[0].unicoding;
+ di.left.codepage = pDiffFileData->m_sFilepath[0].codepage;
+ }
+ }
+
+ gLog.Write
+ (
+ LOGLEVEL::LCOMPAREDATA, _T("name=<%s>, leftdir=<%s>, rightdir=<%s>, code=%d"),
+ (LPCTSTR)di.sfilename, (LPCTSTR)_T("di.left.spath"), (LPCTSTR)_T("di.right.spath"), di.diffcode
+ );
+ pCtxt->AddDiff(di);
+}
+
+/**
+ * @brief Add one compare item to list.
+ */
+static void AddToList(CString sDir, const fentry * lent, const fentry * rent,
+ int code, DiffItemList * pList)
{
// We must store both paths - we cannot get paths later
// and we need unique item paths for example when items
// change to identical
DIFFITEM di;
- di.sSubdir = sDir;
+ di.left.unicoding = 0;
+ di.left.codepage = 0;
+ di.right.unicoding = 0;
+ di.right.codepage = 0;
- if (pDiffFileData)
- {
- di.nsdiffs = pDiffFileData->m_ndiffs - pDiffFileData->m_ntrivialdiffs;
- di.ndiffs = pDiffFileData->m_ndiffs;
- di.left.unicoding = pDiffFileData->m_sFilepath[0].unicoding;
- di.left.codepage = pDiffFileData->m_sFilepath[0].codepage;
- di.right.unicoding = pDiffFileData->m_sFilepath[1].unicoding;
- di.right.codepage = pDiffFileData->m_sFilepath[1].codepage;
- }
+ if (!sDir.IsEmpty())
+ di.sSubdir = sDir;
if (lent)
{
di.sfilename = lent->name;
- //di.left.spath = pCtxt->m_strNormalizedLeft; //paths_ConcatPath(pCtxt->m_strNormalizedLeft, sDir);
di.left.mtime = lent->mtime;
di.left.ctime = lent->ctime;
di.left.size = lent->size;
di.left.flags.attributes = lent->attrs;
}
- else
- {
- di.left.unicoding = 0;
- di.left.codepage = 0;
- }
if (rent)
{
di.sfilename = rent->name;
- //di.right.spath = pCtxt->m_strNormalizedRight; //paths_ConcatPath(pCtxt->m_strNormalizedRight, sDir);
di.right.mtime = rent->mtime;
di.right.ctime = rent->ctime;
di.right.size = rent->size;
di.right.flags.attributes = rent->attrs;
}
- else
- {
- di.right.unicoding = 0;
- di.right.codepage = 0;
- }
di.diffcode = code;
LOGLEVEL::LCOMPAREDATA, _T("name=<%s>, leftdir=<%s>, rightdir=<%s>, code=%d"),
(LPCTSTR)di.sfilename, (LPCTSTR)_T("di.left.spath"), (LPCTSTR)_T("di.right.spath"), code
);
- pCtxt->AddDiff(di);
+ pList->AddDiff(di);
}
-
void // static
DirScan_InitializeDefaultCodepage()
{