summaryrefslogtreecommitdiff
path: root/comparison.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comparison.cpp')
-rw-r--r--comparison.cpp493
1 files changed, 221 insertions, 272 deletions
diff --git a/comparison.cpp b/comparison.cpp
index a43a0c86..c2593ed0 100644
--- a/comparison.cpp
+++ b/comparison.cpp
@@ -7,8 +7,10 @@
#include <wx/msgdlg.h>
#include <wx/log.h>
#include "algorithm.h"
+#include "ui/util.h"
#include <wx/thread.h>
#include <memory>
+#include "shared/stringConv.h"
#include "library/statusHandler.h"
#include "shared/fileHandling.h"
#include "shared/systemFunctions.h"
@@ -17,6 +19,7 @@
#include <map>
#include "fileHierarchy.h"
#include <boost/bind.hpp>
+#include <boost/scoped_array.hpp>
using namespace FreeFileSync;
@@ -65,10 +68,10 @@ public:
const Zstring& relNameParentPf, //postfixed with FILE_NAME_SEPARATOR!
DirContainer& output,
StatusHandler* handler) :
- baseCallback_(baseCallback),
- relNameParentPf_(relNameParentPf),
- output_(output),
- statusHandler(handler) {}
+ baseCallback_(baseCallback),
+ relNameParentPf_(relNameParentPf),
+ output_(output),
+ statusHandler(handler) {}
virtual ~DirCallback() {}
@@ -91,11 +94,11 @@ class BaseDirCallback : public DirCallback<filterActive>
friend class DirCallback<filterActive>;
public:
BaseDirCallback(DirContainer& output, const FilterProcess* filter, StatusHandler* handler) :
- DirCallback<filterActive>(this, Zstring(), output, handler),
- textScanning(Zstring(_("Scanning:")) + wxT(" \n")),
- filterInstance(filter) {}
+ DirCallback<filterActive>(this, Zstring(), output, handler),
+ textScanning(wxToZ(wxString(_("Scanning:")) + wxT(" \n"))),
+ filterInstance(filter) {}
- virtual TraverseCallback::ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName);
+ virtual TraverseCallback::ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const TraverseCallback::FileInfo& details);
private:
typedef boost::shared_ptr<const DirCallback<filterActive> > CallbackPointer;
@@ -109,6 +112,17 @@ private:
template <bool filterActive>
TraverseCallback::ReturnValue DirCallback<filterActive>::onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details)
{
+ //assemble status message (performance optimized) = textScanning + wxT("\"") + fullName + wxT("\"")
+ Zstring statusText = baseCallback_->textScanning;
+ statusText.reserve(statusText.length() + fullName.length() + 2);
+ statusText += DefaultChar('\"');
+ statusText += fullName;
+ statusText += DefaultChar('\"');
+
+ //update UI/commandline status information
+ statusHandler->updateStatusText(statusText);
+
+//------------------------------------------------------------------------------------
//apply filter before processing (use relative name!)
if (filterActive)
{
@@ -119,17 +133,8 @@ TraverseCallback::ReturnValue DirCallback<filterActive>::onFile(const DefaultCha
}
}
- output_.addSubFile(FileDescriptor(shortName, details.lastWriteTimeRaw, details.fileSize), relNameParentPf_);
-
- //assemble status message (performance optimized) = textScanning + wxT("\"") + fullName + wxT("\"")
- Zstring statusText = baseCallback_->textScanning;
- statusText.reserve(statusText.length() + fullName.length() + 2);
- statusText += DefaultChar('\"');
- statusText += fullName;
- statusText += DefaultChar('\"');
+ output_.addSubFile(shortName, FileDescriptor(details.lastWriteTimeRaw, details.fileSize));
- //update UI/commandline status information
- statusHandler->updateStatusText(statusText);
//add 1 element to the progress indicator
statusHandler->updateProcessedData(1, 0); //NO performance issue at all
//trigger display refresh
@@ -144,6 +149,17 @@ TraverseCallback::ReturnValDir DirCallback<filterActive>::onDir(const DefaultCha
{
using globalFunctions::FILE_NAME_SEPARATOR;
+ //assemble status message (performance optimized) = textScanning + wxT("\"") + fullName + wxT("\"")
+ Zstring statusText = baseCallback_->textScanning;
+ statusText.reserve(statusText.length() + fullName.length() + 2);
+ statusText += DefaultChar('\"');
+ statusText += fullName;
+ statusText += DefaultChar('\"');
+
+ //update UI/commandline status information
+ statusHandler->updateStatusText(statusText);
+
+//------------------------------------------------------------------------------------
Zstring relName = relNameParentPf_;
relName += shortName;
@@ -157,7 +173,7 @@ TraverseCallback::ReturnValDir DirCallback<filterActive>::onDir(const DefaultCha
if (subObjMightMatch)
{
- DirContainer& subDir = output_.addSubDir(DirDescriptor(shortName), relNameParentPf_);
+ DirContainer& subDir = output_.addSubDir(shortName);
DirCallback* subDirCallback = new DirCallback(baseCallback_, relName += FILE_NAME_SEPARATOR, subDir, statusHandler);
baseCallback_->callBackBox.push_back(typename BaseDirCallback<filterActive>::CallbackPointer(subDirCallback)); //handle ownership
@@ -170,24 +186,14 @@ TraverseCallback::ReturnValDir DirCallback<filterActive>::onDir(const DefaultCha
}
}
- DirContainer& subDir = output_.addSubDir(DirDescriptor(shortName), relNameParentPf_);
-
+ DirContainer& subDir = output_.addSubDir(shortName);
- //assemble status message (performance optimized) = textScanning + wxT("\"") + fullName + wxT("\"")
- Zstring statusText = baseCallback_->textScanning;
- statusText.reserve(statusText.length() + fullName.length() + 2);
- statusText += DefaultChar('\"');
- statusText += fullName;
- statusText += DefaultChar('\"');
-
- //update UI/commandline status information
- statusHandler->updateStatusText(statusText);
//add 1 element to the progress indicator
statusHandler->updateProcessedData(1, 0); //NO performance issue at all
//trigger display refresh
statusHandler->requestUiRefresh();
- DirCallback* subDirCallback = new DirCallback(baseCallback_, relName+=FILE_NAME_SEPARATOR, subDir, statusHandler);
+ DirCallback* subDirCallback = new DirCallback(baseCallback_, relName += FILE_NAME_SEPARATOR, subDir, statusHandler);
baseCallback_->callBackBox.push_back(typename BaseDirCallback<filterActive>::CallbackPointer(subDirCallback)); //handle ownership
return ReturnValDir(ReturnValDir::Continue(), subDirCallback);
@@ -213,17 +219,20 @@ TraverseCallback::ReturnValue DirCallback<filterActive>::onError(const wxString&
template <bool filterActive>
-TraverseCallback::ReturnValDir BaseDirCallback<filterActive>::onDir(const DefaultChar* shortName, const Zstring& fullName)
+TraverseCallback::ReturnValue BaseDirCallback<filterActive>::onFile(
+ const DefaultChar* shortName,
+ const Zstring& fullName,
+ const TraverseCallback::FileInfo& details)
{
-//#ifdef FFS_WIN => transparency is more important: just scan every file
-// if ( fullName.EndsWith(wxT("\\RECYCLER")) ||
-// fullName.EndsWith(wxT("\\System Volume Information")))
-// {
-// DirCallback<filterActive>::statusHandler->requestUiRefresh();
-// return TraverseCallback::ReturnValDir::Ignore();
-// }
-//#endif // FFS_WIN
- return DirCallback<filterActive>::onDir(shortName, fullName);
+ //do not scan the database file
+#ifdef FFS_WIN
+ if (getSyncDBFilename().CmpNoCase(shortName) == 0)
+#elif defined FFS_LINUX
+ if (getSyncDBFilename().Cmp(shortName) == 0)
+#endif
+ return TraverseCallback::TRAVERSING_CONTINUE;
+
+ return DirCallback<filterActive>::onFile(shortName, fullName, details);
}
@@ -232,8 +241,8 @@ struct DirBufferKey
{
DirBufferKey(const Zstring& dirname,
boost::shared_ptr<const FilterProcess>& filterInst) :
- directoryName(dirname),
- filterInstance(filterInst) {}
+ directoryName(dirname),
+ filterInstance(filterInst) {}
Zstring directoryName;
boost::shared_ptr<const FilterProcess> filterInstance; //buffering has to consider filtering!
@@ -260,16 +269,16 @@ class CompareProcess::DirectoryBuffer //buffer multiple scans of the same direc
{
public:
DirectoryBuffer(const bool traverseDirectorySymlinks, StatusHandler* statusUpdater) :
- m_traverseDirectorySymlinks(traverseDirectorySymlinks),
- m_statusUpdater(statusUpdater) {}
+ m_traverseDirectorySymlinks(traverseDirectorySymlinks),
+ m_statusUpdater(statusUpdater) {}
- const DirContainer& getDirectoryDescription(const Zstring& directoryPostfixed, bool filterActive, const wxString& includeFilter, const wxString& excludeFilter);
+ const DirContainer& getDirectoryDescription(const Zstring& directoryPostfixed, bool filterActive, const Zstring& includeFilter, const Zstring& excludeFilter);
private:
typedef boost::shared_ptr<DirContainer> DirBufferValue; //exception safety: avoid memory leak
typedef std::map<DirBufferKey, DirBufferValue> BufferType;
- static DirBufferKey createKey(const Zstring& directoryPostfixed, bool filterActive, const wxString& includeFilter, const wxString& excludeFilter);
+ static DirBufferKey createKey(const Zstring& directoryPostfixed, bool filterActive, const Zstring& includeFilter, const Zstring& excludeFilter);
DirContainer& insertIntoBuffer(const DirBufferKey& newKey);
BufferType buffer;
@@ -280,7 +289,7 @@ private:
//------------------------------------------------------------------------------------------
-DirBufferKey CompareProcess::DirectoryBuffer::createKey(const Zstring& directoryPostfixed, bool filterActive, const wxString& includeFilter, const wxString& excludeFilter)
+DirBufferKey CompareProcess::DirectoryBuffer::createKey(const Zstring& directoryPostfixed, bool filterActive, const Zstring& includeFilter, const Zstring& excludeFilter)
{
boost::shared_ptr<const FilterProcess> filterInstance(
filterActive && FilterProcess(includeFilter, excludeFilter) != FilterProcess::nullFilter() ? //nullfilter: in: '*', ex ''
@@ -311,8 +320,8 @@ DirContainer& CompareProcess::DirectoryBuffer::insertIntoBuffer(const DirBufferK
const DirContainer& CompareProcess::DirectoryBuffer::getDirectoryDescription(
const Zstring& directoryPostfixed,
bool filterActive,
- const wxString& includeFilter,
- const wxString& excludeFilter)
+ const Zstring& includeFilter,
+ const Zstring& excludeFilter)
{
const DirBufferKey searchKey = createKey(directoryPostfixed, filterActive, includeFilter, excludeFilter);
@@ -340,14 +349,14 @@ void foldersAreValidForComparison(const std::vector<FolderPairCfg>& folderPairsF
checkEmptyDirnameActive = false;
while (true)
{
- const ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Please fill all empty directory fields.")) + wxT("\n\n") +
+ const ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Please fill all empty directory fields.")) + wxT(" \n\n") +
+ wxT("(") + additionalInfo + wxT(")"));
if (rv == ErrorHandler::IGNORE_ERROR)
break;
else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
- assert (false);
+ throw std::logic_error("Programming Error: Unknown return value!");
}
}
}
@@ -356,29 +365,29 @@ void foldersAreValidForComparison(const std::vector<FolderPairCfg>& folderPairsF
if (!i->leftDirectory.empty())
while (!FreeFileSync::dirExists(i->leftDirectory.c_str()))
{
- ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Directory does not exist:")) + wxT("\n") +
- wxT("\"") + i->leftDirectory + wxT("\"") + wxT("\n\n") +
+ ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Directory does not exist:")) + wxT(" \n") +
+ wxT("\"") + zToWx(i->leftDirectory) + wxT("\"") + wxT("\n\n") +
FreeFileSync::getLastErrorFormatted() + wxT(" ") + additionalInfo);
if (rv == ErrorHandler::IGNORE_ERROR)
break;
else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
- assert (false);
+ throw std::logic_error("Programming Error: Unknown return value!");
}
if (!i->rightDirectory.empty())
while (!FreeFileSync::dirExists(i->rightDirectory.c_str()))
{
ErrorHandler::Response rv = statusUpdater->reportError(wxString(_("Directory does not exist:")) + wxT("\n") +
- wxT("\"") + i->rightDirectory + wxT("\"") + wxT("\n\n") +
+ wxT("\"") + zToWx(i->rightDirectory) + wxT("\"") + wxT("\n\n") +
FreeFileSync::getLastErrorFormatted() + wxT(" ") + additionalInfo);
if (rv == ErrorHandler::IGNORE_ERROR)
break;
else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
- assert (false);
+ throw std::logic_error("Programming Error: Unknown return value!");
}
}
}
@@ -390,8 +399,8 @@ bool dependencyExists(const std::set<Zstring>& folders, const Zstring& newFolder
if (newFolder.StartsWith(*i) || i->StartsWith(newFolder))
{
warningMessage = wxString(_("Directories are dependent! Be careful when setting up synchronization rules:")) + wxT("\n") +
- wxT("\"") + i->c_str() + wxT("\",\n") +
- wxT("\"") + newFolder.c_str() + wxT("\"");
+ wxT("\"") + zToWx(*i) + wxT("\",\n") +
+ wxT("\"") + zToWx(newFolder) + wxT("\"");
return true;
}
return false;
@@ -429,33 +438,16 @@ CompareProcess::CompareProcess(const bool traverseSymLinks,
const bool ignoreOneHourDiff,
xmlAccess::OptionalDialogs& warnings,
StatusHandler* handler) :
- fileTimeTolerance(fileTimeTol),
- ignoreOneHourDifference(ignoreOneHourDiff),
- m_warnings(warnings),
- statusUpdater(handler),
- txtComparingContentOfFiles(Zstring(_("Comparing content of files %x")).Replace(wxT("%x"), wxT("\n\"%x\""), false))
+ fileTimeTolerance(fileTimeTol),
+ ignoreOneHourDifference(ignoreOneHourDiff),
+ m_warnings(warnings),
+ statusUpdater(handler),
+ txtComparingContentOfFiles(wxToZ(_("Comparing content of files %x")).Replace(DefaultStr("%x"), DefaultStr("\n\"%x\""), false))
{
directoryBuffer.reset(new DirectoryBuffer(traverseSymLinks, handler));
}
-struct MemoryAllocator
-{
- MemoryAllocator()
- {
- buffer = new unsigned char[bufferSize];
- }
-
- ~MemoryAllocator()
- {
- delete [] buffer;
- }
-
- static const unsigned int bufferSize = 512 * 1024; //512 kb seems to be the perfect buffer size
- unsigned char* buffer;
-};
-
-
//callback functionality for status updates while comparing
class CompareCallback
{
@@ -467,27 +459,36 @@ public:
bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback* callback)
{
- static MemoryAllocator memory1;
- static MemoryAllocator memory2;
-
- wxFFile file1(filename1.c_str(), wxT("rb"));
+ const unsigned int BUFFER_SIZE = 512 * 1024; //512 kb seems to be the perfect buffer size
+ static boost::scoped_array<unsigned char> memory1(new unsigned char[BUFFER_SIZE]);
+ static boost::scoped_array<unsigned char> memory2(new unsigned char[BUFFER_SIZE]);
+
+#ifdef FFS_WIN
+ wxFFile file1(filename1.c_str(), DefaultStr("rb"));
+#elif defined FFS_LINUX
+ wxFFile file1(::fopen(filename1.c_str(), DefaultStr("rb"))); //utilize UTF-8 filename
+#endif
if (!file1.IsOpened())
- throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + filename1.c_str() + wxT("\""));
+ throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + zToWx(filename1) + wxT("\""));
- wxFFile file2(filename2.c_str(), wxT("rb"));
+#ifdef FFS_WIN
+ wxFFile file2(filename2.c_str(), DefaultStr("rb"));
+#elif defined FFS_LINUX
+ wxFFile file2(::fopen(filename2.c_str(), DefaultStr("rb"))); //utilize UTF-8 filename
+#endif
if (!file2.IsOpened()) //NO cleanup necessary for (wxFFile) file1
- throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + filename2.c_str() + wxT("\""));
+ throw FileError(wxString(_("Error opening file:")) + wxT(" \"") + zToWx(filename2) + wxT("\""));
wxLongLong bytesCompared;
do
{
- const size_t length1 = file1.Read(memory1.buffer, MemoryAllocator::bufferSize);
- if (file1.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename1.c_str() + wxT("\""));
+ const size_t length1 = file1.Read(memory1.get(), BUFFER_SIZE);
+ if (file1.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + zToWx(filename1) + wxT("\""));
- const size_t length2 = file2.Read(memory2.buffer, MemoryAllocator::bufferSize);
- if (file2.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename2.c_str() + wxT("\""));
+ const size_t length2 = file2.Read(memory2.get(), BUFFER_SIZE);
+ if (file2.Error()) throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + zToWx(filename2) + wxT("\""));
- if (length1 != length2 || ::memcmp(memory1.buffer, memory2.buffer, length1) != 0)
+ if (length1 != length2 || ::memcmp(memory1.get(), memory2.get(), length1) != 0)
return false;
bytesCompared += length1 * 2;
@@ -509,11 +510,12 @@ class CmpCallbackImpl : public CompareCallback
{
public:
CmpCallbackImpl(StatusHandler* handler, wxLongLong& bytesComparedLast) :
- m_handler(handler),
- m_bytesComparedLast(bytesComparedLast) {}
+ m_handler(handler),
+ m_bytesComparedLast(bytesComparedLast) {}
virtual void updateCompareStatus(const wxLongLong& totalBytesTransferred)
- { //called every 512 kB
+ {
+ //called every 512 kB
//inform about the (differential) processed amount of data
m_handler->updateProcessedData(0, totalBytesTransferred - m_bytesComparedLast);
@@ -554,72 +556,11 @@ bool filesHaveSameContentUpdating(const Zstring& filename1, const Zstring& filen
}
-/* OLD IMPLEMENTATION USING A WORKER THREAD
-
-//handle execution of a method while updating the UI
-class UpdateWhileComparing : public UpdateWhileExecuting
-{
-public:
- UpdateWhileComparing() {}
- ~UpdateWhileComparing() {}
-
- Zstring file1;
- Zstring file2;
- bool success;
- Zstring errorMessage;
- bool sameContent;
-
-private:
- void longRunner() //virtual method implementation
- {
- try
- {
- sameContent = filesHaveSameContent(file1, file2);
- success = true;
- }
- catch (FileError& error)
- {
- success = false;
- errorMessage = error.show();
- }
- }
-};
-
-
-bool filesHaveSameContentUpdating(const Zstring& filename1, const Zstring& filename2, const wxULongLong& totalBytesToCmp, StatusHandler* updateClass)
-{
- static UpdateWhileComparing cmpAndUpdate; //single instantiation: thread enters wait phase after each execution
-
- cmpAndUpdate.waitUntilReady();
-
- //longRunner is called from thread, but no mutex needed here, since thread is in waiting state!
- cmpAndUpdate.file1 = filename1;
- cmpAndUpdate.file2 = filename2;
-
- cmpAndUpdate.execute(updateClass);
-
- //no mutex needed here since longRunner is finished
- if (!cmpAndUpdate.success)
- throw FileError(cmpAndUpdate.errorMessage);
-
- //inform about the processed amount of data
- updateClass->updateProcessedData(0, totalBytesToCmp.ToDouble());
-
- return cmpAndUpdate.sameContent;
-}*/
-
-void formatPair(FolderPairCfg& input)
-{
- input.leftDirectory = FreeFileSync::getFormattedDirectoryName(input.leftDirectory);
- input.rightDirectory = FreeFileSync::getFormattedDirectoryName(input.rightDirectory);
-}
-
-
struct ToBeRemoved
{
bool operator()(const DirMapping& dirObj) const
{
- return !dirObj.selectedForSynchronization && dirObj.subDirs.size() == 0 && dirObj.subFiles.size() == 0;
+ return !dirObj.isActive() && dirObj.subDirs.size() == 0 && dirObj.subFiles.size() == 0;
}
};
@@ -627,39 +568,51 @@ struct ToBeRemoved
class RemoveFilteredDirs
{
public:
- RemoveFilteredDirs(const wxString& include, const wxString& exclude) :
- filterProc(include, exclude) {}
+ RemoveFilteredDirs(const FilterProcess& filterProc) :
+ filterProc_(filterProc) {}
- void operator()(HierarchyObject& hierObj)
+ void execute(HierarchyObject& hierObj)
{
//process subdirs recursively
std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(), *this);
- //filter subdirectories
- std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(), boost::bind(&RemoveFilteredDirs::filterDir, this, _1));
-
//remove superfluous directories
hierObj.subDirs.erase(std::remove_if(hierObj.subDirs.begin(), hierObj.subDirs.end(), ::ToBeRemoved()), hierObj.subDirs.end());
}
- void filterDir(FreeFileSync::DirMapping& dirObj)
- {
- const Zstring relName = dirObj.isEmpty<FreeFileSync::LEFT_SIDE>() ?
- dirObj.getRelativeName<FreeFileSync::RIGHT_SIDE>() :
- dirObj.getRelativeName<FreeFileSync::LEFT_SIDE>();
+private:
+ template<typename Iterator, typename Function>
+ friend Function std::for_each(Iterator, Iterator, Function);
- dirObj.selectedForSynchronization = filterProc.passDirFilter(relName, NULL); //subObjMightMatch is always true in this context!
+ void operator()(DirMapping& dirObj)
+ {
+ dirObj.setActive(filterProc_.passDirFilter(dirObj.getObjRelativeName().c_str(), NULL)); //subObjMightMatch is always true in this context!
+ execute(dirObj);
}
-private:
- const FilterProcess filterProc;
+ const FilterProcess& filterProc_;
};
+inline
+void formatPair(FolderPairCfg& input)
+{
+ //ensure they end with globalFunctions::FILE_NAME_SEPARATOR and replace macros
+ input.leftDirectory = FreeFileSync::getFormattedDirectoryName(input.leftDirectory);
+ input.rightDirectory = FreeFileSync::getFormattedDirectoryName(input.rightDirectory);
+}
+
+
+
+
+//#############################################################################################################################
+
//filters and removes all excluded directories (but keeps those serving as parent folders)
-void filterAndRemoveDirs(BaseDirMapping& baseDir, const wxString& include, const wxString& exclude)
+void filterAndRemoveDirs(BaseDirMapping& baseDir, const Zstring& include, const Zstring& exclude)
{
- RemoveFilteredDirs(include, exclude)(baseDir);
+ FilterProcess filterProc(include, exclude);
+
+ RemoveFilteredDirs(filterProc).execute(baseDir);
}
@@ -676,7 +629,7 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& direc
//init process: keep at beginning so that all gui elements are initialized properly
statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects
- //format directory pairs: ensure they end with globalFunctions::FILE_NAME_SEPARATOR!
+ //format directory pairs: ensure they end with globalFunctions::FILE_NAME_SEPARATOR and replace macros!
std::vector<FolderPairCfg> directoryPairsFormatted = directoryPairs;
std::for_each(directoryPairsFormatted.begin(), directoryPairsFormatted.end(), formatPair);
@@ -717,10 +670,26 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& direc
//attention: some filtered directories are still in the comparison result! (see include filter handling!)
if (fpCfg.filterIsActive) //let's filter them now... (and remove those that contain excluded elements only)
- filterAndRemoveDirs(*j, fpCfg.includeFilter, fpCfg.excludeFilter);
+ filterAndRemoveDirs(*j, fpCfg.includeFilter.c_str(), fpCfg.excludeFilter.c_str());
- //set sync-direction initially
- FreeFileSync::redetermineSyncDirection(fpCfg.syncConfiguration, *j);
+ //set initial sync-direction
+ class RedetermineCallback : public DeterminationProblem
+ {
+ public:
+ RedetermineCallback(bool& warningSyncDatabase, StatusHandler& statusUpdater) :
+ warningSyncDatabase_(warningSyncDatabase),
+ statusUpdater_(statusUpdater) {}
+
+ virtual void reportWarning(const wxString& text)
+ {
+ statusUpdater_.reportWarning(text, warningSyncDatabase_);
+ }
+ private:
+ bool& warningSyncDatabase_;
+ StatusHandler& statusUpdater_;
+ } redetCallback(m_warnings.warningSyncDatabase, *statusUpdater);
+
+ FreeFileSync::redetermineSyncDirection(fpCfg.syncConfiguration, *j, &redetCallback);
}
//only if everything was processed correctly output is written to!
@@ -730,9 +699,9 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& direc
catch (const std::exception& e)
{
if (dynamic_cast<const std::bad_alloc*>(&e) != NULL)
- statusUpdater->reportFatalError(wxString(_("System out of memory!")) + wxT(" ") + wxString::From8BitData(e.what()));
+ statusUpdater->reportFatalError(wxString(_("System out of memory!")) + wxT(" ") + wxString::FromAscii(e.what()));
else
- statusUpdater->reportFatalError(wxString::From8BitData(e.what()));
+ statusUpdater->reportFatalError(wxString::FromAscii(e.what()));
return; //should be obsolete!
}
}
@@ -743,7 +712,7 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& direc
wxString getConflictInvalidDate(const Zstring& fileNameFull, const wxLongLong& utcTime)
{
wxString msg = _("File %x has an invalid date!");
- msg.Replace(wxT("%x"), wxString(wxT("\"")) + fileNameFull.c_str() + wxT("\""));
+ msg.Replace(wxT("%x"), wxString(wxT("\"")) + zToWx(fileNameFull) + wxT("\""));
msg += wxString(wxT("\n\n")) + _("Date") + wxT(": ") + utcTimeToLocalString(utcTime, fileNameFull);
return wxString(_("Conflict detected:")) + wxT("\n") + msg;
}
@@ -760,7 +729,7 @@ wxString getConflictSameDateDiffSize(const FileMapping& fileObj)
right.Pad(maxPref - right.length(), wxT(' '), true);
wxString msg = _("Files %x have the same date but a different size!");
- msg.Replace(wxT("%x"), wxString(wxT("\"")) + fileObj.getRelativeName<LEFT_SIDE>() + wxT("\""));
+ msg.Replace(wxT("%x"), wxString(wxT("\"")) + zToWx(fileObj.getRelativeName<LEFT_SIDE>()) + wxT("\""));
msg += wxT("\n\n");
msg += left + wxT("\t") + _("Date") + wxT(": ") + utcTimeToLocalString(fileObj.getLastWriteTime<LEFT_SIDE>(),
fileObj.getFullName<LEFT_SIDE>()) + wxT(" \t") + _("Size") + wxT(": ") + fileObj.getFileSize<LEFT_SIDE>().ToString() + wxT("\n");
@@ -782,7 +751,7 @@ wxString getConflictChangeWithinHour(const FileMapping& fileObj)
wxString msg = _("Files %x have a file time difference of less than 1 hour!\n\nIt's not safe to decide which one is newer due to Daylight Saving Time issues.");
msg += wxString(wxT("\n")) + _("(Note that only FAT/FAT32 drives are affected by this problem!\nIn all other cases you can disable the setting \"ignore 1-hour difference\".)");
- msg.Replace(wxT("%x"), wxString(wxT("\"")) + fileObj.getRelativeName<LEFT_SIDE>() + wxT("\""));
+ msg.Replace(wxT("%x"), wxString(wxT("\"")) + zToWx(fileObj.getRelativeName<LEFT_SIDE>()) + wxT("\""));
msg += wxT("\n\n");
msg += left + wxT("\t") + _("Date") + wxT(": ") + utcTimeToLocalString(fileObj.getLastWriteTime<LEFT_SIDE>(), fileObj.getFullName<LEFT_SIDE>()) + wxT("\n");
msg += right + wxT("\t") + _("Date") + wxT(": ") + utcTimeToLocalString(fileObj.getLastWriteTime<RIGHT_SIDE>(), fileObj.getFullName<RIGHT_SIDE>());
@@ -791,7 +760,7 @@ wxString getConflictChangeWithinHour(const FileMapping& fileObj)
//-----------------------------------------------------------------------------
inline
-bool sameFileTime(const wxLongLong& a, const wxLongLong& b, const unsigned tolerance)
+bool sameFileTime(const wxLongLong& a, const wxLongLong& b, const unsigned int tolerance)
{
if (a < b)
return b - a <= tolerance;
@@ -802,15 +771,21 @@ bool sameFileTime(const wxLongLong& a, const wxLongLong& b, const unsigned toler
void CompareProcess::compareByTimeSize(const std::vector<FolderPairCfg>& directoryPairsFormatted, FolderComparison& output)
{
+ output.reserve(output.size() + directoryPairsFormatted.size());
+
//process one folder pair after each other
for (std::vector<FolderPairCfg>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair)
{
- BaseDirMapping newEntry(pair->leftDirectory, pair->rightDirectory);
+ BaseDirMapping newEntry(pair->leftDirectory,
+ pair->rightDirectory,
+ pair->filterIsActive,
+ pair->includeFilter,
+ pair->excludeFilter);
output.push_back(newEntry); //attention: push_back() copies by value!!! performance: append BEFORE writing values into fileCmp!
- //do basis scan and retrieve files existing on both sides
+ //do basis scan and retrieve files existing on both sides as "compareCandidates"
std::vector<FileMapping*> compareCandidates;
- performBaseComparison(*pair, output.back(), compareCandidates);
+ performBaseComparison(output.back(), compareCandidates);
//PERF_START;
@@ -829,11 +804,10 @@ void CompareProcess::compareByTimeSize(const std::vector<FolderPairCfg>& directo
line->getLastWriteTime<LEFT_SIDE>() > oneYearFromNow || //dated more than one year in future
line->getLastWriteTime<RIGHT_SIDE>() > oneYearFromNow) //dated more than one year in future
{
- line->cmpResult = FILE_CONFLICT;
if (line->getLastWriteTime<LEFT_SIDE>() < 0 || line->getLastWriteTime<LEFT_SIDE>() > oneYearFromNow)
- line->conflictDescription = getConflictInvalidDate(line->getFullName<LEFT_SIDE>(), line->getLastWriteTime<LEFT_SIDE>());
+ line->setCategoryConflict(getConflictInvalidDate(line->getFullName<LEFT_SIDE>(), line->getLastWriteTime<LEFT_SIDE>()));
else
- line->conflictDescription = getConflictInvalidDate(line->getFullName<RIGHT_SIDE>(), line->getLastWriteTime<RIGHT_SIDE>());
+ line->setCategoryConflict(getConflictInvalidDate(line->getFullName<RIGHT_SIDE>(), line->getLastWriteTime<RIGHT_SIDE>()));
}
else //from this block on all dates are at least "valid"
{
@@ -841,12 +815,9 @@ void CompareProcess::compareByTimeSize(const std::vector<FolderPairCfg>& directo
if (sameFileTime(line->getLastWriteTime<LEFT_SIDE>(), line->getLastWriteTime<RIGHT_SIDE>(), fileTimeTolerance))
{
if (line->getFileSize<LEFT_SIDE>() == line->getFileSize<RIGHT_SIDE>())
- line->cmpResult = FILE_EQUAL;
+ line->setCategory<FILE_EQUAL>();
else
- {
- line->cmpResult = FILE_CONFLICT; //same date, different filesize
- line->conflictDescription = getConflictSameDateDiffSize(*line);
- }
+ line->setCategoryConflict(getConflictSameDateDiffSize(*line)); //same date, different filesize
}
else
{
@@ -855,27 +826,21 @@ void CompareProcess::compareByTimeSize(const std::vector<FolderPairCfg>& directo
{
//date diff < 1 hour is a conflict: it's not safe to determine which file is newer
if (sameFileTime(line->getLastWriteTime<LEFT_SIDE>(), line->getLastWriteTime<RIGHT_SIDE>(), 3600 - 2 - 1))
- {
- line->cmpResult = FILE_CONFLICT;
- line->conflictDescription = getConflictChangeWithinHour(*line);
- }
+ line->setCategoryConflict(getConflictChangeWithinHour(*line));
else //exact +/- 1-hour detected: treat as equal
{
if (line->getFileSize<LEFT_SIDE>() == line->getFileSize<RIGHT_SIDE>())
- line->cmpResult = FILE_EQUAL;
+ line->setCategory<FILE_EQUAL>();
else
- {
- line->cmpResult = FILE_CONFLICT; //same date, different filesize
- line->conflictDescription = getConflictSameDateDiffSize(*line);
- }
+ line->setCategoryConflict(getConflictSameDateDiffSize(*line)); //same date, different filesize
}
}
else
{
if (line->getLastWriteTime<LEFT_SIDE>() < line->getLastWriteTime<RIGHT_SIDE>())
- line->cmpResult = FILE_RIGHT_NEWER;
+ line->setCategory<FILE_RIGHT_NEWER>();
else
- line->cmpResult = FILE_LEFT_NEWER;
+ line->setCategory<FILE_LEFT_NEWER>();
}
}
}
@@ -883,12 +848,9 @@ void CompareProcess::compareByTimeSize(const std::vector<FolderPairCfg>& directo
else //same write time
{
if (line->getFileSize<LEFT_SIDE>() == line->getFileSize<RIGHT_SIDE>())
- line->cmpResult = FILE_EQUAL;
+ line->setCategory<FILE_EQUAL>();
else
- {
- line->cmpResult = FILE_CONFLICT; //same date, different filesize
- line->conflictDescription = getConflictSameDateDiffSize(*line);
- }
+ line->setCategoryConflict(getConflictSameDateDiffSize(*line)); //same date, different filesize
}
}
}
@@ -911,14 +873,21 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director
//PERF_START;
std::vector<FileMapping*> compareCandidates;
+ //attention: make sure pointers in "compareCandidates" remain valid!!!
+ output.reserve(output.size() + directoryPairsFormatted.size());
+
//process one folder pair after each other
for (std::vector<FolderPairCfg>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair)
{
- BaseDirMapping newEntry(pair->leftDirectory, pair->rightDirectory);
+ BaseDirMapping newEntry(pair->leftDirectory,
+ pair->rightDirectory,
+ pair->filterIsActive,
+ pair->includeFilter,
+ pair->excludeFilter);
output.push_back(newEntry); //attention: push_back() copies by value!!! performance: append BEFORE writing values into fileCmp!
//do basis scan and retrieve candidates for binary comparison (files existing on both sides)
- performBaseComparison(*pair, output.back(), compareCandidates);
+ performBaseComparison(output.back(), compareCandidates);
}
//finish categorization...
@@ -931,7 +900,7 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director
{
//pre-check: files have different content if they have a different filesize
if ((*i)->getFileSize<LEFT_SIDE>() != (*i)->getFileSize<RIGHT_SIDE>())
- (*i)->cmpResult = FILE_DIFFERENT;
+ (*i)->setCategory<FILE_DIFFERENT>();
else
filesToCompareBytewise.push_back(*i);
}
@@ -951,7 +920,7 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director
FileMapping* const gridline = *j;
Zstring statusText = txtComparingContentOfFiles;
- statusText.Replace(wxT("%x"), gridline->getRelativeName<LEFT_SIDE>(), false);
+ statusText.Replace(DefaultStr("%x"), gridline->getRelativeName<LEFT_SIDE>(), false);
statusUpdater->updateStatusText(statusText);
//check files that exist in left and right model but have different content
@@ -966,9 +935,9 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director
gridline->getFullName<RIGHT_SIDE>(),
gridline->getFileSize<LEFT_SIDE>() * 2,
statusUpdater))
- gridline->cmpResult = FILE_EQUAL;
+ gridline->setCategory<FILE_EQUAL>();
else
- gridline->cmpResult = FILE_DIFFERENT;
+ gridline->setCategory<FILE_DIFFERENT>();
statusUpdater->updateProcessedData(2, 0); //processed data is communicated in subfunctions!
break;
@@ -978,15 +947,14 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director
ErrorHandler::Response rv = statusUpdater->reportError(error.show());
if (rv == ErrorHandler::IGNORE_ERROR)
{
- gridline->cmpResult = FILE_CONFLICT; //same date, different filesize
- gridline->conflictDescription = wxString(_("Conflict detected:")) + wxT("\n") + _("Comparing files by content failed.");
+ gridline->setCategoryConflict(wxString(_("Conflict detected:")) + wxT("\n") + _("Comparing files by content failed."));
break;
}
else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
- assert (false);
+ throw std::logic_error("Programming Error: Unknown return value!");
}
}
}
@@ -996,12 +964,8 @@ void CompareProcess::compareByContent(const std::vector<FolderPairCfg>& director
class MergeSides
{
public:
- MergeSides(const Zstring& baseDirLeftPf,
- const Zstring& baseDirRightPf,
- std::vector<FileMapping*>& appendUndefinedOut) :
- baseDirLeft(baseDirLeftPf),
- baseDirRight(baseDirRightPf),
- appendUndefined(appendUndefinedOut) {}
+ MergeSides(std::vector<FileMapping*>& appendUndefinedOut) :
+ appendUndefined(appendUndefinedOut) {}
void execute(const DirContainer& leftSide, const DirContainer& rightSide, HierarchyObject& output)
{
@@ -1017,60 +981,52 @@ public:
for (DirContainer::SubFileList::const_iterator i = leftSide.getSubFiles().begin(); i != leftSide.getSubFiles().end(); ++i)
{
- DirContainer::SubFileList::const_iterator j = rightSide.getSubFiles().find(*i);
+ DirContainer::SubFileList::const_iterator j = rightSide.getSubFiles().find(i->first);
//find files that exist on left but not on right
if (j == rightSide.getSubFiles().end())
- output.addSubFile(i->getData(), FILE_LEFT_SIDE_ONLY, FileMapping::nullData(),
- RelNamesBuffered(baseDirLeft, //base sync dir postfixed
- baseDirRight,
- i->getParentRelNamePf())); //relative parent name postfixed
+ output.addSubFile(i->second.getData(), i->first);
//find files that exist on left and right
else
{
appendUndefined.push_back(
- &output.addSubFile(i->getData(), FILE_EQUAL, j->getData(), //FILE_EQUAL is just a dummy-value here
- RelNamesBuffered(baseDirLeft, baseDirRight, i->getParentRelNamePf())));
+ &output.addSubFile(i->second.getData(), i->first, FILE_EQUAL, j->second.getData())); //FILE_EQUAL is just a dummy-value here
}
}
//find files that exist on right but not on left
for (DirContainer::SubFileList::const_iterator j = rightSide.getSubFiles().begin(); j != rightSide.getSubFiles().end(); ++j)
{
- if (leftSide.getSubFiles().find(*j) == leftSide.getSubFiles().end())
- output.addSubFile(FileMapping::nullData(), FILE_RIGHT_SIDE_ONLY, j->getData(),
- RelNamesBuffered(baseDirLeft, baseDirRight, j->getParentRelNamePf()));
+ if (leftSide.getSubFiles().find(j->first) == leftSide.getSubFiles().end())
+ output.addSubFile(j->first, j->second.getData());
}
//-----------------------------------------------------------------------------------------------
for (DirContainer::SubDirList::const_iterator i = leftSide.getSubDirs().begin(); i != leftSide.getSubDirs().end(); ++i)
{
- DirContainer::SubDirList::const_iterator j = rightSide.getSubDirs().find(*i);
+ DirContainer::SubDirList::const_iterator j = rightSide.getSubDirs().find(i->first);
//find directories that exist on left but not on right
if (j == rightSide.getSubDirs().end())
{
- DirMapping& newDirMap = output.addSubDir(i->getData(), DIR_LEFT_SIDE_ONLY, DirMapping::nullData(),
- RelNamesBuffered(baseDirLeft, baseDirRight, i->getParentRelNamePf()));
- fillOneSide<true>(*i, newDirMap); //recurse into subdirectories
+ DirMapping& newDirMap = output.addSubDir(true, i->first, false);
+ fillOneSide<true>(i->second, newDirMap); //recurse into subdirectories
}
else //directories that exist on both sides
{
- DirMapping& newDirMap = output.addSubDir(i->getData(), DIR_EQUAL, j->getData(),
- RelNamesBuffered(baseDirLeft, baseDirRight, i->getParentRelNamePf()));
- execute(*i, *j, newDirMap); //recurse into subdirectories
+ DirMapping& newDirMap = output.addSubDir(true, i->first, true);
+ execute(i->second, j->second, newDirMap); //recurse into subdirectories
}
}
//find directories that exist on right but not on left
for (DirContainer::SubDirList::const_iterator j = rightSide.getSubDirs().begin(); j != rightSide.getSubDirs().end(); ++j)
{
- if (leftSide.getSubDirs().find(*j) == leftSide.getSubDirs().end())
+ if (leftSide.getSubDirs().find(j->first) == leftSide.getSubDirs().end())
{
- DirMapping& newDirMap = output.addSubDir(DirMapping::nullData(), DIR_RIGHT_SIDE_ONLY, j->getData(),
- RelNamesBuffered(baseDirLeft, baseDirRight, j->getParentRelNamePf()));
- fillOneSide<false>(*j, newDirMap); //recurse into subdirectories
+ DirMapping& newDirMap = output.addSubDir(false, j->first, true);
+ fillOneSide<false>(j->second, newDirMap); //recurse into subdirectories
}
}
}
@@ -1086,33 +1042,27 @@ private:
for (DirContainer::SubFileList::const_iterator i = dirCont.getSubFiles().begin(); i != dirCont.getSubFiles().end(); ++i)
{
if (leftSide)
- output.addSubFile(i->getData(), FILE_LEFT_SIDE_ONLY, FileMapping::nullData(),
- RelNamesBuffered(baseDirLeft, baseDirRight, i->getParentRelNamePf()));
+ output.addSubFile(i->second.getData(), i->first);
else
- output.addSubFile(FileMapping::nullData(), FILE_RIGHT_SIDE_ONLY, i->getData(),
- RelNamesBuffered(baseDirLeft, baseDirRight, i->getParentRelNamePf()));
+ output.addSubFile(i->first, i->second.getData());
}
for (DirContainer::SubDirList::const_iterator i = dirCont.getSubDirs().begin(); i != dirCont.getSubDirs().end(); ++i)
{
DirMapping& newDirMap = leftSide ?
- output.addSubDir(i->getData(), DIR_LEFT_SIDE_ONLY, DirMapping::nullData(),
- RelNamesBuffered(baseDirLeft, baseDirRight, i->getParentRelNamePf())) :
- output.addSubDir(DirMapping::nullData(), DIR_RIGHT_SIDE_ONLY, i->getData(),
- RelNamesBuffered(baseDirLeft, baseDirRight, i->getParentRelNamePf()));
+ output.addSubDir(true, i->first, false) :
+ output.addSubDir(false, i->first, true);
- fillOneSide<leftSide>(*i, newDirMap); //recurse into subdirectories
+ fillOneSide<leftSide>(i->second, newDirMap); //recurse into subdirectories
}
}
- const Zstring& baseDirLeft;
- const Zstring& baseDirRight;
std::vector<FileMapping*>& appendUndefined;
};
-void CompareProcess::performBaseComparison(const FolderPairCfg& pair, BaseDirMapping& output, std::vector<FileMapping*>& appendUndefined)
+void CompareProcess::performBaseComparison(BaseDirMapping& output, std::vector<FileMapping*>& appendUndefined)
{
assert(output.subDirs.empty());
assert(output.subFiles.empty());
@@ -1120,24 +1070,23 @@ void CompareProcess::performBaseComparison(const FolderPairCfg& pair, BaseDirMap
//PERF_START;
//scan directories
- const DirContainer& directoryLeft = directoryBuffer->getDirectoryDescription(pair.leftDirectory,
- pair.filterIsActive,
- pair.includeFilter,
- pair.excludeFilter);
+ const DirContainer& directoryLeft = directoryBuffer->getDirectoryDescription(
+ output.getBaseDir<LEFT_SIDE>(),
+ output.getFilter().filterActive,
+ output.getFilter().includeFilter,
+ output.getFilter().excludeFilter);
- const DirContainer& directoryRight = directoryBuffer->getDirectoryDescription(pair.rightDirectory,
- pair.filterIsActive,
- pair.includeFilter,
- pair.excludeFilter);
+ const DirContainer& directoryRight = directoryBuffer->getDirectoryDescription(
+ output.getBaseDir<RIGHT_SIDE>(),
+ output.getFilter().filterActive,
+ output.getFilter().includeFilter,
+ output.getFilter().excludeFilter);
- statusUpdater->updateStatusText(_("Generating file list..."));
+ statusUpdater->updateStatusText(wxToZ(_("Generating file list...")));
statusUpdater->forceUiRefresh(); //keep total number of scanned files up to date
//PERF_STOP;
- MergeSides(pair.leftDirectory,
- pair.rightDirectory,
- appendUndefined).execute(directoryLeft, directoryRight, output);
- //PERF_STOP;
+ MergeSides(appendUndefined).execute(directoryLeft, directoryRight, output);
}
bgstack15