summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/IFileOperation/file_op.cpp14
-rw-r--r--lib/ShadowCopy/LockFile.cpp4
-rw-r--r--lib/ShadowCopy/shadow.cpp4
-rw-r--r--lib/Thumbnail/thumbnail.cpp66
-rw-r--r--lib/Thumbnail/thumbnail.h4
-rw-r--r--lib/db_file.cpp248
-rw-r--r--lib/dir_lock.cpp124
-rw-r--r--lib/dir_lock.h3
-rw-r--r--lib/error_log.cpp101
-rw-r--r--lib/error_log.h49
-rw-r--r--lib/hard_filter.cpp193
-rw-r--r--lib/hard_filter.h14
-rw-r--r--lib/icon_buffer.cpp116
-rw-r--r--lib/icon_buffer.h2
-rw-r--r--lib/localization.cpp5
-rw-r--r--lib/norm_filter.h2
-rw-r--r--lib/parallel_scan.cpp16
-rw-r--r--lib/parse_lng.h13
-rw-r--r--lib/parse_plural.h10
-rw-r--r--lib/process_xml.cpp56
-rw-r--r--lib/process_xml.h2
-rw-r--r--lib/recycler.cpp66
-rw-r--r--lib/recycler.h8
-rw-r--r--lib/resolve_path.cpp83
-rw-r--r--lib/resolve_path.h1
-rw-r--r--lib/resources.cpp7
-rw-r--r--lib/shadow.cpp51
-rw-r--r--lib/statistics.cpp13
-rw-r--r--lib/status_handler.h60
-rw-r--r--lib/status_handler_impl.h34
-rw-r--r--lib/xml_base.cpp14
31 files changed, 587 insertions, 796 deletions
diff --git a/lib/IFileOperation/file_op.cpp b/lib/IFileOperation/file_op.cpp
index 8024ab91..3d7717f4 100644
--- a/lib/IFileOperation/file_op.cpp
+++ b/lib/IFileOperation/file_op.cpp
@@ -24,7 +24,7 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
{
ComPtr<IFileOperation> fileOp;
ZEN_CHECK_COM(::CoCreateInstance(CLSID_FileOperation, //throw ComError
- NULL,
+ nullptr,
CLSCTX_ALL,
IID_PPV_ARGS(fileOp.init())));
@@ -45,7 +45,7 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
//create file/folder item object
ComPtr<IShellItem> psiFile;
HRESULT hr = ::SHCreateItemFromParsingName(fileNames[i],
- NULL,
+ nullptr,
IID_PPV_ARGS(psiFile.init()));
if (FAILED(hr))
{
@@ -55,7 +55,7 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw ComError
throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + fileNames[i] + L"\".", hr);
}
- ZEN_CHECK_COM(fileOp->DeleteItem(psiFile.get(), NULL));
+ ZEN_CHECK_COM(fileOp->DeleteItem(psiFile.get(), nullptr));
++operationCount;
}
@@ -80,7 +80,7 @@ void copyFile(const wchar_t* sourceFile, //throw ComError
{
ComPtr<IFileOperation> fileOp;
ZEN_CHECK_COM(::CoCreateInstance(CLSID_FileOperation, //throw ComError
- NULL,
+ nullptr,
CLSCTX_ALL,
IID_PPV_ARGS(fileOp.init())));
@@ -96,7 +96,7 @@ void copyFile(const wchar_t* sourceFile, //throw ComError
ComPtr<IShellItem> psiSourceFile;
{
HRESULT hr = ::SHCreateItemFromParsingName(sourceFile,
- NULL,
+ nullptr,
IID_PPV_ARGS(psiSourceFile.init()));
if (FAILED(hr))
throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + sourceFile + L"\".", hr);
@@ -113,14 +113,14 @@ void copyFile(const wchar_t* sourceFile, //throw ComError
ComPtr<IShellItem> psiTargetFolder;
{
HRESULT hr = ::SHCreateItemFromParsingName(targetFolder.c_str(),
- NULL,
+ nullptr,
IID_PPV_ARGS(psiTargetFolder.init()));
if (FAILED(hr))
throw ComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\"" + targetFolder + L"\".", hr);
}
//schedule file copy operation
- ZEN_CHECK_COM(fileOp->CopyItem(psiSourceFile.get(), psiTargetFolder.get(), targetFileNameShort.c_str(), NULL));
+ ZEN_CHECK_COM(fileOp->CopyItem(psiSourceFile.get(), psiTargetFolder.get(), targetFileNameShort.c_str(), nullptr));
//perform actual operations
ZEN_CHECK_COM(fileOp->PerformOperations());
diff --git a/lib/ShadowCopy/LockFile.cpp b/lib/ShadowCopy/LockFile.cpp
index 523b01bb..b9008863 100644
--- a/lib/ShadowCopy/LockFile.cpp
+++ b/lib/ShadowCopy/LockFile.cpp
@@ -24,10 +24,10 @@ int wmain(int argc, wchar_t* argv[])
HANDLE hFile = ::CreateFile(filename.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
+ nullptr);
if (hFile == INVALID_HANDLE_VALUE)
{
std::wcout << "Error obtaining exclusive lock on test file: " << filename << "\n\n";
diff --git a/lib/ShadowCopy/shadow.cpp b/lib/ShadowCopy/shadow.cpp
index fc95381d..bc27e2c3 100644
--- a/lib/ShadowCopy/shadow.cpp
+++ b/lib/ShadowCopy/shadow.cpp
@@ -110,7 +110,7 @@ shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError
ZEN_CHECK_COM(fut.Wait());
HRESULT hr = S_OK;
- ZEN_CHECK_COM(fut.QueryStatus(&hr, NULL)); //check if the async operation succeeded...
+ ZEN_CHECK_COM(fut.QueryStatus(&hr, nullptr)); //check if the async operation succeeded...
if (FAILED(hr))
throw ComError(L"Error calling \"fut->QueryStatus\".", hr);
};
@@ -151,7 +151,7 @@ shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError
VSS_SNAPSHOT_PROP props = {};
ZEN_CHECK_COM(backupComp->GetSnapshotProperties(SnapShotId, &props));
- ZEN_ON_BLOCK_EXIT(::VssFreeSnapshotProperties(&props));
+ ZEN_ON_SCOPE_EXIT(::VssFreeSnapshotProperties(&props));
//finally: write volume name of newly created shadow copy
return shadow::ShadowData(backupComp, props.m_pwszSnapshotDeviceObject);
diff --git a/lib/Thumbnail/thumbnail.cpp b/lib/Thumbnail/thumbnail.cpp
index 050251de..0176f89b 100644
--- a/lib/Thumbnail/thumbnail.cpp
+++ b/lib/Thumbnail/thumbnail.cpp
@@ -31,59 +31,59 @@ thumb::HICON thumb::getThumbnail(const wchar_t* filename, int requestedSize) //r
{
HRESULT hr = ::SHGetDesktopFolder(shellFolder.init());
if (FAILED(hr) || !shellFolder)
- return NULL;
+ return nullptr;
}
- PIDLIST_RELATIVE pidlFolder = NULL;
+ PIDLIST_RELATIVE pidlFolder = nullptr;
{
const std::wstring& pathName = beforeLast(filenameStr, '\\');
- HRESULT hr = shellFolder->ParseDisplayName(NULL, // [in] HWND hwnd,
- NULL, // [in] IBindCtx *pbc,
+ HRESULT hr = shellFolder->ParseDisplayName(nullptr, // [in] HWND hwnd,
+ nullptr, // [in] IBindCtx *pbc,
const_cast<LPWSTR>(pathName.c_str()), // [in] LPWSTR pszDisplayName,
- NULL, // [out] ULONG *pchEaten,
- &pidlFolder, // [out] PIDLIST_RELATIVE* ppidl,
- NULL); // [in, out] ULONG *pdwAttributes
+ nullptr, // [out] ULONG *pchEaten,
+ &pidlFolder, // [out] PIDLIST_RELATIVE* ppidl,
+ nullptr); // [in, out] ULONG *pdwAttributes
if (FAILED(hr) || !pidlFolder)
- return NULL;
+ return nullptr;
}
- ZEN_ON_BLOCK_EXIT(::ILFree(pidlFolder)); //older version: ::CoTaskMemFree
+ ZEN_ON_SCOPE_EXIT(::ILFree(pidlFolder)); //older version: ::CoTaskMemFree
ComPtr<IShellFolder> imageFolder;
{
HRESULT hr = shellFolder->BindToObject(pidlFolder, // [in] PCUIDLIST_RELATIVE pidl,
- NULL,
+ nullptr,
IID_PPV_ARGS(imageFolder.init()));
if (FAILED(hr) || !imageFolder)
- return NULL;
+ return nullptr;
}
- PIDLIST_RELATIVE pidImage = NULL;
+ PIDLIST_RELATIVE pidImage = nullptr;
{
const std::wstring& shortName = afterLast(filenameStr, '\\');
- HRESULT hr = imageFolder->ParseDisplayName(NULL, // [in] HWND hwnd,
- NULL, // [in] IBindCtx *pbc,
+ HRESULT hr = imageFolder->ParseDisplayName(nullptr, // [in] HWND hwnd,
+ nullptr, // [in] IBindCtx *pbc,
const_cast<LPWSTR>(shortName.c_str()), // [in] LPWSTR pszDisplayName,
- NULL, // [out] ULONG *pchEaten,
- &pidImage, // [out] PIDLIST_RELATIVE *ppidl,
- NULL); // [in, out] ULONG *pdwAttributes
+ nullptr, // [out] ULONG *pchEaten,
+ &pidImage, // [out] PIDLIST_RELATIVE *ppidl,
+ nullptr); // [in, out] ULONG *pdwAttributes
if (FAILED(hr) || !pidImage)
- return NULL;
+ return nullptr;
}
- ZEN_ON_BLOCK_EXIT(::ILFree(pidImage)); //older version: ::CoTaskMemFree
+ ZEN_ON_SCOPE_EXIT(::ILFree(pidImage)); //older version: ::CoTaskMemFree
ComPtr<IExtractImage> extractImage;
{
PCUITEMID_CHILD_ARRAY pidlIn = reinterpret_cast<PCUITEMID_CHILD_ARRAY>(&pidImage);
//this is where STRICT_TYPED_ITEMIDS gets us ;)
- HRESULT hr = imageFolder->GetUIObjectOf(NULL, // [in] HWND hwndOwner,
+ HRESULT hr = imageFolder->GetUIObjectOf(nullptr, // [in] HWND hwndOwner,
1, // [in] UINT cidl,
pidlIn, // [in] PCUITEMID_CHILD_ARRAY apidl,
IID_IExtractImage, // [in] REFIID riid,
- NULL, // [in, out] UINT *rgfReserved,
+ nullptr, // [in, out] UINT *rgfReserved,
reinterpret_cast<void**>(extractImage.init())); // [out] void **ppv
if (FAILED(hr) || !extractImage)
- return NULL;
+ return nullptr;
}
{
@@ -100,28 +100,28 @@ thumb::HICON thumb::getThumbnail(const wchar_t* filename, int requestedSize) //r
clrDepth, // [in] DWORD dwRecClrDepth,
&flags); // [in, out] DWORD *pdwFlags
if (FAILED(hr))
- return NULL;
+ return nullptr;
}
- HBITMAP bitmap = NULL;
+ HBITMAP bitmap = nullptr;
{
HRESULT hr = extractImage->Extract(&bitmap);
if (FAILED(hr) || !bitmap)
- return NULL;
+ return nullptr;
}
- ZEN_ON_BLOCK_EXIT(::DeleteObject(bitmap));
+ ZEN_ON_SCOPE_EXIT(::DeleteObject(bitmap));
BITMAP bmpInfo = {};
if (::GetObject(bitmap, //__in HGDIOBJ hgdiobj,
sizeof(bmpInfo), //__in int cbBuffer,
&bmpInfo) == 0) //__out LPVOID lpvObject
- return NULL;
+ return nullptr;
- HBITMAP bitmapMask = ::CreateCompatibleBitmap(::GetDC(NULL), bmpInfo.bmWidth, bmpInfo.bmHeight);
+ HBITMAP bitmapMask = ::CreateCompatibleBitmap(::GetDC(nullptr), bmpInfo.bmWidth, bmpInfo.bmHeight);
if (bitmapMask == 0)
- return NULL;
- ZEN_ON_BLOCK_EXIT(::DeleteObject(bitmapMask));
+ return nullptr;
+ ZEN_ON_SCOPE_EXIT(::DeleteObject(bitmapMask));
ICONINFO iconInfo = {};
iconInfo.fIcon = true;
@@ -141,7 +141,7 @@ thumb::HICON thumb::getIconByIndex(int iconIndex, int shilIconType) //return 0 o
HRESULT hr = ::SHGetImageList(shilIconType, //__in int iImageList,
IID_PPV_ARGS(imageList.init()));
if (FAILED(hr) || !imageList)
- return NULL;
+ return nullptr;
}
bool hasAlpha = false; //perf: 0,14 µs
@@ -153,7 +153,7 @@ thumb::HICON thumb::getIconByIndex(int iconIndex, int shilIconType) //return 0 o
hasAlpha = flags & ILIF_ALPHA;
}
- ::HICON hIcon = NULL; //perf: 1,5 ms - the dominant block
+ ::HICON hIcon = nullptr; //perf: 1,5 ms - the dominant block
{
HRESULT hr = imageList->GetIcon(iconIndex, // [in] int i,
hasAlpha ? ILD_IMAGE : ILD_NORMAL, // [in] UINT flags,
@@ -161,7 +161,7 @@ thumb::HICON thumb::getIconByIndex(int iconIndex, int shilIconType) //return 0 o
//other flags: http://msdn.microsoft.com/en-us/library/windows/desktop/bb775230(v=vs.85).aspx
&hIcon); // [out] HICON *picon
if (FAILED(hr) || !hIcon)
- return NULL;
+ return nullptr;
}
return hIcon;
diff --git a/lib/Thumbnail/thumbnail.h b/lib/Thumbnail/thumbnail.h
index 7e11812c..b8b95d8f 100644
--- a/lib/Thumbnail/thumbnail.h
+++ b/lib/Thumbnail/thumbnail.h
@@ -21,8 +21,8 @@ namespace thumb
/*
PREREQUISITES:
-1. COM must be initialized for the current thread via ::CoInitialize(NULL) or ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED),
- but NOT ::CoInitializeEx(NULL, COINIT_MULTITHREADED) -> internal access violation crash!
+1. COM must be initialized for the current thread via ::CoInitialize(nullptr) or ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED),
+ but NOT ::CoInitializeEx(nullptr, COINIT_MULTITHREADED) -> internal access violation crash!
2. call ::FileIconInit() on app start to remedy obscure errors like SHELL_E_WRONG_BITDEPTH (0x80270102)
for certain file types, e.g. lnk, mpg - required on Windows 7 see http://msdn.microsoft.com/en-us/library/ms683212(v=VS.85).aspx
*/
diff --git a/lib/db_file.cpp b/lib/db_file.cpp
index 2d02d634..8ae8f94b 100644
--- a/lib/db_file.cpp
+++ b/lib/db_file.cpp
@@ -60,16 +60,36 @@ Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false)
}
+class CheckedDbReader : public CheckedReader
+{
+public:
+ CheckedDbReader(wxInputStream& stream, const Zstring& errorObjName) : CheckedReader(stream), errorObjName_(errorObjName) {}
+
+private:
+ virtual void throwException() const { throw FileError(_("Error reading from synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); }
+
+ const Zstring errorObjName_;
+};
+
+
+class CheckedDbWriter : public CheckedWriter
+{
+public:
+ CheckedDbWriter(wxOutputStream& stream, const Zstring& errorObjName) : CheckedWriter(stream), errorObjName_(errorObjName) {}
+
+ virtual void throwException() const { throw FileError(_("Error writing to synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); }
+
+ const Zstring errorObjName_;
+};
+
+
+
StreamMapping loadStreams(const Zstring& filename) //throw FileError
{
- if (!zen::fileExists(filename))
- throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" +
- _("One of the FreeFileSync database files is not yet existing:") + L" \n" +
- L"\"" + filename + L"\"");
try
{
//read format description (uncompressed)
- FileInputStream rawStream(filename); //throw FileError
+ FileInputStream rawStream(filename); //throw FileError, ErrorNotExisting
//read FreeFileSync file identifier
char formatDescr[sizeof(FILE_FORMAT_DESCR)] = {};
@@ -80,26 +100,32 @@ StreamMapping loadStreams(const Zstring& filename) //throw FileError
wxZlibInputStream decompressed(rawStream, wxZLIB_ZLIB);
- CheckedReader cr(decompressed, filename);
+ CheckedDbReader cr(decompressed, filename);
- std::int32_t version = cr.readNumberC<std::int32_t>();
+ std::int32_t version = cr.readPOD<std::int32_t>();
if (version != FILE_FORMAT_VER) //read file format version#
throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\"");
//read stream lists
StreamMapping output;
- std::uint32_t dbCount = cr.readNumberC<std::uint32_t>(); //number of databases: one for each sync-pair
+ std::uint32_t dbCount = cr.readPOD<std::uint32_t>(); //number of databases: one for each sync-pair
while (dbCount-- != 0)
{
//DB id of partner databases
- const std::string sessionID = cr.readStringC<std::string>();
- const MemoryStream stream = cr.readStringC<MemoryStream>(); //read db-entry stream (containing DirInformation)
+ const std::string sessionID = cr.readString<std::string>();
+ const MemoryStream stream = cr.readString<MemoryStream>(); //read db-entry stream (containing DirInformation)
output.insert(std::make_pair(sessionID, stream));
}
return output;
}
+ catch (ErrorNotExisting&)
+ {
+ throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" +
+ _("One of the FreeFileSync database files is not yet existing:") + L" \n" +
+ L"\"" + filename + L"\"");
+ }
catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
{
throw FileError(_("Error reading from synchronization database:") + L" (bad alloc)");
@@ -107,7 +133,7 @@ StreamMapping loadStreams(const Zstring& filename) //throw FileError
}
-class StreamParser : private CheckedReader
+class StreamParser : private CheckedDbReader
{
public:
static DirInfoPtr execute(const MemoryStream& stream, const Zstring& fileName) //throw FileError -> return value always bound!
@@ -127,14 +153,14 @@ public:
}
private:
- StreamParser(wxInputStream& stream, const Zstring& errorObjName, DirInformation& dirInfo) : CheckedReader(stream, errorObjName)
+ StreamParser(wxInputStream& stream, const Zstring& errorObjName, DirInformation& dirInfo) : CheckedDbReader(stream, errorObjName)
{
recurse(dirInfo.baseDirContainer);
}
Zstring readStringUtf8() const
{
- return utf8CvrtTo<Zstring>(readStringC<Zbase<char>>());
+ return utf8CvrtTo<Zstring>(readString<Zbase<char>>());
}
FileId readFileId() const
@@ -142,39 +168,39 @@ private:
assert_static(sizeof(FileId().first ) <= sizeof(std::uint64_t));
assert_static(sizeof(FileId().second) <= sizeof(std::uint64_t));
- const auto devId = static_cast<decltype(FileId().first )>(readNumberC<std::uint64_t>()); //
- const auto fId = static_cast<decltype(FileId().second)>(readNumberC<std::uint64_t>()); //silence "loss of precision" compiler warnings
+ const auto devId = static_cast<decltype(FileId().first )>(readPOD<std::uint64_t>()); //
+ const auto fId = static_cast<decltype(FileId().second)>(readPOD<std::uint64_t>()); //silence "loss of precision" compiler warnings
return std::make_pair(devId, fId);
}
void recurse(DirContainer& dirCont) const
{
- while (readNumberC<bool>()) //files
+ while (readPOD<bool>()) //files
{
//attention: order of function argument evaluation is undefined! So do it one after the other...
const Zstring shortName = readStringUtf8(); //file name
- const std::int64_t modTime = readNumberC<std::int64_t>();
- const std::uint64_t fileSize = readNumberC<std::uint64_t>();
+ const std::int64_t modTime = readPOD<std::int64_t>();
+ const std::uint64_t fileSize = readPOD<std::uint64_t>();
const FileId fileID = readFileId();
dirCont.addSubFile(shortName,
FileDescriptor(modTime, fileSize, fileID));
}
- while (readNumberC<bool>()) //symlinks
+ while (readPOD<bool>()) //symlinks
{
//attention: order of function argument evaluation is undefined! So do it one after the other...
const Zstring shortName = readStringUtf8(); //file name
- const std::int64_t modTime = readNumberC<std::int64_t>();
+ const std::int64_t modTime = readPOD<std::int64_t>();
const Zstring targetPath = readStringUtf8(); //file name
- const LinkDescriptor::LinkType linkType = static_cast<LinkDescriptor::LinkType>(readNumberC<std::int32_t>());
+ const LinkDescriptor::LinkType linkType = static_cast<LinkDescriptor::LinkType>(readPOD<std::int32_t>());
dirCont.addSubLink(shortName,
LinkDescriptor(modTime, targetPath, linkType));
}
- while (readNumberC<bool>()) //directories
+ while (readPOD<bool>()) //directories
{
const Zstring shortName = readStringUtf8(); //directory name
DirContainer& subDir = dirCont.addSubDir(shortName);
@@ -201,29 +227,28 @@ void saveFile(const StreamMapping& streamList, const Zstring& filename) //throw
6 1,77 MB - 613 ms
9 (maximal compression) 1,74 MB - 3330 ms */
- CheckedWriter cw(compressed, filename);
+ CheckedDbWriter cw(compressed, filename);
//save file format version
- cw.writeNumberC<std::int32_t>(FILE_FORMAT_VER);
+ cw.writePOD<std::int32_t>(FILE_FORMAT_VER);
//save stream list
- cw.writeNumberC<std::uint32_t>(static_cast<std::uint32_t>(streamList.size())); //number of database records: one for each sync-pair
+ cw.writePOD<std::uint32_t>(static_cast<std::uint32_t>(streamList.size())); //number of database records: one for each sync-pair
for (auto iter = streamList.begin(); iter != streamList.end(); ++iter)
{
- cw.writeStringC<std::string >(iter->first ); //sync session id
- cw.writeStringC<MemoryStream>(iter->second); //DirInformation stream
+ cw.writeString<std::string >(iter->first ); //sync session id
+ cw.writeString<MemoryStream>(iter->second); //DirInformation stream
}
}
- //(try to) hide database file
#ifdef FFS_WIN
- ::SetFileAttributes(zen::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN);
+ ::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); //(try to) hide database file
#endif
}
template <SelectedSide side>
-class StreamGenerator : private CheckedWriter
+class StreamGenerator : private CheckedDbWriter
{
public:
static MemoryStream execute(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName)
@@ -238,7 +263,7 @@ public:
}
private:
- StreamGenerator(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName, wxOutputStream& stream) : CheckedWriter(stream, errorObjName)
+ StreamGenerator(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName, wxOutputStream& stream) : CheckedDbWriter(stream, errorObjName)
{
recurse(baseMapping, oldDirInfo);
}
@@ -247,32 +272,36 @@ private:
{
// for (const auto& fileMap : hierObj.refSubFiles()) { processFile(fileMap, oldDirInfo); }); !
- std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](const FileMapping& fileMap) { this->processFile(fileMap, oldDirInfo); });
- writeNumberC<bool>(false); //mark last entry
+ std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](const FileMapping& fileMap) { this->processFile(fileMap, oldDirInfo); });
+ writePOD<bool>(false); //mark last entry
std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), [&](const SymLinkMapping& linkObj) { this->processLink(linkObj, oldDirInfo); });
- writeNumberC<bool>(false); //mark last entry
- std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), [&](const DirMapping& dirMap) { this->processDir(dirMap, oldDirInfo); });
- writeNumberC<bool>(false); //mark last entry
+ writePOD<bool>(false); //mark last entry
+ std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), [&](const DirMapping& dirMap) { this->processDir (dirMap, oldDirInfo); });
+ writePOD<bool>(false); //mark last entry
}
- void writeStringUtf8(const Zstring& str) { writeStringC(utf8CvrtTo<Zbase<char>>(str)); }
+ void writeStringUtf8(const Zstring& str) { writeString(utf8CvrtTo<Zbase<char>>(str)); }
void writeFileId(const FileId& id)
{
- writeNumberC<std::uint64_t>(id.first ); //device id
- writeNumberC<std::uint64_t>(id.second); //file id
+ writePOD<std::uint64_t>(id.first ); //device id
+ writePOD<std::uint64_t>(id.second); //file id
}
+#ifdef _MSC_VER
+ warn_static("support multiple folder pairs that differ in hard filter only?")
+#endif
+
void processFile(const FileMapping& fileMap, const DirContainer* oldParentDir)
{
if (fileMap.getCategory() == FILE_EQUAL) //data in sync: write current state
{
if (!fileMap.isEmpty<side>())
{
- writeNumberC<bool>(true); //mark beginning of entry
+ writePOD<bool>(true); //mark beginning of entry
writeStringUtf8(fileMap.getShortName<side>()); //save respecting case! (Windows)
- writeNumberC<std:: int64_t>(to<std:: int64_t>(fileMap.getLastWriteTime<side>()));
- writeNumberC<std::uint64_t>(to<std::uint64_t>(fileMap.getFileSize<side>()));
+ writePOD<std:: int64_t>(to<std:: int64_t>(fileMap.getLastWriteTime<side>()));
+ writePOD<std::uint64_t>(to<std::uint64_t>(fileMap.getFileSize<side>()));
writeFileId(fileMap.getFileId<side>());
}
}
@@ -283,10 +312,10 @@ private:
auto iter = oldParentDir->files.find(fileMap.getObjShortName());
if (iter != oldParentDir->files.end())
{
- writeNumberC<bool>(true); //mark beginning of entry
+ writePOD<bool>(true); //mark beginning of entry
writeStringUtf8(iter->first); //save respecting case! (Windows)
- writeNumberC<std:: int64_t>(to<std:: int64_t>(iter->second.lastWriteTimeRaw));
- writeNumberC<std::uint64_t>(to<std::uint64_t>(iter->second.fileSize));
+ writePOD<std:: int64_t>(to<std:: int64_t>(iter->second.lastWriteTimeRaw));
+ writePOD<std::uint64_t>(to<std::uint64_t>(iter->second.fileSize));
writeFileId(iter->second.id);
}
}
@@ -299,11 +328,11 @@ private:
{
if (!linkObj.isEmpty<side>())
{
- writeNumberC<bool>(true); //mark beginning of entry
+ writePOD<bool>(true); //mark beginning of entry
writeStringUtf8(linkObj.getShortName<side>()); //save respecting case! (Windows)
- writeNumberC<std::int64_t>(to<std::int64_t>(linkObj.getLastWriteTime<side>()));
+ writePOD<std::int64_t>(to<std::int64_t>(linkObj.getLastWriteTime<side>()));
writeStringUtf8(linkObj.getTargetPath<side>());
- writeNumberC<std::int32_t>(linkObj.getLinkType<side>());
+ writePOD<std::int32_t>(linkObj.getLinkType<side>());
}
}
else //not in sync: reuse last synchronous state
@@ -313,11 +342,11 @@ private:
auto iter = oldParentDir->links.find(linkObj.getObjShortName());
if (iter != oldParentDir->links.end())
{
- writeNumberC<bool>(true); //mark beginning of entry
+ writePOD<bool>(true); //mark beginning of entry
writeStringUtf8(iter->first); //save respecting case! (Windows)
- writeNumberC<std::int64_t>(to<std::int64_t>(iter->second.lastWriteTimeRaw));
+ writePOD<std::int64_t>(to<std::int64_t>(iter->second.lastWriteTimeRaw));
writeStringUtf8(iter->second.targetPath);
- writeNumberC<std::int32_t>(iter->second.type);
+ writePOD<std::int32_t>(iter->second.type);
}
}
}
@@ -325,8 +354,8 @@ private:
void processDir(const DirMapping& dirMap, const DirContainer* oldParentDir)
{
- const DirContainer* oldDir = NULL;
- const Zstring* oldDirName = NULL;
+ const DirContainer* oldDir = nullptr;
+ const Zstring* oldDirName = nullptr;
if (oldParentDir) //no data is also a "synchronous state"!
{
auto iter = oldParentDir->dirs.find(dirMap.getObjShortName());
@@ -343,7 +372,7 @@ private:
{
if (!dirMap.isEmpty<side>())
{
- writeNumberC<bool>(true); //mark beginning of entry
+ writePOD<bool>(true); //mark beginning of entry
writeStringUtf8(dirMap.getShortName<side>()); //save respecting case! (Windows)
recurse(dirMap, oldDir);
}
@@ -352,7 +381,7 @@ private:
{
if (oldDir)
{
- writeNumberC<bool>(true); //mark beginning of entry
+ writePOD<bool>(true); //mark beginning of entry
writeStringUtf8(*oldDirName); //save respecting case! (Windows)
recurse(dirMap, oldDir);
return;
@@ -372,7 +401,7 @@ private:
assert(false);
break;
case DIR_DIFFERENT_METADATA:
- writeNumberC<bool>(true);
+ writePOD<bool>(true);
writeStringUtf8(dirMap.getShortName<side>());
//ATTENTION: strictly this is a violation of the principle of reporting last synchronous state!
//however in this case this will result in "last sync unsuccessful" for this directory within <automatic> algorithm, which is fine
@@ -396,30 +425,23 @@ std::pair<DirInfoPtr, DirInfoPtr> zen::loadFromDisk(const BaseDirMapping& baseMa
const StreamMapping streamListRight = ::loadStreams(fileNameRight); //throw FileError
//find associated session: there can be at most one session within intersection of left and right ids
- StreamMapping::const_iterator streamLeft = streamListLeft .end();
- StreamMapping::const_iterator streamRight = streamListRight.end();
for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft)
{
auto iterRight = streamListRight.find(iterLeft->first);
if (iterRight != streamListRight.end())
{
- streamLeft = iterLeft;
- streamRight = iterRight;
- break;
+ //read streams into DirInfo
+ DirInfoPtr dirInfoLeft = StreamParser::execute(iterLeft ->second, fileNameLeft); //throw FileError
+ DirInfoPtr dirInfoRight = StreamParser::execute(iterRight->second, fileNameRight); //throw FileError
+
+ return std::make_pair(dirInfoLeft, dirInfoRight);
}
}
- if (streamLeft == streamListLeft .end() ||
- streamRight == streamListRight.end())
- throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" +
- _("Database files do not share a common synchronization session:") + L" \n" +
- L"\"" + fileNameLeft + L"\"\n" +
- L"\"" + fileNameRight + L"\"");
- //read streams into DirInfo
- DirInfoPtr dirInfoLeft = StreamParser::execute(streamLeft ->second, fileNameLeft); //throw FileError
- DirInfoPtr dirInfoRight = StreamParser::execute(streamRight->second, fileNameRight); //throw FileError
-
- return std::make_pair(dirInfoLeft, dirInfoRight);
+ throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" +
+ _("Database files do not share a common synchronization session:") + L" \n" +
+ L"\"" + fileNameLeft + L"\"\n" +
+ L"\"" + fileNameRight + L"\"");
}
@@ -440,75 +462,65 @@ void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError
StreamMapping streamListLeft;
StreamMapping streamListRight;
- try //read file data: list of session ID + DirInfo-stream
- {
- streamListLeft = ::loadStreams(dbNameLeft);
- }
- catch (FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- try
- {
- streamListRight = ::loadStreams(dbNameRight);
- }
+ //read file data: list of session ID + DirInfo-stream
+ try { streamListLeft = ::loadStreams(dbNameLeft ); }
catch (FileError&) {}
+ try { streamListRight = ::loadStreams(dbNameRight); }
+ catch (FileError&) {}
+ //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
//find associated session: there can be at most one session within intersection of left and right ids
- StreamMapping::iterator streamLeft = streamListLeft .end();
- StreamMapping::iterator streamRight = streamListRight.end();
+ auto streamLeftOld = streamListLeft .cend();
+ auto streamRightOld = streamListRight.cend();
for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft)
{
auto iterRight = streamListRight.find(iterLeft->first);
if (iterRight != streamListRight.end())
{
- streamLeft = iterLeft;
- streamRight = iterRight;
+ streamLeftOld = iterLeft;
+ streamRightOld = iterRight;
break;
}
}
//(try to) read old DirInfo
- DirInfoPtr oldDirInfoLeft;
- DirInfoPtr oldDirInfoRight;
- try
- {
- if (streamLeft != streamListLeft .end() &&
- streamRight != streamListRight.end())
+ DirInfoPtr dirInfoLeftOld;
+ DirInfoPtr dirInfoRightOld;
+ if (streamLeftOld != streamListLeft .end() &&
+ streamRightOld != streamListRight.end())
+ try
{
- oldDirInfoLeft = StreamParser::execute(streamLeft ->second, dbNameLeft ); //throw FileError
- oldDirInfoRight = StreamParser::execute(streamRight->second, dbNameRight); //throw FileError
+ dirInfoLeftOld = StreamParser::execute(streamLeftOld ->second, dbNameLeft ); //throw FileError
+ dirInfoRightOld = StreamParser::execute(streamRightOld->second, dbNameRight); //throw FileError
+ }
+ catch (FileError&)
+ {
+ //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
+ dirInfoLeftOld .reset(); //read both or none!
+ dirInfoRightOld.reset(); //
}
- }
- catch (FileError&)
- {
- //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- oldDirInfoLeft .reset(); //read both or none!
- oldDirInfoRight.reset(); //
- }
//create new database entries
- MemoryStream newStreamLeft = StreamGenerator<LEFT_SIDE >::execute(baseMapping, oldDirInfoLeft .get() ? &oldDirInfoLeft ->baseDirContainer : NULL, dbNameLeft);
- MemoryStream newStreamRight = StreamGenerator<RIGHT_SIDE>::execute(baseMapping, oldDirInfoRight.get() ? &oldDirInfoRight->baseDirContainer : NULL, dbNameRight);
+ MemoryStream rawStreamLeftNew = StreamGenerator<LEFT_SIDE >::execute(baseMapping, dirInfoLeftOld .get() ? &dirInfoLeftOld ->baseDirContainer : nullptr, dbNameLeft);
+ MemoryStream rawStreamRightNew = StreamGenerator<RIGHT_SIDE>::execute(baseMapping, dirInfoRightOld.get() ? &dirInfoRightOld->baseDirContainer : nullptr, dbNameRight);
//check if there is some work to do at all
- {
- const bool updateRequiredLeft = streamLeft == streamListLeft .end() || newStreamLeft != streamLeft ->second;
- const bool updateRequiredRight = streamRight == streamListRight.end() || newStreamRight != streamRight->second;
- //some users monitor the *.ffs_db file with RTS => don't touch the file if it isnt't strictly needed
- if (!updateRequiredLeft && !updateRequiredRight)
- return;
- }
-
- //create/update DirInfo-streams
- std::string sessionID = zen::generateGUID();
+ if (streamLeftOld != streamListLeft .end() && rawStreamLeftNew == streamLeftOld ->second &&
+ streamRightOld != streamListRight.end() && rawStreamRightNew == streamRightOld->second)
+ return; //some users monitor the *.ffs_db file with RTS => don't touch the file if it isnt't strictly needed
//erase old session data
- if (streamLeft != streamListLeft.end())
- streamListLeft.erase(streamLeft);
- if (streamRight != streamListRight.end())
- streamListRight.erase(streamRight);
+ if (streamLeftOld != streamListLeft.end())
+ streamListLeft.erase(streamLeftOld);
+ if (streamRightOld != streamListRight.end())
+ streamListRight.erase(streamRightOld);
+
+ //create/update DirInfo-streams
+ const std::string sessionID = zen::generateGUID();
//fill in new
- streamListLeft .insert(std::make_pair(sessionID, newStreamLeft));
- streamListRight.insert(std::make_pair(sessionID, newStreamRight));
+ streamListLeft .insert(std::make_pair(sessionID, rawStreamLeftNew));
+ streamListRight.insert(std::make_pair(sessionID, rawStreamRightNew));
//write (temp-) files...
zen::ScopeGuard guardTempFileLeft = zen::makeGuard([&] {zen::removeFile(dbNameLeftTmp); });
diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp
index 88fb19b3..87864ce4 100644
--- a/lib/dir_lock.cpp
+++ b/lib/dir_lock.cpp
@@ -28,7 +28,6 @@
#elif defined FFS_LINUX
#include <sys/stat.h>
-#include <cerrno>
#include <unistd.h>
#endif
@@ -76,24 +75,24 @@ public:
const char buffer[1] = {' '};
#ifdef FFS_WIN
- //ATTENTION: setting file pointer IS required! => use CreateFile/FILE_GENERIC_WRITE + SetFilePointerEx!
+ //ATTENTION: setting file pointer IS required! => use CreateFile/GENERIC_WRITE + SetFilePointerEx!
//although CreateFile/FILE_APPEND_DATA without SetFilePointerEx works locally, it MAY NOT work on some network shares creating a 4 gig file!!!
const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename_).c_str(),
GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp
FILE_SHARE_READ,
- NULL,
+ nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
- NULL);
+ nullptr);
if (fileHandle == INVALID_HANDLE_VALUE)
return;
- ZEN_ON_BLOCK_EXIT(::CloseHandle(fileHandle));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(fileHandle));
const LARGE_INTEGER moveDist = {};
if (!::SetFilePointerEx(fileHandle, //__in HANDLE hFile,
moveDist, //__in LARGE_INTEGER liDistanceToMove,
- NULL, //__out_opt PLARGE_INTEGER lpNewFilePointer,
+ nullptr, //__out_opt PLARGE_INTEGER lpNewFilePointer,
FILE_END)) //__in DWORD dwMoveMethod
return;
@@ -102,13 +101,13 @@ public:
buffer, //__out LPVOID lpBuffer,
1, //__in DWORD nNumberOfBytesToRead,
&bytesWritten, //__out_opt LPDWORD lpNumberOfBytesWritten,
- NULL); //__inout_opt LPOVERLAPPED lpOverlapped
+ nullptr); //__inout_opt LPOVERLAPPED lpOverlapped
#elif defined FFS_LINUX
- const int fileHandle = ::open(lockfilename_.c_str(), O_WRONLY | O_APPEND); //O_EXCL contains a race condition on NFS file systems: http://linux.die.net/man/2/open
+ const int fileHandle = ::open(lockfilename_.c_str(), O_WRONLY | O_APPEND);
if (fileHandle == -1)
return;
- ZEN_ON_BLOCK_EXIT(::close(fileHandle));
+ ZEN_ON_SCOPE_EXIT(::close(fileHandle));
const ssize_t bytesWritten = ::write(fileHandle, buffer, 1);
(void)bytesWritten;
@@ -127,41 +126,25 @@ UInt64 getLockFileSize(const Zstring& filename) //throw FileError, ErrorNotExist
#ifdef FFS_WIN
WIN32_FIND_DATA fileInfo = {};
const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo);
- if (searchHandle == INVALID_HANDLE_VALUE)
+ if (searchHandle != INVALID_HANDLE_VALUE)
{
- const DWORD lastError = ::GetLastError();
-
- std::wstring errorMessage = _("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted(lastError);
-
- if (lastError == ERROR_FILE_NOT_FOUND ||
- lastError == ERROR_PATH_NOT_FOUND ||
- lastError == ERROR_BAD_NETPATH ||
- lastError == ERROR_NETNAME_DELETED)
- throw ErrorNotExisting(errorMessage);
- else
- throw FileError(errorMessage);
+ ::FindClose(searchHandle);
+ return zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh);
}
- ::FindClose(searchHandle);
-
- return zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh);
-
#elif defined FFS_LINUX
struct ::stat fileInfo = {};
- if (::stat(filename.c_str(), &fileInfo) != 0) //follow symbolic links
- {
- const int lastError = errno;
-
- std::wstring errorMessage = _("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted(lastError);
+ if (::stat(filename.c_str(), &fileInfo) == 0) //follow symbolic links
+ return zen::UInt64(fileInfo.st_size);
+#endif
- if (lastError == ENOENT)
- throw ErrorNotExisting(errorMessage);
- else
- throw FileError(errorMessage);
- }
+ const ErrorCode lastError = getLastError();
+ const std::wstring errorMessage = _("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted(lastError);
- return zen::UInt64(fileInfo.st_size);
-#endif
+ if (errorCodeForNotExisting(lastError))
+ throw ErrorNotExisting(errorMessage);
+ else
+ throw FileError(errorMessage);
}
@@ -177,29 +160,6 @@ Zstring deleteAbandonedLockName(const Zstring& lockfilename) //make sure to NOT
namespace
{
-//read string from file stream
-inline
-std::string readString(wxInputStream& stream) //throw std::exception
-{
- const auto strLength = readPOD<std::uint32_t>(stream);
- std::string output;
- if (strLength > 0)
- {
- output.resize(strLength); //throw std::bad_alloc
- stream.Read(&output[0], strLength);
- }
- return output;
-}
-
-
-inline
-void writeString(wxOutputStream& stream, const std::string& str) //write string to filestream
-{
- writePOD(stream, static_cast<std::uint32_t>(str.length()));
- stream.Write(str.c_str(), str.length());
-}
-
-
std::string getComputerId() //returns empty string on error
{
const wxString fhn = ::wxGetFullHostName();
@@ -234,9 +194,9 @@ struct LockInformation
//some format checking here?
- lockId = readString(stream);
+ lockId = readString<std::string>(stream);
procDescr.processId = static_cast<ProcessId>(readPOD<std::uint64_t>(stream)); //possible loss of precision (32/64 bit process) covered by buildId
- procDescr.computerId = readString(stream);
+ procDescr.computerId = readString<std::string>(stream);
}
void toStream(wxOutputStream& stream) const //write
@@ -282,7 +242,7 @@ ProcessStatus getProcessStatus(const LockInformation::ProcessDescription& procDe
return PROC_STATUS_NO_IDEA; //lock owned by different computer
#ifdef FFS_WIN
- if (procDescr.processId == ::GetCurrentProcessId()) //may seem obscure, but it's possible: a lock file is "stolen" and put back while the program is running
+ if (procDescr.processId == ::GetCurrentProcessId()) //may seem obscure, but it's possible: deletion failed or a lock file is "stolen" and put back while the program is running
return PROC_STATUS_ITS_US;
//note: ::OpenProcess() is no option as it may successfully return for crashed processes!
@@ -291,7 +251,7 @@ ProcessStatus getProcessStatus(const LockInformation::ProcessDescription& procDe
0); //__in DWORD th32ProcessID
if (snapshot == INVALID_HANDLE_VALUE)
return PROC_STATUS_NO_IDEA;
- ZEN_ON_BLOCK_EXIT(::CloseHandle(snapshot));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(snapshot));
PROCESSENTRY32 processEntry = {};
processEntry.dwSize = sizeof(processEntry);
@@ -315,7 +275,7 @@ ProcessStatus getProcessStatus(const LockInformation::ProcessDescription& procDe
if (procDescr.processId <= 0 || procDescr.processId >= 65536)
return PROC_STATUS_NO_IDEA; //invalid process id
- return zen::dirExists(Zstr("/proc/") + zen::toString<Zstring>(procDescr.processId)) ? PROC_STATUS_RUNNING : PROC_STATUS_NOT_RUNNING;
+ return zen::dirExists(Zstr("/proc/") + zen::numberTo<Zstring>(procDescr.processId)) ? PROC_STATUS_RUNNING : PROC_STATUS_NOT_RUNNING;
#endif
}
@@ -374,9 +334,8 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr
const zen::UInt64 fileSizeNew = ::getLockFileSize(lockfilename); //throw FileError, ErrorNotExisting
wxLongLong currentTime = wxGetLocalTimeMillis();
- if (fileSizeNew != fileSizeOld)
+ if (fileSizeNew != fileSizeOld) //received life sign from lock
{
- //received life sign from lock
fileSizeOld = fileSizeNew;
lockSilentStart = currentTime;
}
@@ -413,7 +372,7 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr
long remainingSeconds = ((DETECT_EXITUS_INTERVAL - (wxGetLocalTimeMillis() - lockSilentStart)) / 1000).ToLong();
remainingSeconds = std::max(0L, remainingSeconds);
- const std::wstring remSecMsg = replaceCpy(_P("1 sec", "%x sec", remainingSeconds), L"%x", toString<std::wstring>(remainingSeconds));
+ const std::wstring remSecMsg = replaceCpy(_P("1 sec", "%x sec", remainingSeconds), L"%x", numberTo<std::wstring>(remainingSeconds));
callback->reportInfo(infoMsg + L" " + remSecMsg);
}
@@ -446,10 +405,10 @@ bool tryLock(const Zstring& lockfilename) //throw FileError
const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename).c_str(),
GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
+ nullptr,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
- NULL);
+ nullptr);
if (fileHandle == INVALID_HANDLE_VALUE)
{
if (::GetLastError() == ERROR_FILE_EXISTS)
@@ -473,7 +432,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError
::close(fileHandle);
#endif
- ScopeGuard guardLockFile = zen::makeGuard([&] { zen::removeFile(lockfilename); });
+ ScopeGuard guardLockFile = zen::makeGuard([&] { removeFile(lockfilename); });
//write UUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks, etc.)
writeLockInfo(lockfilename); //throw FileError
@@ -487,7 +446,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError
class DirLock::SharedDirLock
{
public:
- SharedDirLock(const Zstring& lockfilename, DirLockCallback* callback = NULL) : //throw FileError
+ SharedDirLock(const Zstring& lockfilename, DirLockCallback* callback = nullptr) : //throw FileError
lockfilename_(lockfilename)
{
while (!::tryLock(lockfilename)) //throw FileError
@@ -530,17 +489,14 @@ public:
FileToUuidMap::const_iterator iterUuid = fileToUuid.find(lockfilename);
if (iterUuid != fileToUuid.end())
{
- const std::shared_ptr<SharedDirLock>& activeLock = findActive(iterUuid->second); //returns null-lock if not found
- if (activeLock)
+ if (const std::shared_ptr<SharedDirLock>& activeLock = findActive(iterUuid->second)) //returns null-lock if not found
return activeLock; //SharedDirLock is still active -> enlarge circle of shared ownership
}
try //actual check based on lock UUID, deadlock prevention: "lockfilename" may be an alternative name for an already active lock
{
const std::string lockId = retrieveLockId(lockfilename); //throw FileError, ErrorNotExisting
-
- const std::shared_ptr<SharedDirLock>& activeLock = findActive(lockId); //returns null-lock if not found
- if (activeLock)
+ if (const std::shared_ptr<SharedDirLock>& activeLock = findActive(lockId)) //returns null-lock if not found
{
fileToUuid[lockfilename] = lockId; //perf-optimization: update relation
return activeLock;
@@ -549,8 +505,8 @@ public:
catch (FileError&) {} //catch everything, let SharedDirLock constructor deal with errors, e.g. 0-sized/corrupted lock file
//not yet in buffer, so create a new directory lock
- std::shared_ptr<SharedDirLock> newLock(new SharedDirLock(lockfilename, callback)); //throw FileError
- const std::string newLockId = retrieveLockId(lockfilename); //throw FileError, ErrorNotExisting
+ auto newLock = std::make_shared<SharedDirLock>(lockfilename, callback); //throw FileError
+ const std::string& newLockId = retrieveLockId(lockfilename); //throw FileError, ErrorNotExisting
//update registry
fileToUuid[lockfilename] = newLockId; //throw()
@@ -564,16 +520,14 @@ private:
std::shared_ptr<SharedDirLock> findActive(const std::string& lockId) //returns null-lock if not found
{
- UuidToLockMap::const_iterator iterLock = uuidToLock.find(lockId);
+ auto iterLock = uuidToLock.find(lockId);
return iterLock != uuidToLock.end() ?
iterLock->second.lock() : nullptr; //try to get shared_ptr; throw()
}
- typedef std::weak_ptr<SharedDirLock> SharedLock;
-
typedef std::string UniqueId;
- typedef std::map<Zstring, UniqueId, LessFilename> FileToUuidMap; //n:1 handle uppper/lower case correctly
- typedef std::map<UniqueId, SharedLock> UuidToLockMap; //1:1
+ typedef std::map<Zstring, UniqueId, LessFilename> FileToUuidMap; //n:1 handle uppper/lower case correctly
+ typedef std::map<UniqueId, std::weak_ptr<SharedDirLock>> UuidToLockMap; //1:1
FileToUuidMap fileToUuid; //lockname |-> UUID; locks can be referenced by a lockfilename or alternatively a UUID
UuidToLockMap uuidToLock; //UUID |-> "shared lock ownership"
@@ -583,7 +537,7 @@ private:
DirLock::DirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw FileError
{
#ifdef FFS_WIN
- const DWORD bufferSize = std::max(lockfilename.size(), static_cast<size_t>(10000));
+ const DWORD bufferSize = 10000;
std::vector<wchar_t> volName(bufferSize);
if (::GetVolumePathName(lockfilename.c_str(), //__in LPCTSTR lpszFileName,
&volName[0], //__out LPTSTR lpszVolumePathName,
diff --git a/lib/dir_lock.h b/lib/dir_lock.h
index 9938d554..3e9f2a79 100644
--- a/lib/dir_lock.h
+++ b/lib/dir_lock.h
@@ -25,11 +25,12 @@ RAII structure to place a directory lock against other FFS processes:
- detects and resolves abandoned locks (instantly if lock is associated with local pc, else after 30 seconds)
- temporary locks created during abandoned lock resolution keep "lockfilename"'s extension
- race-free (Windows, almost on Linux(NFS))
+ - currently NOT thread-safe! (static LockAdmin)
*/
class DirLock
{
public:
- DirLock(const Zstring& lockfilename, DirLockCallback* callback = NULL); //throw FileError, callback only used during construction
+ DirLock(const Zstring& lockfilename, DirLockCallback* callback = nullptr); //throw FileError, callback only used during construction
private:
class LockAdmin;
diff --git a/lib/error_log.cpp b/lib/error_log.cpp
deleted file mode 100644
index a71e72e1..00000000
--- a/lib/error_log.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#include "error_log.h"
-#include <zen/time.h>
-#include <zen/i18n.h>
-#include <algorithm>
-
-using namespace zen;
-
-
-void ErrorLogging::logMsg(const wxString& message, zen::MessageType type)
-{
- Entry newEntry;
- newEntry.type = type;
- newEntry.time = std::time(NULL);
- newEntry.message = message;
-
- messages.push_back(newEntry);
-
- ++statistics[type];
-}
-
-
-int ErrorLogging::typeCount(int typeFilter) const
-{
- int count = 0;
-
- if (typeFilter & TYPE_INFO)
- count += statistics[TYPE_INFO];
- if (typeFilter & TYPE_WARNING)
- count += statistics[TYPE_WARNING];
- if (typeFilter & TYPE_ERROR)
- count += statistics[TYPE_ERROR];
- if (typeFilter & TYPE_FATAL_ERROR)
- count += statistics[TYPE_FATAL_ERROR];
-
- return count;
-}
-
-
-std::vector<wxString> ErrorLogging::getFormattedMessages(int typeFilter) const
-{
- std::vector<wxString> output;
-
- std::for_each(messages.begin(), messages.end(),
- [&](const Entry& entry)
- {
- if (entry.type & typeFilter)
- output.push_back(formatMessage(entry));
- });
-
- return output;
-}
-
-
-wxString ErrorLogging::formatMessage(const Entry& msg)
-{
- wxString typeName;
- switch (msg.type)
- {
- case TYPE_INFO:
- typeName = _("Info");
- break;
- case TYPE_WARNING:
- typeName = _("Warning");
- break;
- case TYPE_ERROR:
- typeName = _("Error");
- break;
- case TYPE_FATAL_ERROR:
- typeName = _("Fatal Error");
- break;
- }
-
- const wxString prefix = L"[" + formatTime<wxString>(FORMAT_TIME, localTime(msg.time)) + L"] " + typeName + L": ";
-
- wxString formattedText = prefix;
- for (auto iter = msg.message.begin(); iter != msg.message.end(); )
- if (*iter == L'\n')
- {
- formattedText += L'\n';
-
- wxString blanks;
- blanks.resize(prefix.size(), L' ');
- formattedText += blanks;
-
- do //remove duplicate newlines
- {
- ++iter;
- }
- while (iter != msg.message.end() && *iter == L'\n');
- }
- else
- formattedText += *iter++;
-
- return formattedText;
-}
diff --git a/lib/error_log.h b/lib/error_log.h
deleted file mode 100644
index 62aac70f..00000000
--- a/lib/error_log.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef ERRORLOGGING_H_INCLUDED
-#define ERRORLOGGING_H_INCLUDED
-
-#include <map>
-#include <vector>
-#include <wx/string.h>
-
-namespace zen
-{
-enum MessageType
-{
- TYPE_INFO = 1,
- TYPE_WARNING = 2,
- TYPE_ERROR = 4,
- TYPE_FATAL_ERROR = 8,
-};
-
-class ErrorLogging
-{
-public:
- void logMsg(const wxString& message, MessageType type);
-
- int typeCount(int typeFilter = TYPE_INFO | TYPE_WARNING | TYPE_ERROR | TYPE_FATAL_ERROR) const;
-
- std::vector<wxString> getFormattedMessages(int typeFilter = TYPE_INFO | TYPE_WARNING | TYPE_ERROR | TYPE_FATAL_ERROR) const;
-
-private:
- struct Entry
- {
- MessageType type;
- time_t time;
- wxString message;
- };
-
- static wxString formatMessage(const Entry& msg);
-
- std::vector<Entry> messages; //list of non-resolved errors and warnings
-
- mutable std::map<MessageType, int> statistics;
-};
-}
-
-#endif // ERRORLOGGING_H_INCLUDED
diff --git a/lib/hard_filter.cpp b/lib/hard_filter.cpp
index fcef6a9f..603d27b0 100644
--- a/lib/hard_filter.cpp
+++ b/lib/hard_filter.cpp
@@ -57,8 +57,17 @@ HardFilter::FilterRef HardFilter::loadFilter(wxInputStream& stream)
}
-//--------------------------------------------------------------------------------------------------
-void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, std::set<Zstring>& directoryFilter)
+namespace
+{
+//constructing them in addFilterEntry becomes perf issue for large filter lists
+const Zstring asterisk(Zstr('*'));
+const Zstring sepAsterisk = FILE_NAME_SEPARATOR + asterisk;
+const Zstring asteriskSep = asterisk + FILE_NAME_SEPARATOR;
+const Zstring asteriskSepAsterisk = asteriskSep + asterisk;
+}
+
+
+void addFilterEntry(const Zstring& filtername, std::vector<Zstring>& fileFilter, std::vector<Zstring>& directoryFilter)
{
Zstring filterFormatted = filtername;
@@ -68,70 +77,73 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st
#elif defined FFS_LINUX
//Linux DOES distinguish between upper/lower-case: nothing to do here
#endif
+ if (startsWith(filterFormatted, FILE_NAME_SEPARATOR)) // \abc
+ filterFormatted = afterFirst(filterFormatted, FILE_NAME_SEPARATOR); //leading separator is optional!
- const Zstring sepAsterisk = Zstring(FILE_NAME_SEPARATOR) + Zchar('*');
- const Zstring sepQuestionMark = Zstring(FILE_NAME_SEPARATOR) + Zchar('?');
- const Zstring asteriskSep = Zstring(Zstr('*')) + FILE_NAME_SEPARATOR;
- const Zstring questionMarkSep = Zstring(Zstr('?')) + FILE_NAME_SEPARATOR;
-
- //--------------------------------------------------------------------------------------------------
- //add some syntactic sugar: handle beginning of filtername
- if (startsWith(filterFormatted, FILE_NAME_SEPARATOR))
+ //some syntactic sugar:
+ if (filterFormatted == asteriskSepAsterisk) // *\* := match everything except files directly in base directory
{
- //remove leading separators (keep BEFORE test for Zstring::empty()!)
- filterFormatted = afterFirst(filterFormatted, FILE_NAME_SEPARATOR);
+ fileFilter. push_back(filterFormatted);
+ directoryFilter.push_back(asterisk);
+ return;
}
- else if (startsWith(filterFormatted, asteriskSep) || // *\abc
- startsWith(filterFormatted, questionMarkSep)) // ?\abc
+ //more syntactic sugar: handle beginning of filtername
+ else if (startsWith(filterFormatted, asteriskSep)) // *\abc
{
- addFilterEntry(Zstring(filterFormatted.c_str() + 1), fileFilter, directoryFilter); //prevent further recursion by prefix
+ addFilterEntry(filterFormatted.c_str() + 2, fileFilter, directoryFilter); //recursion is finite
}
-
//--------------------------------------------------------------------------------------------------
//even more syntactic sugar: handle end of filtername
if (endsWith(filterFormatted, FILE_NAME_SEPARATOR))
{
const Zstring candidate = beforeLast(filterFormatted, FILE_NAME_SEPARATOR);
if (!candidate.empty())
- directoryFilter.insert(candidate); //only relevant for directory filtering
+ directoryFilter.push_back(candidate); //only relevant for directory filtering
}
- else if (endsWith(filterFormatted, sepAsterisk) || // abc\*
- endsWith(filterFormatted, sepQuestionMark)) // abc\?
+ else if (endsWith(filterFormatted, sepAsterisk)) // abc\*
{
- fileFilter.insert( filterFormatted);
- directoryFilter.insert(filterFormatted);
+ fileFilter .push_back(filterFormatted);
+ directoryFilter.push_back(filterFormatted);
const Zstring candidate = beforeLast(filterFormatted, FILE_NAME_SEPARATOR);
if (!candidate.empty())
- directoryFilter.insert(candidate); //only relevant for directory filtering
+ directoryFilter.push_back(candidate); //only relevant for directory filtering
}
else if (!filterFormatted.empty())
{
- fileFilter. insert(filterFormatted);
- directoryFilter.insert(filterFormatted);
+ fileFilter. push_back(filterFormatted);
+ directoryFilter.push_back(filterFormatted);
}
}
namespace
{
-template <class T> inline
-const T* cStringFind(const T* str1, T ch) //strchr()
+template <class Char> inline
+const Char* cStringFind(const Char* str, Char ch) //strchr()
{
- while (*str1 != ch) //ch is allowed to be 0 by contract! must return end of string in this case
+ for (;;)
{
- if (*str1 == 0)
- return NULL;
- ++str1;
+ const Char s = *str;
+ if (s == ch) //ch is allowed to be 0 by contract! must return end of string in this case
+ return str;
+
+ if (s == 0)
+ return nullptr;
+ ++str;
}
- return str1;
}
+
bool matchesMask(const Zchar* str, const Zchar* mask)
{
- for (Zchar ch; (ch = *mask) != 0; ++mask, ++str)
+ for (;; ++mask, ++str)
{
- switch (ch)
+ Zchar m = *mask;
+ if (m == 0)
+ return *str == 0;
+
+ switch (m)
{
case Zstr('?'):
if (*str == 0)
@@ -139,96 +151,91 @@ bool matchesMask(const Zchar* str, const Zchar* mask)
break;
case Zstr('*'):
- //advance to next non-*/? char
+ //advance mask to next non-* char
do
{
- ++mask;
- ch = *mask;
+ m = *++mask;
}
- while (ch == Zstr('*') || ch == Zstr('?'));
- //if mask ends with '*':
- if (ch == 0)
+ while (m == Zstr('*'));
+
+ if (m == 0) //mask ends with '*':
return true;
+ //*? - pattern
+ if (m == Zstr('?'))
+ {
+ ++mask;
+ while (*str++ != 0)
+ if (matchesMask(str, mask))
+ return true;
+ return false;
+ }
+
+ //*[letter] - pattern
++mask;
- while ((str = cStringFind(str, ch)) != NULL)
+ for (;;)
{
+ str = cStringFind(str, m);
+ if (!str)
+ return false;
+
++str;
if (matchesMask(str, mask))
return true;
}
- return false;
default:
- if (*str != ch)
+ if (*str != m)
return false;
}
}
- return *str == 0;
}
+
//returns true if string matches at least the beginning of mask
inline
bool matchesMaskBegin(const Zchar* str, const Zchar* mask)
{
- for (Zchar ch; (ch = *mask) != 0; ++mask, ++str)
+ for (;; ++mask, ++str)
{
- if (*str == 0)
- return true;
+ const Zchar m = *mask;
+ if (m == 0)
+ return *str == 0;
- switch (ch)
+ switch (m)
{
case Zstr('?'):
+ if (*str == 0)
+ return true;
break;
case Zstr('*'):
return true;
default:
- if (*str != ch)
- return false;
+ if (*str != m)
+ return *str == 0;
}
}
- return *str == 0;
}
}
-class MatchFound : public std::unary_function<Zstring, bool>
-{
-public:
- MatchFound(const Zstring& name) : name_(name) {}
-
- bool operator()(const Zstring& mask) const
- {
- return matchesMask(name_.c_str(), mask.c_str());
- }
-private:
- const Zstring& name_;
-};
-
-
inline
-bool matchesFilter(const Zstring& nameFormatted, const std::set<Zstring>& filter)
+bool matchesFilter(const Zstring& name, const std::vector<Zstring>& filter)
{
- return std::find_if(filter.begin(), filter.end(), MatchFound(nameFormatted)) != filter.end();
+ return std::any_of(filter.begin(), filter.end(), [&](const Zstring& mask) { return matchesMask(name.c_str(), mask.c_str()); });
}
inline
-bool matchesFilterBegin(const Zstring& nameFormatted, const std::set<Zstring>& filter)
+bool matchesFilterBegin(const Zstring& name, const std::vector<Zstring>& filter)
{
- for (std::set<Zstring>::const_iterator i = filter.begin(); i != filter.end(); ++i)
- if (matchesMaskBegin(nameFormatted.c_str(), i->c_str()))
- return true;
- return false;
-
- // return std::find_if(filter.begin(), filter.end(),
- // boost::bind(matchesMaskBegin, nameFormatted.c_str(), _1)) != filter.end();
+ return std::any_of(filter.begin(), filter.end(), [&](const Zstring& mask) { return matchesMaskBegin(name.c_str(), mask.c_str()); });
}
-std::vector<Zstring> compoundStringToFilter(const Zstring& filterString)
+std::vector<Zstring> splitByDelimiter(const Zstring& filterString)
{
//delimiters may be ';' or '\n'
std::vector<Zstring> output;
@@ -256,16 +263,29 @@ NameFilter::NameFilter(const Zstring& includeFilter, const Zstring& excludeFilte
includeFilterTmp(includeFilter), //save constructor arguments for serialization
excludeFilterTmp(excludeFilter)
{
- //no need for regular expressions! In tests wxRegex was by factor of 10 slower than wxString::Matches()!!
+ //no need for regular expressions: In tests wxRegex was by factor of 10 slower than wxString::Matches()
//load filter into vectors of strings
//delimiters may be ';' or '\n'
- const std::vector<Zstring>& includeList = compoundStringToFilter(includeFilter);
- const std::vector<Zstring>& excludeList = compoundStringToFilter(excludeFilter);
+ const std::vector<Zstring>& includeList = splitByDelimiter(includeFilter);
+ const std::vector<Zstring>& excludeList = splitByDelimiter(excludeFilter);
//setup include/exclude filters for files and directories
std::for_each(includeList.begin(), includeList.end(), [&](const Zstring& entry) { addFilterEntry(entry, filterFileIn, filterFolderIn); });
std::for_each(excludeList.begin(), excludeList.end(), [&](const Zstring& entry) { addFilterEntry(entry, filterFileEx, filterFolderEx); });
+
+ auto removeDuplicates = [](std::vector<Zstring>& cont)
+ {
+ std::vector<Zstring> output;
+ std::set<Zstring> used;
+ std::copy_if(cont.begin(), cont.end(), std::back_inserter(output), [&](const Zstring& item) { return used.insert(item).second; });
+ output.swap(cont);
+ };
+
+ removeDuplicates(filterFileIn);
+ removeDuplicates(filterFolderIn);
+ removeDuplicates(filterFileEx);
+ removeDuplicates(filterFolderEx);
}
@@ -278,14 +298,14 @@ bool NameFilter::passFileFilter(const Zstring& relFilename) const
const Zstring& nameFormatted = relFilename; //nothing to do here
#endif
- return matchesFilter(nameFormatted, filterFileIn) && //process include filters
- !matchesFilter(nameFormatted, filterFileEx); //process exclude filters
+ return matchesFilter(nameFormatted, filterFileIn) && //process include filters
+ !matchesFilter(nameFormatted, filterFileEx); //process exclude filters
}
bool NameFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const
{
- assert(subObjMightMatch == NULL || *subObjMightMatch == true); //check correct usage
+ assert(!subObjMightMatch || *subObjMightMatch == true); //check correct usage
#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case
Zstring nameFormatted = relDirname;
@@ -317,6 +337,17 @@ bool NameFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch
}
+bool NameFilter::isNull(const Zstring& includeFilter, const Zstring& excludeFilter)
+{
+ Zstring include = includeFilter;
+ Zstring exclude = excludeFilter;
+ trim(include);
+ trim(exclude);
+
+ return include == Zstr("*") && exclude.empty();
+ //return NameFilter(includeFilter, excludeFilter).isNull(); -> very expensive for huge lists
+}
+
bool NameFilter::isNull() const
{
static NameFilter output(Zstr("*"), Zstring());
diff --git a/lib/hard_filter.h b/lib/hard_filter.h
index 476f5ac1..1a9943a3 100644
--- a/lib/hard_filter.h
+++ b/lib/hard_filter.h
@@ -7,7 +7,7 @@
#ifndef FFS_FILTER_H_INCLUDED
#define FFS_FILTER_H_INCLUDED
-#include <set>
+#include <vector>
#include <memory>
#include <wx/stream.h>
#include <zen/zstring.h>
@@ -88,7 +88,9 @@ public:
virtual bool passFileFilter(const Zstring& relFilename) const;
virtual bool passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const;
+
virtual bool isNull() const;
+ static bool isNull(const Zstring& includeFilter, const Zstring& excludeFilter); //*fast* check without expensively constructing NameFilter instance!
private:
friend class HardFilter;
@@ -97,10 +99,10 @@ private:
static FilterRef load(wxInputStream& stream); //"serial constructor"
virtual bool cmpLessSameType(const HardFilter& other) const;
- std::set<Zstring> filterFileIn; //upper case (windows)
- std::set<Zstring> filterFolderIn; //
- std::set<Zstring> filterFileEx; //
- std::set<Zstring> filterFolderEx; //
+ std::vector<Zstring> filterFileIn; //
+ std::vector<Zstring> filterFolderIn; //upper case (windows) + unique items by construction
+ std::vector<Zstring> filterFileEx; //
+ std::vector<Zstring> filterFolderEx; //
const Zstring includeFilterTmp; //save constructor arguments for serialization
const Zstring excludeFilterTmp; //
@@ -162,7 +164,7 @@ bool NullFilter::passFileFilter(const Zstring& relFilename) const
inline
bool NullFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const
{
- assert(subObjMightMatch == NULL || *subObjMightMatch == true); //check correct usage
+ assert(!subObjMightMatch || *subObjMightMatch == true); //check correct usage
return true;
}
diff --git a/lib/icon_buffer.cpp b/lib/icon_buffer.cpp
index 647228e3..e1518d30 100644
--- a/lib/icon_buffer.cpp
+++ b/lib/icon_buffer.cpp
@@ -17,9 +17,7 @@
#include <zen/win_ver.h>
#elif defined FFS_LINUX
-#include <giomm/file.h>
-#include <gtkmm/icontheme.h>
-#include <gtkmm/main.h>
+#include <gtk/gtk.h>
#endif
using namespace zen;
@@ -59,10 +57,10 @@ public:
typedef GdkPixbuf* HandleType;
#endif
- IconHolder(HandleType handle = 0) : handle_(handle) {} //take ownership!
+ explicit IconHolder(HandleType handle = 0) : handle_(handle) {} //take ownership!
//icon holder has value semantics!
- IconHolder(const IconHolder& other) : handle_(other.handle_ == NULL ? NULL :
+ IconHolder(const IconHolder& other) : handle_(other.handle_ == nullptr ? nullptr :
#ifdef FFS_WIN
::CopyIcon(other.handle_)
#elif defined FFS_LINUX
@@ -70,7 +68,7 @@ public:
#endif
) {}
- IconHolder(IconHolder&& other) : handle_(other.handle_) { other.handle_ = NULL; }
+ IconHolder(IconHolder&& other) : handle_(other.handle_) { other.handle_ = nullptr; }
IconHolder& operator=(IconHolder other) //unifying assignment: no need for r-value reference optimization!
{
@@ -80,11 +78,11 @@ public:
~IconHolder()
{
- if (handle_ != NULL)
+ if (handle_ != nullptr)
#ifdef FFS_WIN
::DestroyIcon(handle_);
#elif defined FFS_LINUX
- ::g_object_unref(handle_);
+ ::g_object_unref(handle_); //superseedes "::gdk_pixbuf_unref"!
#endif
}
@@ -92,7 +90,7 @@ public:
wxIcon toWxIcon(int expectedSize) const //copy HandleType, caller needs to take ownership!
{
- if (handle_ == NULL)
+ if (handle_ == nullptr)
return wxNullIcon;
IconHolder clone(*this);
@@ -107,7 +105,7 @@ public:
if (::GetIconInfo(clone.handle_, &icoInfo))
{
::DeleteObject(icoInfo.hbmMask); //nice potential for a GDI leak!
- ZEN_ON_BLOCK_EXIT(::DeleteObject(icoInfo.hbmColor)); //
+ ZEN_ON_SCOPE_EXIT(::DeleteObject(icoInfo.hbmColor)); //
BITMAP bmpInfo = {};
if (::GetObject(icoInfo.hbmColor, //__in HGDIOBJ hgdiobj,
@@ -130,7 +128,7 @@ public:
#elif defined FFS_LINUX //
newIcon.SetPixbuf(clone.handle_); // transfer ownership!!
#endif //
- clone.handle_ = NULL; //
+ clone.handle_ = nullptr; //
return newIcon;
}
@@ -140,7 +138,7 @@ private:
public:
//use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20)
- operator int ConversionToBool::* () const { return handle_ != NULL ? &ConversionToBool::dummy : NULL; }
+ operator int ConversionToBool::* () const { return handle_ != nullptr ? &ConversionToBool::dummy : nullptr; }
};
@@ -210,13 +208,13 @@ IconHolder getIconByAttribute(LPCWSTR pszPath, DWORD dwFileAttributes, IconBuffe
SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);
//no need to IUnknown::Release() imgList!
if (!imgList)
- return NULL;
+ return IconHolder();
boost::call_once(initGetIconByIndexOnce, []() //thread-safe init
{
getIconByIndex = DllFun<thumb::GetIconByIndexFct>(thumb::getDllName(), thumb::getIconByIndexFctName);
});
- return getIconByIndex ? static_cast<HICON>(getIconByIndex(fileInfo.iIcon, getShilIconType(sz))) : NULL;
+ return IconHolder(getIconByIndex ? static_cast<HICON>(getIconByIndex(fileInfo.iIcon, getShilIconType(sz))) : nullptr);
}
@@ -243,19 +241,11 @@ IconHolder getThumbnail(const Zstring& filename, int requestedSize) //return 0 o
{
getThumbnailIcon = DllFun<GetThumbnailFct>(getDllName(), getThumbnailFctName);
});
- return getThumbnailIcon ? static_cast< ::HICON>(getThumbnailIcon(filename.c_str(), requestedSize)) : NULL;
+ return IconHolder(getThumbnailIcon ? static_cast< ::HICON>(getThumbnailIcon(filename.c_str(), requestedSize)) : nullptr);
#elif defined FFS_LINUX
- //call Gtk::Main::init_gtkmm_internals() on application startup!!
- try
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = Gdk::Pixbuf::create_from_file(filename.c_str(), requestedSize, requestedSize);
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
- }
- catch (const Glib::Error&) {}
-
- return IconHolder();
+ GdkPixbuf* pixBuf = gdk_pixbuf_new_from_file_at_size(filename.c_str(), requestedSize, requestedSize, nullptr);
+ return IconHolder(pixBuf); //pass ownership (may be 0)
#endif
}
@@ -276,30 +266,11 @@ IconHolder getGenericFileIcon(IconBuffer::IconSize sz)
#elif defined FFS_LINUX
const int requestedSize = cvrtSize(sz);
- try
- {
- Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
- if (iconTheme)
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf;
- std::find_if(mimeFileIcons, mimeFileIcons + sizeof(mimeFileIcons) / sizeof(mimeFileIcons[0]),
- [&](const char* mimeName) -> bool
- {
- try
- {
- iconPixbuf = iconTheme->load_icon(mimeName, requestedSize, Gtk::ICON_LOOKUP_USE_BUILTIN);
- }
- catch (const Glib::Error&) { return false; }
-
- return iconPixbuf;
- }
- );
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); // transfer ownership!!
- }
- }
- catch (const Glib::Error&) {}
+ if (GtkIconTheme* defaultTheme = gtk_icon_theme_get_default()) //not owned!
+ for (auto iter = std::begin(mimeFileIcons); iter != std::end(mimeFileIcons); ++iter)
+ if (GdkPixbuf* pixBuf = gtk_icon_theme_load_icon(defaultTheme, *iter, requestedSize, GTK_ICON_LOOKUP_USE_BUILTIN, nullptr))
+ return IconHolder(pixBuf); //pass ownership (may be nullptr)
return IconHolder();
#endif
}
@@ -343,44 +314,35 @@ IconHolder getAssociatedIcon(const Zstring& filename, IconBuffer::IconSize sz)
//http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx
if (!imgList)
- return NULL;
+ return IconHolder();
//imgList->Release(); //empiric study: crash on XP if we release this! Seems we do not own it... -> also no GDI leak on Win7 -> okay
//another comment on http://msdn.microsoft.com/en-us/library/bb762179(v=VS.85).aspx describes exact same behavior on Win7/XP
- boost::call_once(initGetIconByIndexOnce, []() //thread-safe init
+ boost::call_once(initGetIconByIndexOnce, [] //thread-safe init
{
getIconByIndex = DllFun<thumb::GetIconByIndexFct>(thumb::getDllName(), thumb::getIconByIndexFctName);
});
- return getIconByIndex ? static_cast<HICON>(getIconByIndex(fileInfo.iIcon, getShilIconType(sz))) : NULL;
+ return IconHolder(getIconByIndex ? static_cast<HICON>(getIconByIndex(fileInfo.iIcon, getShilIconType(sz))) : nullptr);
#elif defined FFS_LINUX
const int requestedSize = cvrtSize(sz);
- //call Gtk::Main::init_gtkmm_internals() on application startup!!
- try
+
+ GFile* file = g_file_new_for_path(filename.c_str()); //never fails
+ ZEN_ON_SCOPE_EXIT(g_object_unref(file);)
+
+ if (GFileInfo* fileInfo = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_ICON, G_FILE_QUERY_INFO_NONE, nullptr, nullptr))
{
- Glib::RefPtr<Gio::File> fileObj = Gio::File::create_for_path(filename.c_str()); //never fails
- Glib::RefPtr<Gio::FileInfo> fileInfo = fileObj->query_info(G_FILE_ATTRIBUTE_STANDARD_ICON);
- if (fileInfo)
- {
- Glib::RefPtr<Gio::Icon> gicon = fileInfo->get_icon();
- if (gicon)
- {
- Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
- if (iconTheme)
+ ZEN_ON_SCOPE_EXIT(g_object_unref(fileInfo);)
+
+ if (GIcon* gicon = g_file_info_get_icon(fileInfo)) //not owned!
+ if (GtkIconTheme* defaultTheme = gtk_icon_theme_get_default()) //not owned!
+ if (GtkIconInfo* iconInfo = gtk_icon_theme_lookup_by_gicon(defaultTheme, gicon, requestedSize, GTK_ICON_LOOKUP_USE_BUILTIN)) //this may fail if icon is not installed on system
{
- Gtk::IconInfo iconInfo = iconTheme->lookup_icon(gicon, requestedSize, Gtk::ICON_LOOKUP_USE_BUILTIN); //this may fail if icon is not installed on system
- if (iconInfo)
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconInfo.load_icon(); //render icon into Pixbuf
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
- }
+ ZEN_ON_SCOPE_EXIT(gtk_icon_info_free(iconInfo);)
+ if (GdkPixbuf* pixBuf = gtk_icon_info_load_icon(iconInfo, nullptr))
+ return IconHolder(pixBuf); //pass ownership (may be nullptr)
}
- }
- }
}
- catch (const Glib::Error&) {}
-
//fallback: icon lookup may fail because some icons are currently not present on system
return ::getGenericFileIcon(sz);
#endif
@@ -450,14 +412,14 @@ typedef std::queue<Zstring> IconDbSequence; //entryName
class Buffer
{
public:
- bool requestFileIcon(const Zstring& fileName, IconHolder* icon = NULL)
+ bool requestFileIcon(const Zstring& fileName, IconHolder* icon = nullptr)
{
boost::lock_guard<boost::mutex> dummy(lockBuffer);
auto iter = iconMappping.find(fileName);
if (iter != iconMappping.end())
{
- if (icon != NULL)
+ if (icon != nullptr)
*icon = iter->second;
return true;
}
@@ -518,8 +480,8 @@ void WorkerThread::operator()() //thread entry
//Prerequisites, see thumbnail.h
//1. Initialize COM
- ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
- ZEN_ON_BLOCK_EXIT(::CoUninitialize());
+ ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+ ZEN_ON_SCOPE_EXIT(::CoUninitialize());
//2. Initialize system image list
typedef BOOL (WINAPI* FileIconInitFun)(BOOL fRestoreCache);
diff --git a/lib/icon_buffer.h b/lib/icon_buffer.h
index 3f77a520..f3a358ef 100644
--- a/lib/icon_buffer.h
+++ b/lib/icon_buffer.h
@@ -32,7 +32,7 @@ public:
int getSize() const; //*maximum* icon size in pixel
- bool requestFileIcon(const Zstring& filename, wxIcon* icon = NULL); //returns false if icon is not in buffer
+ bool requestFileIcon(const Zstring& filename, wxIcon* icon = nullptr); //returns false if icon is not in buffer
void setWorkload(const std::vector<Zstring>& load); //(re-)set new workload of icons to be retrieved;
private:
diff --git a/lib/localization.cpp b/lib/localization.cpp
index e8867129..3c997074 100644
--- a/lib/localization.cpp
+++ b/lib/localization.cpp
@@ -183,7 +183,7 @@ ExistingTranslations::ExistingTranslations()
for (auto i = lngFiles.begin(); i != lngFiles.end(); ++i)
try
{
- std::string stream = loadStream(*i);; //throw XmlFileError
+ std::string stream = loadStream(*i); //throw XmlFileError
try
{
lngfile::TransHeader lngHeader;
@@ -193,8 +193,7 @@ ExistingTranslations::ExistingTranslations()
There is some buggy behavior in wxWidgets which maps "zh_TW" to simplified chinese.
Fortunately locales can be also entered as description. I changed to "Chinese (Traditional)" which works fine.
*/
- const wxLanguageInfo* locInfo = wxLocale::FindLanguageInfo(utf8CvrtTo<wxString>(lngHeader.localeName));
- if (locInfo)
+ if (const wxLanguageInfo* locInfo = wxLocale::FindLanguageInfo(utf8CvrtTo<wxString>(lngHeader.localeName)))
{
ExistingTranslations::Entry newEntry;
newEntry.languageID = locInfo->Language;
diff --git a/lib/norm_filter.h b/lib/norm_filter.h
index a47fd910..dc73bc6b 100644
--- a/lib/norm_filter.h
+++ b/lib/norm_filter.h
@@ -29,7 +29,7 @@ NormalizedFilter normalizeFilters(const FilterConfig& global, const FilterConfig
inline
bool isNullFilter(const FilterConfig& filterCfg)
{
- return NameFilter(filterCfg.includeFilter, filterCfg.excludeFilter).isNull() &&
+ return NameFilter::isNull(filterCfg.includeFilter, filterCfg.excludeFilter) &&
SoftFilter(filterCfg.timeSpan, filterCfg.unitTimeSpan,
filterCfg.sizeMin, filterCfg.unitSizeMin,
filterCfg.sizeMax, filterCfg.unitSizeMax).isNull();
diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp
index 774cbeb7..6c9fd3ee 100644
--- a/lib/parallel_scan.cpp
+++ b/lib/parallel_scan.cpp
@@ -88,22 +88,22 @@ DiskInfo retrieveDiskInfo(const Zstring& pathName)
0,
OPEN_EXISTING,
0,
- NULL);
+ nullptr);
if (hVolume == INVALID_HANDLE_VALUE)
return output;
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hVolume));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hVolume));
std::vector<char> buffer(sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT)); //reserve buffer for at most one disk! call below will then fail if volume spans multiple disks!
DWORD bytesReturned = 0;
if (!::DeviceIoControl(hVolume, // handle to device
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, // dwIoControlCode
- NULL, // lpInBuffer
+ nullptr, // lpInBuffer
0, // nInBufferSize
&buffer[0], // output buffer
static_cast<DWORD>(buffer.size()), // size of output buffer
&bytesReturned, // number of bytes returned
- NULL)) // OVERLAPPED structure
+ nullptr)) // OVERLAPPED structure
return output;
const VOLUME_DISK_EXTENTS& volDisks = *reinterpret_cast<VOLUME_DISK_EXTENTS*>(&buffer[0]);
@@ -254,7 +254,7 @@ public:
if (activeCount >= 2)
{
statusText += L" " + _P("[1 Thread]", "[%x Threads]", activeCount);
- replace(statusText, L"%x", toString<std::wstring>(activeCount));
+ replace(statusText, L"%x", numberTo<std::wstring>(activeCount));
}
statusText += std::wstring(L" \n") + L'\"' + filename + L'\"';
return statusText;
@@ -481,7 +481,7 @@ public:
void operator()() //thread entry
{
acb_->incActiveWorker();
- ZEN_ON_BLOCK_EXIT(acb_->decActiveWorker(););
+ ZEN_ON_SCOPE_EXIT(acb_->decActiveWorker(););
std::for_each(workload_.begin(), workload_.end(),
[&](std::pair<DirectoryKey, DirectoryValue*>& item)
@@ -515,7 +515,7 @@ public:
break;
}
- DstHackCallback* dstCallbackPtr = NULL;
+ DstHackCallback* dstCallbackPtr = nullptr;
#ifdef FFS_WIN
DstHackCallbackImpl dstCallback(*acb_, threadID_);
dstCallbackPtr = &dstCallback;
@@ -546,7 +546,7 @@ void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
std::vector<boost::thread> worker; //note: GCC doesn't allow to construct an array of empty threads since they would be initialized by const boost::thread&
worker.reserve(buckets.size());
- zen::ScopeGuard guardWorker = zen::makeGuard([&]()
+ zen::ScopeGuard guardWorker = zen::makeGuard([&]
{
std::for_each(worker.begin(), worker.end(), [](boost::thread& wt) { wt.interrupt(); }); //interrupt all at once, then join
std::for_each(worker.begin(), worker.end(), [](boost::thread& wt) { wt.join(); });
diff --git a/lib/parse_lng.h b/lib/parse_lng.h
index e876c5a9..07932c3a 100644
--- a/lib/parse_lng.h
+++ b/lib/parse_lng.h
@@ -213,15 +213,6 @@ private:
TokenMap tokens;
};
-struct IsWhiteSpace : public std::unary_function<char, bool>
-{
- bool operator()(char c) const
- {
- const unsigned char usc = c; //caveat 1: std::isspace() takes an int, but expects an unsigned char
- return usc < 128 && //caveat 2: some parts of UTF-8 chars are erroneously seen as whitespace, e.g. the a0 from "\xec\x8b\a0" (MSVC)
- std::isspace(usc) != 0; //[!]
- }
-};
class Scanner
{
@@ -231,7 +222,7 @@ public:
Token nextToken()
{
//skip whitespace
- pos = std::find_if(pos, stream.end(), std::not1(IsWhiteSpace()));
+ pos = std::find_if(pos, stream.end(), [](char c) { return !zen::isWhiteSpace(c); });
if (pos == stream.end())
return Token(Token::TK_END);
@@ -289,7 +280,7 @@ private:
static void normalize(std::string& text)
{
//remmove whitespace from end
- while (!text.empty() && IsWhiteSpace()(*text.rbegin()))
+ while (!text.empty() && zen::isWhiteSpace(*text.rbegin()))
text.resize(text.size() - 1);
//ensure c-style line breaks
diff --git a/lib/parse_plural.h b/lib/parse_plural.h
index 297aaafc..3c5820d0 100644
--- a/lib/parse_plural.h
+++ b/lib/parse_plural.h
@@ -9,6 +9,7 @@
#include <list>
#include <memory>
+#include <functional>
#include <zen/string_base.h>
@@ -185,7 +186,7 @@ private:
Token nextToken()
{
//skip whitespace
- pos = std::find_if(pos, stream.end(), std::not1(std::ptr_fun(std::iswspace)));
+ pos = std::find_if(pos, stream.end(), [](char c) { return !zen::isWhiteSpace(c); });
if (pos == stream.end()) return Token(Token::TK_END);
@@ -196,12 +197,12 @@ private:
return Token(i->second);
}
- Wstring::const_iterator digitEnd = std::find_if(pos, stream.end(), std::not1(std::ptr_fun(std::iswdigit)));
+ Wstring::const_iterator digitEnd = std::find_if(pos, stream.end(), [](char c) { return !zen::isDigit(c); });
int digitCount = digitEnd - pos;
if (digitCount != 0)
{
Token out(Token::TK_NUMBER);
- out.number = zen::toNumber<int>(Wstring(&*pos, digitCount));
+ out.number = zen::stringTo<int>(Wstring(&*pos, digitCount));
pos += digitCount;
return out;
}
@@ -391,8 +392,7 @@ private:
template <class T>
const T& manageObj(const T& obj)
{
- std::shared_ptr<Expression> newEntry(new T(obj));
- dump_.push_back(newEntry);
+ dump_.push_back(std::make_shared<T>(obj));
return static_cast<T&>(*dump_.back());
}
diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp
index 4ee215b9..7fc7b066 100644
--- a/lib/process_xml.cpp
+++ b/lib/process_xml.cpp
@@ -79,15 +79,15 @@ wxString xmlAccess::getGlobalConfigFile()
void xmlAccess::OptionalDialogs::resetDialogs()
{
- warningDependentFolders = true;
- warningMultiFolderWriteAccess = true;
- warningSignificantDifference = true;
- warningNotEnoughDiskSpace = true;
- warningUnresolvedConflicts = true;
- warningSyncDatabase = true;
- warningRecyclerMissing = true;
- popupOnConfigChange = true;
- showSummaryBeforeSync = true;
+ warningDependentFolders = true;
+ warningMultiFolderWriteAccess = true;
+ warningSignificantDifference = true;
+ warningNotEnoughDiskSpace = true;
+ warningUnresolvedConflicts = true;
+ warningSyncDatabase = true;
+ warningRecyclerMissing = true;
+ popupOnConfigChange = true;
+ showSummaryBeforeSync = true;
}
@@ -496,21 +496,21 @@ void writeText(const UnitTime& value, std::string& output)
case UTIME_NONE:
output = "Inactive";
break;
- // case UTIME_LAST_X_HOURS:
- // output = "x-hours";
- // break;
case UTIME_TODAY:
output = "Today";
break;
- case UTIME_THIS_WEEK:
- output = "Week";
- break;
+ //case UTIME_THIS_WEEK:
+ // output = "Week";
+ // break;
case UTIME_THIS_MONTH:
output = "Month";
break;
case UTIME_THIS_YEAR:
output = "Year";
break;
+ case UTIME_LAST_X_DAYS:
+ output = "x-days";
+ break;
}
}
@@ -521,16 +521,16 @@ bool readText(const std::string& input, UnitTime& value)
zen::trim(tmp);
if (tmp == "Inactive")
value = UTIME_NONE;
- // else if (tmp == "x-hours")
- // value = UTIME_LAST_X_HOURS;
else if (tmp == "Today")
value = UTIME_TODAY;
- else if (tmp == "Week")
- value = UTIME_THIS_WEEK;
+ //else if (tmp == "Week")
+ // value = UTIME_THIS_WEEK;
else if (tmp == "Month")
value = UTIME_THIS_MONTH;
else if (tmp == "Year")
value = UTIME_THIS_YEAR;
+ else if (tmp == "x-days")
+ value = UTIME_LAST_X_DAYS;
else
return false;
return true;
@@ -540,13 +540,13 @@ bool readText(const std::string& input, UnitTime& value)
template <> inline
void writeText(const ColumnTypeRim& value, std::string& output)
{
- output = toString<std::string>(value);
+ output = numberTo<std::string>(value);
}
template <> inline
bool readText(const std::string& input, ColumnTypeRim& value)
{
- value = static_cast<ColumnTypeRim>(toNumber<int>(input));
+ value = static_cast<ColumnTypeRim>(stringTo<int>(input));
return true;
}
@@ -554,13 +554,13 @@ bool readText(const std::string& input, ColumnTypeRim& value)
template <> inline
void writeText(const ColumnTypeNavi& value, std::string& output)
{
- output = toString<std::string>(value);
+ output = numberTo<std::string>(value);
}
template <> inline
bool readText(const std::string& input, ColumnTypeNavi& value)
{
- value = static_cast<ColumnTypeNavi>(toNumber<int>(input));
+ value = static_cast<ColumnTypeNavi>(stringTo<int>(input));
return true;
}
@@ -740,8 +740,7 @@ void readConfig(const XmlIn& in, FolderPairEnh& enhPair)
//###########################################################
//alternate comp configuration (optional)
- XmlIn inAltCmp = in["CompareConfig"];
- if (inAltCmp)
+ if (XmlIn inAltCmp = in["CompareConfig"])
{
CompConfig altCmpCfg;
readConfig(inAltCmp, altCmpCfg);
@@ -750,8 +749,7 @@ void readConfig(const XmlIn& in, FolderPairEnh& enhPair)
}
//###########################################################
//alternate sync configuration (optional)
- XmlIn inAltSync = in["SyncConfig"];
- if (inAltSync)
+ if (XmlIn inAltSync = in["SyncConfig"])
{
SyncConfig altSyncCfg;
readConfig(inAltSync, altSyncCfg);
@@ -874,6 +872,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
inWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
+ inWnd["ShowIcons"](config.gui.showIcons);
inWnd["IconSize"](config.gui.iconSize);
//###########################################################
@@ -929,7 +928,7 @@ void readConfig(const Zstring& filename, XmlType type, ConfigType& config)
::readConfig(in, config);
if (in.errorsOccured())
- throw FfsXmlError(_("Error parsing configuration file:") + L"\n\"" + filename + L"\"\n\n" +
+ throw FfsXmlError(_("Configuration loaded partially only:") + L"\n\"" + filename + L"\"\n\n" +
getErrorMessageFormatted(in), FfsXmlError::WARNING);
}
}
@@ -1139,6 +1138,7 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
outWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
+ outWnd["ShowIcons"](config.gui.showIcons);
outWnd["IconSize"](config.gui.iconSize);
//###########################################################
diff --git a/lib/process_xml.h b/lib/process_xml.h
index 5abbfdc9..801deede 100644
--- a/lib/process_xml.h
+++ b/lib/process_xml.h
@@ -161,6 +161,7 @@ struct XmlGlobalSettings
#elif defined FFS_LINUX
textSearchRespectCase(true),
#endif
+ showIcons(true),
iconSize(ICON_SIZE_SMALL),
lastUpdateCheck(0)
{
@@ -209,6 +210,7 @@ struct XmlGlobalSettings
bool useRecyclerForManualDeletion;
bool textSearchRespectCase;
+ bool showIcons;
FileIconSize iconSize;
long lastUpdateCheck; //time of last update check
diff --git a/lib/recycler.cpp b/lib/recycler.cpp
index 11ed77f7..1c743a0c 100644
--- a/lib/recycler.cpp
+++ b/lib/recycler.cpp
@@ -22,8 +22,9 @@
#include "IFileOperation/file_op.h"
#elif defined FFS_LINUX
+#include <zen/scope_guard.h>
#include <sys/stat.h>
-#include <giomm/file.h>
+#include <gio/gio.h>
#endif
using namespace zen;
@@ -52,7 +53,7 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw F
static bool useIFileOperation = false;
static boost::once_flag once = BOOST_ONCE_INIT; //caveat: function scope static initialization is not thread-safe in VS 2010!
- boost::call_once(once, []() { useIFileOperation = vistaOrLater(); });
+ boost::call_once(once, [] { useIFileOperation = vistaOrLater(); });
if (useIFileOperation) //new recycle bin usage: available since Vista
{
@@ -65,8 +66,8 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw F
const DllFun<GetLastErrorFct> getLastError (getDllName(), getLastErrorFctName);
if (!moveToRecycler || !getLastError)
- throw FileError(_("Error moving to Recycle Bin:") + L"\n\"" + fileNames[0] + L"\"" + //report first file only... better than nothing
- L"\n\n" + _("Could not load a required DLL:") + L" \"" + getDllName() + L"\"");
+ throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", std::wstring(L"\"") + fileNames[0] + L"\"") + L"\n\n" + //report first file only... better than nothing
+ replaceCpy(_("Cannot load file %x."), L"%x", std::wstring(L"\"") + getDllName() + L"\""));
//#warning moving long file paths to recycler does not work! clarify!
// std::vector<Zstring> temp;
@@ -76,10 +77,11 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw F
if (!moveToRecycler(&fileNames[0], //array must not be empty
fileNames.size()))
{
- wchar_t errorMessage[2000];
- getLastError(errorMessage, 2000);
- throw FileError(_("Error moving to Recycle Bin:") + L"\n\"" + fileNames[0] + L"\"" + //report first file only... better than nothing
- L"\n\n" + L"(" + errorMessage + L")");
+ std::vector<wchar_t> msgBuffer(2000);
+ getLastError(&msgBuffer[0], msgBuffer.size());
+
+ throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", std::wstring(L"\"") + fileNames[0] + L"\"") + L"\n\n" + //report first file only... better than nothing
+ &msgBuffer[0]);
}
}
else //regular recycle bin usage: available since XP
@@ -95,18 +97,18 @@ void moveToWindowsRecycler(const std::vector<Zstring>& filesToDelete) //throw F
}
SHFILEOPSTRUCT fileOp = {};
- fileOp.hwnd = NULL;
+ fileOp.hwnd = nullptr;
fileOp.wFunc = FO_DELETE;
fileOp.pFrom = filenameDoubleNull.c_str();
- fileOp.pTo = NULL;
+ fileOp.pTo = nullptr;
fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
fileOp.fAnyOperationsAborted = false;
- fileOp.hNameMappings = NULL;
- fileOp.lpszProgressTitle = NULL;
+ fileOp.hNameMappings = nullptr;
+ fileOp.lpszProgressTitle = nullptr;
if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted)
{
- throw FileError(_("Error moving to Recycle Bin:") + L"\n\"" + filenameDoubleNull + L"\""); //report first file only... better than nothing
+ throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", std::wstring(L"\"") + filenameDoubleNull.c_str() + L"\"")); //report first file only... better than nothing
}
}
}
@@ -128,17 +130,20 @@ bool zen::moveToRecycleBin(const Zstring& filename) //throw FileError
::moveToWindowsRecycler(fileNames); //throw FileError
#elif defined FFS_LINUX
- Glib::RefPtr<Gio::File> fileObj = Gio::File::create_for_path(filename.c_str()); //never fails
- try
- {
- if (!fileObj->trash())
- throw FileError(_("Error moving to Recycle Bin:") + L"\n\"" + filename + L"\"" +
- L"\n\n" + L"(unknown error)");
- }
- catch (const Glib::Error& errorObj)
+ GFile* file = g_file_new_for_path(filename.c_str()); //never fails according to docu
+ ZEN_ON_SCOPE_EXIT(g_object_unref(file);)
+
+ GError* error = nullptr;
+ ZEN_ON_SCOPE_EXIT(if (error) g_error_free(error););
+
+ if (!g_file_trash(file, nullptr, &error))
{
+ if (!error)
+ throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", L"\"" + filename + L"\"") + L"\n\n" +
+ L"Unknown error.");
+
//implement same behavior as in Windows: if recycler is not existing, delete permanently
- if (errorObj.code() == G_IO_ERROR_NOT_SUPPORTED)
+ if (error->code == G_IO_ERROR_NOT_SUPPORTED)
{
struct stat fileInfo = {};
if (::lstat(filename.c_str(), &fileInfo) != 0)
@@ -152,11 +157,11 @@ bool zen::moveToRecycleBin(const Zstring& filename) //throw FileError
}
//assemble error message
- const std::wstring errorMessage = L"Glib Error Code " + toString<std::wstring>(errorObj.code()) + /* L", " +
- g_quark_to_string(errorObj.domain()) + */ L": " + utf8CvrtTo<std::wstring>(errorObj.what());
+ const std::wstring errorMessage = L"Glib Error Code " + numberTo<std::wstring>(error->code) + /* L", " +
+ g_quark_to_string(error->domain) + */ L": " + utf8CvrtTo<std::wstring>(error->message);
- throw FileError(_("Error moving to Recycle Bin:") + L"\n\"" + filename + L"\"" +
- L"\n\n" + L"(" + errorMessage + L")");
+ throw FileError(replaceCpy(_("Unable to move %x to the Recycle Bin!"), L"%x", L"\"" + filename + L"\"") + L"\n\n" +
+ errorMessage);
}
#endif
return true;
@@ -166,10 +171,11 @@ bool zen::moveToRecycleBin(const Zstring& filename) //throw FileError
#ifdef FFS_WIN
zen::StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
{
- std::vector<wchar_t> buffer(MAX_PATH + 1);
- if (::GetVolumePathName(applyLongPathPrefix(pathName).c_str(), //__in LPCTSTR lpszFileName,
- &buffer[0], //__out LPTSTR lpszVolumePathName,
- static_cast<DWORD>(buffer.size()))) //__in DWORD cchBufferLength
+ const DWORD bufferSize = MAX_PATH + 1;
+ std::vector<wchar_t> buffer(bufferSize);
+ if (::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName,
+ &buffer[0], //__out LPTSTR lpszVolumePathName,
+ bufferSize)) //__in DWORD cchBufferLength
{
Zstring rootPath = &buffer[0];
if (!endsWith(rootPath, FILE_NAME_SEPARATOR)) //a trailing backslash is required
diff --git a/lib/recycler.h b/lib/recycler.h
index 37b9250e..8eab5b21 100644
--- a/lib/recycler.h
+++ b/lib/recycler.h
@@ -19,12 +19,14 @@ namespace zen
Windows
-------
-Recycler always available: during runtime either SHFileOperation or (since Vista) IFileOperation will be dynamically selected
+Recycler API always available: during runtime either SHFileOperation or IFileOperation (since Vista) will be dynamically selected
Linux
-----
-Compiler flag: `pkg-config --cflags gtkmm-2.4`
-Linker flag: `pkg-config --libs gtkmm-2.4`
+Compiler flags: `pkg-config --cflags gio-2.0`
+Linker flags: `pkg-config --libs gio-2.0`
+
+Already included in package "gtk+-2.0"!
*/
//move a file or folder to Recycle Bin (deletes permanently if recycle is not available)
diff --git a/lib/resolve_path.cpp b/lib/resolve_path.cpp
index 178e70e2..1b241956 100644
--- a/lib/resolve_path.cpp
+++ b/lib/resolve_path.cpp
@@ -30,17 +30,17 @@ namespace
Zstring resolveRelativePath(Zstring relativeName) //note: ::GetFullPathName() is documented not threadsafe!
{
const DWORD bufferSize = 10000;
- std::vector<Zchar> fullPath(bufferSize);
+ std::vector<wchar_t> buffer(bufferSize);
- const DWORD rv = ::GetFullPathName(applyLongPathPrefix(relativeName).c_str(), //__in LPCTSTR lpFileName,
- bufferSize, //__in DWORD nBufferLength,
- &fullPath[0], //__out LPTSTR lpBuffer,
- NULL); //__out LPTSTR *lpFilePart
- if (rv == 0 || rv >= bufferSize) //theoretically, rv can never be == bufferSize
+ const DWORD charsWritten = ::GetFullPathName(applyLongPathPrefix(relativeName).c_str(), //__in LPCTSTR lpFileName,
+ bufferSize, //__in DWORD nBufferLength,
+ &buffer[0], //__out LPTSTR lpBuffer,
+ nullptr); //__out LPTSTR *lpFilePart
+ if (charsWritten == 0 || charsWritten >= bufferSize) //theoretically, charsWritten can never be == bufferSize
//ERROR! Don't do anything
return relativeName;
- return Zstring(&fullPath[0], rv);
+ return Zstring(&buffer[0], charsWritten);
}
#elif defined FFS_LINUX
@@ -52,7 +52,7 @@ Zstring resolveRelativePath(const Zstring& relativeName)
if (!startsWith(relativeName, FILE_NAME_SEPARATOR)) //absolute names are exactly those starting with a '/'
{
std::vector<char> buffer(10000);
- if (::getcwd(&buffer[0], buffer.size()) != NULL)
+ if (::getcwd(&buffer[0], buffer.size()) != nullptr)
{
Zstring workingDir = &buffer[0];
if (!endsWith(workingDir, FILE_NAME_SEPARATOR))
@@ -64,10 +64,10 @@ Zstring resolveRelativePath(const Zstring& relativeName)
return relativeName;
/*
- char* absPath = ::realpath(relativeName.c_str(), NULL);
+ char* absPath = ::realpath(relativeName.c_str(), nullptr);
if (!absPath)
return relativeName; //ERROR! Don't do anything
- ZEN_ON_BLOCK_EXIT(::free(absPath));
+ ZEN_ON_SCOPE_EXIT(::free(absPath));
return Zstring(absPath);
*/
@@ -93,9 +93,9 @@ private:
auto addCsidl = [&](int csidl, const Zstring& paramName)
{
wchar_t buffer[MAX_PATH];
- if (SUCCEEDED(::SHGetFolderPath(NULL, //__in HWND hwndOwner,
+ if (SUCCEEDED(::SHGetFolderPath(nullptr, //__in HWND hwndOwner,
csidl | CSIDL_FLAG_DONT_VERIFY, //__in int nFolder,
- NULL, //__in HANDLE hToken,
+ nullptr, //__in HANDLE hToken,
0 /* == SHGFP_TYPE_CURRENT*/, //__in DWORD dwFlags,
buffer))) //__out LPTSTR pszPath
{
@@ -294,41 +294,44 @@ Zstring volumenNameToPath(const Zstring& volumeName) //return empty string on er
HANDLE hVol = ::FindFirstVolume(&volGuid[0], static_cast<DWORD>(volGuid.size()));
if (hVol != INVALID_HANDLE_VALUE)
{
- ZEN_ON_BLOCK_EXIT(::FindVolumeClose(hVol));
+ ZEN_ON_SCOPE_EXIT(::FindVolumeClose(hVol));
do
{
std::vector<wchar_t> volName(MAX_PATH + 1);
- if (::GetVolumeInformation(&volGuid[0], //__in_opt LPCTSTR lpRootPathName,
- &volName[0], //__out LPTSTR lpVolumeNameBuffer,
+ if (::GetVolumeInformation(&volGuid[0], //__in_opt LPCTSTR lpRootPathName,
+ &volName[0], //__out LPTSTR lpVolumeNameBuffer,
static_cast<DWORD>(volName.size()), //__in DWORD nVolumeNameSize,
- NULL, //__out_opt LPDWORD lpVolumeSerialNumber,
- NULL, //__out_opt LPDWORD lpMaximumComponentLength,
- NULL, //__out_opt LPDWORD lpFileSystemFlags,
- NULL, //__out LPTSTR lpFileSystemNameBuffer,
- 0)) //__in DWORD nFileSystemNameSize
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
+ 0)) //__in DWORD nFileSystemNameSize
{
if (EqualFilename()(volumeName, Zstring(&volName[0])))
{
//GetVolumePathNamesForVolumeName is not available for Windows 2000!
typedef BOOL (WINAPI* GetVolumePathNamesForVolumeNameWFunc)(LPCWSTR lpszVolumeName,
- LPWCH lpszVolumePathNames,
- DWORD cchBufferLength,
+ LPWCH lpszVolumePathNames,
+ DWORD cchBufferLength,
PDWORD lpcchReturnLength);
const SysDllFun<GetVolumePathNamesForVolumeNameWFunc> getVolumePathNamesForVolumeName(L"kernel32.dll", "GetVolumePathNamesForVolumeNameW");
if (getVolumePathNamesForVolumeName)
{
- std::vector<wchar_t> volPath(10000);
-
+ std::vector<wchar_t> buffer(10000);
DWORD returnedLen = 0;
- if (getVolumePathNamesForVolumeName(&volGuid[0], //__in LPCTSTR lpszVolumeName,
- &volPath[0], //__out LPTSTR lpszVolumePathNames,
- static_cast<DWORD>(volPath.size()), //__in DWORD cchBufferLength,
- &returnedLen)) //__out PDWORD lpcchReturnLength
+ if (getVolumePathNamesForVolumeName(&volGuid[0], //__in LPCTSTR lpszVolumeName,
+ &buffer[0], //__out LPTSTR lpszVolumePathNames,
+ static_cast<DWORD>(buffer.size()), //__in DWORD cchBufferLength,
+ &returnedLen)) //__out PDWORD lpcchReturnLength
{
- return &volPath[0]; //return first path name in double-null terminated list!
+ //Attention: in contrast to documentation, this function may write a *single* 0 into
+ //buffer if volGuid does not have any associated volume paths (e.g. a hidden volume)
+ const Zstring volPath(&buffer[0]);
+ if (!volPath.empty())
+ return volPath; //return first path name in double-null terminated list!
}
}
return &volGuid[0]; //GUID looks ugly, but should be working correctly
@@ -364,10 +367,10 @@ Zstring volumePathToName(const Zstring& volumePath) //return empty string on err
if (::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
&volName[0], //__out LPTSTR lpVolumeNameBuffer,
bufferSize, //__in DWORD nVolumeNameSize,
- NULL, //__out_opt LPDWORD lpVolumeSerialNumber,
- NULL, //__out_opt LPDWORD lpMaximumComponentLength,
- NULL, //__out_opt LPDWORD lpFileSystemFlags,
- NULL, //__out LPTSTR lpFileSystemNameBuffer,
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
0)) //__in DWORD nFileSystemNameSize
{
return &volName[0];
@@ -612,8 +615,8 @@ void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteractio
//note: following function call may block heavily if network is not reachable!!!
DWORD rv2 = ::WNetAddConnection2(&trgRes, // __in LPNETRESOURCE lpNetResource,
- NULL, // __in LPCTSTR lpPassword,
- NULL, // __in LPCTSTR lpUsername,
+ nullptr, // __in LPCTSTR lpPassword,
+ nullptr, // __in LPCTSTR lpUsername,
allowUserInteraction ? CONNECT_INTERACTIVE : 0); //__in DWORD dwFlags
if (rv2 == NO_ERROR)
return; //mapping reestablished
@@ -647,8 +650,8 @@ void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteractio
//note: following function call may block heavily if network is not reachable!!!
DWORD rv2 = ::WNetAddConnection2(&trgRes, // __in LPNETRESOURCE lpNetResource,
- NULL, // __in LPCTSTR lpPassword,
- NULL, // __in LPCTSTR lpUsername,
+ nullptr, // __in LPCTSTR lpPassword,
+ nullptr, // __in LPCTSTR lpUsername,
allowUserInteraction ? CONNECT_INTERACTIVE : 0); //__in DWORD dwFlags
if (rv2 == NO_ERROR)
return; //mapping reestablished
@@ -661,7 +664,7 @@ void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteractio
DWORD bufferSize = sizeof(NETRESOURCE) + 20000;
std::vector<char> buffer(bufferSize);
- LPTSTR relPath = NULL;
+ LPTSTR relPath = nullptr;
//note: following function call may block heavily if network is not reachable!!!
const DWORD rv = WNetGetResourceInformation(&nr, // __in LPNETRESOURCE lpNetResource,
@@ -680,8 +683,8 @@ void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteractio
{
//note: following function call may block heavily if network is not reachable!!!
DWORD rv2 = ::WNetAddConnection2(&trgRes, // __in LPNETRESOURCE lpNetResource,
- NULL, // __in LPCTSTR lpPassword,
- NULL, // __in LPCTSTR lpUsername,
+ nullptr, // __in LPCTSTR lpPassword,
+ nullptr, // __in LPCTSTR lpUsername,
allowUserInteraction ? CONNECT_INTERACTIVE : 0); //__in DWORD dwFlags
if (rv2 == NO_ERROR)
return; //mapping reestablished
diff --git a/lib/resolve_path.h b/lib/resolve_path.h
index 2fd5008e..bc74441a 100644
--- a/lib/resolve_path.h
+++ b/lib/resolve_path.h
@@ -12,6 +12,7 @@
namespace zen
{
+//resolve environment variables, relative paths, ect. and append file name separator
Zstring getFormattedDirectoryName(const Zstring& dirString); //throw() - non-blocking! no I/O!
#ifdef FFS_WIN
diff --git a/lib/resources.cpp b/lib/resources.cpp
index e47065e6..f5def2c6 100644
--- a/lib/resources.cpp
+++ b/lib/resources.cpp
@@ -46,18 +46,19 @@ void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation& anim)
GlobalResources::GlobalResources()
{
- wxFFileInputStream input(toWx(zen::getResourceDir()) + wxT("Resources.zip"));
+ wxFFileInputStream input(toWx(zen::getResourceDir()) + L"Resources.zip");
if (input.IsOk()) //if not... we don't want to react too harsh here
{
//activate support for .png files
wxImage::AddHandler(new wxPNGHandler); //ownership passed
- wxZipInputStream resourceFile(input);
+ wxZipInputStream resourceFile(input, wxConvUTF8);
+ //do NOT rely on wxConvLocal! May result in "Cannot convert from the charset 'Unknown encoding (-1)'!"
while (true)
{
std::unique_ptr<wxZipEntry> entry(resourceFile.GetNextEntry()); //take ownership!
- if (entry.get() == NULL)
+ if (entry.get() == nullptr)
break;
const wxString name = entry->GetName();
diff --git a/lib/shadow.cpp b/lib/shadow.cpp
index d00aa2f3..0a34ae5a 100644
--- a/lib/shadow.cpp
+++ b/lib/shadow.cpp
@@ -20,7 +20,6 @@ namespace
{
bool runningWOW64() //test if process is running under WOW64 (reference http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx)
{
- //dynamically load windows API function
typedef BOOL (WINAPI* IsWow64ProcessFun)(HANDLE hProcess, PBOOL Wow64Process);
const SysDllFun<IsWow64ProcessFun> isWow64Process(L"kernel32.dll", "IsWow64Process");
@@ -47,41 +46,36 @@ public:
getShadowVolume (getDllName(), getShadowVolumeFctName),
backupHandle(nullptr)
{
- //check if shadow copy dll was loaded correctly
- if (!createShadowCopy || !releaseShadowCopy || !getShadowVolume)
- throw FileError(_("Error accessing Volume Shadow Copy Service!") + L"\n" +
- _("Could not load a required DLL:") + L" \"" + getDllName() + L"\"");
-
//VSS does not support running under WOW64 except for Windows XP and Windows Server 2003
//(Reference: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx)
if (runningWOW64())
throw FileError(_("Error accessing Volume Shadow Copy Service!") + L"\n" +
_("Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version."));
+
+ //check if shadow copy dll was loaded correctly
+ if (!createShadowCopy || !releaseShadowCopy || !getShadowVolume)
+ throw FileError(_("Error accessing Volume Shadow Copy Service!") + L"\n" +
+ replaceCpy(_("Cannot load file %x."), L"%x", std::wstring(L"\"") + getDllName() + L"\""));
+
//---------------------------------------------------------------------------------------------------------
//start shadow volume copy service:
- wchar_t errorMessage[1000];
+ const unsigned int BUFFER_SIZE = 10000;
+ std::vector<wchar_t> msgBuffer(BUFFER_SIZE);
backupHandle = createShadowCopy(volumeNameFormatted.c_str(),
- errorMessage,
- 1000);
+ &msgBuffer[0], BUFFER_SIZE);
if (!backupHandle)
throw FileError(_("Error accessing Volume Shadow Copy Service!") + L"\n" +
- L"(" + errorMessage + L" Volume: \"" + volumeNameFormatted + L"\")");
+ &msgBuffer[0] + L" Volume: \"" + volumeNameFormatted + L"\"");
- wchar_t shadowVolName[1000];
- getShadowVolume(backupHandle, shadowVolName, 1000);
- shadowVol = Zstring(shadowVolName) + FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash
+ std::vector<wchar_t> volBuffer(BUFFER_SIZE);
+ getShadowVolume(backupHandle, &volBuffer[0], BUFFER_SIZE);
+ shadowVol = Zstring(&volBuffer[0]) + FILE_NAME_SEPARATOR; //shadowVolName NEVER has a trailing backslash
}
- ~ShadowVolume()
- {
- releaseShadowCopy(backupHandle); //fast! no performance optimization necessary
- }
+ ~ShadowVolume() { releaseShadowCopy(backupHandle); } //fast! no performance optimization necessary
- Zstring getShadowVolumeName() const //trailing path separator
- {
- return shadowVol;
- }
+ Zstring getShadowVolumeName() const { return shadowVol; } //with trailing path separator
private:
ShadowVolume(const ShadowVolume&);
@@ -100,14 +94,13 @@ private:
Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile)
{
- wchar_t volumeNameRaw[1000];
-
+ std::vector<wchar_t> volBuffer(1000);
if (!::GetVolumePathName(inputFile.c_str(), //__in LPCTSTR lpszFileName,
- volumeNameRaw, //__out LPTSTR lpszVolumePathName,
- 1000)) //__in DWORD cchBufferLength
- throw FileError(_("Could not determine volume name for file:") + L"\n\"" + inputFile + L"\"");
+ &volBuffer[0], //__out LPTSTR lpszVolumePathName,
+ static_cast<DWORD>(volBuffer.size()))) //__in DWORD cchBufferLength
+ throw FileError(_("Cannot determine volume name for file:") + L"\n\"" + inputFile + L"\"");
- Zstring volumeNameFormatted = volumeNameRaw;
+ Zstring volumeNameFormatted = &volBuffer[0];
if (!endsWith(volumeNameFormatted, FILE_NAME_SEPARATOR))
volumeNameFormatted += FILE_NAME_SEPARATOR;
@@ -115,7 +108,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile)
const size_t pos = inputFile.find(volumeNameFormatted); //inputFile needs NOT to begin with volumeNameFormatted: consider for example \\?\ prefix!
if (pos == Zstring::npos)
{
- std::wstring msg = _("Volume name %x not part of filename %y!");
+ std::wstring msg = _("Volume name %x not part of file name %y!");
replace(msg, L"%x", std::wstring(L"\"") + volumeNameFormatted + L"\"", false);
replace(msg, L"%y", std::wstring(L"\"") + inputFile + L"\"", false);
throw FileError(msg);
@@ -125,7 +118,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile)
VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNameFormatted);
if (iter == shadowVol.end())
{
- std::shared_ptr<ShadowVolume> newEntry(new ShadowVolume(volumeNameFormatted));
+ auto newEntry = std::make_shared<ShadowVolume>(volumeNameFormatted);
iter = shadowVol.insert(std::make_pair(volumeNameFormatted, newEntry)).first;
}
diff --git a/lib/statistics.cpp b/lib/statistics.cpp
index 9914d455..7b3bceae 100644
--- a/lib/statistics.cpp
+++ b/lib/statistics.cpp
@@ -6,14 +6,13 @@
#include "statistics.h"
-#include <wx/ffile.h>
-#include <zen/basic_math.h>
-#include "status_handler.h"
-#include <wx+/format_unit.h>
#include <limits>
+#include <wx/ffile.h>
#include <wx/stopwatch.h>
+#include <zen/basic_math.h>
#include <zen/assert_static.h>
#include <zen/i18n.h>
+#include <wx+/format_unit.h>
using namespace zen;
@@ -29,11 +28,11 @@ RetrieveStatistics::~RetrieveStatistics()
std::for_each(data.begin(), data.end(),
[&](const StatEntry& entry)
{
- outputFile.Write(toString<wxString>(entry.time));
+ outputFile.Write(numberTo<wxString>(entry.time));
outputFile.Write(wxT(";"));
- outputFile.Write(toString<wxString>(entry.objects));
+ outputFile.Write(numberTo<wxString>(entry.objects));
outputFile.Write(wxT(";"));
- outputFile.Write(toString<wxString>(entry.value));
+ outputFile.Write(numberTo<wxString>(entry.value));
outputFile.Write(wxT("\n"));
});
}
diff --git a/lib/status_handler.h b/lib/status_handler.h
index a37d2257..b246e49c 100644
--- a/lib/status_handler.h
+++ b/lib/status_handler.h
@@ -7,6 +7,7 @@
#ifndef STATUSHANDLER_H_INCLUDED
#define STATUSHANDLER_H_INCLUDED
+#include "../process_callback.h"
#include <string>
#include <zen/int64.h>
@@ -19,64 +20,9 @@ void updateUiNow(); //do the updating
Updating GUI is fast!
time per single call to ProcessCallback::forceUiRefresh()
- Comparison 25 µs
- - Synchronization 0.6 ms (despite complex graph!)
+ - Synchronization 0.6 ms (despite complex graph control!)
*/
-//interfaces for status updates (can be implemented by GUI or Batch mode)
-
-
-//report status during comparison and synchronization
-struct ProcessCallback
-{
- virtual ~ProcessCallback() {}
-
- //identifiers of different phases
- enum Process
- {
- PROCESS_NONE = 10,
- PROCESS_SCANNING,
- PROCESS_COMPARING_CONTENT,
- PROCESS_SYNCHRONIZING
- };
-
- //these methods have to be implemented in the derived classes to handle error and status information
- virtual void initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID) = 0; //informs about the total amount of data that will be processed from now on
-
- //note: this one must NOT throw in order to properly allow undoing setting of statistics!
- //it is in general paired with a call to requestUiRefresh() to compensate!
- virtual void updateProcessedData(int objectsDelta, zen::Int64 dataDelta) = 0; //throw()!!
- virtual void updateTotalData (int objectsDelta, zen::Int64 dataDelta) = 0; //
- /*the estimated total may change *during* sync:
- 1. move file -> fallback to copy + delete
- 2. file copy, actual size changed after comparison
- 3. auto-resolution for failed create operations due to missing source
- 4. directory deletion: may contain more items than scanned by FFS: excluded by filter
- 5. delete directory to recycler or move to user-defined dir on same volume: no matter how many sub-elements exist, this is only 1 object to process!
- 6. user-defined deletion directory on different volume: full file copy required (instead of move) */
-
- //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
- virtual void requestUiRefresh() = 0; //throw ?
- virtual void forceUiRefresh () = 0; //throw ? - call before starting long running task which doesn't update regularly
-
- //called periodically after data was processed: expected(!) to request GUI update
- virtual void reportStatus(const std::wstring& text) = 0; //status info only, should not be logged!
-
- //called periodically after data was processed: expected(!) to request GUI update
- virtual void reportInfo(const std::wstring& text) = 0;
-
- virtual void reportWarning(const std::wstring& warningMessage, bool& warningActive) = 0;
-
- //error handling:
- enum Response
- {
- IGNORE_ERROR = 10,
- RETRY
- };
- virtual Response reportError (const std::wstring& errorMessage) = 0; //recoverable error situation
- virtual void reportFatalError(const std::wstring& errorMessage) = 0; //non-recoverable error situation
-};
-
-
//gui may want to abort process
struct AbortCallback
{
@@ -108,6 +54,4 @@ private:
bool abortRequested;
};
-
-
#endif // STATUSHANDLER_H_INCLUDED
diff --git a/lib/status_handler_impl.h b/lib/status_handler_impl.h
new file mode 100644
index 00000000..7141d75c
--- /dev/null
+++ b/lib/status_handler_impl.h
@@ -0,0 +1,34 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef STATUSHANDLER_IMPL_H_INCLUDED
+#define STATUSHANDLER_IMPL_H_INCLUDED
+
+#include <zen/file_error.h>
+#include "status_handler.h"
+
+template <typename Function> inline
+bool tryReportingError(Function cmd, ProcessCallback& handler) //return "true" on success, "false" if error was ignored
+{
+ for (;;)
+ try
+ {
+ cmd(); //throw FileError
+ return true;
+ }
+ catch (zen::FileError& error)
+ {
+ switch (handler.reportError(error.toString())) //may throw!
+ {
+ case ProcessCallback::IGNORE_ERROR:
+ return false;
+ case ProcessCallback::RETRY:
+ break; //continue with loop
+ }
+ }
+}
+
+#endif //STATUSHANDLER_IMPL_H_INCLUDED
diff --git a/lib/xml_base.cpp b/lib/xml_base.cpp
index e6b1e840..10bb698a 100644
--- a/lib/xml_base.cpp
+++ b/lib/xml_base.cpp
@@ -63,13 +63,17 @@ void xmlAccess::loadXmlDocument(const Zstring& filename, XmlDoc& doc) //throw Ff
const std::wstring xmlAccess::getErrorMessageFormatted(const XmlIn& in)
{
- std::wstring errorMessage = _("Could not read values for the following XML nodes:") + L"\n";
+ std::wstring msg;
- std::vector<std::wstring> failedNodes = in.getErrorsAs<std::wstring>();
- std::for_each(failedNodes.begin(), failedNodes.end(),
- [&](const std::wstring& str) { errorMessage += str + L'\n'; });
+ const auto& failedElements = in.getErrorsAs<std::wstring>();
+ if (!failedElements.empty())
+ {
+ msg = _("Cannot read the following XML elements:") + L"\n";
+ std::for_each(failedElements.begin(), failedElements.end(),
+ [&](const std::wstring& str) { msg += str + L'\n'; });
+ }
- return errorMessage;
+ return msg;
}
bgstack15