summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ShadowCopy/Shadow_Server2003.vcxproj2
-rw-r--r--lib/ShadowCopy/Shadow_Windows7.vcxproj2
-rw-r--r--lib/ShadowCopy/Shadow_XP.vcxproj2
-rw-r--r--lib/ShadowCopy/shadow.cpp22
-rw-r--r--lib/Thumbnail/Thumbnail.vcxproj10
-rw-r--r--lib/Thumbnail/thumbnail.cpp35
-rw-r--r--lib/binary.cpp2
-rw-r--r--lib/db_file.cpp260
-rw-r--r--lib/db_file.h59
-rw-r--r--lib/dir_exist_async.h2
-rw-r--r--lib/dir_lock.cpp92
-rw-r--r--lib/ffs_paths.cpp32
-rw-r--r--lib/hard_filter.cpp12
-rw-r--r--lib/help_provider.h8
-rw-r--r--lib/icon_buffer.cpp82
-rw-r--r--lib/localization.cpp84
-rw-r--r--lib/osx_file_icon.h10
-rw-r--r--lib/osx_file_icon.mm32
-rw-r--r--lib/parallel_scan.cpp34
-rw-r--r--lib/parallel_scan.h2
-rw-r--r--lib/parse_lng.h220
-rw-r--r--lib/parse_plural.h2
-rw-r--r--lib/process_xml.cpp18
-rw-r--r--lib/process_xml.h16
-rw-r--r--lib/resolve_path.cpp71
-rw-r--r--lib/resolve_path.h6
-rw-r--r--lib/resources.cpp8
-rw-r--r--lib/resources.h2
-rw-r--r--lib/shadow.cpp14
-rw-r--r--lib/shadow.h1
-rw-r--r--lib/versioning.cpp104
-rw-r--r--lib/versioning.h8
-rw-r--r--lib/xml_base.cpp4
-rw-r--r--lib/xml_base.h4
34 files changed, 660 insertions, 602 deletions
diff --git a/lib/ShadowCopy/Shadow_Server2003.vcxproj b/lib/ShadowCopy/Shadow_Server2003.vcxproj
index 4622c246..520a4d6d 100644
--- a/lib/ShadowCopy/Shadow_Server2003.vcxproj
+++ b/lib/ShadowCopy/Shadow_Server2003.vcxproj
@@ -68,10 +68,8 @@
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
diff --git a/lib/ShadowCopy/Shadow_Windows7.vcxproj b/lib/ShadowCopy/Shadow_Windows7.vcxproj
index c735371b..1fe769d0 100644
--- a/lib/ShadowCopy/Shadow_Windows7.vcxproj
+++ b/lib/ShadowCopy/Shadow_Windows7.vcxproj
@@ -68,10 +68,8 @@
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
diff --git a/lib/ShadowCopy/Shadow_XP.vcxproj b/lib/ShadowCopy/Shadow_XP.vcxproj
index a5d07786..0d231f3d 100644
--- a/lib/ShadowCopy/Shadow_XP.vcxproj
+++ b/lib/ShadowCopy/Shadow_XP.vcxproj
@@ -67,10 +67,8 @@
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
diff --git a/lib/ShadowCopy/shadow.cpp b/lib/ShadowCopy/shadow.cpp
index 4f6881ad..e915663f 100644
--- a/lib/ShadowCopy/shadow.cpp
+++ b/lib/ShadowCopy/shadow.cpp
@@ -75,7 +75,7 @@ std::wstring formatVssError(HRESULT hr) //at least the one's from IVssBackupComp
}
-shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError
+shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw SysError
{
ComPtr<IVssBackupComponents> backupComp;
{
@@ -83,13 +83,13 @@ shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError
if (FAILED(hr))
{
if (hr == E_ACCESSDENIED)
- throw ComError(L"The caller does not have sufficient backup privileges or is not an administrator.", hr);
- throw ComError(L"Error calling \"CreateVssBackupComponents\".", hr);
+ throw SysError(formatComError(L"The caller does not have sufficient backup privileges or is not an administrator.", hr));
+ throw SysError(formatComError(L"Error calling \"CreateVssBackupComponents\".", hr));
}
}
- ZEN_COM_CHECK(backupComp->InitializeForBackup()); //throw ComError
- ZEN_COM_CHECK(backupComp->SetBackupState(false, false, VSS_BT_FULL)); //throw ComError
+ ZEN_COM_CHECK(backupComp->InitializeForBackup()); //throw SysError
+ ZEN_COM_CHECK(backupComp->SetBackupState(false, false, VSS_BT_FULL)); //throw SysError
auto waitForComFuture = [](IVssAsync& fut)
{
@@ -98,7 +98,7 @@ shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError
HRESULT hr = S_OK;
ZEN_COM_CHECK(fut.QueryStatus(&hr, nullptr)); //check if the async operation succeeded...
if (FAILED(hr))
- throw ComError(L"Error calling \"fut->QueryStatus\".", hr);
+ throw SysError(formatComError(L"Error calling \"fut->QueryStatus\".", hr));
};
ComPtr<IVssAsync> gatherAsync;
@@ -117,12 +117,12 @@ shadow::ShadowData createShadowCopy(const wchar_t* volumeName) //throw ComError
if (FAILED(hr))
{
if (hr == VSS_E_VOLUME_NOT_SUPPORTED)
- throw ComError(L"Volume Shadow Copy Service is not supported on this volume!");
+ throw SysError(L"Volume Shadow Copy Service is not supported on this volume!");
const std::wstring vssError = formatVssError(hr);
if (!vssError.empty())
- throw ComError(L"Error calling \"backupComp->AddToSnapshotSet\": " + vssError);
+ throw SysError(L"Error calling \"backupComp->AddToSnapshotSet\": " + vssError);
else
- throw ComError(L"Error calling \"backupComp->AddToSnapshotSet\".", hr);
+ throw SysError(formatComError(L"Error calling \"backupComp->AddToSnapshotSet\".", hr));
}
}
@@ -151,10 +151,10 @@ shadow::ShadowHandle shadow::createShadowCopy(const wchar_t* volumeName)
{
try
{
- ShadowData result = ::createShadowCopy(volumeName); //throw ComError
+ ShadowData result = ::createShadowCopy(volumeName); //throw SysError
return new ShadowData(result); //shadow handle owned by caller! std::bad_alloc?
}
- catch (const zen::ComError& e)
+ catch (const zen::SysError& e)
{
lastErrorMessage.reset(new std::wstring(e.toString()));
return nullptr;
diff --git a/lib/Thumbnail/Thumbnail.vcxproj b/lib/Thumbnail/Thumbnail.vcxproj
index 2045f10e..87fb152b 100644
--- a/lib/Thumbnail/Thumbnail.vcxproj
+++ b/lib/Thumbnail/Thumbnail.vcxproj
@@ -66,10 +66,8 @@
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">OBJ\$(ProjectName)_$(Configuration)_$(Platform)\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
@@ -87,7 +85,7 @@
</BuildLog>
<ClCompile>
<Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>FFS_WIN;FFS_WIN;_DEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;ZEN_WIN;_DEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -122,7 +120,7 @@
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>FFS_WIN;_DEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;_DEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -155,7 +153,7 @@
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>FFS_WIN;FFS_WIN;NDEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
@@ -192,7 +190,7 @@
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>FFS_WIN;NDEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeader>
diff --git a/lib/Thumbnail/thumbnail.cpp b/lib/Thumbnail/thumbnail.cpp
index b00ce81d..53c30bc3 100644
--- a/lib/Thumbnail/thumbnail.cpp
+++ b/lib/Thumbnail/thumbnail.cpp
@@ -11,6 +11,7 @@
#define WIN32_LEAN_AND_MEAN
#include <zen/win.h>
#include <zen/win_ver.h>
+#include <zen/sys_error.h>
#define STRICT_TYPED_ITEMIDS //better type safety for IDLists
#include <Shlobj.h>
@@ -30,9 +31,9 @@ using namespace zen;
namespace
{
-thumb::ImageData* allocImageData(int width, int height) //throw ComError; return value always bound!
+thumb::ImageData* allocImageData(int width, int height) //throw SysError; return value always bound!
{
- ZEN_COM_ASSERT(width >= 0 && height >= 0); //throw ComError
+ ZEN_COM_ASSERT(width >= 0 && height >= 0); //throw SysError
std::unique_ptr<thumb::ImageData> idata = make_unique<thumb::ImageData>();
@@ -55,7 +56,7 @@ void releaseImageData_impl(const thumb::ImageData* id)
//caller takes ownership!
-HICON createIconFromBitmap(HBITMAP bitmap) //throw ComError
+HICON createIconFromBitmap(HBITMAP bitmap) //throw SysError
{
BITMAP bmpInfo = {};
ZEN_COM_ASSERT(::GetObject(bitmap, //__in HGDIOBJ hgdiobj,
@@ -77,13 +78,13 @@ HICON createIconFromBitmap(HBITMAP bitmap) //throw ComError
iconInfo.hbmMask = bitmapMask;
HICON result = ::CreateIconIndirect(&iconInfo);
- if (!result) throw ComError(L"Error calling \"CreateIconIndirect\".", GetLastError());
+ if (!result) throw SysError(formatSystemError(L"CreateIconIndirect", getLastError()));
return result;
}
//caller takes ownership!
-thumb::ImageData* convertToImageData(HBITMAP bmp) //throw ComError
+thumb::ImageData* convertToImageData(HBITMAP bmp) //throw SysError
{
//GetDIBits ????
@@ -145,13 +146,13 @@ thumb::ImageData* convertToImageData(HBITMAP bmp) //throw ComError
0, //_In_ int nXSrc,
0, //_In_ int nYSrc,
SRCCOPY)) //_In_ DWORD dwRop
- throw ComError(L"Error calling \"BitBlt\".", GetLastError());
+ throw SysError(formatSystemError(L"BitBlt", getLastError()));
//CreateDIBSection: "Access to the bitmap must be synchronized. [...]. This applies to any use of the pointer to the bitmap bit values."
/*bool rv = */
::GdiFlush();
- thumb::ImageData* imgOut = allocImageData(bmpInfo.bmWidth, bmpInfo.bmHeight); //throw ComError
+ thumb::ImageData* imgOut = allocImageData(bmpInfo.bmWidth, bmpInfo.bmHeight); //throw SysError
ScopeGuard guardImgData = zen::makeGuard([&] { releaseImageData_impl(imgOut); });
unsigned char* rgbPtr = imgOut->rgb;
@@ -176,13 +177,13 @@ thumb::ImageData* convertToImageData(HBITMAP bmp) //throw ComError
//caller takes ownership!
-const thumb::ImageData* getThumbnail_impl(const wchar_t* filename, int requestedSize) //throw ComError
+const thumb::ImageData* getThumbnail_impl(const wchar_t* filename, int requestedSize) //throw SysError
{
const std::wstring filenameStr(filename);
ComPtr<IShellFolder> desktopFolder;
- ZEN_COM_CHECK(::SHGetDesktopFolder(desktopFolder.init())); //throw ComError
- ZEN_COM_ASSERT(desktopFolder); //throw ComError -> better safe than sorry?
+ ZEN_COM_CHECK(::SHGetDesktopFolder(desktopFolder.init())); //throw SysError
+ ZEN_COM_ASSERT(desktopFolder); //throw SysError -> better safe than sorry?
PIDLIST_RELATIVE pidlFolder = nullptr;
{
@@ -246,14 +247,14 @@ const thumb::ImageData* getThumbnail_impl(const wchar_t* filename, int requested
ZEN_COM_ASSERT(bitmap);
ZEN_ON_SCOPE_EXIT(::DeleteObject(bitmap));
- return convertToImageData(bitmap); //throw ComError, pass ownership
+ return convertToImageData(bitmap); //throw SysError, pass ownership
}
const bool wereVistaOrLater = vistaOrLater(); //thread-safety: init at startup
//caller takes ownership!
-const thumb::ImageData* getIconByIndex_impl(int iconIndex, thumb::IconSizeType st) //throw ComError
+const thumb::ImageData* getIconByIndex_impl(int iconIndex, thumb::IconSizeType st) //throw SysError
{
//Note:
//- using IExtractIcon::Extract is *no* alternative, just as ::SHGetFileInfo(), it only supports small (16x16) and large (32x32) icons
@@ -413,7 +414,7 @@ const thumb::ImageData* getIconByIndex_impl(int iconIndex, thumb::IconSizeType s
/*bool rv = */
::GdiFlush();
- ImageData* imgOut = allocImageData(targetWidth, targetHeight); //throw ComError
+ ImageData* imgOut = allocImageData(targetWidth, targetHeight); //throw SysError
ScopeGuard guardImgData = zen::makeGuard([&] { releaseImageData_impl(imgOut); });
unsigned char* rgbPtr = imgOut->rgb;
@@ -457,9 +458,9 @@ const thumb::ImageData* thumb::getThumbnail(const wchar_t* filename, int request
{
try
{
- return getThumbnail_impl(filename, requestedSize); //throw ComError
+ return getThumbnail_impl(filename, requestedSize); //throw SysError
}
- catch (const ComError&)
+ catch (const SysError&)
{
return nullptr;
}
@@ -470,9 +471,9 @@ const thumb::ImageData* thumb::getIconByIndex(int iconIndex, thumb::IconSizeType
{
try
{
- return getIconByIndex_impl(iconIndex, st); //throw ComError
+ return getIconByIndex_impl(iconIndex, st); //throw SysError
}
- catch (const ComError&)
+ catch (const SysError&)
{
return nullptr;
}
diff --git a/lib/binary.cpp b/lib/binary.cpp
index 4ef30c15..0e41f7a6 100644
--- a/lib/binary.cpp
+++ b/lib/binary.cpp
@@ -95,7 +95,7 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename
const TickVal startTime = getTicks();
- const size_t length1 = file1.read(&memory1[0], bufferSize); //throw FileError()
+ const size_t length1 = file1.read(&memory1[0], bufferSize); //throw FileError
const size_t length2 = file2.read(&memory2[0], bufferSize); //returns actual number of bytes read
//send progress updates immediately after reading to reliably allow speed calculations for our clients!
callback.updateCompareStatus(to<Int64>(std::max(length1, length2)));
diff --git a/lib/db_file.cpp b/lib/db_file.cpp
index e4e3d748..2f699e3a 100644
--- a/lib/db_file.cpp
+++ b/lib/db_file.cpp
@@ -12,7 +12,7 @@
#include <zen/serialize.h>
#include <wx+/zlib_wrap.h>
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
#include <zen/win.h> //includes "windows.h"
#include <zen/long_path_prefix.h>
#endif
@@ -25,6 +25,11 @@ namespace
//-------------------------------------------------------------------------------------------------------------------------------
const char FILE_FORMAT_DESCR[] = "FreeFileSync";
const int DB_FILE_FORMAT_VER = 9;
+
+warn_static("wee need two version ids!")
+//const int DB_FILE_FORMAT_CONTAINER = 10;
+//const int DB_FILE_FORMAT_STREAM = 1;
+
//-------------------------------------------------------------------------------------------------------------------------------
typedef std::string UniqueId;
@@ -34,22 +39,21 @@ typedef std::map<UniqueId, BinaryStream> StreamMapping; //list of streams ordere
//| ensure 32/64 bit portability: use fixed size data types only e.g. std::uint32_t |
//-----------------------------------------------------------------------------------
-
template <SelectedSide side> inline
-Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false)
+Zstring getDBFilename(const BaseDirPair& baseDirObj, bool tempfile = false)
{
//Linux and Windows builds are binary incompatible: different file id?, problem with case sensitivity? are UTC file times really compatible?
//what about endianess!?
//however 32 and 64 bit db files *are* designed to be binary compatible!
//Give db files different names.
//make sure they end with ".ffs_db". These files will be excluded from comparison
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
Zstring dbname = Zstring(Zstr("sync")) + (tempfile ? Zstr(".tmp") : Zstr("")) + SYNC_DB_FILE_ENDING;
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
//files beginning with dots are hidden e.g. in Nautilus
Zstring dbname = Zstring(Zstr(".sync")) + (tempfile ? Zstr(".tmp") : Zstr("")) + SYNC_DB_FILE_ENDING;
#endif
- return baseMap.getBaseDirPf<side>() + dbname;
+ return baseDirObj.getBaseDirPf<side>() + dbname;
}
//#######################################################################################################################################
@@ -76,7 +80,7 @@ void saveStreams(const StreamMapping& streamList, const Zstring& filename) //thr
assert(!somethingExists(filename)); //orphan tmp files should be cleaned up already at this point!
saveBinStream(filename, streamOut.get()); //throw FileError
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//be careful to avoid CreateFile() + CREATE_ALWAYS on a hidden file -> see file_io.cpp
::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); //(try to) hide database file
#endif
@@ -125,8 +129,8 @@ StreamMapping loadStreams(const Zstring& filename) //throw FileError, FileErrorD
}
catch (const std::bad_alloc& e) //still required?
{
- throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filename) + L"\n\n" +
- _("Out of memory!") + L" " + utfCvrtTo<std::wstring>(e.what()));
+ throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filename),
+ _("Out of memory.") + L" " + utfCvrtTo<std::wstring>(e.what()));
}
}
@@ -167,7 +171,7 @@ public:
}
catch (ZlibInternalError&)
{
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename)) + L" (zlib error)");
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename)), L"zlib internal error");
}
};
@@ -201,31 +205,31 @@ public:
private:
void recurse(const InSyncDir& container)
{
- // for (const auto& filePair : container.files) { processFile(filePair); }); !
+ // for (const auto& dbFile : container.files) { processFile(dbFile); }); !
writeNumber<std::uint32_t>(outputBoth, static_cast<std::uint32_t>(container.files.size()));
- std::for_each(container.files.begin(), container.files.end(), [&](const std::pair<Zstring, InSyncFile>& filePair) { this->process(filePair); });
+ std::for_each(container.files.begin(), container.files.end(), [&](const std::pair<Zstring, InSyncFile>& dbFile) { this->process(dbFile); });
writeNumber<std::uint32_t>(outputBoth, static_cast<std::uint32_t>(container.symlinks.size()));
- std::for_each(container.symlinks.begin(), container.symlinks.end(), [&](const std::pair<Zstring, InSyncSymlink>& symlinkPair) { this->process(symlinkPair); });
+ std::for_each(container.symlinks.begin(), container.symlinks.end(), [&](const std::pair<Zstring, InSyncSymlink>& dbSymlink) { this->process(dbSymlink); });
writeNumber<std::uint32_t>(outputBoth, static_cast<std::uint32_t>(container.dirs.size()));
- std::for_each(container.dirs.begin(), container.dirs.end(), [&](const std::pair<Zstring, InSyncDir>& dirPair) { this->process(dirPair); });
+ std::for_each(container.dirs.begin(), container.dirs.end(), [&](const std::pair<Zstring, InSyncDir>& dbDir) { this->process(dbDir); });
}
static void writeUtf8(BinStreamOut& output, const Zstring& str) { writeContainer(output, utfCvrtTo<Zbase<char>>(str)); }
- static void write(BinStreamOut& output, const FileDescriptor& descr)
+ static void writeFile(BinStreamOut& output, const InSyncDescrFile& descr, const UInt64& fileSize)
{
writeNumber<std:: int64_t>(output, to<std:: int64_t>(descr.lastWriteTimeRaw));
- writeNumber<std::uint64_t>(output, to<std::uint64_t>(descr.fileSize));
- writeNumber<std::uint64_t>(output, descr.devId);
- writeNumber<std::uint64_t>(output, descr.fileIdx);
- assert_static(sizeof(descr.devId ) <= sizeof(std::uint64_t));
- assert_static(sizeof(descr.fileIdx) <= sizeof(std::uint64_t));
+ writeNumber<std::uint64_t>(output, to<std::uint64_t>(fileSize));
+ writeNumber<std::uint64_t>(output, descr.fileId.first);
+ writeNumber<std::uint64_t>(output, descr.fileId.second);
+ assert_static(sizeof(descr.fileId.first ) <= sizeof(std::uint64_t));
+ assert_static(sizeof(descr.fileId.second) <= sizeof(std::uint64_t));
}
- static void write(BinStreamOut& output, const LinkDescriptor& descr)
+ static void writeLink(BinStreamOut& output, const InSyncDescrLink& descr)
{
writeNumber<std::int64_t>(output, to<std:: int64_t>(descr.lastWriteTimeRaw));
@@ -236,37 +240,39 @@ private:
writeNumber<std::int32_t>(output, 0);
}
- static void write(BinStreamOut& output, const InSyncDir::InSyncStatus& status)
+ static void writeDir(BinStreamOut& output, const InSyncDir::InSyncStatus& status)
{
writeNumber<std::int32_t>(output, status);
}
- void process(const std::pair<Zstring, InSyncFile>& filePair)
+ void process(const std::pair<Zstring, InSyncFile>& dbFile)
{
- writeUtf8(outputBoth, filePair.first);
- writeNumber<std::int32_t>(outputBoth, filePair.second.inSyncType);
+ writeUtf8(outputBoth, dbFile.first);
+ writeNumber<std::int32_t>(outputBoth, dbFile.second.inSyncType);
- write(outputLeft, filePair.second.left);
- write(outputRight, filePair.second.right);
+ warn_static("implement proper migration: get rid of duplicate fileSize!")
+
+ writeFile(outputLeft, dbFile.second.left, dbFile.second.fileSize);
+ writeFile(outputRight, dbFile.second.right, dbFile.second.fileSize);
}
- void process(const std::pair<Zstring, InSyncSymlink>& symlinkPair)
+ void process(const std::pair<Zstring, InSyncSymlink>& dbSymlink)
{
- writeUtf8(outputBoth, symlinkPair.first);
+ writeUtf8(outputBoth, dbSymlink.first);
warn_static("new parameter: imp proper migration!")
- //writeNumber<std::int32_t>(outputBoth, symlinkPair.second.inSyncType);
+ //writeNumber<std::int32_t>(outputBoth, dbSymlink.second.inSyncType);
- write(outputLeft, symlinkPair.second.left);
- write(outputRight, symlinkPair.second.right);
+ writeLink(outputLeft, dbSymlink.second.left);
+ writeLink(outputRight, dbSymlink.second.right);
}
- void process(const std::pair<Zstring, InSyncDir>& dirPair)
+ void process(const std::pair<Zstring, InSyncDir>& dbDir)
{
- writeUtf8(outputBoth, dirPair.first);
- write(outputBoth, dirPair.second.status);
+ writeUtf8(outputBoth, dbDir.first);
+ writeDir(outputBoth, dbDir.second.status);
- recurse(dirPair.second);
+ recurse(dbDir.second);
}
BinStreamOut outputLeft; //data related to one side only
@@ -291,7 +297,7 @@ public:
}
catch (ZlibInternalError&)
{
- throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(filename)) + L" (zlib error)");
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(filename)), L"zlib internal error");
}
};
@@ -319,11 +325,11 @@ public:
const BinaryStream tmpL = readContainer<BinaryStream>(inL);
const BinaryStream tmpR = readContainer<BinaryStream>(inR);
- auto output = std::make_shared<InSyncDir>(InSyncDir::STATUS_IN_SYNC);
- StreamParser(decompStream(tmpL, filenameL),
- decompStream(tmpR, filenameR),
- decompStream(tmpB, filenameL + Zstr("/") + filenameR),
- *output); //throw UnexpectedEndOfStreamError
+ auto output = std::make_shared<InSyncDir>(InSyncDir::DIR_STATUS_IN_SYNC);
+ StreamParser parser(decompStream(tmpL, filenameL),
+ decompStream(tmpR, filenameR),
+ decompStream(tmpB, filenameL + Zstr("/") + filenameR));
+ parser.recurse(*output); //throw UnexpectedEndOfStreamError
return output;
}
catch (const UnexpectedEndOfStreamError&)
@@ -332,43 +338,46 @@ public:
}
catch (const std::bad_alloc& e) //still required?
{
- throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filenameL) + L"\n" + fmtFileName(filenameR) + L"\n\n" +
- _("Out of memory!") + L" " + utfCvrtTo<std::wstring>(e.what()));
+ throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filenameL) + L"\n" + fmtFileName(filenameR),
+ _("Out of memory.") + L" " + utfCvrtTo<std::wstring>(e.what()));
}
}
private:
StreamParser(const BinaryStream& bufferL,
const BinaryStream& bufferR,
- const BinaryStream& bufferB,
- InSyncDir& container) :
+ const BinaryStream& bufferB) :
inputLeft (bufferL),
inputRight(bufferR),
- inputBoth (bufferB) { recurse(container); }
+ inputBoth (bufferB) {}
static Zstring readUtf8(BinStreamIn& input) { return utfCvrtTo<Zstring>(readContainer<Zbase<char>>(input)); } //throw UnexpectedEndOfStreamError
- static void read(BinStreamIn& input, FileDescriptor& descr)
+ static InSyncDescrFile readFile(BinStreamIn& input, UInt64& fileSize)
{
//attention: order of function argument evaluation is undefined! So do it one after the other...
- descr.lastWriteTimeRaw = readNumber<std::int64_t>(input); //throw UnexpectedEndOfStreamError
- descr.fileSize = readNumber<std::uint64_t>(input);
- descr.devId = static_cast<DeviceId >(readNumber<std::uint64_t>(input)); //
- descr.fileIdx = static_cast<FileIndex>(readNumber<std::uint64_t>(input)); //silence "loss of precision" compiler warnings
+ auto lastWriteTimeRaw = readNumber<std::int64_t>(input); //throw UnexpectedEndOfStreamError
+ warn_static("implement proper migration!")
+ fileSize = readNumber<std::uint64_t>(input);
+ auto devId = static_cast<DeviceId >(readNumber<std::uint64_t>(input)); //
+ auto fileIdx = static_cast<FileIndex>(readNumber<std::uint64_t>(input)); //silence "loss of precision" compiler warnings
+ return InSyncDescrFile(lastWriteTimeRaw, FileId(devId, fileIdx));
}
- static void read(BinStreamIn& input, LinkDescriptor& descr)
+ static InSyncDescrLink readLink(BinStreamIn& input)
{
- descr.lastWriteTimeRaw = readNumber<std::int64_t>(input);
+ auto lastWriteTimeRaw = readNumber<std::int64_t>(input);
warn_static("implement proper migration!")
//descr.targetPath = readUtf8(input);
readUtf8(input);
//descr.type = static_cast<LinkDescriptor::LinkType>(readNumber<std::int32_t>(input));
readNumber<std::int32_t>(input);
+
+ return InSyncDescrLink(lastWriteTimeRaw);
}
- static void read(BinStreamIn& input, InSyncDir::InSyncStatus& status)
+ static void readDir(BinStreamIn& input, InSyncDir::InSyncStatus& status)
{
status = static_cast<InSyncDir::InSyncStatus>(readNumber<std::int32_t>(input));
}
@@ -378,15 +387,16 @@ private:
size_t fileCount = readNumber<std::uint32_t>(inputBoth);
while (fileCount-- != 0)
{
+ warn_static("migrate from InSyncType to CompareVariant!!!")
const Zstring shortName = readUtf8(inputBoth);
const auto inSyncType = static_cast<InSyncType>(readNumber<std::int32_t>(inputBoth));
- FileDescriptor dataL;
- FileDescriptor dataR;
- read(inputLeft, dataL);
- read(inputRight, dataR);
+ warn_static("implement proper migration: get rid of duplicate fileSize!")
- container.addFile(shortName, dataL, dataR, inSyncType);
+ UInt64 fileSize;
+ const InSyncDescrFile dataL = readFile(inputLeft, fileSize);
+ const InSyncDescrFile dataR = readFile(inputRight, fileSize);
+ container.addFile(shortName, dataL, dataR, inSyncType, fileSize);
}
size_t linkCount = readNumber<std::uint32_t>(inputBoth);
@@ -395,14 +405,11 @@ private:
const Zstring shortName = readUtf8(inputBoth);
warn_static("new parameter: imp proper migration!")
- const auto inSyncType = IN_SYNC_BINARY_EQUAL;
+ const auto inSyncType = IN_SYNC_BINARY_EQUAL;
//const auto inSyncType = static_cast<InSyncType>(readNumber<std::int32_t>(inputBoth));
- LinkDescriptor dataL;
- LinkDescriptor dataR;
- read(inputLeft, dataL);
- read(inputRight, dataR);
-
+ InSyncDescrLink dataL = readLink(inputLeft);
+ InSyncDescrLink dataR = readLink(inputRight);
container.addSymlink(shortName, dataL, dataR, inSyncType);
}
@@ -411,8 +418,8 @@ private:
{
const Zstring shortName = readUtf8(inputBoth);
- InSyncDir::InSyncStatus status = InSyncDir::STATUS_STRAW_MAN;
- read(inputBoth, status);
+ InSyncDir::InSyncStatus status = InSyncDir::DIR_STATUS_STRAW_MAN;
+ readDir(inputBoth, status);
InSyncDir& subDir = container.addDir(shortName, status);
recurse(subDir);
@@ -435,10 +442,10 @@ class UpdateLastSynchronousState
=> update all database entries!
*/
public:
- static void execute(const BaseDirMapping& baseMapping, InSyncDir& dir)
+ static void execute(const BaseDirPair& baseDirObj, InSyncDir& dir)
{
bool binaryComparison = false;
- switch (baseMapping.getCompVariant())
+ switch (baseDirObj.getCompVariant())
{
case CMP_BY_TIME_SIZE:
break;
@@ -447,8 +454,8 @@ public:
break;
}
- UpdateLastSynchronousState updater(baseMapping.getFilter(), binaryComparison);
- updater.recurse(baseMapping, dir);
+ UpdateLastSynchronousState updater(baseDirObj.getFilter(), binaryComparison);
+ updater.recurse(baseDirObj, dir);
}
private:
@@ -469,7 +476,7 @@ private:
auto rv = map.insert(typename M::value_type(key, value));
if (!rv.second)
{
-#if defined FFS_WIN || defined FFS_MAC //caveat: key must be updated, if there is a change in short name case!!!
+#if defined ZEN_WIN || defined ZEN_MAC //caveat: key must be updated, if there is a change in short name case!!!
if (rv.first->first != key)
{
map.erase(rv.first);
@@ -490,7 +497,7 @@ private:
auto it = map.lower_bound(key);
if (it != map.end() && !(map.key_comp()(key, it->first)))
{
- #if defined FFS_WIN || defined FFS_MAC //caveat: key might need to be updated, too, if there is a change in short name case!!!
+ #if defined ZEN_WIN || defined ZEN_MAC //caveat: key might need to be updated, too, if there is a change in short name case!!!
if (it->first != key)
{
map.erase(it); //don't fiddle with decrementing "it"! - you might lose while optimizing pointlessly
@@ -507,38 +514,40 @@ private:
void process(const HierarchyObject::SubFileVec& currentFiles, const Zstring& parentRelativeNamePf, InSyncDir::FileList& dbFiles)
{
hash_set<const InSyncFile*> toPreserve; //referencing fixed-in-memory std::map elements
- std::for_each(currentFiles.begin(), currentFiles.end(), [&](const FileMapping& fileMap)
+ std::for_each(currentFiles.begin(), currentFiles.end(), [&](const FilePair& fileObj)
{
- if (!fileMap.isEmpty())
+ if (!fileObj.isEmpty())
{
- if (fileMap.getCategory() == FILE_EQUAL) //data in sync: write current state
+ if (fileObj.getCategory() == FILE_EQUAL) //data in sync: write current state
{
//Caveat: If FILE_EQUAL, we *implicitly* assume equal left and right short names matching case: InSyncDir's mapping tables use short name as a key!
//This makes us silently dependent from code in algorithm.h!!!
- assert(fileMap.getShortName<LEFT_SIDE>() == fileMap.getShortName<RIGHT_SIDE>());
+ assert(fileObj.getShortName<LEFT_SIDE>() == fileObj.getShortName<RIGHT_SIDE>());
+ //this should be taken for granted:
+ assert(fileObj.getFileSize<LEFT_SIDE>() == fileObj.getFileSize<RIGHT_SIDE>());
//create or update new "in-sync" state
- InSyncFile& file = updateItem(dbFiles, fileMap.getObjShortName(),
- InSyncFile(FileDescriptor(fileMap.getLastWriteTime<LEFT_SIDE>(),
- fileMap.getFileSize <LEFT_SIDE>(),
- fileMap.getFileId <LEFT_SIDE>()),
- FileDescriptor(fileMap.getLastWriteTime<RIGHT_SIDE>(),
- fileMap.getFileSize <RIGHT_SIDE>(),
- fileMap.getFileId <RIGHT_SIDE>()),
+ InSyncFile& file = updateItem(dbFiles, fileObj.getObjShortName(),
+ InSyncFile(InSyncDescrFile(fileObj.getLastWriteTime<LEFT_SIDE>(),
+ fileObj.getFileId <LEFT_SIDE>()),
+ InSyncDescrFile(fileObj.getLastWriteTime<RIGHT_SIDE>(),
+ fileObj.getFileId <RIGHT_SIDE>()),
binaryComparison_ ?
IN_SYNC_BINARY_EQUAL :
- IN_SYNC_ATTRIBUTES_EQUAL));
+ IN_SYNC_ATTRIBUTES_EQUAL,
+ fileObj.getFileSize<LEFT_SIDE>()));
toPreserve.insert(&file);
}
else //not in sync: preserve last synchronous state
{
- auto it = dbFiles.find(fileMap.getObjShortName());
+ auto it = dbFiles.find(fileObj.getObjShortName());
if (it != dbFiles.end())
toPreserve.insert(&it->second);
}
}
});
+ warn_static("consider temporarily excluded items due to traveral error just like a fixed file filter here!?")
//delete removed items (= "in-sync") from database
map_remove_if(dbFiles, [&](const InSyncDir::FileList::value_type& v) -> bool
{
@@ -553,18 +562,18 @@ private:
void process(const HierarchyObject::SubLinkVec& currentLinks, const Zstring& parentRelativeNamePf, InSyncDir::LinkList& dbLinks)
{
hash_set<const InSyncSymlink*> toPreserve;
- std::for_each(currentLinks.begin(), currentLinks.end(), [&](const SymLinkMapping& linkMap)
+ std::for_each(currentLinks.begin(), currentLinks.end(), [&](const SymlinkPair& linkObj)
{
- if (!linkMap.isEmpty())
+ if (!linkObj.isEmpty())
{
- if (linkMap.getLinkCategory() == SYMLINK_EQUAL) //data in sync: write current state
+ if (linkObj.getLinkCategory() == SYMLINK_EQUAL) //data in sync: write current state
{
- assert(linkMap.getShortName<LEFT_SIDE>() == linkMap.getShortName<RIGHT_SIDE>());
+ assert(linkObj.getShortName<LEFT_SIDE>() == linkObj.getShortName<RIGHT_SIDE>());
//create or update new "in-sync" state
- InSyncSymlink& link = updateItem(dbLinks, linkMap.getObjShortName(),
- InSyncSymlink(LinkDescriptor(linkMap.getLastWriteTime<LEFT_SIDE>()),
- LinkDescriptor(linkMap.getLastWriteTime<RIGHT_SIDE>()),
+ InSyncSymlink& link = updateItem(dbLinks, linkObj.getObjShortName(),
+ InSyncSymlink(InSyncDescrLink(linkObj.getLastWriteTime<LEFT_SIDE>()),
+ InSyncDescrLink(linkObj.getLastWriteTime<RIGHT_SIDE>()),
binaryComparison_ ?
IN_SYNC_BINARY_EQUAL :
IN_SYNC_ATTRIBUTES_EQUAL));
@@ -572,7 +581,7 @@ private:
}
else //not in sync: preserve last synchronous state
{
- auto it = dbLinks.find(linkMap.getObjShortName());
+ auto it = dbLinks.find(linkObj.getObjShortName());
if (it != dbLinks.end())
toPreserve.insert(&it->second);
}
@@ -593,22 +602,21 @@ private:
void process(const HierarchyObject::SubDirVec& currentDirs, const Zstring& parentRelativeNamePf, InSyncDir::DirList& dbDirs)
{
hash_set<const InSyncDir*> toPreserve;
- std::for_each(currentDirs.begin(), currentDirs.end(), [&](const DirMapping& dirMap)
+ std::for_each(currentDirs.begin(), currentDirs.end(), [&](const DirPair& dirObj)
{
- if (!dirMap.isEmpty())
- {
- switch (dirMap.getDirCategory())
+ if (!dirObj.isEmpty())
+ switch (dirObj.getDirCategory())
{
case DIR_EQUAL:
{
- assert(dirMap.getShortName<LEFT_SIDE>() == dirMap.getShortName<RIGHT_SIDE>());
+ assert(dirObj.getShortName<LEFT_SIDE>() == dirObj.getShortName<RIGHT_SIDE>());
//update directory entry only (shallow), but do *not touch* exising child elements!!!
- const Zstring& key = dirMap.getObjShortName();
- auto insertResult = dbDirs.insert(std::make_pair(key, InSyncDir(InSyncDir::STATUS_IN_SYNC))); //get or create
+ const Zstring& key = dirObj.getObjShortName();
+ auto insertResult = dbDirs.insert(std::make_pair(key, InSyncDir(InSyncDir::DIR_STATUS_IN_SYNC))); //get or create
auto it = insertResult.first;
-#if defined FFS_WIN || defined FFS_MAC //caveat: key might need to be updated, too, if there is a change in short name case!!!
+#if defined ZEN_WIN || defined ZEN_MAC //caveat: key might need to be updated, too, if there is a change in short name case!!!
const bool alreadyExisting = !insertResult.second;
if (alreadyExisting && it->first != key)
{
@@ -618,9 +626,9 @@ private:
}
#endif
InSyncDir& dir = it->second;
- dir.status = InSyncDir::STATUS_IN_SYNC; //update immediate directory entry
+ dir.status = InSyncDir::DIR_STATUS_IN_SYNC; //update immediate directory entry
toPreserve.insert(&dir);
- recurse(dirMap, dir);
+ recurse(dirObj, dir);
}
break;
@@ -630,9 +638,9 @@ private:
//Example: directories on left and right differ in case while sub-files are equal
{
//reuse last "in-sync" if available or insert strawman entry (do not try to update thereby removing child elements!!!)
- InSyncDir& dir = dbDirs.insert(std::make_pair(dirMap.getObjShortName(), InSyncDir(InSyncDir::STATUS_STRAW_MAN))).first->second;
+ InSyncDir& dir = dbDirs.insert(std::make_pair(dirObj.getObjShortName(), InSyncDir(InSyncDir::DIR_STATUS_STRAW_MAN))).first->second;
toPreserve.insert(&dir);
- recurse(dirMap, dir);
+ recurse(dirObj, dir);
}
break;
@@ -640,16 +648,15 @@ private:
case DIR_LEFT_SIDE_ONLY:
case DIR_RIGHT_SIDE_ONLY:
{
- auto it = dbDirs.find(dirMap.getObjShortName());
+ auto it = dbDirs.find(dirObj.getObjShortName());
if (it != dbDirs.end())
{
toPreserve.insert(&it->second);
- recurse(dirMap, it->second); //although existing sub-items cannot be in sync, items deleted on both sides *are* in-sync!!!
+ recurse(dirObj, it->second); //although existing sub-items cannot be in sync, items deleted on both sides *are* in-sync!!!
}
}
break;
}
- }
});
//delete removed items (= "in-sync") from database
@@ -657,13 +664,12 @@ private:
{
if (toPreserve.find(&v.second) != toPreserve.end())
return false;
- //all items not existing in "currentDirs" have either been deleted meanwhile or been excluded via filter:
const Zstring& shortName = v.first;
return filter_.passDirFilter(parentRelativeNamePf + shortName, nullptr);
//if directory is not included in "currentDirs", it is either not existing anymore, in which case it should be deleted from database
- //or it was excluded via filter, in which case the database entry should be preserved
- //-> we can't tell and need to preserve the old db entry -> all child db elements are preserved since they are not recursed in the loop above!!!
- //-> no problem with filter logic of excluding complete directory subtrees, if top folder is excluded directly!
+ //or it was excluded via filter, in which case the database entry should be preserved:
+ //=> all child db elements are also preserved since they are not recursed in the loop above!!!
+ //=> no problem with filter logic of excluding complete directory subtrees, if top folder is excluded directly!
});
}
@@ -674,17 +680,17 @@ private:
//#######################################################################################################################################
-std::shared_ptr<InSyncDir> zen::loadLastSynchronousState(const BaseDirMapping& baseMapping) //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
+std::shared_ptr<InSyncDir> zen::loadLastSynchronousState(const BaseDirPair& baseDirObj) //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
{
- const Zstring fileNameLeft = getDBFilename<LEFT_SIDE >(baseMapping);
- const Zstring fileNameRight = getDBFilename<RIGHT_SIDE>(baseMapping);
+ const Zstring fileNameLeft = getDBFilename<LEFT_SIDE >(baseDirObj);
+ const Zstring fileNameRight = getDBFilename<RIGHT_SIDE>(baseDirObj);
- if (!baseMapping.isExisting<LEFT_SIDE >() ||
- !baseMapping.isExisting<RIGHT_SIDE>())
+ if (!baseDirObj.isExisting<LEFT_SIDE >() ||
+ !baseDirObj.isExisting<RIGHT_SIDE>())
{
//avoid race condition with directory existence check: reading sync.ffs_db may succeed although first dir check had failed => conflicts!
//https://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3531351&group_id=234430
- const Zstring filename = !baseMapping.isExisting<LEFT_SIDE>() ? fileNameLeft : fileNameRight;
+ const Zstring filename = !baseDirObj.isExisting<LEFT_SIDE>() ? fileNameLeft : fileNameRight;
throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" + //it could be due to a to-be-created target directory not yet existing => FileErrorDatabaseNotExisting
replaceCpy(_("Database file %x does not yet exist."), L"%x", fmtFileName(filename)));
}
@@ -710,14 +716,14 @@ std::shared_ptr<InSyncDir> zen::loadLastSynchronousState(const BaseDirMapping& b
}
-void zen::saveLastSynchronousState(const BaseDirMapping& baseMapping) //throw FileError
+void zen::saveLastSynchronousState(const BaseDirPair& baseDirObj) //throw FileError
{
//transactional behaviour! write to tmp files first
- const Zstring dbNameLeftTmp = getDBFilename<LEFT_SIDE >(baseMapping, true);
- const Zstring dbNameRightTmp = getDBFilename<RIGHT_SIDE>(baseMapping, true);
+ const Zstring dbNameLeftTmp = getDBFilename<LEFT_SIDE >(baseDirObj, true);
+ const Zstring dbNameRightTmp = getDBFilename<RIGHT_SIDE>(baseDirObj, true);
- const Zstring dbNameLeft = getDBFilename<LEFT_SIDE >(baseMapping);
- const Zstring dbNameRight = getDBFilename<RIGHT_SIDE>(baseMapping);
+ const Zstring dbNameLeft = getDBFilename<LEFT_SIDE >(baseDirObj);
+ const Zstring dbNameRight = getDBFilename<RIGHT_SIDE>(baseDirObj);
//delete old tmp file, if necessary -> throws if deletion fails!
removeFile(dbNameLeftTmp); //
@@ -749,7 +755,7 @@ void zen::saveLastSynchronousState(const BaseDirMapping& baseMapping) //throw Fi
}
//load last synchrounous state
- std::shared_ptr<InSyncDir> lastSyncState = std::make_shared<InSyncDir>(InSyncDir::STATUS_IN_SYNC);
+ std::shared_ptr<InSyncDir> lastSyncState = std::make_shared<InSyncDir>(InSyncDir::DIR_STATUS_IN_SYNC);
if (streamIterLeftOld != streamListLeft .end() &&
streamIterRightOld != streamListRight.end())
try
@@ -762,7 +768,7 @@ void zen::saveLastSynchronousState(const BaseDirMapping& baseMapping) //throw Fi
catch (FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
//update last synchrounous state
- UpdateLastSynchronousState::execute(baseMapping, *lastSyncState);
+ UpdateLastSynchronousState::execute(baseDirObj, *lastSyncState);
//serialize again
BinaryStream updatedStreamLeft;
diff --git a/lib/db_file.h b/lib/db_file.h
index 181a433e..b352ba5d 100644
--- a/lib/db_file.h
+++ b/lib/db_file.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef DBFILE_H_INCLUDED
-#define DBFILE_H_INCLUDED
+#ifndef DBFILE_H_834275398588021574
+#define DBFILE_H_834275398588021574
#include <zen/file_error.h>
#include "../file_hierarchy.h"
@@ -20,31 +20,50 @@ enum InSyncType
IN_SYNC_ATTRIBUTES_EQUAL, //only "looks" like they're equal
};
+struct InSyncDescrFile //subset of FileDescriptor
+{
+ InSyncDescrFile(const Int64& lastWriteTimeRawIn,
+ const FileId& idIn) :
+ lastWriteTimeRaw(lastWriteTimeRawIn),
+ fileId(idIn) {}
+
+ Int64 lastWriteTimeRaw;
+ FileId fileId; // == file id: optional! (however, always set on Linux, and *generally* available on Windows)
+};
+
+struct InSyncDescrLink
+{
+ explicit InSyncDescrLink(const Int64& lastWriteTimeRawIn) : lastWriteTimeRaw(lastWriteTimeRawIn) {}
+ Int64 lastWriteTimeRaw;
+};
+
+
//artificial hierarchy of last synchronous state:
struct InSyncFile
{
- InSyncFile(const FileDescriptor& l, const FileDescriptor& r, InSyncType type) : left(l), right(r), inSyncType(type) {}
- FileDescriptor left;
- FileDescriptor right;
+ InSyncFile(const InSyncDescrFile& l, const InSyncDescrFile& r, InSyncType type, const UInt64& fileSizeIn) : left(l), right(r), inSyncType(type), fileSize(fileSizeIn) {}
+ InSyncDescrFile left;
+ InSyncDescrFile right;
InSyncType inSyncType;
+ UInt64 fileSize; //file size must be identical on both sides!
};
struct InSyncSymlink
{
- InSyncSymlink(const LinkDescriptor& l, const LinkDescriptor& r, InSyncType type) : left(l), right(r), inSyncType(type) {}
- LinkDescriptor left;
- LinkDescriptor right;
+ InSyncSymlink(const InSyncDescrLink& l, const InSyncDescrLink& r, InSyncType type) : left(l), right(r), inSyncType(type) {}
+ InSyncDescrLink left;
+ InSyncDescrLink right;
InSyncType inSyncType;
};
struct InSyncDir
{
- //for directories we have a logical problem: we cannot have "not existent" as an indicator for "no last synchronous state" since this precludes
- //child elements that may be in sync!
+ //for directories we have a logical problem: we cannot have "not existent" as an indicator for
+ //"no last synchronous state" since this precludes child elements that may be in sync!
enum InSyncStatus
{
- STATUS_IN_SYNC,
- STATUS_STRAW_MAN //there is no last synchronous state, but used as container only
+ DIR_STATUS_IN_SYNC,
+ DIR_STATUS_STRAW_MAN //there is no last synchronous state, but used as container only
};
InSyncDir(InSyncStatus statusIn) : status(statusIn) {}
@@ -61,18 +80,18 @@ struct InSyncDir
LinkList symlinks; //non-followed symlinks
//convenience
- InSyncDir& addDir(const Zstring& shortName, InSyncStatus statusIn)
+ InSyncDir& addDir(const Zstring& shortName, InSyncStatus st)
{
//use C++11 emplace when available
- return dirs.insert(std::make_pair(shortName, InSyncDir(statusIn))).first->second;
+ return dirs.insert(std::make_pair(shortName, InSyncDir(st))).first->second;
}
- void addFile(const Zstring& shortName, const FileDescriptor& dataL, const FileDescriptor& dataR, InSyncType type)
+ void addFile(const Zstring& shortName, const InSyncDescrFile& dataL, const InSyncDescrFile& dataR, InSyncType type, const UInt64& fileSize)
{
- files.insert(std::make_pair(shortName, InSyncFile(dataL, dataR, type)));
+ files.insert(std::make_pair(shortName, InSyncFile(dataL, dataR, type, fileSize)));
}
- void addSymlink(const Zstring& shortName, const LinkDescriptor& dataL, const LinkDescriptor& dataR, InSyncType type)
+ void addSymlink(const Zstring& shortName, const InSyncDescrLink& dataL, const InSyncDescrLink& dataR, InSyncType type)
{
symlinks.insert(std::make_pair(shortName, InSyncSymlink(dataL, dataR, type)));
}
@@ -81,9 +100,9 @@ struct InSyncDir
DEFINE_NEW_FILE_ERROR(FileErrorDatabaseNotExisting);
-std::shared_ptr<InSyncDir> loadLastSynchronousState(const BaseDirMapping& baseMapping); //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
+std::shared_ptr<InSyncDir> loadLastSynchronousState(const BaseDirPair& baseDirObj); //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
-void saveLastSynchronousState(const BaseDirMapping& baseMapping); //throw FileError
+void saveLastSynchronousState(const BaseDirPair& baseDirObj); //throw FileError
}
-#endif //DBFILE_H_INCLUDED
+#endif //DBFILE_H_834275398588021574
diff --git a/lib/dir_exist_async.h b/lib/dir_exist_async.h
index b96dc7e1..dd77a36a 100644
--- a/lib/dir_exist_async.h
+++ b/lib/dir_exist_async.h
@@ -34,7 +34,7 @@ std::set<Zstring, LessFilename> getExistingDirsUpdating(const std::set<Zstring,
{
if (dirname.empty())
return false;
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//1. login to network share, if necessary
loginNetworkShare(dirname, allowUserInteraction);
#endif
diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp
index f3a16677..60d83a67 100644
--- a/lib/dir_lock.cpp
+++ b/lib/dir_lock.cpp
@@ -7,7 +7,7 @@
#include <utility>
#include <wx/log.h>
#include <memory>
-#include <zen/last_error.h>
+#include <zen/sys_error.h>
#include <zen/thread.h> //includes <boost/thread.hpp>
#include <zen/scope_guard.h>
#include <zen/guid.h>
@@ -18,14 +18,14 @@
#include <zen/serialize.h>
#include <zen/optional.h>
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
#include <tlhelp32.h>
#include <zen/win.h> //includes "windows.h"
#include <zen/long_path_prefix.h>
#include <Sddl.h> //login sid
#include <Lmcons.h> //UNLEN
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
#include <fcntl.h> //open()
#include <sys/stat.h> //
#include <unistd.h> //getsid()
@@ -68,14 +68,14 @@ public:
}
catch (const std::exception& e) //exceptions must be catched per thread
{
- wxSafeShowMessage(_("An exception occurred!") + L" (Dirlock)", utfCvrtTo<wxString>(e.what())); //simple wxMessageBox won't do for threads
+ wxSafeShowMessage(_("An exception occurred"), utfCvrtTo<wxString>(e.what()) + L" (Dirlock)"); //simple wxMessageBox won't do for threads
}
}
void emitLifeSign() const //try to append one byte...; throw()
{
const char buffer[1] = {' '};
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//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!!!
@@ -105,7 +105,7 @@ public:
nullptr)) //_Inout_opt_ LPOVERLAPPED lpOverlapped
return;
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
const int fileHandle = ::open(lockfilename_.c_str(), O_WRONLY | O_APPEND);
if (fileHandle == -1)
return;
@@ -125,7 +125,7 @@ namespace
{
UInt64 getLockFileSize(const Zstring& filename) //throw FileError, ErrorNotExisting
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
WIN32_FIND_DATA fileInfo = {};
const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo);
if (searchHandle != INVALID_HANDLE_VALUE)
@@ -133,20 +133,22 @@ UInt64 getLockFileSize(const Zstring& filename) //throw FileError, ErrorNotExist
::FindClose(searchHandle);
return UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh);
}
-
-#elif defined FFS_LINUX || defined FFS_MAC
+ const wchar_t functionName[] = L"FindFirstFile";
+#elif defined ZEN_LINUX || defined ZEN_MAC
struct ::stat fileInfo = {};
if (::stat(filename.c_str(), &fileInfo) == 0) //follow symbolic links
return UInt64(fileInfo.st_size);
+ const wchar_t functionName[] = L"stat";
#endif
const ErrorCode lastError = getLastError();
- const std::wstring errorMessage = replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted(lastError);
+ const std::wstring errorMsg = replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename));
+ const std::wstring errorDescr = formatSystemError(functionName, lastError);
if (errorCodeForNotExisting(lastError))
- throw ErrorNotExisting(errorMessage);
+ throw ErrorNotExisting(errorMsg, errorDescr);
else
- throw FileError(errorMessage);
+ throw FileError(errorMsg, errorDescr);
}
@@ -160,14 +162,14 @@ Zstring deleteAbandonedLockName(const Zstring& lockfilename) //make sure to NOT
}
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
Zstring getLoginSid() //throw FileError
{
HANDLE hToken = 0;
if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
TOKEN_ALL_ACCESS, //__in DWORD DesiredAccess,
&hToken)) //__out PHANDLE TokenHandle
- throw FileError(_("Cannot get process information.") + L" (OpenProcessToken)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"OpenProcessToken", getLastError()));
ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
DWORD bufferSize = 0;
@@ -179,7 +181,7 @@ Zstring getLoginSid() //throw FileError
&buffer[0], //__out_opt LPVOID TokenInformation,
bufferSize, //__in DWORD TokenInformationLength,
&bufferSize)) //__out PDWORD ReturnLength
- throw FileError(_("Cannot get process information.") + L" (GetTokenInformation)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"GetTokenInformation", getLastError()));
auto groups = reinterpret_cast<const TOKEN_GROUPS*>(&buffer[0]);
@@ -189,20 +191,19 @@ Zstring getLoginSid() //throw FileError
LPTSTR sidStr = nullptr;
if (!::ConvertSidToStringSid(groups->Groups[i].Sid, //__in PSID Sid,
&sidStr)) //__out LPTSTR *StringSid
- throw FileError(_("Cannot get process information.") + L" (ConvertSidToStringSid)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"ConvertSidToStringSid", getLastError()));
ZEN_ON_SCOPE_EXIT(::LocalFree(sidStr));
-
return sidStr;
}
- throw FileError(_("Cannot get process information.") + L" (no login found)" + L"\n\n" + getLastErrorFormatted()); //shouldn't happen
+ throw FileError(_("Cannot get process information."), L"no login found"); //shouldn't happen
}
#endif
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
typedef DWORD ProcessId;
typedef DWORD SessionId;
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
typedef pid_t ProcessId;
typedef pid_t SessionId;
#endif
@@ -210,12 +211,12 @@ typedef pid_t SessionId;
//return ppid on Windows, sid on Linux/Mac, "no value" if process corresponding to "processId" is not existing
Opt<SessionId> getSessionId(ProcessId processId) //throw FileError
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//note: ::OpenProcess() is no alternative as it may successfully return for crashed processes! -> remark: "WaitForSingleObject" may identify this case!
HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, //__in DWORD dwFlags,
0); //__in DWORD th32ProcessID
if (snapshot == INVALID_HANDLE_VALUE)
- throw FileError(_("Cannot get process information.") + L" (CreateToolhelp32Snapshot)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"CreateToolhelp32Snapshot", getLastError()));
ZEN_ON_SCOPE_EXIT(::CloseHandle(snapshot));
PROCESSENTRY32 processEntry = {};
@@ -223,7 +224,7 @@ Opt<SessionId> getSessionId(ProcessId processId) //throw FileError
if (!::Process32First(snapshot, //__in HANDLE hSnapshot,
&processEntry)) //__inout LPPROCESSENTRY32 lppe
- throw FileError(_("Cannot get process information.") + L" (Process32First)" + L"\n\n" + getLastErrorFormatted()); //ERROR_NO_MORE_FILES not possible
+ throw FileError(_("Cannot get process information."), formatSystemError(L"Process32First", getLastError())); //ERROR_NO_MORE_FILES not possible
do
{
if (processEntry.th32ProcessID == processId) //yes, MSDN says this is the way: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684868(v=vs.85).aspx
@@ -231,17 +232,17 @@ Opt<SessionId> getSessionId(ProcessId processId) //throw FileError
}
while (::Process32Next(snapshot, &processEntry));
if (::GetLastError() != ERROR_NO_MORE_FILES) //yes, they call it "files"
- throw FileError(_("Cannot get process information.") + L" (Process32Next)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"Process32Next", getLastError()));
return NoValue();
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
if (::kill(processId, 0) != 0) //sig == 0: no signal sent, just existence check
return NoValue();
pid_t procSid = ::getsid(processId); //NOT to be confused with "login session", e.g. not stable on OS X!!!
if (procSid == -1)
- throw FileError(_("Cannot get process information.") + L" (getsid)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"getsid", getLastError()));
return procSid;
#endif
@@ -255,7 +256,7 @@ struct LockInformation //throw FileError
explicit LockInformation(FromCurrentProcess) :
lockId(zen::generateGUID()),
sessionId(), //dummy value
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
processId(::GetCurrentProcessId()) //never fails
{
DWORD bufferSize = 0;
@@ -265,28 +266,29 @@ struct LockInformation //throw FileError
if (!::GetComputerNameEx(ComputerNameDnsFullyQualified, //__in COMPUTER_NAME_FORMAT NameType,
&buffer[0], //__out LPTSTR lpBuffer,
&bufferSize)) //__inout LPDWORD lpnSize
- throw FileError(_("Cannot get process information.") + L" (GetComputerNameEx)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"GetComputerNameEx", getLastError()));
+
computerName = "Windows." + utfCvrtTo<std::string>(&buffer[0]);
bufferSize = UNLEN + 1;
buffer.resize(bufferSize);
if (!::GetUserName(&buffer[0], //__out LPTSTR lpBuffer,
&bufferSize)) //__inout LPDWORD lpnSize
- throw FileError(_("Cannot get process information.") + L" (GetUserName)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"GetUserName", getLastError()));
userId = utfCvrtTo<std::string>(&buffer[0]);
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
processId(::getpid()) //never fails
{
std::vector<char> buffer(10000);
if (::gethostname(&buffer[0], buffer.size()) != 0)
- throw FileError(_("Cannot get process information.") + L" (gethostname)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"gethostname", getLastError()));
computerName += "Linux."; //distinguish linux/windows lock files
computerName += &buffer[0];
if (::getdomainname(&buffer[0], buffer.size()) != 0)
- throw FileError(_("Cannot get process information.") + L" (getdomainname)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"getdomainname", getLastError()));
computerName += ".";
computerName += &buffer[0];
@@ -298,15 +300,15 @@ struct LockInformation //throw FileError
struct passwd buffer2 = {};
struct passwd* pwsEntry = nullptr;
if (::getpwuid_r(userIdNo, &buffer2, &buffer[0], buffer.size(), &pwsEntry) != 0) //getlogin() is deprecated and not working on Ubuntu at all!!!
- throw FileError(_("Cannot get process information.") + L" (getpwuid_r)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), formatSystemError(L"getpwuid_r", getLastError()));
if (!pwsEntry)
- throw FileError(_("Cannot get process information.") + L" (no login found)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), L"no login found"); //should not happen?
userId += pwsEntry->pw_name;
#endif
Opt<SessionId> sessionIdTmp = getSessionId(processId); //throw FileError
if (!sessionIdTmp)
- throw FileError(_("Cannot get process information.") + L" (getSessionId)" + L"\n\n" + getLastErrorFormatted());
+ throw FileError(_("Cannot get process information."), L"no session id found"); //should not happen?
sessionId = *sessionIdTmp;
}
@@ -357,14 +359,6 @@ struct LockInformation //throw FileError
//wxGetFullHostName() is a performance killer for some users, so don't touch!
-void writeLockInfo(const Zstring& lockfilename) //throw FileError
-{
- BinStreamOut streamOut;
- LockInformation(FromCurrentProcess()).toStream(streamOut);
- saveBinStream(lockfilename, streamOut.get()); //throw FileError
-}
-
-
LockInformation retrieveLockInfo(const Zstring& lockfilename) //throw FileError, ErrorNotExisting
{
BinStreamIn streamIn = loadBinStream<BinaryStream>(lockfilename); //throw FileError, ErrorNotExisting
@@ -374,7 +368,7 @@ LockInformation retrieveLockInfo(const Zstring& lockfilename) //throw FileError,
}
catch (UnexpectedEndOfStreamError&)
{
- throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(lockfilename)) + L" (unexpected end of stream)");
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(lockfilename)), L"unexpected end of stream");
}
}
@@ -519,7 +513,7 @@ void releaseLock(const Zstring& lockfilename) //throw ()
bool tryLock(const Zstring& lockfilename) //throw FileError
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
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,
@@ -534,7 +528,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError
lastError == ERROR_ALREADY_EXISTS) //comment on msdn claims, this one is used on Windows Mobile 6
return false;
else
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(lockfilename)) + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(lockfilename)), formatSystemError(L"CreateFile", getLastError()));
}
ScopeGuard guardLockFile = zen::makeGuard([&] { removeFile(lockfilename); });
FileOutput fileOut(fileHandle, lockfilename); //pass handle ownership
@@ -542,7 +536,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError
//be careful to avoid CreateFile() + CREATE_ALWAYS on a hidden file -> see file_io.cpp
//=> we don't need it that badly //::SetFileAttributes(applyLongPathPrefix(lockfilename).c_str(), FILE_ATTRIBUTE_HIDDEN); //(try to) hide it
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
::umask(0); //important! -> why?
//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_CREAT | O_WRONLY | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO);
@@ -551,7 +545,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError
if (errno == EEXIST)
return false;
else
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(lockfilename)) + L"\n\n" + zen::getLastErrorFormatted());
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(lockfilename)), formatSystemError(L"open", getLastError()));
}
ScopeGuard guardLockFile = zen::makeGuard([&] { removeFile(lockfilename); });
FileOutputUnbuffered fileOut(fileHandle, lockfilename); //pass handle ownership
@@ -675,7 +669,7 @@ DirLock::DirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw
if (callback)
callback->reportStatus(replaceCpy(_("Creating file %x"), L"%x", fmtFileName(lockfilename)));
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
const DWORD bufferSize = 10000;
std::vector<wchar_t> volName(bufferSize);
if (::GetVolumePathName(lockfilename.c_str(), //__in LPCTSTR lpszFileName,
diff --git a/lib/ffs_paths.cpp b/lib/ffs_paths.cpp
index 5ee4a3eb..0f01b8d1 100644
--- a/lib/ffs_paths.cpp
+++ b/lib/ffs_paths.cpp
@@ -9,7 +9,7 @@
#include <wx/stdpaths.h>
#include <wx+/string_conv.h>
-#ifdef FFS_MAC
+#ifdef ZEN_MAC
#include <vector>
#include <zen/scope_guard.h>
#include <zen/osx_string.h>
@@ -22,7 +22,7 @@ using namespace zen;
namespace
{
-#if defined FFS_WIN || defined FFS_LINUX
+#if defined ZEN_WIN || defined ZEN_LINUX
inline
Zstring getExecutableDir() //directory containing executable WITH path separator at end
{
@@ -30,7 +30,7 @@ Zstring getExecutableDir() //directory containing executable WITH path separator
}
#endif
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
inline
Zstring getInstallDir() //root install directory WITH path separator at end
{
@@ -39,10 +39,10 @@ Zstring getInstallDir() //root install directory WITH path separator at end
#endif
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
inline
bool isPortableVersion() { return !fileExists(getInstallDir() + L"uninstall.exe"); } //this check is a bit lame...
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
inline
bool isPortableVersion() { return !endsWith(getExecutableDir(), "/bin/"); } //this check is a bit lame...
#endif
@@ -51,9 +51,9 @@ bool isPortableVersion() { return !endsWith(getExecutableDir(), "/bin/"); } //th
bool zen::manualProgramUpdateRequired()
{
-#if defined FFS_WIN || defined FFS_MAC
+#if defined ZEN_WIN || defined ZEN_MAC
return true;
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
return isPortableVersion(); //locally installed version is updated by system
#endif
}
@@ -61,14 +61,14 @@ bool zen::manualProgramUpdateRequired()
Zstring zen::getResourceDir()
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
return getInstallDir();
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
if (isPortableVersion())
return getExecutableDir();
else //use OS' standard paths
return appendSeparator(toZ(wxStandardPathsBase::Get().GetResourcesDir()));
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
return appendSeparator(toZ(wxStandardPathsBase::Get().GetResourcesDir())); //if packaged, used "Contents/Resources", else the executable directory
#endif
}
@@ -76,13 +76,13 @@ Zstring zen::getResourceDir()
Zstring zen::getConfigDir()
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
if (isPortableVersion())
return getInstallDir();
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
if (isPortableVersion())
return getExecutableDir();
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
//portable apps do not seem common on OS - fine with me: http://theocacao.com/document.page/319
#endif
//use OS' standard paths
@@ -102,13 +102,13 @@ Zstring zen::getConfigDir()
//this function is called by RealtimeSync!!!
Zstring zen::getFreeFileSyncLauncher()
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
return getInstallDir() + Zstr("FreeFileSync.exe");
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
return getExecutableDir() + Zstr("FreeFileSync");
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
CFURLRef appURL = nullptr;
ZEN_ON_SCOPE_EXIT(if (appURL) ::CFRelease(appURL));
diff --git a/lib/hard_filter.cpp b/lib/hard_filter.cpp
index bb94b25d..39cb07f6 100644
--- a/lib/hard_filter.cpp
+++ b/lib/hard_filter.cpp
@@ -69,10 +69,10 @@ void addFilterEntry(const Zstring& filtername, std::vector<Zstring>& fileFilter,
{
Zstring filterFormatted = filtername;
-#if defined FFS_WIN || defined FFS_MAC
+#if defined ZEN_WIN || defined ZEN_MAC
//Windows does NOT distinguish between upper/lower-case
makeUpper(filterFormatted);
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
//Linux DOES distinguish between upper/lower-case: nothing to do here
#endif
if (startsWith(filterFormatted, FILE_NAME_SEPARATOR)) // \abc
@@ -289,10 +289,10 @@ NameFilter::NameFilter(const Zstring& includeFilter, const Zstring& excludeFilte
bool NameFilter::passFileFilter(const Zstring& relFilename) const
{
-#if defined FFS_WIN || defined FFS_MAC //Windows does NOT distinguish between upper/lower-case
+#if defined ZEN_WIN || defined ZEN_MAC //Windows does NOT distinguish between upper/lower-case
Zstring nameFormatted = relFilename;
makeUpper(nameFormatted);
-#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case
+#elif defined ZEN_LINUX //Linux DOES distinguish between upper/lower-case
const Zstring& nameFormatted = relFilename; //nothing to do here
#endif
@@ -305,10 +305,10 @@ bool NameFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch
{
assert(!subObjMightMatch || *subObjMightMatch == true); //check correct usage
-#if defined FFS_WIN || defined FFS_MAC //Windows does NOT distinguish between upper/lower-case
+#if defined ZEN_WIN || defined ZEN_MAC //Windows does NOT distinguish between upper/lower-case
Zstring nameFormatted = relDirname;
makeUpper(nameFormatted);
-#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case
+#elif defined ZEN_LINUX //Linux DOES distinguish between upper/lower-case
const Zstring& nameFormatted = relDirname; //nothing to do here
#endif
diff --git a/lib/help_provider.h b/lib/help_provider.h
index 040eb33c..8ddc34c7 100644
--- a/lib/help_provider.h
+++ b/lib/help_provider.h
@@ -7,11 +7,11 @@
#ifndef HELPPROVIDER_H_INCLUDED
#define HELPPROVIDER_H_INCLUDED
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
#include <zen/zstring.h>
#include <wx/msw/helpchm.h>
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
#include <wx/html/helpctrl.h>
#endif
@@ -35,7 +35,7 @@ void displayHelpEntry(const wxString& section, wxWindow* parent);
namespace impl
{
//finish wxWidgets' job
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
class FfsHelpController
{
public:
@@ -55,7 +55,7 @@ private:
wxCHMHelpController chmHlp;
};
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
class FfsHelpController
{
public:
diff --git a/lib/icon_buffer.cpp b/lib/icon_buffer.cpp
index 04364b32..cf916174 100644
--- a/lib/icon_buffer.cpp
+++ b/lib/icon_buffer.cpp
@@ -10,16 +10,16 @@
#include <zen/thread.h> //includes <boost/thread.hpp>
#include <zen/scope_guard.h>
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
#include <zen/dll.h>
#include <zen/win_ver.h>
#include <wx/image.h>
#include "Thumbnail/thumbnail.h"
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
#include <gtk/gtk.h>
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
#include "osx_file_icon.h"
#endif
@@ -34,7 +34,7 @@ const size_t BUFFER_SIZE_MAX = 600; //maximum number of icons to hold in buffer
boost::thread::id mainThreadId = boost::this_thread::get_id();
#endif
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
const bool isXpOrLater = winXpOrLater(); //VS2010 compiled DLLs are not supported on Win 2000: Popup dialog "DecodePointer not found"
#define DEF_DLL_FUN(name) const auto name = isXpOrLater ? DllFun<thumb::FunType_##name>(thumb::getDllName(), thumb::funName_##name) : DllFun<thumb::FunType_##name>();
@@ -46,11 +46,11 @@ DEF_DLL_FUN(releaseImageData); //
class IconHolder //handle HICON/GdkPixbuf ownership supporting thread-safe usage (in contrast to wxIcon/wxBitmap)
{
public:
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
typedef const thumb::ImageData* HandleType;
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
typedef GdkPixbuf* HandleType;
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
typedef osx::ImageData* HandleType;
#endif
@@ -67,11 +67,11 @@ public:
~IconHolder()
{
if (handle_ != nullptr)
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
releaseImageData(handle_); //should be checked already before creating IconHolder!
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
::g_object_unref(handle_); //superseedes "::gdk_pixbuf_unref"!
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
delete handle_;
#endif
}
@@ -93,7 +93,7 @@ public:
if (!handle_)
return wxNullBitmap;
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
ZEN_ON_SCOPE_EXIT(IconHolder().swap(*this)); //destroy after extraction
//let wxImage reference data without taking ownership:
@@ -101,7 +101,7 @@ public:
fileIcon.SetAlpha(handle_->alpha, true);
return wxBitmap(fileIcon);
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
#if wxCHECK_VERSION(2, 9, 4)
return wxBitmap(release()); //ownership passed!
#else
@@ -110,7 +110,7 @@ public:
return newIcon;
#endif
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
ZEN_ON_SCOPE_EXIT(IconHolder().swap(*this)); //destroy after extraction
//let wxImage reference data without taking ownership:
@@ -137,7 +137,7 @@ public:
};
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
Zstring getFileExtension(const Zstring& filename)
{
const Zstring shortName = afterLast(filename, Zchar('\\')); //warning: using windows file name separator!
@@ -217,7 +217,7 @@ IconHolder getAssociatedIconByExt(const Zstring& extension, IconBuffer::IconSize
return getIconByAttribute((L"dummy." + extension).c_str(), FILE_ATTRIBUTE_NORMAL, sz);
}
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
IconHolder iconHolderFromGicon(GIcon* gicon, IconBuffer::IconSize sz)
{
if (gicon)
@@ -237,11 +237,11 @@ IconHolder iconHolderFromGicon(GIcon* gicon, IconBuffer::IconSize sz)
IconHolder getThumbnailIcon(const Zstring& filename, int requestedSize) //return 0 on failure
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
if (getThumbnail && releaseImageData)
return IconHolder(getThumbnail(filename.c_str(), requestedSize));
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
gint width = 0;
gint height = 0;
if (GdkPixbufFormat* fmt = ::gdk_pixbuf_get_file_info(filename.c_str(), &width, &height))
@@ -263,12 +263,12 @@ IconHolder getThumbnailIcon(const Zstring& filename, int requestedSize) //return
}
}
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
try
{
- return IconHolder(new osx::ImageData(osx::getThumbnail(filename.c_str(), requestedSize))); //throw OsxError
+ return IconHolder(new osx::ImageData(osx::getThumbnail(filename.c_str(), requestedSize))); //throw SysError
}
- catch (osx::OsxError&) {}
+ catch (zen::SysError&) {}
#endif
return IconHolder();
}
@@ -277,10 +277,10 @@ IconHolder getThumbnailIcon(const Zstring& filename, int requestedSize) //return
IconHolder getGenericFileIcon(IconBuffer::IconSize sz)
{
//we're called by getAssociatedIcon()! -> avoid endless recursion!
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
return getIconByAttribute(L"dummy", FILE_ATTRIBUTE_NORMAL, sz);
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
const char* mimeFileIcons[] =
{
"application-x-zerosize", //Kubuntu: /usr/share/icons/oxygen/48x48/mimetypes
@@ -296,12 +296,12 @@ IconHolder getGenericFileIcon(IconBuffer::IconSize sz)
return IconHolder(pixBuf); //pass ownership
return IconHolder();
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
try
{
- return IconHolder(new osx::ImageData(osx::getDefaultFileIcon(IconBuffer::getSize(sz)))); //throw OsxError
+ return IconHolder(new osx::ImageData(osx::getDefaultFileIcon(IconBuffer::getSize(sz)))); //throw SysError
}
- catch (osx::OsxError&) {}
+ catch (zen::SysError&) {}
return IconHolder();
#endif
}
@@ -309,20 +309,20 @@ IconHolder getGenericFileIcon(IconBuffer::IconSize sz)
IconHolder getGenericDirectoryIcon(IconBuffer::IconSize sz)
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
return getIconByAttribute(L"dummy", //Windows 7 doesn't like this parameter to be an empty string!
FILE_ATTRIBUTE_DIRECTORY, sz);
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
if (GIcon* dirIcon = ::g_content_type_get_icon("inode/directory")) //should contain fallback to GTK_STOCK_DIRECTORY ("gtk-directory")
return iconHolderFromGicon(dirIcon, sz);
return IconHolder();
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
try
{
- return IconHolder(new osx::ImageData(osx::getDefaultFolderIcon(IconBuffer::getSize(sz)))); //throw OsxError
+ return IconHolder(new osx::ImageData(osx::getDefaultFolderIcon(IconBuffer::getSize(sz)))); //throw SysError
}
- catch (osx::OsxError&) { return IconHolder(); }
+ catch (zen::SysError&) { return IconHolder(); }
#endif
}
@@ -345,7 +345,7 @@ IconHolder getAssociatedIcon(const Zstring& filename, IconBuffer::IconSize sz)
warn_static("problem: für folder links ist getThumbnail erfolgreich => SFGAO_LINK nicht gecheckt!")
//2. retrieve file icons
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//perf: optimize fallback case for SIZE_MEDIUM and SIZE_LARGE:
const Zstring& extension = getFileExtension(filename);
if (isCheapExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
@@ -381,7 +381,7 @@ IconHolder getAssociatedIcon(const Zstring& filename, IconBuffer::IconSize sz)
return IconHolder(imgData);
}
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
GFile* file = ::g_file_new_for_path(filename.c_str()); //documented to "never fail"
ZEN_ON_SCOPE_EXIT(::g_object_unref(file);)
@@ -393,12 +393,12 @@ IconHolder getAssociatedIcon(const Zstring& filename, IconBuffer::IconSize sz)
}
//need fallback: icon lookup may fail because some icons are currently not present on system
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
try
{
- return IconHolder(new osx::ImageData(osx::getFileIcon(filename.c_str(), IconBuffer::getSize(sz)))); //throw OsxError
+ return IconHolder(new osx::ImageData(osx::getFileIcon(filename.c_str(), IconBuffer::getSize(sz)))); //throw SysError
}
- catch (osx::OsxError&) {}
+ catch (zen::SysError&) {}
#endif
return ::getGenericFileIcon(sz); //make sure this does not internally call getAssociatedIcon("someDefaultFile.txt")!!! => endless recursion!
}
@@ -548,7 +548,7 @@ private:
void WorkerThread::operator()() //thread entry
{
//failure to initialize COM for each thread is a source of hard to reproduce bugs: https://sourceforge.net/tracker/?func=detail&aid=3160472&group_id=234430&atid=1093080
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//Prerequisites, see thumbnail.h
//1. Initialize COM
@@ -611,13 +611,13 @@ int IconBuffer::getSize(IconSize icoSize)
switch (icoSize)
{
case IconBuffer::SIZE_SMALL:
-#if defined FFS_WIN || defined FFS_MAC
+#if defined ZEN_WIN || defined ZEN_MAC
return 16;
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
return 24;
#endif
case IconBuffer::SIZE_MEDIUM:
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
if (!wereVistaOrLater) return 32; //48x48 doesn't look sharp on XP
#endif
return 48;
@@ -632,7 +632,7 @@ int IconBuffer::getSize(IconSize icoSize)
bool IconBuffer::readyForRetrieval(const Zstring& filename)
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
if (iconSizeType == IconBuffer::SIZE_SMALL)
if (isCheapExtension(getFileExtension(filename)))
return true;
@@ -643,7 +643,7 @@ bool IconBuffer::readyForRetrieval(const Zstring& filename)
Opt<wxBitmap> IconBuffer::retrieveFileIcon(const Zstring& filename)
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//perf: let's read icons which don't need file access right away! No async delay justified!
if (iconSizeType == IconBuffer::SIZE_SMALL) //non-thumbnail view, we need file type icons only!
{
diff --git a/lib/localization.cpp b/lib/localization.cpp
index f050e255..5526cdce 100644
--- a/lib/localization.cpp
+++ b/lib/localization.cpp
@@ -10,18 +10,19 @@
#include <iterator>
#include <zen/string_tools.h>
#include <zen/file_traverser.h>
-#include <zenxml/io.h>
+#include <zen/serialize.h>
#include <zen/i18n.h>
#include <zen/format_unit.h>
#include <wx/intl.h>
+#include <wx/log.h>
#include "parse_plural.h"
#include "parse_lng.h"
#include "ffs_paths.h"
-#ifdef FFS_LINUX
+#ifdef ZEN_LINUX
#include <wchar.h> //wcscasecmp
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
#include <CoreServices/CoreServices.h>
#endif
@@ -33,7 +34,7 @@ namespace
class FFSTranslation : public TranslationHandler
{
public:
- FFSTranslation(const std::wstring& filename, wxLanguage languageId); //throw lngfile::ParsingError, parse_plural::ParsingError
+ FFSTranslation(const Zstring& filename, wxLanguage languageId); //throw lngfile::ParsingError, parse_plural::ParsingError
wxLanguage langId() const { return langId_; }
@@ -69,16 +70,16 @@ private:
};
-FFSTranslation::FFSTranslation(const std::wstring& filename, wxLanguage languageId) : langId_(languageId) //throw lngfile::ParsingError, parse_plural::ParsingError
+FFSTranslation::FFSTranslation(const Zstring& filename, wxLanguage languageId) : langId_(languageId) //throw lngfile::ParsingError, parse_plural::ParsingError
{
std::string inputStream;
try
{
- inputStream = loadStream(filename); //throw XmlFileError
+ inputStream = loadBinStream<std::string>(filename); //throw FileError
}
- catch (const XmlFileError&)
+ catch (const FileError& e)
{
- throw lngfile::ParsingError(0, 0);
+ throw lngfile::ParsingError(e.toString(), 0, 0); //passing FileError is too high a level for Parsing error, OTOH user is unlikely to see this since file I/O issues are sorted out by ExistingTranslations()!
}
lngfile::TransHeader header;
@@ -122,7 +123,7 @@ public:
}
virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { return LINK_SKIP; }
- virtual std::shared_ptr<TraverseCallback> onDir(const Zchar* shortName, const Zstring& fullName) { return nullptr; }
+ virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName) { return nullptr; }
virtual HandleError reportDirError (const std::wstring& msg) { assert(false); return ON_ERROR_IGNORE; } //errors are not really critical in this context
virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName) { assert(false); return ON_ERROR_IGNORE; } //
@@ -136,7 +137,7 @@ struct LessTranslation : public std::binary_function<ExistingTranslations::Entry
bool operator()(const ExistingTranslations::Entry& lhs, const ExistingTranslations::Entry& rhs) const
{
//use a more "natural" sort: ignore case and diacritics
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
const int rv = ::CompareString(LOCALE_USER_DEFAULT, //__in LCID Locale,
NORM_IGNORECASE, //__in DWORD dwCmpFlags,
lhs.languageName.c_str(), //__in LPCTSTR lpString1,
@@ -148,11 +149,11 @@ struct LessTranslation : public std::binary_function<ExistingTranslations::Entry
else
return rv == CSTR_LESS_THAN; //convert to C-style string compare result
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
return ::wcscasecmp(lhs.languageName.c_str(), rhs.languageName.c_str()) < 0; //ignores case; locale-dependent!
//return lhs.languageName.CmpNoCase(rhs.languageName) < 0;
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
auto allocCFStringRef = [](const std::wstring& str) -> CFStringRef //output not owned!
{
return ::CFStringCreateWithCString(nullptr, //CFAllocatorRef alloc,
@@ -182,7 +183,7 @@ ExistingTranslations::ExistingTranslations()
newEntry.languageName = L"English (US)";
newEntry.languageFile = L"";
newEntry.translatorName = L"Zenju";
- newEntry.languageFlag = L"usa.png";
+ newEntry.languageFlag = L"flag_usa.png";
locMapping.push_back(newEntry);
}
@@ -196,30 +197,33 @@ ExistingTranslations::ExistingTranslations()
for (auto it = lngFiles.begin(); it != lngFiles.end(); ++it)
try
{
- std::string stream = loadStream(*it); //throw XmlFileError
- try
+ const std::string stream = loadBinStream<std::string>(utfCvrtTo<Zstring>(*it)); //throw FileError
+
+ lngfile::TransHeader lngHeader;
+ lngfile::parseHeader(stream, lngHeader); //throw ParsingError
+
+ assert(!lngHeader.languageName .empty());
+ assert(!lngHeader.translatorName.empty());
+ assert(!lngHeader.localeName .empty());
+ assert(!lngHeader.flagFile .empty());
+ /*
+ 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.
+ */
+ if (const wxLanguageInfo* locInfo = wxLocale::FindLanguageInfo(utfCvrtTo<wxString>(lngHeader.localeName)))
{
- lngfile::TransHeader lngHeader;
- lngfile::parseHeader(stream, lngHeader); //throw ParsingError
-
- /*
- 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.
- */
- if (const wxLanguageInfo* locInfo = wxLocale::FindLanguageInfo(utfCvrtTo<wxString>(lngHeader.localeName)))
- {
- ExistingTranslations::Entry newEntry;
- newEntry.languageID = locInfo->Language;
- newEntry.languageName = utfCvrtTo<std::wstring>(lngHeader.languageName);
- newEntry.languageFile = utfCvrtTo<std::wstring>(*it);
- newEntry.translatorName = utfCvrtTo<std::wstring>(lngHeader.translatorName);
- newEntry.languageFlag = utfCvrtTo<std::wstring>(lngHeader.flagFile);
- locMapping.push_back(newEntry);
- }
+ ExistingTranslations::Entry newEntry;
+ newEntry.languageID = locInfo->Language;
+ newEntry.languageName = utfCvrtTo<std::wstring>(lngHeader.languageName);
+ newEntry.languageFile = utfCvrtTo<std::wstring>(*it);
+ newEntry.translatorName = utfCvrtTo<std::wstring>(lngHeader.translatorName);
+ newEntry.languageFlag = utfCvrtTo<std::wstring>(lngHeader.flagFile);
+ locMapping.push_back(newEntry);
}
- catch (lngfile::ParsingError&) { assert(false); } //better not show an error message here; scenario: batch jobs
+ else assert(false);
}
- catch (...) { assert(false); }
+ catch (FileError&) { assert(false); }
+ catch (lngfile::ParsingError&) { assert(false); } //better not show an error message here; scenario: batch jobs
std::sort(locMapping.begin(), locMapping.end(), LessTranslation());
}
@@ -397,6 +401,9 @@ public:
const bool sysLangIsRTL = sysLngInfo ? sysLngInfo->LayoutDirection == wxLayout_RightToLeft : false;
const bool selectedLangIsRTL = selLngInfo ? selLngInfo->LayoutDirection == wxLayout_RightToLeft : false;
+#ifdef NDEBUG
+ wxLogNull dummy; //rather than implementing a reasonable error handling wxWidgets decides to shows a modal dialog in wxLocale::Init -> at least we can shut it up!
+#endif
if (sysLangIsRTL == selectedLangIsRTL)
locale->Init(wxLANGUAGE_DEFAULT); //use sys-lang to preserve sub-language specific rules (e.g. german swiss number punctation)
else
@@ -444,18 +451,19 @@ void zen::setLanguage(int language) //throw FileError
else
try
{
- zen::setTranslator(new FFSTranslation(languageFile, static_cast<wxLanguage>(language))); //throw lngfile::ParsingError, parse_plural::ParsingError
+ zen::setTranslator(new FFSTranslation(utfCvrtTo<Zstring>(languageFile), static_cast<wxLanguage>(language))); //throw lngfile::ParsingError, parse_plural::ParsingError
}
catch (lngfile::ParsingError& e)
{
throw FileError(replaceCpy(replaceCpy(replaceCpy(_("Error parsing file %x, row %y, column %z."),
L"%x", fmtFileName(utfCvrtTo<Zstring>(languageFile))),
- L"%y", numberTo<std::wstring>(e.row + 1)),
- L"%z", numberTo<std::wstring>(e.col + 1)));
+ L"%y", numberTo<std::wstring>(e.row_ + 1)),
+ L"%z", numberTo<std::wstring>(e.col_ + 1))
+ + L"\n\n" + e.msg_);
}
catch (parse_plural::ParsingError&)
{
- throw FileError(L"Invalid Plural Form");
+ throw FileError(L"Invalid plural form definition"); //user should never see this!
}
//handle RTL swapping: we need wxWidgets to do this
diff --git a/lib/osx_file_icon.h b/lib/osx_file_icon.h
index e9b17988..5edfd740 100644
--- a/lib/osx_file_icon.h
+++ b/lib/osx_file_icon.h
@@ -8,7 +8,7 @@
#define OSX_FILE_ICON_8427508422345342
#include <vector>
-#include <zen/osx_error.h>
+#include <zen/sys_error.h>
namespace osx
{
@@ -27,10 +27,10 @@ private:
ImageData& operator=(const ImageData&);
};
-ImageData getThumbnail(const char* filename, int requestedSize); //throw OsxError
-ImageData getFileIcon (const char* filename, int requestedSize); //throw OsxError
-ImageData getDefaultFileIcon (int requestedSize); //throw OsxError
-ImageData getDefaultFolderIcon(int requestedSize); //throw OsxError
+ImageData getThumbnail(const char* filename, int requestedSize); //throw SysError
+ImageData getFileIcon (const char* filename, int requestedSize); //throw SysError
+ImageData getDefaultFileIcon (int requestedSize); //throw SysError
+ImageData getDefaultFolderIcon(int requestedSize); //throw SysError
}
#endif //OSX_FILE_ICON_8427508422345342
diff --git a/lib/osx_file_icon.mm b/lib/osx_file_icon.mm
index 11fb053f..4db6642a 100644
--- a/lib/osx_file_icon.mm
+++ b/lib/osx_file_icon.mm
@@ -11,7 +11,7 @@
namespace
{
-osx::ImageData extractBytes(NSImage* nsImg, int requestedSize) //throw OsxError; NSException?
+osx::ImageData extractBytes(NSImage* nsImg, int requestedSize) //throw SysError; NSException?
{
/*
wxBitmap(NSImage*) is not good enough: it calls "[NSBitmapImageRep imageRepWithData:[img TIFFRepresentation]]"
@@ -93,53 +93,53 @@ osx::ImageData extractBytes(NSImage* nsImg, int requestedSize) //throw OsxError;
}
-osx::ImageData osx::getThumbnail(const char* filename, int requestedSize) //throw OsxError
+osx::ImageData osx::getThumbnail(const char* filename, int requestedSize) //throw SysError
{
@try
{
@autoreleasepool
{
NSString* nsFile = [NSString stringWithCString:filename encoding:NSUTF8StringEncoding];
- ZEN_OSX_ASSERT(nsFile != nil); //throw OsxError; can this fail? not documented
+ ZEN_OSX_ASSERT(nsFile != nil); //throw SysError; can this fail? not documented
//stringWithCString returns string which is already set to autorelease!
NSImage* nsImg = [[[NSImage alloc] initWithContentsOfFile:nsFile] autorelease];
ZEN_OSX_ASSERT(nsImg != nil); //may fail
- return extractBytes(nsImg, requestedSize); //throw OsxError
+ return extractBytes(nsImg, requestedSize); //throw SysError
}
}
- @catch (NSException* e)
+ @catch(NSException* e)
{
- throwOsxError(e); //throw OsxError
+ throwSysError(e); //throw SysError
}
}
-osx::ImageData osx::getFileIcon(const char* filename, int requestedSize) //throw OsxError
+osx::ImageData osx::getFileIcon(const char* filename, int requestedSize) //throw SysError
{
@try
{
@autoreleasepool
{
NSString* nsFile = [NSString stringWithCString:filename encoding:NSUTF8StringEncoding];
- ZEN_OSX_ASSERT(nsFile != nil); //throw OsxError; can this fail? not documented
+ ZEN_OSX_ASSERT(nsFile != nil); //throw SysError; can this fail? not documented
//stringWithCString returns string which is already set to autorelease!
NSImage* nsImg = [[NSWorkspace sharedWorkspace] iconForFile:nsFile];
ZEN_OSX_ASSERT(nsImg != nil); //can this fail? not documented
- return extractBytes(nsImg, requestedSize); //throw OsxError
+ return extractBytes(nsImg, requestedSize); //throw SysError
}
}
@catch (NSException* e)
{
- throwOsxError(e); //throw OsxError
+ throwSysError(e); //throw SysError
}
}
-osx::ImageData osx::getDefaultFileIcon(int requestedSize) //throw OsxError
+osx::ImageData osx::getDefaultFileIcon(int requestedSize) //throw SysError
{
@try
{
@@ -149,17 +149,17 @@ osx::ImageData osx::getDefaultFileIcon(int requestedSize) //throw OsxError
//NSImage* nsImg = [[NSWorkspace sharedWorkspace] iconForFileType:@"dat"];
ZEN_OSX_ASSERT(nsImg != nil); //can this fail? not documented
- return extractBytes(nsImg, requestedSize); //throw OsxError
+ return extractBytes(nsImg, requestedSize); //throw SysError
}
}
@catch (NSException* e)
{
- throwOsxError(e); //throw OsxError
+ throwSysError(e); //throw SysError
}
}
-osx::ImageData osx::getDefaultFolderIcon(int requestedSize) //throw OsxError
+osx::ImageData osx::getDefaultFolderIcon(int requestedSize) //throw SysError
{
@try
{
@@ -169,11 +169,11 @@ osx::ImageData osx::getDefaultFolderIcon(int requestedSize) //throw OsxError
//NSImage* nsImg = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericFolderIcon)];
ZEN_OSX_ASSERT(nsImg != nil); //may fail
- return extractBytes(nsImg, requestedSize); //throw OsxError
+ return extractBytes(nsImg, requestedSize); //throw SysError
}
}
@catch (NSException* e)
{
- throwOsxError(e); //throw OsxError
+ throwSysError(e); //throw SysError
}
}
diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp
index 33d8174f..df8ff095 100644
--- a/lib/parallel_scan.cpp
+++ b/lib/parallel_scan.cpp
@@ -20,7 +20,7 @@ using namespace zen;
namespace
{
/*
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
struct DiskInfo
{
@@ -288,7 +288,7 @@ public:
handleSymlinks_(handleSymlinks),
filterInstance(filter),
failedDirReads_(failedDirReads),
- failedItemReads_(failedItemReads),
+ failedItemReads_(failedItemReads),
acb_(acb),
threadID_(threadID) {}
@@ -296,7 +296,7 @@ public:
const HardFilter::FilterRef filterInstance; //always bound!
std::set<Zstring>& failedDirReads_;
- std::set<Zstring>& failedItemReads_;
+ std::set<Zstring>& failedItemReads_;
AsyncCallback& acb_;
const long threadID_;
@@ -313,10 +313,11 @@ public:
relNameParentPf_(relNameParentPf),
output_(output) {}
- virtual std::shared_ptr<TraverseCallback>
- onDir (const Zchar* shortName, const Zstring& fullName);
virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details);
virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details);
+ virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName);
+ virtual void releaseDirTraverser(TraverseCallback* trav);
+
virtual HandleError reportDirError (const std::wstring& msg);
virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName);
@@ -357,7 +358,7 @@ void DirCallback::onFile(const Zchar* shortName, const Zstring& fullName, const
Linux: retrieveFileID takes about 50% longer in VM! (avoidable because of redundant stat() call!)
*/
- output_.addSubFile(fileNameShort, FileDescriptor(details.lastWriteTime, details.fileSize, details.id));
+ output_.addSubFile(fileNameShort, FileDescriptor(details.lastWriteTime, details.fileSize, details.id, details.symlinkInfo != nullptr));
cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator
}
@@ -398,7 +399,7 @@ DirCallback::HandleLink DirCallback::onSymlink(const Zchar* shortName, const Zst
}
-std::shared_ptr<TraverseCallback> DirCallback::onDir(const Zchar* shortName, const Zstring& fullName)
+TraverseCallback* DirCallback::onDir(const Zchar* shortName, const Zstring& fullName)
{
boost::this_thread::interruption_point();
@@ -419,7 +420,14 @@ std::shared_ptr<TraverseCallback> DirCallback::onDir(const Zchar* shortName, con
if (passFilter)
cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator
- return std::make_shared<DirCallback>(cfg, relName + FILE_NAME_SEPARATOR, subDir);
+ return new DirCallback(cfg, relName + FILE_NAME_SEPARATOR, subDir); //releaseDirTraverser() is guaranteed to be called in any case
+}
+
+
+void DirCallback::releaseDirTraverser(TraverseCallback* trav)
+{
+ TraverseCallback::releaseDirTraverser(trav); //no-op, introduce compile-time coupling
+ delete trav;
}
@@ -428,7 +436,7 @@ DirCallback::HandleError DirCallback::reportDirError(const std::wstring& msg)
switch (cfg.acb_.reportError(msg))
{
case FillBufferCallback::ON_ERROR_IGNORE:
- cfg.failedDirReads_.insert(relNameParentPf_);
+ cfg.failedDirReads_.insert(relNameParentPf_);
return ON_ERROR_IGNORE;
case FillBufferCallback::ON_ERROR_RETRY:
@@ -444,7 +452,7 @@ DirCallback::HandleError DirCallback::reportItemError(const std::wstring& msg, c
switch (cfg.acb_.reportError(msg))
{
case FillBufferCallback::ON_ERROR_IGNORE:
- cfg.failedItemReads_.insert(relNameParentPf_ + shortName);
+ cfg.failedItemReads_.insert(relNameParentPf_ + shortName);
return ON_ERROR_IGNORE;
case FillBufferCallback::ON_ERROR_RETRY:
@@ -455,7 +463,7 @@ DirCallback::HandleError DirCallback::reportItemError(const std::wstring& msg, c
}
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
class DstHackCallbackImpl : public DstHackCallback
{
public:
@@ -501,7 +509,7 @@ public:
dirKey_.handleSymlinks_, //shared by all(!) instances of DirCallback while traversing a folder hierarchy
dirKey_.filter_,
dirOutput_.failedDirReads,
- dirOutput_.failedItemReads,
+ dirOutput_.failedItemReads,
*acb_);
DirCallback traverser(travCfg,
@@ -509,7 +517,7 @@ public:
dirOutput_.dirCont);
DstHackCallback* dstCallbackPtr = nullptr;
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
DstHackCallbackImpl dstCallback(*acb_, threadID_);
dstCallbackPtr = &dstCallback;
#endif
diff --git a/lib/parallel_scan.h b/lib/parallel_scan.h
index b7518428..c3806373 100644
--- a/lib/parallel_scan.h
+++ b/lib/parallel_scan.h
@@ -47,7 +47,7 @@ struct DirectoryValue
{
DirContainer dirCont;
std::set<Zstring> failedDirReads; //relative postfixed names (or empty string for root) for directories that could not be read (completely), e.g. access denied, or temporal network drop
- std::set<Zstring> failedItemReads; //relative postfixed names (never empty) for failure to read single file/dir/symlink
+ std::set<Zstring> failedItemReads; //relative postfixed names (never empty) for failure to read single file/dir/symlink
};
diff --git a/lib/parse_lng.h b/lib/parse_lng.h
index 48c7044b..8cd8e943 100644
--- a/lib/parse_lng.h
+++ b/lib/parse_lng.h
@@ -10,7 +10,6 @@
#include <algorithm>
#include <cctype>
#include <functional>
-//#include <list>
#include <memory>
#include <map>
#include <set>
@@ -18,6 +17,7 @@
#include <stdexcept>
#include <string>
#include <vector>
+#include <list>
#include <zen/utf.h>
#include <zen/string_tools.h>
#include "parse_plural.h"
@@ -47,15 +47,16 @@ struct TransHeader
struct ParsingError
{
- ParsingError(size_t rowNo, size_t colNo) : row(rowNo), col(colNo) {}
- size_t row; //starting with 0
- size_t col; //
+ ParsingError(const std::wstring& msg, size_t row, size_t col) : msg_(msg), row_(row), col_(col) {}
+ std::wstring msg_; //parser error message
+ size_t row_; //starting with 0
+ size_t col_; //
};
void parseLng(const std::string& fileStream, TransHeader& header, TranslationMap& out, TranslationPluralMap& pluralOut); //throw ParsingError
void parseHeader(const std::string& fileStream, TransHeader& header); //throw ParsingError
-class TranslationList; //unordered list of unique translation items
-std::string generateLng(const TranslationList& in, const TransHeader& header);
+class TranslationUnorderedList; //unordered list of unique translation items
+std::string generateLng(const TranslationUnorderedList& in, const TransHeader& header);
@@ -76,45 +77,56 @@ std::string generateLng(const TranslationList& in, const TransHeader& header);
//--------------------------- implementation ---------------------------
-class TranslationList //unordered list of unique translation items
+class TranslationUnorderedList //unordered list of unique translation items
{
public:
- void addItem(const std::string& orig, const std::string& trans)
+ TranslationUnorderedList(TranslationMap&& transOld, TranslationPluralMap&& transPluralOld) : transOld_(std::move(transOld)), transPluralOld_(std::move(transPluralOld)) {}
+
+ void addItem(const std::string& orig)
{
if (!transUnique.insert(orig).second) return;
- sequence.push_back(std::make_shared<RegularItem>(std::make_pair(orig, trans)));
+ auto it = transOld_.find(orig);
+ if (it != transOld_.end() && !it->second.empty()) //preserve old translation from .lng file if existing
+ sequence.push_back(std::make_shared<RegularItem>(std::make_pair(orig, it->second)));
+ else
+ sequence.push_front(std::make_shared<RegularItem>(std::make_pair(orig, std::string()))); //put untranslated items to the front of the .lng file
}
- void addPluralItem(const SingularPluralPair& orig, const PluralForms& trans)
+
+ void addItem(const SingularPluralPair& orig)
{
if (!pluralUnique.insert(orig).second) return;
- sequence.push_back(std::make_shared<PluralItem>(std::make_pair(orig, trans)));
+ auto it = transPluralOld_.find(orig);
+ if (it != transPluralOld_.end() && !it->second.empty()) //preserve old translation from .lng file if existing
+ sequence.push_back(std::make_shared<PluralItem>(std::make_pair(orig, it->second)));
+ else
+ sequence.push_front(std::make_shared<PluralItem>(std::make_pair(orig, PluralForms()))); //put untranslated items to the front of the .lng file
}
- bool untranslatedTextExists() const
+ bool untranslatedTextExists() const { return std::any_of(sequence.begin(), sequence.end(), [](const std::shared_ptr<Item>& item) { return !item->hasTranslation(); }); }
+
+ template <class Function, class Function2>
+ void visitItems(Function onTrans, Function2 onPluralTrans) const //onTrans takes (const TranslationMap::value_type&), onPluralTrans takes (const TranslationPluralMap::value_type&)
{
for (auto it = sequence.begin(); it != sequence.end(); ++it)
- if (const TranslationList::RegularItem* regular = dynamic_cast<const TranslationList::RegularItem*>(it->get()))
- {
- if (regular->value.second.empty())
- return true;
- }
- else if (const TranslationList::PluralItem* plural = dynamic_cast<const TranslationList::PluralItem* >(it->get()))
- if (plural->value.second.empty())
- return true;
- return false;
+ if (auto regular = dynamic_cast<const RegularItem*>(it->get()))
+ onTrans(regular->value);
+ else if (auto plural = dynamic_cast<const PluralItem*>(it->get()))
+ onPluralTrans(plural->value);
+ else assert(false);
}
private:
- friend std::string generateLng(const TranslationList& in, const TransHeader& header);
+ struct Item { virtual ~Item() {} virtual bool hasTranslation() const = 0; };
+ struct RegularItem : public Item { RegularItem(const TranslationMap ::value_type& val) : value(val) {} virtual bool hasTranslation() const { return !value.second.empty(); } TranslationMap ::value_type value; };
+ struct PluralItem : public Item { PluralItem (const TranslationPluralMap::value_type& val) : value(val) {} virtual bool hasTranslation() const { return !value.second.empty(); } TranslationPluralMap::value_type value; };
- struct Item { virtual ~Item() {} };
- struct RegularItem : public Item { RegularItem(const TranslationMap ::value_type& val) : value(val) {} TranslationMap ::value_type value; };
- struct PluralItem : public Item { PluralItem (const TranslationPluralMap::value_type& val) : value(val) {} TranslationPluralMap::value_type value; };
-
- std::vector<std::shared_ptr<Item>> sequence; //ordered list of translation elements
+ std::list<std::shared_ptr<Item>> sequence; //ordered list of translation elements
std::set<TranslationMap ::key_type> transUnique; //check uniqueness
std::set<TranslationPluralMap::key_type> pluralUnique; //
+
+ const TranslationMap transOld_; //reuse existing translation
+ const TranslationPluralMap transPluralOld_; //
};
@@ -179,18 +191,18 @@ private:
//header information
tokens.insert(std::make_pair(Token::TK_HEADER_BEGIN, "<header>"));
tokens.insert(std::make_pair(Token::TK_HEADER_END, "</header>"));
- tokens.insert(std::make_pair(Token::TK_LANG_NAME_BEGIN, "<language name>"));
- tokens.insert(std::make_pair(Token::TK_LANG_NAME_END, "</language name>"));
+ tokens.insert(std::make_pair(Token::TK_LANG_NAME_BEGIN, "<language>"));
+ tokens.insert(std::make_pair(Token::TK_LANG_NAME_END, "</language>"));
tokens.insert(std::make_pair(Token::TK_TRANS_NAME_BEGIN, "<translator>"));
tokens.insert(std::make_pair(Token::TK_TRANS_NAME_END, "</translator>"));
tokens.insert(std::make_pair(Token::TK_LOCALE_NAME_BEGIN, "<locale>"));
tokens.insert(std::make_pair(Token::TK_LOCALE_NAME_END, "</locale>"));
- tokens.insert(std::make_pair(Token::TK_FLAG_FILE_BEGIN, "<flag file>"));
- tokens.insert(std::make_pair(Token::TK_FLAG_FILE_END, "</flag file>"));
- tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_BEGIN, "<plural forms>"));
- tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_END, "</plural forms>"));
- tokens.insert(std::make_pair(Token::TK_PLURAL_DEF_BEGIN, "<plural definition>"));
- tokens.insert(std::make_pair(Token::TK_PLURAL_DEF_END, "</plural definition>"));
+ tokens.insert(std::make_pair(Token::TK_FLAG_FILE_BEGIN, "<flag_image>"));
+ tokens.insert(std::make_pair(Token::TK_FLAG_FILE_END, "</flag_image>"));
+ tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_BEGIN, "<plural_form_count>"));
+ tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_END, "</plural_form_count>"));
+ tokens.insert(std::make_pair(Token::TK_PLURAL_DEF_BEGIN, "<plural_definition>"));
+ tokens.insert(std::make_pair(Token::TK_PLURAL_DEF_END, "</plural_definition>"));
//item level
tokens.insert(std::make_pair(Token::TK_SRC_BEGIN, "<source>"));
@@ -317,7 +329,7 @@ public:
}
catch (const parse_plural::InvalidPluralForm&)
{
- throw ParsingError(scn.posRow(), scn.posCol());
+ throw ParsingError(L"Invalid plural form definition", scn.posRow(), scn.posCol());
}
}
@@ -421,7 +433,7 @@ private:
void validateTranslation(const std::string& original, const std::string& translation) //throw ParsingError
{
if (original.empty())
- throw ParsingError(scn.posRow(), scn.posCol());
+ throw ParsingError(L"Source translation is empty", scn.posRow(), scn.posCol());
if (!translation.empty())
{
@@ -430,31 +442,36 @@ private:
{
if (zen::contains(original, placeholder) &&
!zen::contains(translation, placeholder))
- throw ParsingError(scn.posRow(), scn.posCol());
+ throw ParsingError(zen::replaceCpy<std::wstring>(L"Placeholder %x missing in translation", L"%x", zen::utfCvrtTo<std::wstring>(placeholder)), scn.posRow(), scn.posCol());
};
checkPlaceholder("%x");
checkPlaceholder("%y");
checkPlaceholder("%z");
+
+ //if source contains ampersand to mark menu accellerator key, so must translation
+ if (hasSingleAmpersand(original) && !hasSingleAmpersand(translation))
+ throw ParsingError(L"Translation is missing the & character to mark an access key for the menu item", scn.posRow(), scn.posCol());
}
}
void validateTranslation(const SingularPluralPair& original, const PluralForms& translation, const parse_plural::PluralFormInfo& pluralInfo) //throw ParsingError
{
+ using namespace zen;
//check the primary placeholder is existing at least for the second english text
- if (!zen::contains(original.second, "%x"))
- throw ParsingError(scn.posRow(), scn.posCol());
+ if (!contains(original.second, "%x"))
+ throw ParsingError(L"Plural form source does not contain %x placeholder", scn.posRow(), scn.posCol());
if (!translation.empty())
{
//check for invalid number of plural forms
if (pluralInfo.getCount() != static_cast<int>(translation.size()))
- throw ParsingError(scn.posRow(), scn.posCol());
+ throw ParsingError(replaceCpy(replaceCpy<std::wstring>(L"Invalid number of plural forms; actual: %x, expected: %y", L"%x", numberTo<std::wstring>(translation.size())), L"%y", numberTo<std::wstring>(pluralInfo.getCount())), scn.posRow(), scn.posCol());
//ensure the placeholder is used when needed
int pos = 0;
for (auto it = translation.begin(); it != translation.end(); ++it, ++pos)
- if (!pluralInfo.isSingleNumberForm(pos) && !zen::contains(*it, "%x"))
- throw ParsingError(scn.posRow(), scn.posCol());
+ if (!pluralInfo.isSingleNumberForm(pos) && !contains(*it, "%x"))
+ throw ParsingError(replaceCpy<std::wstring>(L"Plural form at index position %y is missing the %x placeholder", L"%y", numberTo<std::wstring>(pos)), scn.posRow(), scn.posCol());
auto checkSecondaryPlaceholder = [&](const std::string& placeholder)
{
@@ -464,11 +481,11 @@ private:
{
if (!zen::contains(original.first, placeholder) ||
!zen::contains(original.second, placeholder))
- throw ParsingError(scn.posRow(), scn.posCol());
+ throw ParsingError(zen::replaceCpy<std::wstring>(L"Placeholder %x missing in plural form source", L"%x", zen::utfCvrtTo<std::wstring>(placeholder)), scn.posRow(), scn.posCol());
//secondary placeholder is required for all plural forms
if (!std::all_of(translation.begin(), translation.end(), [&](const std::string& pform) { return zen::contains(pform, placeholder); }))
- throw ParsingError(scn.posRow(), scn.posCol());
+ throw ParsingError(zen::replaceCpy<std::wstring>(L"Placeholder %x missing in plural form translation", L"%x", zen::utfCvrtTo<std::wstring>(placeholder)), scn.posRow(), scn.posCol());
}
};
@@ -477,6 +494,24 @@ private:
}
}
+ static bool hasSingleAmpersand(const std::string& str)
+ {
+ size_t pos = 0;
+ for (;;)
+ {
+ pos = str.find('&', pos);
+ if (pos == std::string::npos)
+ return false;
+
+ bool freeBefore = pos == 0 || str[pos - 1] != '&';
+ bool freeAfter = pos >= str.size() - 1 || str[pos + 1] != '&'; //str.size() > 0 here!
+
+ if (freeBefore && freeAfter) //make sure to not catch && which windows resolves as just one & for display!
+ return true;
+ ++pos;
+ }
+ }
+
void nextToken() { tk = scn.nextToken(); }
const Token& token() const { return tk; }
@@ -489,7 +524,7 @@ private:
void expectToken(Token::Type t) //throw ParsingError
{
if (token().type != t)
- throw ParsingError(scn.posRow(), scn.posCol());
+ throw ParsingError(L"Unexpected token", scn.posRow(), scn.posCol());
}
Scanner scn;
@@ -529,7 +564,7 @@ void formatMultiLineText(std::string& text)
}
-std::string generateLng(const TranslationList& in, const TransHeader& header)
+std::string generateLng(const TranslationUnorderedList& in, const TransHeader& header)
{
std::string out;
//header
@@ -564,66 +599,55 @@ std::string generateLng(const TranslationList& in, const TransHeader& header)
out += '\n';
- //items
- for (auto it = in.sequence.begin(); it != in.sequence.end(); ++it)
+ in.visitItems([&](const TranslationMap::value_type& trans)
{
- const TranslationList::RegularItem* regular = dynamic_cast<const TranslationList::RegularItem*>(it->get());
- const TranslationList::PluralItem* plural = dynamic_cast<const TranslationList::PluralItem* >(it->get());
+ std::string original = trans.first;
+ std::string translation = trans.second;
- if (regular)
- {
- std::string original = regular->value.first;
- std::string translation = regular->value.second;
+ formatMultiLineText(original);
+ formatMultiLineText(translation);
- formatMultiLineText(original);
- formatMultiLineText(translation);
+ out += KnownTokens::text(Token::TK_SRC_BEGIN);
+ out += original;
+ out += KnownTokens::text(Token::TK_SRC_END) + '\n';
- out += KnownTokens::text(Token::TK_SRC_BEGIN);
- out += original;
- out += KnownTokens::text(Token::TK_SRC_END) + '\n';
-
- out += KnownTokens::text(Token::TK_TRG_BEGIN);
- out += translation;
- out += KnownTokens::text(Token::TK_TRG_END) + '\n' + '\n';
-
- }
- else if (plural)
+ out += KnownTokens::text(Token::TK_TRG_BEGIN);
+ out += translation;
+ out += KnownTokens::text(Token::TK_TRG_END) + '\n' + '\n';
+ },
+ [&](const TranslationPluralMap::value_type& transPlural)
+ {
+ std::string engSingular = transPlural.first.first;
+ std::string engPlural = transPlural.first.second;
+ const PluralForms& forms = transPlural.second;
+
+ formatMultiLineText(engSingular);
+ formatMultiLineText(engPlural);
+
+ out += KnownTokens::text(Token::TK_SRC_BEGIN) + '\n';
+ out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
+ out += engSingular;
+ out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
+ out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
+ out += engPlural;
+ out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
+ out += KnownTokens::text(Token::TK_SRC_END) + '\n';
+
+ out += KnownTokens::text(Token::TK_TRG_BEGIN);
+ if (!forms.empty()) out += '\n';
+
+ for (PluralForms::const_iterator j = forms.begin(); j != forms.end(); ++j)
{
- std::string engSingular = plural->value.first.first;
- std::string engPlural = plural->value.first.second;
- const PluralForms& forms = plural->value.second;
-
- formatMultiLineText(engSingular);
- formatMultiLineText(engPlural);
+ std::string plForm = *j;
+ formatMultiLineText(plForm);
- out += KnownTokens::text(Token::TK_SRC_BEGIN) + '\n';
out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- out += engSingular;
+ out += plForm;
out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
- out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- out += engPlural;
- out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
- out += KnownTokens::text(Token::TK_SRC_END) + '\n';
-
- out += KnownTokens::text(Token::TK_TRG_BEGIN);
- if (!forms.empty()) out += '\n';
-
- for (PluralForms::const_iterator j = forms.begin(); j != forms.end(); ++j)
- {
- std::string plForm = *j;
- formatMultiLineText(plForm);
-
- out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- out += plForm;
- out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
- }
- out += KnownTokens::text(Token::TK_TRG_END) + '\n' + '\n';
- }
- else
- {
- throw std::logic_error("that's what you get for brittle design ;)");
}
- }
+ out += KnownTokens::text(Token::TK_TRG_END) + '\n' + '\n';
+ });
+
assert(!zen::contains(out, "\r\n") && !zen::contains(out, "\r"));
return zen::replaceCpy(out, '\n', "\r\n"); //back to win line endings
}
diff --git a/lib/parse_plural.h b/lib/parse_plural.h
index bb32f81f..e9e04dbc 100644
--- a/lib/parse_plural.h
+++ b/lib/parse_plural.h
@@ -460,7 +460,7 @@ PluralFormInfo::PluralFormInfo(const std::string& definition, int pluralCount) /
inline
-PluralForm::PluralForm(const std::string& stream) : expr(implementation::Parser(stream, n_).parse()) {} //throw ParsingError
+PluralForm::PluralForm(const std::string& stream) : expr(implementation::Parser(stream, n_).parse()) {} //throw ParsingError
}
#endif // PARSE_PLURAL_H_INCLUDED \ No newline at end of file
diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp
index 78a40159..2422b2ef 100644
--- a/lib/process_xml.cpp
+++ b/lib/process_xml.cpp
@@ -47,17 +47,16 @@ XmlType getXmlType(const zen::XmlDoc& doc) //throw()
XmlType xmlAccess::getXmlType(const Zstring& filename) //throw()
{
- XmlDoc doc;
try
{
//do NOT use zen::loadStream as it will superfluously load even huge files!
- loadXmlDocument(filename, doc); //throw FfsXmlError, quick exit if file is not an FFS XML
+ XmlDoc doc = loadXmlDocument(filename); //throw FfsXmlError, quick exit if file is not an FFS XML
+ return ::getXmlType(doc);
}
catch (const FfsXmlError&)
{
return XML_TYPE_OTHER;
}
- return ::getXmlType(doc);
}
@@ -1122,8 +1121,7 @@ bool needsMigration(const XmlDoc& doc, int currentXmlFormatVer)
template <class ConfigType>
void readConfig(const Zstring& filename, XmlType type, ConfigType& cfg, int currentXmlFormatVer, bool& needMigration) //throw FfsXmlError
{
- XmlDoc doc;
- loadXmlDocument(filename, doc); //throw FfsXmlError
+ XmlDoc doc = loadXmlDocument(filename); //throw FfsXmlError
if (getXmlType(doc) != type) //throw()
throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
@@ -1209,8 +1207,7 @@ void xmlAccess::readAnyConfig(const std::vector<Zstring>& filenames, XmlGuiConfi
const Zstring& filename = *it;
const bool firstItem = it == filenames.begin(); //init all non-"mainCfg" settings with first config file
- XmlDoc doc;
- loadXmlDocument(filename, doc); //throw FfsXmlError
+ XmlDoc doc = loadXmlDocument(filename); //throw FfsXmlError
//do NOT use zen::loadStream as it will superfluously load even huge files!
switch (::getXmlType(doc))
@@ -1220,8 +1217,7 @@ void xmlAccess::readAnyConfig(const std::vector<Zstring>& filenames, XmlGuiConfi
XmlGuiConfig guiCfg = parseConfig<XmlGuiConfig>(doc, filename, XML_FORMAT_VER_FFS_GUI, warning); //nothrow
if (firstItem)
config = guiCfg;
- else
- mainCfgs.push_back(guiCfg.mainCfg);
+ mainCfgs.push_back(guiCfg.mainCfg);
}
break;
@@ -1230,8 +1226,7 @@ void xmlAccess::readAnyConfig(const std::vector<Zstring>& filenames, XmlGuiConfi
XmlBatchConfig batchCfg = parseConfig<XmlBatchConfig>(doc, filename, XML_FORMAT_VER_FFS_BATCH, warning); //nothrow
if (firstItem)
config = convertBatchToGui(batchCfg);
- else
- mainCfgs.push_back(batchCfg.mainCfg);
+ mainCfgs.push_back(batchCfg.mainCfg);
}
break;
@@ -1240,7 +1235,6 @@ void xmlAccess::readAnyConfig(const std::vector<Zstring>& filenames, XmlGuiConfi
throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
}
}
- mainCfgs.push_back(config.mainCfg); //save cfg from first line
config.mainCfg = merge(mainCfgs);
diff --git a/lib/process_xml.h b/lib/process_xml.h
index 626fafe0..95fa644d 100644
--- a/lib/process_xml.h
+++ b/lib/process_xml.h
@@ -175,17 +175,17 @@ struct XmlGlobalSettings
cfgFileHistMax(30),
folderHistMax(15),
onCompletionHistoryMax(8),
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
defaultExclusionFilter(Zstr("\\System Volume Information\\") Zstr("\n")
Zstr("\\$Recycle.Bin\\") Zstr("\n")
Zstr("\\RECYCLER\\") Zstr("\n")
Zstr("\\RECYCLED\\") Zstr("\n")
Zstr("*\\desktop.ini") Zstr("\n")
Zstr("*\\thumbs.db")),
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
defaultExclusionFilter(Zstr("/.Trash-*/") Zstr("\n")
Zstr("/.recycle/")),
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
defaultExclusionFilter(Zstr("/.fseventsd/") Zstr("\n")
Zstr("/.Spotlight-V100/") Zstr("\n")
Zstr("/.Trashes/") Zstr("\n")
@@ -194,9 +194,9 @@ struct XmlGlobalSettings
#endif
//deleteOnBothSides(false),
useRecyclerForManualDeletion(true), //enable if OS supports it; else user will have to activate first and then get an error message
-#if defined FFS_WIN || defined FFS_MAC
+#if defined ZEN_WIN || defined ZEN_MAC
textSearchRespectCase(false),
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
textSearchRespectCase(true),
#endif
showIcons(true),
@@ -204,16 +204,16 @@ struct XmlGlobalSettings
lastUpdateCheck(0)
{
//default external apps will be translated "on the fly"!!! First entry will be used for [Enter] or mouse double-click!
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
externelApplications.push_back(std::make_pair(L"Show in Explorer", L"explorer /select, \"%item_path%\""));
externelApplications.push_back(std::make_pair(L"Open with default application", L"\"%item_path%\""));
//mark for extraction: _("Show in Explorer")
//mark for extraction: _("Open with default application")
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
externelApplications.push_back(std::make_pair(L"Browse directory", L"xdg-open \"%item_folder%\""));
externelApplications.push_back(std::make_pair(L"Open with default application", L"xdg-open \"%item_path%\""));
//mark for extraction: _("Browse directory") Linux doesn't use the term "folder"
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
externelApplications.push_back(std::make_pair(L"Browse directory", L"open -R \"%item_path%\""));
externelApplications.push_back(std::make_pair(L"Open with default application", L"open \"%item_path%\""));
#endif
diff --git a/lib/resolve_path.cpp b/lib/resolve_path.cpp
index bf6f99a2..035e1d77 100644
--- a/lib/resolve_path.cpp
+++ b/lib/resolve_path.cpp
@@ -4,9 +4,10 @@
#include <zen/time.h>
#include <zen/thread.h>
#include <zen/utf.h>
+#include <zen/scope_guard.h>
#include <wx/utils.h> //wxGetEnv
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
#include <zen/long_path_prefix.h>
#include <zen/file_handling.h>
#include <zen/win.h> //includes "windows.h"
@@ -16,8 +17,9 @@
#pragma comment(lib, "Mpr.lib")
#endif
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
#include <stdlib.h> //getenv()
+#include <unistd.h> //getcwd
#endif
using namespace zen;
@@ -25,24 +27,25 @@ using namespace zen;
namespace
{
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
Zstring resolveRelativePath(const Zstring& relativeName) //note: ::GetFullPathName() is documented not threadsafe!
{
- const DWORD bufferSize = 10000;
- std::vector<wchar_t> buffer(bufferSize);
-
//don't use long path prefix! does not work with relative paths "." and ".."
- const DWORD charsWritten = ::GetFullPathName(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 cannot be == "bufferSize"
- return relativeName; //ERROR! Don't do anything
-
- return Zstring(&buffer[0], charsWritten);
+ const DWORD bufferSize = ::GetFullPathName(relativeName.c_str(), 0, nullptr, nullptr);
+ if (bufferSize > 0)
+ {
+ std::vector<wchar_t> buffer(bufferSize);
+ const DWORD charsWritten = ::GetFullPathName(relativeName.c_str(), //__in LPCTSTR lpFileName,
+ bufferSize, //__in DWORD nBufferLength,
+ &buffer[0], //__out LPTSTR lpBuffer,
+ nullptr); //__out LPTSTR *lpFilePart
+ if (0 < charsWritten && charsWritten < bufferSize) //theoretically, charsWritten can never be == "bufferSize"
+ return Zstring(&buffer[0], charsWritten);
+ }
+ return relativeName; //ERROR! Don't do anything
}
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
Zstring resolveRelativePath(const Zstring& relativeName)
{
//http://linux.die.net/man/2/path_resolution
@@ -69,16 +72,18 @@ Zstring resolveRelativePath(const Zstring& relativeName)
}
//we cannot use ::realpath() since it resolves *existing* relative paths only!
- std::vector<char> buffer(10000);
- if (::getcwd(&buffer[0], buffer.size()) != nullptr)
- return appendSeparator(&buffer[0]) + relativeName;
+ if (char* dirpath = ::getcwd(nullptr, 0))
+ {
+ ZEN_ON_SCOPE_EXIT(::free(dirpath));
+ return appendSeparator(dirpath) + relativeName;
+ }
}
return relativeName;
}
#endif
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
class CsidlConstants
{
public:
@@ -273,7 +278,7 @@ std::unique_ptr<Zstring> resolveMacro(const Zstring& macro, //macro without %-ch
if (std::unique_ptr<Zstring> value = getEnvironmentVar(macro))
return value;
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//try to resolve as CSIDL value
{
const auto& csidlMap = CsidlConstants::get();
@@ -316,8 +321,8 @@ Zstring zen::expandMacros(const Zstring& text) { return ::expandMacros(text, std
namespace
{
-#ifdef FFS_WIN
-//networks and cdrom excluded - this should not block
+#ifdef ZEN_WIN
+//networks and cdrom excluded - may still block for slow USB sticks!
Zstring getPathByVolumenName(const Zstring& volumeName) //return empty string on error
{
//FindFirstVolume(): traverses volumes on local hard disks only!
@@ -412,11 +417,11 @@ Zstring expandVolumeName(const Zstring& text) // [volname]:\folder [volna
rest = afterFirst(rest, Zstr(':'));
if (startsWith(rest, FILE_NAME_SEPARATOR))
rest = afterFirst(rest, FILE_NAME_SEPARATOR);
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//[.*] pattern was found...
if (!volname.empty())
{
- Zstring volPath = getPathByVolumenName(volname); //should not block?!
+ Zstring volPath = getPathByVolumenName(volname); //may block for slow USB sticks!
if (!volPath.empty())
return appendSeparator(volPath) + rest; //successfully replaced pattern
}
@@ -430,7 +435,7 @@ Zstring expandVolumeName(const Zstring& text) // [volname]:\folder [volna
C:\Program Files\FreeFileSync\[FFS USB]\FreeFileSync\ */
return L"?:\\[" + volname + L"]\\" + rest;
-#elif defined FFS_LINUX || defined FFS_MAC //neither supported nor needed
+#elif defined ZEN_LINUX || defined ZEN_MAC //neither supported nor needed
return "/.../[" + volname + "]/" + rest;
#endif
}
@@ -442,8 +447,8 @@ Zstring expandVolumeName(const Zstring& text) // [volname]:\folder [volna
void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, LessFilename>& output)
{
-#ifdef FFS_WIN
- //1. replace volume path by volume name: c:\dirname -> [SYSTEM]\dirname
+#ifdef ZEN_WIN
+ //1. replace volume path by volume name: c:\dirname -> [SYSTEM]\dirname
if (dirname.size() >= 3 &&
std::iswalpha(dirname[0]) &&
dirname[1] == L':' &&
@@ -473,7 +478,7 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less
if (std::unique_ptr<Zstring> value = getEnvironmentVar(envName))
envToDir.insert(std::make_pair(envName, *value));
};
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
addEnvVar(L"AllUsersProfile"); // C:\ProgramData
addEnvVar(L"AppData"); // C:\Users\<user>\AppData\Roaming
addEnvVar(L"LocalAppData"); // C:\Users\<user>\AppData\Local
@@ -491,19 +496,19 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less
const auto& csidlMap = CsidlConstants::get();
envToDir.insert(csidlMap.begin(), csidlMap.end());
-#elif defined FFS_LINUX || defined FFS_MAC
+#elif defined ZEN_LINUX || defined ZEN_MAC
addEnvVar("HOME"); //Linux: /home/<user> Mac: /Users/<user>
#endif
//substitute paths by symbolic names
auto pathStartsWith = [](const Zstring& path, const Zstring& prefix) -> bool
{
-#if defined FFS_WIN || defined FFS_MAC
+#if defined ZEN_WIN || defined ZEN_MAC
Zstring tmp = path;
Zstring tmp2 = prefix;
::makeUpper(tmp);
::makeUpper(tmp2);
return startsWith(tmp, tmp2);
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
return startsWith(path, prefix);
#endif
};
@@ -557,7 +562,7 @@ Zstring zen::getFormattedDirectoryName(const Zstring& dirString) // throw()
return Zstring();
dirname = expandMacros(dirname);
- dirname = expandVolumeName(dirname); //should not block
+ dirname = expandVolumeName(dirname); //may block for slow USB sticks!
/*
need to resolve relative paths:
@@ -575,7 +580,7 @@ Zstring zen::getFormattedDirectoryName(const Zstring& dirString) // throw()
}
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
void zen::loginNetworkShare(const Zstring& dirnameOrig, bool allowUserInteraction) //throw() - user interaction: show OS password prompt
{
/*
diff --git a/lib/resolve_path.h b/lib/resolve_path.h
index 4e85c8ee..b9c7196f 100644
--- a/lib/resolve_path.h
+++ b/lib/resolve_path.h
@@ -19,14 +19,14 @@ FULL directory format:
- convert relative paths into absolute
- trim whitespace and append file name separator
*/
-Zstring getFormattedDirectoryName(const Zstring& dirString); //throw() - non-blocking! no I/O! not thread-safe!!!(see ::GetFullPathName())
+Zstring getFormattedDirectoryName(const Zstring& dirString); //throw() - may still block for slow USB sticks! not thread-safe!!!(see ::GetFullPathName())
//macro substitution only
Zstring expandMacros(const Zstring& text);
-std::vector<Zstring> getDirectoryAliases(const Zstring& dirString);
+std::vector<Zstring> getDirectoryAliases(const Zstring& dirString); //may block for slow USB sticks when resolving [<volume name>]
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//*blocks* if network is not reachable or when showing login prompt dialog!
void loginNetworkShare(const Zstring& dirname, bool allowUserInteraction); //throw() - user interaction: show OS password prompt
#endif
diff --git a/lib/resources.cpp b/lib/resources.cpp
index 6f48e2e1..6deaf0ec 100644
--- a/lib/resources.cpp
+++ b/lib/resources.cpp
@@ -69,19 +69,19 @@ GlobalResources::GlobalResources()
else if (name == L"wink.gif")
loadAnimFromZip(resourceFile, aniWink);
else if (name == L"working.gif")
- loadAnimFromZip(resourceFile, aniSync);
+ loadAnimFromZip(resourceFile, aniWorking);
}
}
-#ifdef FFS_WIN
+#ifdef ZEN_WIN
//for compatibility it seems we need to stick with a "real" icon
programIconFFS = wxIcon(L"A_FFS_ICON");
-#elif defined FFS_LINUX
+#elif defined ZEN_LINUX
//attention: make sure to not implicitly call "instance()" again => deadlock on Linux
programIconFFS.CopyFromBitmap(getImage(L"FreeFileSync")); //use big logo bitmap for better quality
-#elif defined FFS_MAC
+#elif defined ZEN_MAC
assert(getImage(L"FreeFileSync").GetWidth () == getImage(L"FreeFileSync").GetHeight() &&
getImage(L"FreeFileSync").GetWidth() % 128 == 0);
//wxWidgets' bitmap to icon conversion on OS X can only deal with very specific sizes
diff --git a/lib/resources.h b/lib/resources.h
index df651eaa..1cb05f20 100644
--- a/lib/resources.h
+++ b/lib/resources.h
@@ -22,7 +22,7 @@ public:
//global image resource objects
wxAnimation aniWink;
- wxAnimation aniSync;
+ wxAnimation aniWorking;
wxIcon programIconFFS;
private:
diff --git a/lib/shadow.cpp b/lib/shadow.cpp
index 4bb299ac..1161646e 100644
--- a/lib/shadow.cpp
+++ b/lib/shadow.cpp
@@ -53,20 +53,20 @@ public:
//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(_("Cannot access Volume Shadow Copy Service.") + L"\n" +
+ throw FileError(_("Cannot access Volume Shadow Copy Service."),
_("Please use FreeFileSync 64-bit version to create shadow copies on this system."));
//check if shadow copy dll was loaded correctly
if (!createShadowCopy || !releaseShadowCopy || !getShadowVolume || !getLastError)
- throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" +
+ throw FileError(_("Cannot access Volume Shadow Copy Service."),
replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName())));
//---------------------------------------------------------------------------------------------------------
//start volume shadow copy service:
backupHandle = createShadowCopy(volumeNamePf.c_str());
if (!backupHandle)
- throw FileError(_("Cannot access Volume Shadow Copy Service.") + L"\n" +
- getLastError() + L" Volume: " + fmtFileName(volumeNamePf));
+ throw FileError(_("Cannot access Volume Shadow Copy Service."),
+ getLastError() + std::wstring(L" Volume: ") + fmtFileName(volumeNamePf));
shadowVolPf = appendSeparator(getShadowVolume(backupHandle)); //shadowVolName NEVER has a trailing backslash
}
@@ -96,7 +96,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile, const std::function
//try to resolve symlinks and junctions:
//1. symlinks: we need to retrieve the target path, else we would just return a symlink on a VSS volume while the target outside were still locked!
- //2. junctions: C:\Users\<username> is a junction that may link to e.g. D:\Users\<username>, so GetVolumePathName() returns "D:\" => "Volume name %x not part of file name %y!"
+ //2. junctions: C:\Users\<username> is a junction that may link to e.g. D:\Users\<username>, so GetVolumePathName() returns "D:\" => "Volume name %x not part of file name %y."
if (wereVistaOrLater)
filenameFinal = getResolvedFilePath(inputFile); //throw FileError; requires Vista or later!
//-> returns paths with \\?\ prefix! => make sure to avoid duplicate shadow copies for volume paths with/without prefix
@@ -106,7 +106,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile, const std::function
if (!::GetVolumePathName(filenameFinal.c_str(), //__in LPCTSTR lpszFileName,
&volBuffer[0], //__out LPTSTR lpszVolumePathName,
bufferSize)) //__in DWORD cchBufferLength
- throw FileError(replaceCpy(_("Path %x does not contain a volume name."), L"%x", fmtFileName(filenameFinal)));
+ throw FileError(replaceCpy(_("Cannot determine volume name for %x."), L"%x", fmtFileName(filenameFinal)), formatSystemError(L"GetVolumePathName", ::GetLastError()));
const Zstring volumeNamePf = appendSeparator(&volBuffer[0]); //msdn: if buffer is 1 char too short, GetVolumePathName() may skip last separator without error!
@@ -114,7 +114,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile, const std::function
const size_t pos = filenameFinal.find(volumeNamePf); //filenameFinal needs NOT to begin with volumeNamePf: consider for example \\?\ prefix!
if (pos == Zstring::npos)
{
- std::wstring msg = _("Volume name %x not part of file name %y!");
+ std::wstring msg = _("Volume name %x not part of file name %y.");
replace(msg, L"%x", fmtFileName(volumeNamePf), false);
replace(msg, L"%y", fmtFileName(filenameFinal), false);
throw FileError(msg);
diff --git a/lib/shadow.h b/lib/shadow.h
index f59d7753..36c72c25 100644
--- a/lib/shadow.h
+++ b/lib/shadow.h
@@ -13,7 +13,6 @@
#include <zen/zstring.h>
#include <zen/file_error.h>
-
namespace shadow
{
class ShadowCopy //take and buffer Windows Volume Shadow Copy snapshots as needed
diff --git a/lib/versioning.cpp b/lib/versioning.cpp
index a5bd17be..1bf5a65e 100644
--- a/lib/versioning.cpp
+++ b/lib/versioning.cpp
@@ -73,7 +73,7 @@ namespace
- create target super directories if missing
*/
template <class Function>
-void moveItemToVersioning(const Zstring& sourceObj, //throw FileError
+void moveItemToVersioning(const Zstring& fullName, //throw FileError
const Zstring& relativeName,
const Zstring& versioningDirectory,
const Zstring& timestamp,
@@ -82,37 +82,36 @@ void moveItemToVersioning(const Zstring& sourceObj, //throw FileError
{
assert(!startsWith(relativeName, FILE_NAME_SEPARATOR));
assert(!endsWith (relativeName, FILE_NAME_SEPARATOR));
- assert(endsWith(sourceObj, relativeName)); //usually, yes, but we might relax this in the future
- Zstring targetObj;
+ Zstring targetName;
switch (versioningStyle)
{
case VER_STYLE_REPLACE:
- targetObj = appendSeparator(versioningDirectory) + relativeName;
+ targetName = appendSeparator(versioningDirectory) + relativeName;
break;
case VER_STYLE_ADD_TIMESTAMP:
//assemble time-stamped version name
- targetObj = appendSeparator(versioningDirectory) + relativeName + Zstr(' ') + timestamp + getExtension(relativeName);
- assert(impl::isMatchingVersion(afterLast(relativeName, FILE_NAME_SEPARATOR), afterLast(targetObj, FILE_NAME_SEPARATOR))); //paranoid? no!
+ targetName = appendSeparator(versioningDirectory) + relativeName + Zstr(' ') + timestamp + getExtension(relativeName);
+ assert(impl::isMatchingVersion(afterLast(relativeName, FILE_NAME_SEPARATOR), afterLast(targetName, FILE_NAME_SEPARATOR))); //paranoid? no!
break;
}
try
{
- moveObj(sourceObj, targetObj); //throw FileError
+ moveObj(fullName, targetName); //throw FileError
}
catch (FileError&) //expected to fail if target directory is not yet existing!
{
- if (!somethingExists(sourceObj)) //no source at all is not an error (however a directory as source when a file is expected, *is* an error!)
+ if (!somethingExists(fullName)) //no source at all is not an error (however a directory as source when a file is expected, *is* an error!)
return; //object *not* processed
//create intermediate directories if missing
- const Zstring targetDir = beforeLast(targetObj, FILE_NAME_SEPARATOR);
+ const Zstring targetDir = beforeLast(targetName, FILE_NAME_SEPARATOR);
if (!dirExists(targetDir)) //->(minor) file system race condition!
{
makeDirectory(targetDir); //throw FileError
- moveObj(sourceObj, targetObj); //throw FileError -> this should work now!
+ moveObj(fullName, targetName); //throw FileError -> this should work now!
}
else
throw;
@@ -126,36 +125,45 @@ void moveItemToVersioning(const Zstring& sourceObj, //throw FileError
template <class Function>
void moveObject(const Zstring& sourceFile, //throw FileError
const Zstring& targetFile,
- Function copyDelete) //fallback if move failed; may throw FileError
+ Function copyDelete) //throw FileError; fallback if move failed
{
assert(!dirExists(sourceFile) || symlinkExists(sourceFile)); //we process files and symlinks only
+ auto removeTarget = [&]()
+ {
+ //remove target object
+ if (fileExists(targetFile)) //file or symlink
+ removeFile(targetFile); //throw FileError
+ else if (dirExists(targetFile)) //directory or symlink
+ removeDirectory(targetFile); //throw FileError
+ //we do not expect targetFile to be a directory in general => no callback required
+ else assert(false);
+ };
+
//first try to move directly without copying
- bool targetExisting = false;
try
{
renameFile(sourceFile, targetFile); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
return; //great, we get away cheaply!
}
//if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file)
- catch (const ErrorDifferentVolume&) {}
- catch (const ErrorTargetExisting&) { targetExisting = true; }
-
- if (!targetExisting)
- targetExisting = somethingExists(targetFile);
-
- //remove target object
- if (targetExisting)
+ catch (const ErrorDifferentVolume&)
{
- if (fileExists(targetFile)) //file or symlink
- removeFile(targetFile); //throw FileError
- else if (dirExists(targetFile)) //directory or symlink
- removeDirectory(targetFile); //throw FileError
- //we do not expect targetFile to be a directory in general => no callback required
- else assert(false);
+ removeTarget(); //throw FileError
+ copyDelete(); //
+ }
+ catch (const ErrorTargetExisting&)
+ {
+ removeTarget(); //throw FileError
+ try
+ {
+ renameFile(sourceFile, targetFile); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
+ }
+ catch (const ErrorDifferentVolume&)
+ {
+ copyDelete(); //throw FileError
+ }
}
-
- copyDelete();
}
@@ -219,7 +227,7 @@ private:
return LINK_SKIP;
}
- virtual std::shared_ptr<TraverseCallback> onDir(const Zchar* shortName, const Zstring& fullName)
+ virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName)
{
dirs_.push_back(shortName);
return nullptr; //DON'T traverse into subdirs; moveDirectory works recursively!
@@ -234,7 +242,7 @@ private:
}
-bool FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
+bool FileVersioner::revisionFile(const Zstring& fullName, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
{
struct CallbackMoveFileImpl : public CallbackMoveDir
{
@@ -246,15 +254,15 @@ bool FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relat
CallbackMoveFile& callback_;
} cb(callback);
- return revisionFileImpl(sourceFile, relativeName, cb); //throw FileError
+ return revisionFileImpl(fullName, relativeName, cb); //throw FileError
}
-bool FileVersioner::revisionFileImpl(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
+bool FileVersioner::revisionFileImpl(const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
{
bool moveSuccessful = false;
- moveItemToVersioning(sourceFile, //throw FileError
+ moveItemToVersioning(fullName, //throw FileError
relativeName,
versioningDirectory_,
timeStamp_,
@@ -280,23 +288,23 @@ bool FileVersioner::revisionFileImpl(const Zstring& sourceFile, const Zstring& r
}
-void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
+void FileVersioner::revisionDir(const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
{
//no error situation if directory is not existing! manual deletion relies on it!
- if (!somethingExists(sourceDir))
+ if (!somethingExists(fullName))
return; //neither directory nor any other object (e.g. broken symlink) with that name existing
- revisionDirImpl(sourceDir, relativeName, callback); //throw FileError
+ revisionDirImpl(fullName, relativeName, callback); //throw FileError
}
-void FileVersioner::revisionDirImpl(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
+void FileVersioner::revisionDirImpl(const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
{
- assert(somethingExists(sourceDir)); //[!]
+ assert(somethingExists(fullName)); //[!]
//create target
- if (symlinkExists(sourceDir)) //on Linux there is just one type of symlink, and since we do revision file symlinks, we should revision dir symlinks as well!
+ if (symlinkExists(fullName)) //on Linux there is just one type of symlink, and since we do revision file symlinks, we should revision dir symlinks as well!
{
- moveItemToVersioning(sourceDir, //throw FileError
+ moveItemToVersioning(fullName, //throw FileError
relativeName,
versioningDirectory_,
timeStamp_,
@@ -310,7 +318,7 @@ void FileVersioner::revisionDirImpl(const Zstring& sourceDir, const Zstring& rel
else
{
assert(!startsWith(relativeName, FILE_NAME_SEPARATOR));
- assert(endsWith(sourceDir, relativeName)); //usually, yes, but we might relax this in the future
+ assert(endsWith(fullName, relativeName)); //usually, yes, but we might relax this in the future
const Zstring targetDir = appendSeparator(versioningDirectory_) + relativeName;
//makeDirectory(targetDir); //FileError -> create only when needed in moveFileToVersioning(); avoids empty directories
@@ -320,17 +328,17 @@ void FileVersioner::revisionDirImpl(const Zstring& sourceDir, const Zstring& rel
std::vector<Zstring> dirList; //
{
TraverseFilesOneLevel tol(fileList, dirList); //throw FileError
- traverseFolder(sourceDir, tol); //
+ traverseFolder(fullName, tol); //
}
- const Zstring sourceDirPf = appendSeparator(sourceDir);
+ const Zstring fullNamePf = appendSeparator(fullName);
const Zstring relnamePf = appendSeparator(relativeName);
//move files
std::for_each(fileList.begin(), fileList.end(),
[&](const Zstring& shortname)
{
- revisionFileImpl(sourceDirPf + shortname, //throw FileError
+ revisionFileImpl(fullNamePf + shortname, //throw FileError
relnamePf + shortname,
callback);
});
@@ -339,14 +347,14 @@ void FileVersioner::revisionDirImpl(const Zstring& sourceDir, const Zstring& rel
std::for_each(dirList.begin(), dirList.end(),
[&](const Zstring& shortname)
{
- revisionDirImpl(sourceDirPf + shortname, //throw FileError
+ revisionDirImpl(fullNamePf + shortname, //throw FileError
relnamePf + shortname,
callback);
});
//delete source
- callback.onBeforeDirMove(sourceDir, targetDir);
- removeDirectory(sourceDir); //throw FileError
+ callback.onBeforeDirMove(fullName, targetDir);
+ removeDirectory(fullName); //throw FileError
}
}
@@ -427,7 +435,7 @@ void FileVersioner::limitVersions(std::function<void()> updateUI) //throw FileEr
}
catch (FileError&)
{
-#ifdef FFS_WIN //if it's a directory symlink:
+#ifdef ZEN_WIN //if it's a directory symlink:
if (symlinkExists(fullnameVer) && dirExists(fullnameVer))
removeDirectory(fullnameVer); //throw FileError
else
diff --git a/lib/versioning.h b/lib/versioning.h
index faa96359..33dc31c4 100644
--- a/lib/versioning.h
+++ b/lib/versioning.h
@@ -46,14 +46,14 @@ public:
throw FileError(_("Failure to create timestamp for versioning:") + L" \'" + timeStamp_ + L"\'");
}
- bool revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError; return "false" if file is not existing
- void revisionDir (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
+ bool revisionFile(const Zstring& fullName, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError; return "false" if file is not existing
+ void revisionDir (const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
//void limitVersions(std::function<void()> updateUI); //throw FileError; call when done revisioning!
private:
- bool revisionFileImpl(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
- void revisionDirImpl (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
+ bool revisionFileImpl(const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
+ void revisionDirImpl (const Zstring& fullName, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
const VersioningStyle versioningStyle_;
const Zstring versioningDirectory_;
diff --git a/lib/xml_base.cpp b/lib/xml_base.cpp
index f5091cd6..123060f4 100644
--- a/lib/xml_base.cpp
+++ b/lib/xml_base.cpp
@@ -14,7 +14,7 @@ using namespace zen;
//loadXmlDocument vs loadStream:
//1. better error reporting
//2. quick exit if (potentially large) input file is not an XML
-void xmlAccess::loadXmlDocument(const Zstring& filename, XmlDoc& doc) //throw FfsXmlError
+XmlDoc xmlAccess::loadXmlDocument(const Zstring& filename) //throw FfsXmlError
{
std::string stream;
try
@@ -51,7 +51,7 @@ void xmlAccess::loadXmlDocument(const Zstring& filename, XmlDoc& doc) //throw Ff
try
{
- zen::parse(stream, doc); //throw XmlParsingError
+ return zen::parse(stream); //throw XmlParsingError
}
catch (const XmlParsingError& e)
{
diff --git a/lib/xml_base.h b/lib/xml_base.h
index ceaf609b..85d4dfa1 100644
--- a/lib/xml_base.h
+++ b/lib/xml_base.h
@@ -11,7 +11,7 @@
#include <zen/zstring.h>
#include <zen/file_error.h>
-//bind zenxml and zen file handling together
+//bind zen::Xml and zen file handling together
namespace xmlAccess
{
@@ -34,7 +34,7 @@ private:
};
void saveXmlDocument(const zen::XmlDoc& doc, const Zstring& filename); //throw FfsXmlError
-void loadXmlDocument(const Zstring& filename, zen::XmlDoc& doc); //throw FfsXmlError
+zen::XmlDoc loadXmlDocument(const Zstring& filename); //throw FfsXmlError
const std::wstring getErrorMessageFormatted(const std::vector<std::wstring>& failedElements);
}
bgstack15