summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:19:14 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:19:14 +0200
commit01eb8253196672c969a39587e90b49321a182428 (patch)
tree4a3b71d7913de519744466c9227fda6461c4f0b5 /zen
parent5.0 (diff)
downloadFreeFileSync-01eb8253196672c969a39587e90b49321a182428.tar.gz
FreeFileSync-01eb8253196672c969a39587e90b49321a182428.tar.bz2
FreeFileSync-01eb8253196672c969a39587e90b49321a182428.zip
5.1
Diffstat (limited to 'zen')
-rw-r--r--zen/FindFilePlus/find_file_plus.cpp32
-rw-r--r--zen/FindFilePlus/find_file_plus.h2
-rw-r--r--zen/basic_math.h50
-rw-r--r--zen/com_error.h4
-rw-r--r--zen/com_ptr.h2
-rw-r--r--zen/com_util.h6
-rw-r--r--zen/debug_new.cpp10
-rw-r--r--zen/dir_watcher.cpp54
-rw-r--r--zen/dll.h39
-rw-r--r--zen/dst_hack.cpp40
-rw-r--r--zen/error_log.h133
-rw-r--r--zen/file_handling.cpp365
-rw-r--r--zen/file_handling.h6
-rw-r--r--zen/file_id.cpp6
-rw-r--r--zen/file_id_def.h18
-rw-r--r--zen/file_io.cpp54
-rw-r--r--zen/file_traverser.cpp65
-rw-r--r--zen/file_traverser.h2
-rw-r--r--zen/fixed_list.h32
-rw-r--r--zen/i18n.h2
-rw-r--r--zen/int64.h28
-rw-r--r--zen/last_error.h60
-rw-r--r--zen/long_path_prefix.h2
-rw-r--r--zen/notify_removal.cpp18
-rw-r--r--zen/optional.h14
-rw-r--r--zen/perf.h69
-rw-r--r--zen/privilege.cpp24
-rw-r--r--zen/privilege.h1
-rw-r--r--zen/scope_guard.h8
-rw-r--r--zen/stl_tools.h14
-rw-r--r--zen/string_base.h187
-rw-r--r--zen/string_tools.h169
-rw-r--r--zen/string_traits.h84
-rw-r--r--zen/symlink_target.h8
-rw-r--r--zen/time.h56
-rw-r--r--zen/type_tools.h49
-rw-r--r--zen/type_traits.h81
-rw-r--r--zen/utf8.h129
-rw-r--r--zen/zstring.cpp42
-rw-r--r--zen/zstring.h2
40 files changed, 1035 insertions, 932 deletions
diff --git a/zen/FindFilePlus/find_file_plus.cpp b/zen/FindFilePlus/find_file_plus.cpp
index 70076aa2..46eb956c 100644
--- a/zen/FindFilePlus/find_file_plus.cpp
+++ b/zen/FindFilePlus/find_file_plus.cpp
@@ -129,10 +129,10 @@ private:
FileSearcher::FileSearcher(const wchar_t* dirname) :
- hDir(NULL),
+ hDir(nullptr),
nextEntryOffset(0)
{
- dirnameNt.Buffer = NULL;
+ dirnameNt.Buffer = nullptr;
dirnameNt.Length = 0;
dirnameNt.MaximumLength = 0;
@@ -148,17 +148,17 @@ FileSearcher::FileSearcher(const wchar_t* dirname) :
// RtlDosPathNameToRelativeNtPathName_U: used by Win7/Win8 available with OS version 5.2 (Windows Server 2003) and higher
if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName,
&dirnameNt, //__out ntFileName,
- NULL, //__out_optFilePart,
- NULL)) //__out_opt relativeName - empty if dosFileName is absolute
+ nullptr, //__out_optFilePart,
+ nullptr)) //__out_opt relativeName - empty if dosFileName is absolute
throw NtFileError(STATUS_OBJECT_PATH_NOT_FOUND); //translates to ERROR_PATH_NOT_FOUND, same behavior like ::FindFirstFileEx()
OBJECT_ATTRIBUTES objAttr = {};
- InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes,
- &dirnameNt, //[in] PUNICODE_STRING objectName,
+ InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes,
+ &dirnameNt, //[in] PUNICODE_STRING objectName,
OBJ_CASE_INSENSITIVE, //[in] ULONG attributes,
- NULL, //[in] HANDLE rootDirectory,
- NULL); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor
+ nullptr, //[in] HANDLE rootDirectory,
+ nullptr); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor
{
IO_STATUS_BLOCK status = {};
NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle,
@@ -236,15 +236,15 @@ void FileSearcher::readDirImpl(FileInformation& output) //throw FileError
/* corresponding first access in ::FindFirstFileW()
NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle,
- NULL, //__in_opt HANDLE event,
- NULL, //__in_opt PIO_APC_ROUTINE apcRoutine,
- NULL, //__in_opt PVOID apcContext,
+ nullptr, //__in_opt HANDLE event,
+ nullptr, //__in_opt PIO_APC_ROUTINE apcRoutine,
+ nullptr, //__in_opt PVOID apcContext,
&status, //__out PIO_STATUS_BLOCK ioStatusBlock,
&buffer, //__out_bcount(Length) PVOID fileInformation,
BUFFER_SIZE, //__in ULONG length, ::FindFirstFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * MAX_PATH == 0x268
FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation"
true, //__in BOOLEAN returnSingleEntry,
- NULL, //__in_opt PUNICODE_STRING mask,
+ nullptr, //__in_opt PUNICODE_STRING mask,
false); //__in BOOLEAN restartScan
*/
@@ -253,15 +253,15 @@ void FileSearcher::readDirImpl(FileInformation& output) //throw FileError
{
IO_STATUS_BLOCK status = {};
NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle,
- NULL, //__in_opt HANDLE event,
- NULL, //__in_opt PIO_APC_ROUTINE apcRoutine,
- NULL, //__in_opt PVOID apcContext,
+ nullptr, //__in_opt HANDLE event,
+ nullptr, //__in_opt PIO_APC_ROUTINE apcRoutine,
+ nullptr, //__in_opt PVOID apcContext,
&status, //__out PIO_STATUS_BLOCK ioStatusBlock,
&buffer, //__out_bcount(Length) PVOID fileInformation,
BUFFER_SIZE, //__in ULONG length, ::FindNextFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 == 0x1000
QueryPolicy::fileInformationClass, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation"
false, //__in BOOLEAN returnSingleEntry,
- NULL, //__in_opt PUNICODE_STRING mask,
+ nullptr, //__in_opt PUNICODE_STRING mask,
false); //__in BOOLEAN restartScan
if (!NT_SUCCESS(rv))
{
diff --git a/zen/FindFilePlus/find_file_plus.h b/zen/FindFilePlus/find_file_plus.h
index cf1174eb..7306c32e 100644
--- a/zen/FindFilePlus/find_file_plus.h
+++ b/zen/FindFilePlus/find_file_plus.h
@@ -44,7 +44,7 @@ class FileSearcher;
typedef FileSearcher* FindHandle;
DLL_FUNCTION_DECLARATION
-FindHandle openDir(const wchar_t* dirname); //returns NULL on error, call ::GetLastError()
+FindHandle openDir(const wchar_t* dirname); //returns nullptr on error, call ::GetLastError()
//note: do NOT place an asterisk at end, e.g. C:\SomeDir\*, as one would do for ::FindFirstFile()
DLL_FUNCTION_DECLARATION
diff --git a/zen/basic_math.h b/zen/basic_math.h
index e9ab1a2f..dbc2d922 100644
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -12,6 +12,7 @@
#include <iterator>
#include <limits>
#include <functional>
+#include <cassert>
namespace numeric
@@ -32,7 +33,7 @@ template <class T>
const T& max(const T& a, const T& b, const T& c);
template <class T>
-void restrict(T& val, const T& minVal, const T& maxVal); //make sure minVal <= val && val <= maxVal
+void confine(T& val, const T& minVal, const T& maxVal); //make sure minVal <= val && val <= maxVal
template <class InputIterator>
std::pair<InputIterator, InputIterator> minMaxElement(InputIterator first, InputIterator last);
@@ -57,13 +58,12 @@ template <class RandomAccessIterator>
double median(RandomAccessIterator first, RandomAccessIterator last); //note: invalidates input range!
template <class InputIterator>
-double stdDeviation(InputIterator first, InputIterator last, double* mean = NULL); //estimate standard deviation (and thereby arithmetic mean)
+double stdDeviation(InputIterator first, InputIterator last, double* mean = nullptr); //estimate standard deviation (and thereby arithmetic mean)
//median absolute deviation: "mad / 0.6745" is a robust measure for standard deviation of a normal distribution
template <class RandomAccessIterator>
double mad(RandomAccessIterator first, RandomAccessIterator last); //note: invalidates input range!
-
template <class InputIterator>
double norm2(InputIterator first, InputIterator last);
@@ -99,7 +99,10 @@ const double ln2 = 0.693147180559945309417;
template <class T> inline
T abs(T value)
{
- return value < 0 ? -1 * value : value;
+ if (value < 0)
+ return -value; // operator "?:" caveat: may be different type than "value"
+ else
+ return value;
}
template <class T> inline
@@ -131,7 +134,7 @@ const T& max(const T& a, const T& b, const T& c)
template <class T> inline
-void restrict(T& val, const T& minVal, const T& maxVal)
+void confine(T& val, const T& minVal, const T& maxVal)
{
assert(minVal <= maxVal);
if (val < minVal)
@@ -142,19 +145,36 @@ void restrict(T& val, const T& minVal, const T& maxVal)
template <class InputIterator, class Compare> inline
-std::pair<InputIterator, InputIterator> minMaxElement(InputIterator first, InputIterator last, Compare comp)
+std::pair<InputIterator, InputIterator> minMaxElement(InputIterator first, InputIterator last, Compare compLess)
{
+ //by factor 1.5 to 3 faster than boost::minmax_element (=two-step algorithm) for built-in types!
+
InputIterator lowest = first;
InputIterator largest = first;
if (first != last)
- while (++first != last)
+ {
+ auto minVal = *lowest; //nice speedup on 64 bit!
+ auto maxVal = *largest; //
+ for (;;)
{
- if (comp(*largest, *first)) // or: if (comp(*largest,*lowest)) for the comp version
+ ++first;
+ if (first == last)
+ break;
+ const auto val = *first;
+
+ if (compLess(maxVal, val))
+ {
largest = first;
- else if (comp(*first, *lowest))
+ maxVal = val;
+ }
+ else if (compLess(val, minVal))
+ {
lowest = first;
+ minVal = val;
+ }
}
+ }
return std::make_pair(lowest, largest);
}
@@ -207,10 +227,10 @@ template <class T>
struct PowerImpl<10, T>; //not defined: invalidates power<N> for N >= 10
}
-template <size_t N, class T> inline
+template <size_t n, class T> inline
T power(const T& value)
{
- return PowerImpl<N, T>::result(value);
+ return PowerImpl<n, T>::result(value);
}
@@ -231,8 +251,7 @@ double degToRad(double degree)
template <class InputIterator> inline
double arithmeticMean(InputIterator first, InputIterator last)
{
- //low level implementation to avoid random-access requirement on iterator
- size_t n = 0;
+ size_t n = 0; //avoid random-access requirement for iterator!
double sum_xi = 0;
for (; first != last; ++first, ++n)
@@ -280,10 +299,7 @@ double mad(RandomAccessIterator first, RandomAccessIterator last) //note: invali
if (n % 2 != 0)
return midVal;
else //n is even and >= 2 in this context: return mean of two middle values
- {
- const double midVal2 = abs(*std::max_element(first, first + n / 2, lessMedAbs) - m);
- return 0.5 * (midVal2 + midVal);
- }
+ return 0.5 * (abs(*std::max_element(first, first + n / 2, lessMedAbs) - m) + midVal);
}
return 0;
}
diff --git a/zen/com_error.h b/zen/com_error.h
index 7f967f7c..c67c4193 100644
--- a/zen/com_error.h
+++ b/zen/com_error.h
@@ -63,11 +63,11 @@ Equivalent to:
std::wstring formatWin32Msg(DWORD dwMessageId) //return empty string on error
{
std::wstring output;
- LPWSTR buffer = NULL;
+ LPWSTR buffer = nullptr;
if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_MAX_WIDTH_MASK |
FORMAT_MESSAGE_IGNORE_INSERTS | //important: without this flag ::FormatMessage() will fail if message contains placeholders
- FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, dwMessageId, 0, reinterpret_cast<LPWSTR>(&buffer), 0, NULL) != 0)
+ FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, dwMessageId, 0, reinterpret_cast<LPWSTR>(&buffer), 0, nullptr) != 0)
{
if (buffer) //just to be sure
{
diff --git a/zen/com_ptr.h b/zen/com_ptr.h
index b55d873e..98963cd1 100644
--- a/zen/com_ptr.h
+++ b/zen/com_ptr.h
@@ -20,7 +20,7 @@ Example:
--------
ComPtr<IUPnPDeviceFinder> devFinder;
if (FAILED(::CoCreateInstance(CLSID_UPnPDeviceFinder,
- NULL,
+ nullptr,
CLSCTX_ALL,
IID_PPV_ARGS(devFinder.init()))))
return -1;
diff --git a/zen/com_util.h b/zen/com_util.h
index 2845e352..fe02eadd 100644
--- a/zen/com_util.h
+++ b/zen/com_util.h
@@ -82,7 +82,7 @@ std::vector<ComPtr<T> > convertEnum(const ComPtr<U>& enumObj)
if (enumUnknown)
{
ComPtr<IUnknown> itemTmp;
- while (enumUnknown->Next(1, itemTmp.init(), NULL) == S_OK) //returns S_FALSE == 1 when finished! Don't use SUCCEEDED()!!!
+ while (enumUnknown->Next(1, itemTmp.init(), nullptr) == S_OK) //returns S_FALSE == 1 when finished! Don't use SUCCEEDED()!!!
{
ComPtr<T> itemNew = com_dynamic_cast<T>(itemTmp);
if (itemNew)
@@ -103,11 +103,11 @@ std::wstring getText(ComPtr<T> comObj, MemFun memFun)
if (!comObj)
return std::wstring();
- BSTR bstr = NULL;
+ BSTR bstr = nullptr;
if (FAILED((comObj.get()->*memFun)(&bstr)))
return std::wstring();
- if (bstr) //NULL means "no text"
+ if (bstr) //nullptr means "no text"
{
text = std::wstring(bstr, ::SysStringLen(bstr)); //correctly copy 0-characters
::SysFreeString(bstr);
diff --git a/zen/debug_new.cpp b/zen/debug_new.cpp
index 9992f0b3..6cc0e2da 100644
--- a/zen/debug_new.cpp
+++ b/zen/debug_new.cpp
@@ -15,14 +15,14 @@ namespace
{
LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo)
{
- HANDLE hFile = ::CreateFile(L"exception.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE hFile = ::CreateFile(L"exception.dmp", GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile != INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION exInfo = {};
exInfo.ThreadId = ::GetCurrentThreadId();
exInfo.ExceptionPointers = pExceptionInfo;
- MINIDUMP_EXCEPTION_INFORMATION* exceptParam = pExceptionInfo ? &exInfo : NULL;
+ MINIDUMP_EXCEPTION_INFORMATION* exceptParam = pExceptionInfo ? &exInfo : nullptr;
/*bool rv = */
::MiniDumpWriteDump(::GetCurrentProcess(), //__in HANDLE hProcess,
@@ -30,8 +30,8 @@ LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo)
hFile, //__in HANDLE hFile,
MiniDumpWithDataSegs, //__in MINIDUMP_TYPE DumpType, ->Standard: MiniDumpNormal, Medium: MiniDumpWithDataSegs, Full: MiniDumpWithFullMemory
exceptParam, //__in PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
- NULL, //__in PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
- NULL); //__in PMINIDUMP_CALLBACK_INFORMATION CallbackParam
+ nullptr, //__in PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ nullptr); //__in PMINIDUMP_CALLBACK_INFORMATION CallbackParam
::CloseHandle(hFile);
}
@@ -45,5 +45,5 @@ struct Dummy { Dummy() { ::SetUnhandledExceptionFilter(writeDumpOnException); }}
void mem_check::writeMinidump()
{
- writeDumpOnException(NULL);
+ writeDumpOnException(nullptr);
}
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 6ab56100..ed07a1e4 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -28,15 +28,6 @@ using namespace zen;
#ifdef FFS_WIN
namespace
{
-inline
-bool errorCodeForNotExisting(const DWORD lastError)
-{
- return lastError == ERROR_PATH_NOT_FOUND ||
- lastError == ERROR_BAD_NETPATH ||
- lastError == ERROR_NETNAME_DELETED;
-}
-
-
class SharedData
{
public:
@@ -152,13 +143,13 @@ public:
hDir = ::CreateFile(applyLongPathPrefix(dirname.c_str()).c_str(),
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
- NULL);
+ nullptr);
if (hDir == INVALID_HANDLE_VALUE)
{
- const std::wstring errorMsg = _("Could not initialize directory monitoring:") + L"\n\"" + dirname + L"\"" + L"\n\n" + zen::getLastErrorFormatted();
+ const std::wstring errorMsg = _("Could not initialize directory monitoring:") + L"\n\"" + dirname + L"\"" L"\n\n" + zen::getLastErrorFormatted();
if (errorCodeForNotExisting(::GetLastError()))
throw ErrorNotExisting(errorMsg);
throw FileError(errorMsg);
@@ -185,30 +176,30 @@ public:
//actual work
OVERLAPPED overlapped = {};
- overlapped.hEvent = ::CreateEvent(NULL, //__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
- true, //__in BOOL bManualReset,
- false, //__in BOOL bInitialState,
- NULL); //__in_opt LPCTSTR lpName
- if (overlapped.hEvent == NULL)
- return shared_->reportError(_("Error when monitoring directories.") + L" (CreateEvent)" + L"\n\n" + getLastErrorFormatted(), ::GetLastError());
- ZEN_ON_BLOCK_EXIT(::CloseHandle(overlapped.hEvent));
+ overlapped.hEvent = ::CreateEvent(nullptr, //__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
+ true, //__in BOOL bManualReset,
+ false, //__in BOOL bInitialState,
+ nullptr); //__in_opt LPCTSTR lpName
+ if (overlapped.hEvent == nullptr)
+ return shared_->reportError(_("Error when monitoring directories.") + L" (CreateEvent)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(overlapped.hEvent));
//asynchronous variant: runs on this thread's APC queue!
- if (!::ReadDirectoryChangesW(hDir, // __in HANDLE hDirectory,
- &buffer[0], // __out LPVOID lpBuffer,
+ if (!::ReadDirectoryChangesW(hDir, // __in HANDLE hDirectory,
+ &buffer[0], // __out LPVOID lpBuffer,
static_cast<DWORD>(buffer.size()), // __in DWORD nBufferLength,
- true, // __in BOOL bWatchSubtree,
+ true, // __in BOOL bWatchSubtree,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE, // __in DWORD dwNotifyFilter,
- NULL, // __out_opt LPDWORD lpBytesReturned,
+ nullptr, // __out_opt LPDWORD lpBytesReturned,
&overlapped, // __inout_opt LPOVERLAPPED lpOverlapped,
- NULL)) // __in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
- return shared_->reportError(_("Error when monitoring directories.") + L" (ReadDirectoryChangesW)" + L"\n\n" + getLastErrorFormatted(), ::GetLastError());
+ nullptr)) // __in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
+ return shared_->reportError(_("Error when monitoring directories.") + L" (ReadDirectoryChangesW)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
//async I/O is a resource that needs to be guarded since it will write to local variable "buffer"!
- zen::ScopeGuard lockAio = zen::makeGuard([&]()
+ zen::ScopeGuard guardAio = zen::makeGuard([&]
{
//http://msdn.microsoft.com/en-us/library/aa363789(v=vs.85).aspx
if (::CancelIo(hDir) == TRUE) //cancel all async I/O related to this handle and thread
@@ -218,16 +209,15 @@ public:
}
});
- DWORD bytesWritten = 0;
-
//wait for results
+ DWORD bytesWritten = 0;
while (!::GetOverlappedResult(hDir, //__in HANDLE hFile,
&overlapped, //__in LPOVERLAPPED lpOverlapped,
&bytesWritten, //__out LPDWORD lpNumberOfBytesTransferred,
false)) //__in BOOL bWait
{
if (::GetLastError() != ERROR_IO_INCOMPLETE)
- return shared_->reportError(_("Error when monitoring directories.") + L" (GetOverlappedResult)" + L"\n\n" + getLastErrorFormatted(), ::GetLastError());
+ return shared_->reportError(_("Error when monitoring directories.") + L" (GetOverlappedResult)" L"\n\n" + getLastErrorFormatted(), ::GetLastError());
//execute asynchronous procedure calls (APC) queued on this thread
::SleepEx(50, // __in DWORD dwMilliseconds,
@@ -235,7 +225,7 @@ public:
boost::this_thread::interruption_point();
}
- lockAio.dismiss();
+ guardAio.dismiss();
shared_->addChanges(&buffer[0], bytesWritten, dirname); //throw ()
}
@@ -370,8 +360,8 @@ public:
DirsOnlyTraverser(std::vector<Zstring>& dirs,
const std::shared_ptr<TraverseCallback>& otherMe) : otherMe_(otherMe), dirs_(dirs) {}
- virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details) {}
- virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) {}
+ virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details) {}
+ virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) {}
virtual std::shared_ptr<TraverseCallback> onDir(const Zchar* shortName, const Zstring& fullName)
{
dirs_.push_back(fullName);
diff --git a/zen/dll.h b/zen/dll.h
index e25e6916..f80a5f45 100644
--- a/zen/dll.h
+++ b/zen/dll.h
@@ -21,7 +21,7 @@ Manage DLL function and library ownership
Usage:
typedef BOOL (WINAPI* IsWow64ProcessFun)(HANDLE hProcess, PBOOL Wow64Process);
- const zen::DllFun<IsWow64ProcessFun> isWow64Process(L"kernel32.dll", "IsWow64Process");
+ const zen::SysDllFun<IsWow64ProcessFun> isWow64Process(L"kernel32.dll", "IsWow64Process");
if (isWow64Process) ... use function ptr ...
*/
@@ -29,11 +29,11 @@ template <class Func>
class DllFun
{
public:
- DllFun() : fun(NULL) {}
+ DllFun() : fun(nullptr) {}
DllFun(const wchar_t* libraryName, const char* functionName) :
hLibRef(new HMODULE(::LoadLibrary(libraryName)), deleter),
- fun(*hLibRef ? reinterpret_cast<Func>(::GetProcAddress(*hLibRef, functionName)) : NULL) {}
+ fun(*hLibRef ? reinterpret_cast<Func>(::GetProcAddress(*hLibRef, functionName)) : nullptr) {}
operator Func() const { return fun; }
@@ -50,10 +50,13 @@ template <class Func>
class SysDllFun
{
public:
- SysDllFun() : fun(NULL) {}
+ SysDllFun() : fun(nullptr) {}
- SysDllFun(const wchar_t* systemLibrary, const char* functionName) :
- fun(reinterpret_cast<Func>(::GetProcAddress(::GetModuleHandle(systemLibrary), functionName))) {}
+ SysDllFun(const wchar_t* systemLibrary, const char* functionName)
+ {
+ HMODULE mod = ::GetModuleHandle(systemLibrary);
+ fun = mod ? reinterpret_cast<Func>(::GetProcAddress(mod, functionName)) : nullptr;
+ }
operator Func() const { return fun; }
@@ -88,32 +91,24 @@ std::string getResourceStream(const std::wstring& libraryName, size_t resourceId
-//---------------Inline Implementation---------------------------------------------------
+//--------------- implementation---------------------------------------------------
inline
std::string getResourceStream(const wchar_t* libraryName, size_t resourceId)
{
- std::string output;
- HMODULE module = ::LoadLibrary(libraryName);
- if (module)
+ if (HMODULE module = ::LoadLibrary(libraryName))
{
- ZEN_ON_BLOCK_EXIT(::FreeLibrary(module));
+ ZEN_ON_SCOPE_EXIT(::FreeLibrary(module));
- const HRSRC res = ::FindResource(module, MAKEINTRESOURCE(resourceId), RT_RCDATA);
- if (res != NULL)
+ if (HRSRC res = ::FindResource(module, MAKEINTRESOURCE(resourceId), RT_RCDATA))
{
- const HGLOBAL resHandle = ::LoadResource(module, res);
- if (resHandle != NULL)
+ if (HGLOBAL resHandle = ::LoadResource(module, res))
{
- const char* stream = static_cast<const char*>(::LockResource(resHandle));
- if (stream)
- {
- const DWORD streamSize = ::SizeofResource(module, res);
- output.assign(stream, streamSize);
- }
+ if (const char* stream = static_cast<const char*>(::LockResource(resHandle)))
+ return std::string(stream, static_cast<size_t>(::SizeofResource(module, res))); //size is 0 on error
}
}
}
- return output;
+ return std::string();
}
}
diff --git a/zen/dst_hack.cpp b/zen/dst_hack.cpp
index 9fe3a550..3ecfd8e9 100644
--- a/zen/dst_hack.cpp
+++ b/zen/dst_hack.cpp
@@ -17,9 +17,9 @@ namespace
Zstring getVolumeName(const Zstring& filename)
{
//this call is expensive: ~1.5 ms!
- // if (!::GetVolumePathName(applyLongPathPrefix(filename).c_str(), //__in LPCTSTR lpszFileName,
- // fsName, //__out LPTSTR lpszVolumePathName,
- // BUFFER_SIZE)) //__in DWORD cchBufferLength
+ // if (!::GetVolumePathName(filename.c_str(), //__in LPCTSTR lpszFileName,
+ // fsName, //__out LPTSTR lpszVolumePathName,
+ // BUFFER_SIZE)) //__in DWORD cchBufferLength
// ...
// Zstring volumePath = fsName;
// if (!volumePath.EndsWith(FILE_NAME_SEPARATOR)) //a trailing backslash is required
@@ -65,11 +65,11 @@ bool dst::isFatDrive(const Zstring& fileName) //throw()
//suprisingly fast: ca. 0.03 ms per call!
if (!::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
- NULL, //__out LPTSTR lpVolumeNameBuffer,
+ nullptr, //__out LPTSTR lpVolumeNameBuffer,
0, //__in DWORD nVolumeNameSize,
- NULL, //__out_opt LPDWORD lpVolumeSerialNumber,
- NULL, //__out_opt LPDWORD lpMaximumComponentLength,
- NULL, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
fsName, //__out LPTSTR lpFileSystemNameBuffer,
BUFFER_SIZE)) //__in DWORD nFileSystemNameSize
{
@@ -105,11 +105,11 @@ bool dst::isFatDrive(HANDLE hFile) //throw()
wchar_t fsName[BUFFER_SIZE];
if (!getVolumeInformationByHandle(hFile, //__in HANDLE hFile,
- NULL, //__out LPTSTR lpVolumeNameBuffer,
+ nullptr, //__out LPTSTR lpVolumeNameBuffer,
0, //__in DWORD nVolumeNameSize,
- NULL, //__out_opt LPDWORD lpVolumeSerialNumber,
- NULL, //__out_opt LPDWORD lpMaximumComponentLength,
- NULL, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
fsName, //__out LPTSTR lpFileSystemNameBuffer,
BUFFER_SIZE)) //__in DWORD nFileSystemNameSize
{
@@ -158,6 +158,7 @@ Int64 toInt64(const FILETIME& fileTime)
}
+inline
FILETIME utcToLocal(const FILETIME& utcTime) //throw (std::runtime_error)
{
//treat binary local time representation (which is invariant under DST time zone shift) as logical UTC:
@@ -167,14 +168,15 @@ FILETIME utcToLocal(const FILETIME& utcTime) //throw (std::runtime_error)
&localTime)) //__out LPFILETIME lpLocalFileTime
{
const std::wstring errorMessage = _("Conversion error:") + L" FILETIME -> local FILETIME: " + L"(" +
- L"High: " + toString<std::wstring>(utcTime.dwHighDateTime) + L" " +
- L"Low: " + toString<std::wstring>(utcTime.dwLowDateTime) + L") " + L"\n\n" + getLastErrorFormatted();
+ L"High: " + numberTo<std::wstring>(utcTime.dwHighDateTime) + L" " +
+ L"Low: " + numberTo<std::wstring>(utcTime.dwLowDateTime) + L") " + L"\n\n" + getLastErrorFormatted();
throw std::runtime_error(wideToUtf8<std::string>(errorMessage));
}
return localTime;
}
+inline
FILETIME localToUtc(const FILETIME& localTime) //throw (std::runtime_error)
{
//treat binary local time representation (which is invariant under DST time zone shift) as logical UTC:
@@ -184,8 +186,8 @@ FILETIME localToUtc(const FILETIME& localTime) //throw (std::runtime_error)
&utcTime)) //__out LPFILETIME lpFileTime
{
const std::wstring errorMessage = _("Conversion error:") + L" local FILETIME -> FILETIME: " + L"(" +
- L"High: " + toString<std::wstring>(localTime.dwHighDateTime) + L" " +
- L"Low: " + toString<std::wstring>(localTime.dwLowDateTime) + L") " + L"\n\n" + getLastErrorFormatted();
+ L"High: " + numberTo<std::wstring>(localTime.dwHighDateTime) + L" " +
+ L"Low: " + numberTo<std::wstring>(localTime.dwLowDateTime) + L") " + L"\n\n" + getLastErrorFormatted();
throw std::runtime_error(wideToUtf8<std::string>(errorMessage));
}
return utcTime;
@@ -214,7 +216,7 @@ const size_t UTC_LOCAL_OFFSET_BITS = 7;
const size_t WRITE_TIME_HASH_BITS = CREATE_TIME_INFO_BITS - INDICATOR_EXISTING_BITS - UTC_LOCAL_OFFSET_BITS;
-template <size_t precision>
+template <size_t precision> inline
FILETIME encodeRawInformation(UInt64 rawInfo)
{
rawInfo *= precision;
@@ -225,7 +227,7 @@ FILETIME encodeRawInformation(UInt64 rawInfo)
}
-template <size_t precision>
+template <size_t precision> inline
UInt64 extractRawInformation(const FILETIME& createTime)
{
assert(toUInt64(FAT_MIN_TIME) <= toUInt64(createTime));
@@ -243,6 +245,7 @@ UInt64 extractRawInformation(const FILETIME& createTime)
//convert write time to it's minimal representation (no restriction to FAT range "1980 - 2107")
+inline
UInt64 extractRawWriteTime(const FILETIME& writeTime)
{
UInt64 rawInfo = toUInt64(writeTime);
@@ -253,6 +256,7 @@ UInt64 extractRawWriteTime(const FILETIME& writeTime)
//files with different resolution than 2 seconds are rounded up when written to FAT
+inline
FILETIME roundToFatWriteTime(const FILETIME& writeTime)
{
UInt64 rawData = toUInt64(writeTime);
@@ -284,7 +288,7 @@ std::bitset<UTC_LOCAL_OFFSET_BITS> getUtcLocalShift()
timeShiftSec % (60 * 15) != 0) //all known time shift have at least 15 minute granularity!
{
const std::wstring errorMessage = _("Conversion error:") + L" Unexpected UTC <-> local time shift: " +
- L"(" + toString<std::wstring>(timeShiftSec) + L") " + L"\n\n" + getLastErrorFormatted();
+ L"(" + numberTo<std::wstring>(timeShiftSec) + L") " + L"\n\n" + getLastErrorFormatted();
throw std::runtime_error(wideToUtf8<std::string>(errorMessage));
}
diff --git a/zen/error_log.h b/zen/error_log.h
new file mode 100644
index 00000000..f3f67233
--- /dev/null
+++ b/zen/error_log.h
@@ -0,0 +1,133 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef ERRORLOGGING_H_INCLUDED
+#define ERRORLOGGING_H_INCLUDED
+
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <zen/time.h>
+#include <zen/i18n.h>
+
+namespace zen
+{
+enum MessageType
+{
+ TYPE_INFO = 1,
+ TYPE_WARNING = 2,
+ TYPE_ERROR = 4,
+ TYPE_FATAL_ERROR = 8,
+};
+
+struct LogEntry
+{
+ time_t time;
+ MessageType type;
+ std::wstring message;
+};
+
+std::wstring formatMessage(const LogEntry& msg);
+
+
+class ErrorLog
+{
+public:
+ void logMsg(const std::wstring& message, MessageType type);
+
+ int getItemCount(int typeFilter = TYPE_INFO | TYPE_WARNING | TYPE_ERROR | TYPE_FATAL_ERROR) const;
+
+ const std::vector<LogEntry>& getEntries() const { return logEntries; }
+
+private:
+ std::vector<LogEntry> logEntries; //list of non-resolved errors and warnings
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//######################## implementation ##########################
+
+inline
+void ErrorLog::logMsg(const std::wstring& message, zen::MessageType type)
+{
+ const LogEntry newEntry = { std::time(nullptr), type, message };
+ logEntries.push_back(newEntry);
+}
+
+
+inline
+int ErrorLog::getItemCount(int typeFilter) const
+{
+ return static_cast<int>(std::count_if(logEntries.begin(), logEntries.end(), [&](const LogEntry& e) { return e.type & typeFilter; }));
+}
+
+
+namespace
+{
+std::wstring formatMessageImpl(const LogEntry& entry) //internal linkage
+{
+ auto getTypeName = [&]() -> std::wstring
+ {
+ switch (entry.type)
+ {
+ case TYPE_INFO:
+ return _("Info");
+ case TYPE_WARNING:
+ return _("Warning");
+ case TYPE_ERROR:
+ return _("Error");
+ case TYPE_FATAL_ERROR:
+ return _("Fatal Error");
+ }
+ return std::wstring();
+ };
+
+ std::wstring formattedText = L"[" + formatTime<std::wstring>(FORMAT_TIME, localTime(entry.time)) + L"] " + getTypeName() + L": ";
+ const size_t prefixLen = formattedText.size();
+
+ for (auto iter = entry.message.begin(); iter != entry.message.end(); )
+ if (*iter == L'\n')
+ {
+ formattedText += L'\n';
+
+ std::wstring blanks;
+ blanks.resize(prefixLen, L' ');
+ formattedText += blanks;
+
+ do //skip duplicate newlines
+ {
+ ++iter;
+ }
+ while (iter != entry.message.end() && *iter == L'\n');
+ }
+ else
+ formattedText += *iter++;
+
+ return formattedText;
+}
+}
+
+inline std::wstring formatMessage(const LogEntry& entry) { return formatMessageImpl(entry); }
+
+}
+
+#endif // ERRORLOGGING_H_INCLUDED
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index dd5276a4..a81b3a80 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -31,7 +31,6 @@
#include <sys/stat.h>
#include <time.h>
#include <utime.h>
-#include <cerrno>
#include <sys/time.h>
#ifdef HAVE_SELINUX
@@ -89,7 +88,8 @@ bool zen::symlinkExists(const Zstring& objname)
bool zen::somethingExists(const Zstring& objname) //throw() check whether any object with this name exists
{
#ifdef FFS_WIN
- return ::GetFileAttributes(applyLongPathPrefix(objname).c_str()) != INVALID_FILE_ATTRIBUTES;
+ const DWORD rv = ::GetFileAttributes(applyLongPathPrefix(objname).c_str());
+ return rv != INVALID_FILE_ATTRIBUTES || ::GetLastError() == ERROR_SHARING_VIOLATION; //"C:\pagefile.sys"
#elif defined FFS_LINUX
struct stat fileInfo = {};
@@ -142,10 +142,10 @@ void getFileAttrib(const Zstring& filename, FileAttrib& attr, ProcSymlink procSl
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
+ nullptr);
if (hFile == INVALID_HANDLE_VALUE)
throw FileError(_("Error reading file attributes:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hFile));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
BY_HANDLE_FILE_INFORMATION fileInfoHnd = {};
if (!::GetFileInformationByHandle(hFile, &fileInfoHnd))
@@ -211,12 +211,12 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //return 0 on error!
DWORD volumeSerial = 0;
if (!::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
- NULL, //__out LPTSTR lpVolumeNameBuffer,
+ nullptr, //__out LPTSTR lpVolumeNameBuffer,
0, //__in DWORD nVolumeNameSize,
&volumeSerial, //__out_opt LPDWORD lpVolumeSerialNumber,
- NULL, //__out_opt LPDWORD lpMaximumComponentLength,
- NULL, //__out_opt LPDWORD lpFileSystemFlags,
- NULL, //__out LPTSTR lpFileSystemNameBuffer,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
0)) //__in DWORD nFileSystemNameSize
return 0;
@@ -260,34 +260,27 @@ zen::ResponseSame zen::onSameVolume(const Zstring& folderLeft, const Zstring& fo
bool zen::removeFile(const Zstring& filename) //throw FileError;
{
#ifdef FFS_WIN
- //remove file, support for \\?\-prefix
- const Zstring filenameFmt = applyLongPathPrefix(filename);
+ const Zstring& filenameFmt = applyLongPathPrefix(filename);
if (!::DeleteFile(filenameFmt.c_str()))
#elif defined FFS_LINUX
if (::unlink(filename.c_str()) != 0)
#endif
{
+ ErrorCode lastError = getLastError();
+ if (errorCodeForNotExisting(lastError)) //no error situation if file is not existing! manual deletion relies on it!
+ return false;
#ifdef FFS_WIN
- //perf: apply ONLY when necessary!
- if (::GetLastError() == ERROR_ACCESS_DENIED) //function fails if file is read-only
+ else if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only
{
- //(try to) normalize file attributes
- ::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL);
+ ::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL); //(try to) normalize file attributes
- //now try again...
- if (::DeleteFile(filenameFmt.c_str()))
+ if (::DeleteFile(filenameFmt.c_str())) //now try again...
return true;
+ lastError = ::GetLastError();
}
- //eval error code before next call
- DWORD lastError = ::GetLastError();
-#elif defined FFS_LINUX
- int lastError = errno;
#endif
-
- //no error situation if file is not existing! manual deletion relies on it!
- //perf: check is placed in error handling block
- //warning: this call changes error code!!
- if (!somethingExists(filename))
+ //after "lastError" evaluation it *may* be redundant to check existence again, but better be safe than sorry:
+ if (!somethingExists(filename)) //warning: changes global error code!!
return false; //neither file nor any other object (e.g. broken symlink) with that name existing
throw FileError(_("Error deleting file:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted(lastError));
@@ -383,7 +376,7 @@ Zstring getFilenameFmt(const Zstring& filename, Function fun) //throw(); returns
{
const Zstring filenameFmt = applyLongPathPrefix(filename);
- const DWORD bufferSize = fun(filenameFmt.c_str(), NULL, 0);
+ const DWORD bufferSize = fun(filenameFmt.c_str(), nullptr, 0);
if (bufferSize == 0)
return Zstring();
@@ -407,11 +400,12 @@ Zstring findUnused8Dot3Name(const Zstring& filename) //find a unique 8.3 short n
Zstring extension = afterLast(afterLast(filename, FILE_NAME_SEPARATOR), Zchar('.')); //extension needn't contain reasonable data
if (extension.empty())
extension = Zstr("FFS");
- truncate(extension, 3);
+ else if (extension.length() > 3)
+ extension.resize(3);
for (int index = 0; index < 100000000; ++index) //filename must be representable by <= 8 characters
{
- const Zstring output = pathPrefix + toString<Zstring>(index) + Zchar('.') + extension;
+ const Zstring output = pathPrefix + numberTo<Zstring>(index) + Zchar('.') + extension;
if (!somethingExists(output)) //ensure uniqueness
return output;
}
@@ -559,7 +553,7 @@ void zen::moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ig
copySymlink(sourceFile, targetFile, false); //throw FileError; don't copy filesystem permissions
else
{
- std::unique_ptr<CopyCallbackImpl> copyCallback(callback != NULL ? new CopyCallbackImpl(sourceFile, targetFile, *callback) : NULL);
+ std::unique_ptr<CopyCallbackImpl> copyCallback(callback ? new CopyCallbackImpl(sourceFile, targetFile, *callback) : nullptr);
copyFile(sourceFile, targetFile, false, true, copyCallback.get()); //throw FileError;
}
@@ -687,7 +681,7 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool
}
//delete source
- std::unique_ptr<RemoveCallbackImpl> removeCallback(callback != NULL ? new RemoveCallbackImpl(*callback) : NULL);
+ std::unique_ptr<RemoveCallbackImpl> removeCallback(callback ? new RemoveCallbackImpl(*callback) : nullptr);
removeDirectory(sourceDir, removeCallback.get()); //throw FileError;
if (callback) callback->objectProcessed();
@@ -779,32 +773,32 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
std::vector<Zstring> fileList;
std::vector<Zstring> dirList;
+ {
+ //get all files and directories from current directory (WITHOUT subdirectories!)
+ FilesDirsOnlyTraverser traverser(fileList, dirList);
+ traverseFolder(directory, false, traverser); //don't follow symlinks
+ }
- //get all files and directories from current directory (WITHOUT subdirectories!)
- FilesDirsOnlyTraverser traverser(fileList, dirList);
- traverseFolder(directory, false, traverser); //don't follow symlinks
+ //delete directories recursively
+ for (auto iter = dirList.begin(); iter != dirList.end(); ++iter)
+ removeDirectory(*iter, callback); //call recursively to correctly handle symbolic links
//delete files
- for (std::vector<Zstring>::const_iterator i = fileList.begin(); i != fileList.end(); ++i)
+ for (auto iter = fileList.begin(); iter != fileList.end(); ++iter)
{
- const bool workDone = removeFile(*i);
+ const bool workDone = removeFile(*iter);
if (callback && workDone)
- callback->notifyFileDeletion(*i); //call once per file
+ callback->notifyFileDeletion(*iter); //call once per file
}
- //delete directories recursively
- for (std::vector<Zstring>::const_iterator i = dirList.begin(); i != dirList.end(); ++i)
- removeDirectory(*i, callback); //call recursively to correctly handle symbolic links
-
//parent directory is deleted last
#ifdef FFS_WIN
- if (!::RemoveDirectory(directoryFmt.c_str())) //remove directory, support for \\?\-prefix
+ if (!::RemoveDirectory(directoryFmt.c_str()))
#else
if (::rmdir(directory.c_str()) != 0)
#endif
- {
throw FileError(_("Error deleting directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + getLastErrorFormatted());
- }
+
if (callback)
callback->notifyDirDeletion(directory); //and once per folder
}
@@ -848,7 +842,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | //needed to open a directory
(procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //process symlinks
- NULL);
+ nullptr);
});
if (targetHandle.get() == INVALID_HANDLE_VALUE)
@@ -865,8 +859,8 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
auto isNullTime = [](const FILETIME & ft) { return ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0; };
if (!::SetFileTime(targetHandle.get(),
- isNullTime(creationTime) ? NULL : &creationTime,
- NULL,
+ isNullTime(creationTime) ? nullptr : &creationTime,
+ nullptr,
&lastWriteTime))
throw FileError(_("Error changing modification time:") + L"\n\"" + filename + L"\"" + L"\n\n" + getLastErrorFormatted());
@@ -887,7 +881,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
if (procSl == SYMLINK_FOLLOW)
{
struct utimbuf newTimes = {};
- newTimes.actime = ::time(NULL);
+ newTimes.actime = ::time(nullptr);
newTimes.modtime = to<time_t>(modificationTime);
// set new "last write time"
@@ -897,7 +891,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
else
{
struct timeval newTimes[2] = {};
- newTimes[0].tv_sec = ::time(NULL); /* seconds */
+ newTimes[0].tv_sec = ::time(nullptr); /* seconds */
newTimes[0].tv_usec = 0; /* microseconds */
newTimes[1].tv_sec = to<time_t>(modificationTime);
@@ -913,43 +907,65 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
bool zen::supportsPermissions(const Zstring& dirname) //throw FileError
{
#ifdef FFS_WIN
- const HANDLE hDir = ::CreateFile(zen::applyLongPathPrefix(dirname).c_str(),
- 0,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, // | FILE_FLAG_OPEN_REPARSE_POINT -> follow symlinks
- NULL);
- if (hDir == INVALID_HANDLE_VALUE)
+ std::vector<wchar_t> buffer(MAX_PATH + 1);
+ if (!::GetVolumePathName(dirname.c_str(), //__in LPCTSTR lpszFileName,
+ &buffer[0], //__out LPTSTR lpszVolumePathName,
+ static_cast<DWORD>(buffer.size()))) //__in DWORD cchBufferLength
throw FileError(_("Error reading file attributes:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hDir));
-
- //dynamically load windows API function (existing since Windows XP)
- typedef BOOL (WINAPI* GetVolumeInformationByHandleWFun)(HANDLE hFile,
- LPWSTR lpVolumeNameBuffer,
- DWORD nVolumeNameSize,
- LPDWORD lpVolumeSerialNumber,
- LPDWORD lpMaximumComponentLength,
- LPDWORD lpFileSystemFlags,
- LPWSTR lpFileSystemNameBuffer,
- DWORD nFileSystemNameSize);
-
- const SysDllFun<GetVolumeInformationByHandleWFun> getVolumeInformationByHandleW(L"kernel32.dll", "GetVolumeInformationByHandleW");
- if (!getVolumeInformationByHandleW)
- throw FileError(_("Error loading library function:") + L"\n\"" + L"GetVolumeInformationByHandleW" + L"\"");
-
- DWORD fileSystemFlags = 0;
- if (!getVolumeInformationByHandleW(hDir, //__in HANDLE hFile,
- NULL, //__out_opt LPTSTR lpVolumeNameBuffer,
- 0, //__in DWORD nVolumeNameSize,
- NULL, //__out_opt LPDWORD lpVolumeSerialNumber,
- NULL, //__out_opt LPDWORD lpMaximumComponentLength,
- &fileSystemFlags, //__out_opt LPDWORD lpFileSystemFlags,
- NULL, //__out LPTSTR lpFileSystemNameBuffer,
- 0)) //__in DWORD nFileSystemNameSize
+
+ DWORD fsFlags = 0;
+ if (!::GetVolumeInformation(&buffer[0], //__in_opt LPCTSTR lpRootPathName,
+ nullptr, //__out LPTSTR lpVolumeNameBuffer,
+ 0, //__in DWORD nVolumeNameSize,
+ nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ &fsFlags, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
+ 0)) //__in DWORD nFileSystemNameSize
throw FileError(_("Error reading file attributes:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
- return (fileSystemFlags & FILE_PERSISTENT_ACLS) != 0;
+ return (fsFlags & FILE_PERSISTENT_ACLS) != 0;
+
+
+ // -> the following approach is *only* working since Windows Vista:
+ // const HANDLE hDir = ::CreateFile(zen::applyLongPathPrefix(dirname).c_str(),
+ // 0,
+ // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ // nullptr,
+ // OPEN_EXISTING,
+ // FILE_FLAG_BACKUP_SEMANTICS, // | FILE_FLAG_OPEN_REPARSE_POINT -> follow symlinks
+ // nullptr);
+ // if (hDir == INVALID_HANDLE_VALUE)
+ // throw FileError(_("Error reading file attributes:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
+ // ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
+ //
+ // //dynamically load windows API function (existing since Windows XP)
+ // typedef BOOL (WINAPI* GetVolumeInformationByHandleWFun)(HANDLE hFile,
+ // LPWSTR lpVolumeNameBuffer,
+ // DWORD nVolumeNameSize,
+ // LPDWORD lpVolumeSerialNumber,
+ // LPDWORD lpMaximumComponentLength,
+ // LPDWORD lpFileSystemFlags,
+ // LPWSTR lpFileSystemNameBuffer,
+ // DWORD nFileSystemNameSize);
+ //
+ // const SysDllFun<GetVolumeInformationByHandleWFun> getVolumeInformationByHandleW(L"kernel32.dll", "GetVolumeInformationByHandleW"); //available since Windows Vista
+ // if (!getVolumeInformationByHandleW)
+ // return true; //Windows XP, 2000 -> do not show this error message
+ // //throw FileError(rror loading library function+ L"\n\"" + L"GetVolumeInformationByHandleW" + L"\"");
+ //
+ // DWORD fileSystemFlags = 0;
+ // if (!getVolumeInformationByHandleW(hDir, //__in HANDLE hFile,
+ // nullptr, //__out_opt LPTSTR lpVolumeNameBuffer,
+ // 0, //__in DWORD nVolumeNameSize,
+ // nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+ // nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ // &fileSystemFlags, //__out_opt LPDWORD lpFileSystemFlags,
+ // nullptr, //__out LPTSTR lpFileSystemNameBuffer,
+ // 0)) //__in DWORD nFileSystemNameSize
+ // throw FileError(_("Error reading file attributes:") + L"\n\"" + dirname + L"\"" + L"\n\n" + getLastErrorFormatted());
+ //
+ // return (fileSystemFlags & FILE_PERSISTENT_ACLS) != 0;
#elif defined FFS_LINUX
return true;
@@ -969,10 +985,10 @@ Zstring getSymlinkTargetPath(const Zstring& symlink) //throw FileError
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory
- NULL);
+ nullptr);
if (hDir == INVALID_HANDLE_VALUE)
throw FileError(_("Error resolving symbolic link:") + L"\n\"" + symlink + L"\"" + L"\n\n" + getLastErrorFormatted());
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hDir));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
//dynamically load windows API function
typedef DWORD (WINAPI* GetFinalPathNameByHandleWFunc)(HANDLE hFile,
@@ -1006,7 +1022,7 @@ Zstring getSymlinkTargetPath(const Zstring& symlink) //throw FileError
//copy SELinux security context
void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymlink procSl) //throw FileError
{
- security_context_t contextSource = NULL;
+ security_context_t contextSource = nullptr;
const int rv = procSl == SYMLINK_FOLLOW ?
::getfilecon(source.c_str(), &contextSource) :
::lgetfilecon(source.c_str(), &contextSource);
@@ -1018,10 +1034,10 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
throw FileError(_("Error reading security context:") + L"\n\"" + source + L"\"" + L"\n\n" + getLastErrorFormatted());
}
- ZEN_ON_BLOCK_EXIT(::freecon(contextSource));
+ ZEN_ON_SCOPE_EXIT(::freecon(contextSource));
{
- security_context_t contextTarget = NULL;
+ security_context_t contextTarget = nullptr;
const int rv2 = procSl == SYMLINK_FOLLOW ?
::getfilecon(target.c_str(), &contextTarget) :
::lgetfilecon(target.c_str(), &contextTarget);
@@ -1033,7 +1049,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
}
else
{
- ZEN_ON_BLOCK_EXIT(::freecon(contextTarget));
+ ZEN_ON_SCOPE_EXIT(::freecon(contextTarget));
if (::strcmp(contextSource, contextTarget) == 0) //nothing to do
return;
@@ -1121,11 +1137,11 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
throw FileError(_("Error copying file permissions:") + L"\n\"" + sourceResolved + L"\" ->\n\"" + targetResolved + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (W)");
/*
- PSECURITY_DESCRIPTOR buffer = NULL;
- PSID owner = NULL;
- PSID group = NULL;
- PACL dacl = NULL;
- PACL sacl = NULL;
+ PSECURITY_DESCRIPTOR buffer = nullptr;
+ PSID owner = nullptr;
+ PSID group = nullptr;
+ PACL dacl = nullptr;
+ PACL sacl = nullptr;
//File Security and Access Rights: http://msdn.microsoft.com/en-us/library/aa364399(v=VS.85).aspx
//SECURITY_INFORMATION Access Rights: http://msdn.microsoft.com/en-us/library/windows/desktop/aa379573(v=vs.85).aspx
@@ -1135,10 +1151,10 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory
- NULL);
+ nullptr);
if (hSource == INVALID_HANDLE_VALUE)
throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted() + L" (OR)");
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hSource));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hSource));
// DWORD rc = ::GetNamedSecurityInfo(const_cast<WCHAR*>(applyLongPathPrefix(source).c_str()), -> does NOT dereference symlinks!
DWORD rc = ::GetSecurityInfo(hSource, //__in LPTSTR pObjectName,
@@ -1152,7 +1168,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
&buffer); //__out_opt PSECURITY_DESCRIPTOR *ppSecurityDescriptor
if (rc != ERROR_SUCCESS)
throw FileError(_("Error copying file permissions:") + L"\n\"" + source + L"\" ->\n\"" + target + L"\"" + L"\n\n" + getLastErrorFormatted(rc) + L" (R)");
- ZEN_ON_BLOCK_EXIT(::LocalFree(buffer));
+ ZEN_ON_SCOPE_EXIT(::LocalFree(buffer));
SECURITY_DESCRIPTOR_CONTROL secCtrl = 0;
{
@@ -1172,7 +1188,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
0, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDisposition
FILE_FLAG_BACKUP_SEMANTICS | (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), // dwFlagsAndAttributes
- NULL); // hTemplateFile
+ nullptr); // hTemplateFile
});
if (targetHandle.get() == INVALID_HANDLE_VALUE)
@@ -1233,7 +1249,7 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
//- it may fail with "wrong parameter (error code 87)" when source is on mapped online storage
//- automatically copies symbolic links if encountered: unfortunately it doesn't copy symlinks over network shares but silently creates empty folders instead (on XP)!
//- it isn't able to copy most junctions because of missing permissions (although target path can be retrieved alternatively!)
- if (!::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), NULL))
+ if (!::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), nullptr))
#elif defined FFS_LINUX
if (::mkdir(directory.c_str(), 0755) != 0)
#endif
@@ -1282,10 +1298,10 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
+ nullptr);
if (hDir != INVALID_HANDLE_VALUE)
{
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hDir));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
USHORT cmpState = COMPRESSION_FORMAT_DEFAULT;
@@ -1294,16 +1310,16 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
FSCTL_SET_COMPRESSION, //dwIoControlCode
&cmpState, //input buffer
sizeof(cmpState), //size of input buffer
- NULL, //lpOutBuffer
+ nullptr, //lpOutBuffer
0, //OutBufferSize
&bytesReturned, //number of bytes returned
- NULL); //OVERLAPPED structure
+ nullptr); //OVERLAPPED structure
}
}
}
}
#endif
- zen::ScopeGuard guardNewDir = zen::makeGuard([&]() { removeDirectory(directory); }); //ensure cleanup:
+ zen::ScopeGuard guardNewDir = zen::makeGuard([&] { removeDirectory(directory); }); //ensure cleanup:
//enforce copying file permissions: it's advertized on GUI...
if (copyFilePermissions)
@@ -1333,7 +1349,7 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat
if (dirExists(directory))
return;
#endif
- else //if "somethingExists" we needn't create the parent directory
+ else //if "not somethingExists" we need to create the parent directory
{
//try to create parent folders first
const Zstring dirParent = beforeLast(directory, FILE_NAME_SEPARATOR);
@@ -1399,7 +1415,7 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
throw FileError(_("Error copying symbolic link:") + L"\n\"" + sourceLink + L"\" ->\n\"" + targetLink + L"\"" + L"\n\n" + getLastErrorFormatted());
//allow only consistent objects to be created -> don't place before ::symlink, targetLink may already exist
- zen::ScopeGuard guardNewDir = zen::makeGuard([&]()
+ zen::ScopeGuard guardNewDir = zen::makeGuard([&]
{
#ifdef FFS_WIN
if (isDirLink)
@@ -1430,7 +1446,7 @@ Zstring createTempName(const Zstring& filename)
//ensure uniqueness
for (int i = 1; somethingExists(output); ++i)
- output = filename + Zchar('_') + toString<Zstring>(i) + zen::TEMP_FILE_ENDING;
+ output = filename + Zchar('_') + numberTo<Zstring>(i) + zen::TEMP_FILE_ENDING;
return output;
}
@@ -1439,20 +1455,17 @@ Zstring createTempName(const Zstring& filename)
class CallbackData
{
public:
- CallbackData(CallbackCopyFile* cb, //may be NULL
+ CallbackData(CallbackCopyFile* cb, //may be nullptr
const Zstring& sourceFile,
- const Zstring& targetFile,
- bool osIsvistaOrLater) :
+ const Zstring& targetFile) :
userCallback(cb),
sourceFile_(sourceFile),
targetFile_(targetFile),
- osIsvistaOrLater_(osIsvistaOrLater),
exceptionInUserCallback(false) {}
CallbackCopyFile* userCallback; //optional!
const Zstring& sourceFile_;
const Zstring& targetFile_;
- const bool osIsvistaOrLater_;
//there is mixed responsibility in this class, pure read-only data and abstraction for error reporting
//however we need to keep it together as ::CopyFileEx() requires!
@@ -1526,7 +1539,7 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
CallbackData& cbd = *static_cast<CallbackData*>(lpData);
if (dwCallbackReason == CALLBACK_STREAM_SWITCH && //called up-front for every file (even if 0-sized)
- dwStreamNumber == 1) //ADS!
+ dwStreamNumber == 1) //consider ADS!
{
//#################### return source file attributes ################################
BY_HANDLE_FILE_INFORMATION fileInfoSrc = {};
@@ -1556,14 +1569,14 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
if (!::GetFileTime(hSourceFile, //__in HANDLE hFile,
&creationTime, //__out_opt LPFILETIME lpCreationTime,
- NULL, //__out_opt LPFILETIME lpLastAccessTime,
- NULL)) //__out_opt LPFILETIME lpLastWriteTime
+ nullptr, //__out_opt LPFILETIME lpLastAccessTime,
+ nullptr)) //__out_opt LPFILETIME lpLastWriteTime
{
cbd.reportError(_("Error reading file attributes:") + L"\n\"" + cbd.sourceFile_ + L"\"" + L"\n\n" + getLastErrorFormatted());
return PROGRESS_CANCEL;
}
- ::SetFileTime(hDestinationFile, &creationTime, NULL, NULL); //no error handling!
+ ::SetFileTime(hDestinationFile, &creationTime, nullptr, nullptr); //no error handling!
//##############################################################################
}
@@ -1574,11 +1587,11 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
{
//some odd check for some possible(?) error condition
if (totalBytesTransferred.QuadPart < 0) //let's see if someone answers the call...
- ::MessageBox(NULL, L"You've just discovered a bug in WIN32 API function \"CopyFileEx\"! \n\n\
+ ::MessageBox(nullptr, L"You've just discovered a bug in WIN32 API function \"CopyFileEx\"! \n\n\
Please write a mail to the author of FreeFileSync at zhnmju123@gmx.de and simply state that\n\
\"totalBytesTransferred.HighPart can be below zero\"!\n\n\
This will then be handled in future versions of FreeFileSync.\n\nThanks -ZenJu",
- NULL, 0);
+ nullptr, 0);
try
{
cbd.userCallback->updateCopyStatus(UInt64(totalBytesTransferred.QuadPart));
@@ -1604,7 +1617,8 @@ void rawCopyWinApi_sub(const Zstring& sourceFile,
CallbackCopyFile* callback,
FileAttrib* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked
{
- zen::ScopeGuard guardTarget = zen::makeGuard([&]() { removeFile(targetFile); }); //transactional behavior: guard just before starting copy, we don't trust ::CopyFileEx(), do we ;)
+ zen::ScopeGuard guardTarget = zen::makeGuard([&] { try { removeFile(targetFile); } catch (...) {} });
+ //transactional behavior: guard just before starting copy, we don't trust ::CopyFileEx(), do we? ;)
DWORD copyFlags = COPY_FILE_FAIL_IF_EXISTS;
@@ -1612,25 +1626,19 @@ void rawCopyWinApi_sub(const Zstring& sourceFile,
static bool nonEncSupported = false;
{
static boost::once_flag initNonEncOnce = BOOST_ONCE_INIT; //caveat: function scope static initialization is not thread-safe in VS 2010!
- boost::call_once(initNonEncOnce, []() { nonEncSupported = winXpOrLater(); }); //encrypted destination is not supported with Windows 2000
+ boost::call_once(initNonEncOnce, [] { nonEncSupported = winXpOrLater(); }); //encrypted destination is not supported with Windows 2000
}
if (nonEncSupported)
copyFlags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION;
- static bool osIsvistaOrLater = false;
- {
- static boost::once_flag initVistaLaterOnce = BOOST_ONCE_INIT; //caveat: function scope static initialization is not thread-safe in VS 2010!
- boost::call_once(initVistaLaterOnce, []() { osIsvistaOrLater = vistaOrLater(); });
- }
-
- CallbackData cbd(callback, sourceFile, targetFile, osIsvistaOrLater);
+ CallbackData cbd(callback, sourceFile, targetFile);
const bool success = ::CopyFileEx( //same performance like CopyFile()
applyLongPathPrefix(sourceFile).c_str(),
applyLongPathPrefix(targetFile).c_str(),
copyCallbackInternal,
&cbd,
- NULL,
+ nullptr,
copyFlags) == TRUE; //silence x64 perf warning
cbd.evaluateErrors(); //throw ?, process errors in callback first!
@@ -1725,8 +1733,8 @@ void rawCopyWinApi(const Zstring& sourceFile,
// /*
// BackupRead() FileRead() CopyFileEx()
// --------------------------------------------
-// Attributes NO NO YES
-// create time NO NO NO
+// Attributes NO NO YES
+// create time NO NO NO
// ADS YES NO YES
// Encrypted NO(silent fail) NO YES
// Compressed NO NO NO
@@ -1737,18 +1745,20 @@ void rawCopyWinApi(const Zstring& sourceFile,
// compatible with: BackupRead() FileRead()
// */
//
+//FILE_FLAG_BACKUP_SEMANTICS ??????
+//
// //open sourceFile for reading
// HANDLE hFileIn = ::CreateFile(applyLongPathPrefix(sourceFile).c_str(),
// GENERIC_READ,
// FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //all shared modes are required to read files that are open in other applications
-// 0,
+// nullptr,
// OPEN_EXISTING,
// FILE_FLAG_SEQUENTIAL_SCAN,
-// NULL);
+// nullptr);
// if (hFileIn == INVALID_HANDLE_VALUE)
// {
// const DWORD lastError = ::GetLastError();
-// const std::wstring& errorMessage = _("Error opening file:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted(lastError);
+// const std::wstring& errorMessage = Error opening file: + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted(lastError);
//
// //if file is locked (try to) use Windows Volume Shadow Copy Service
// if (lastError == ERROR_SHARING_VIOLATION ||
@@ -1757,12 +1767,12 @@ void rawCopyWinApi(const Zstring& sourceFile,
//
// throw FileError(errorMessage);
// }
-// ZEN_ON_BLOCK_EXIT(::CloseHandle, hFileIn);
+// ZEN_ON_SCOPE_EXIT(::CloseHandle, hFileIn);
//
//
// BY_HANDLE_FILE_INFORMATION infoFileIn = {};
// if (!::GetFileInformationByHandle(hFileIn, &infoFileIn))
-// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
+// throw FileError(Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
//
// //####################################### DST hack ###########################################
// if (dst::isFatDrive(sourceFile)) //throw()
@@ -1794,15 +1804,14 @@ void rawCopyWinApi(const Zstring& sourceFile,
// HANDLE hFileOut = ::CreateFile(applyLongPathPrefix(targetFile).c_str(),
// GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION
// FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-// 0,
+// nullptr,
// CREATE_NEW,
// (infoFileIn.dwFileAttributes & validAttribs) | FILE_FLAG_SEQUENTIAL_SCAN,
-// NULL);
+// nullptr);
// if (hFileOut == INVALID_HANDLE_VALUE)
// {
// const DWORD lastError = ::GetLastError();
-// const std::wstring& errorMessage = _("Error writing file:") + "\n\"" + targetFile + "\"" +
-// "\n\n" + getLastErrorFormatted(lastError);
+// const std::wstring& errorMessage =
//
// if (lastError == ERROR_FILE_EXISTS)
// throw ErrorTargetExisting(errorMessage);
@@ -1814,7 +1823,7 @@ void rawCopyWinApi(const Zstring& sourceFile,
// }
// Loki::ScopeGuard guardTarget = Loki::MakeGuard(&removeFile, targetFile); //transactional behavior: guard just after opening target and before managing hFileOut
//
-// ZEN_ON_BLOCK_EXIT(::CloseHandle, hFileOut);
+// ZEN_ON_SCOPE_EXIT(::CloseHandle, hFileOut);
//
//
//#ifndef _MSC_VER
@@ -1822,14 +1831,14 @@ void rawCopyWinApi(const Zstring& sourceFile,
//#endif
// DWORD fsFlags = 0;
// if (!GetVolumeInformationByHandleW(hFileOut, //__in HANDLE hFile,
-// NULL, //__out_opt LPTSTR lpVolumeNameBuffer,
+// nullptr, //__out_opt LPTSTR lpVolumeNameBuffer,
// 0, //__in DWORD nVolumeNameSize,
-// NULL, //__out_opt LPDWORD lpVolumeSerialNumber,
-// NULL, //__out_opt LPDWORD lpMaximumComponentLength,
+// nullptr, //__out_opt LPDWORD lpVolumeSerialNumber,
+// nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
// &fsFlags, //__out_opt LPDWORD lpFileSystemFlags,
-// NULL, //__out LPTSTR lpFileSystemNameBuffer,
+// nullptr, //__out LPTSTR lpFileSystemNameBuffer,
// 0)) //__in DWORD nFileSystemNameSize
-// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
+// throw FileError(Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
//
// const bool sourceIsEncrypted = (infoFileIn.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0;
// const bool sourceIsCompressed = (infoFileIn.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
@@ -1851,12 +1860,11 @@ void rawCopyWinApi(const Zstring& sourceFile,
// FSCTL_SET_COMPRESSION, //dwIoControlCode
// &cmpState, //input buffer
// sizeof(cmpState), //size of input buffer
-// NULL, //lpOutBuffer
+// nullptr, //lpOutBuffer
// 0, //OutBufferSize
// &bytesReturned, //number of bytes returned
-// NULL)) //OVERLAPPED structure
-// throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" +
-// "\n\n" + getLastErrorFormatted() +
+// nullptr)) //OVERLAPPED structure
+// throw FileError( ddd +
// "\nFailed to write NTFS compressed attribute!");
// }
//
@@ -1868,14 +1876,13 @@ void rawCopyWinApi(const Zstring& sourceFile,
// DWORD bytesReturned = 0;
// if (!DeviceIoControl(hFileOut, //handle to file
// FSCTL_SET_SPARSE, //dwIoControlCode
-// NULL, //input buffer
+// nullptr, //input buffer
// 0, //size of input buffer
-// NULL, //lpOutBuffer
+// nullptr, //lpOutBuffer
// 0, //OutBufferSize
// &bytesReturned, //number of bytes returned
-// NULL)) //OVERLAPPED structure
-// throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" +
-// "\n\n" + getLastErrorFormatted() +
+// nullptr)) //OVERLAPPED structure
+// throw FileError(dddd
// "\nFailed to write NTFS sparse attribute!");
// }
// }
@@ -1889,13 +1896,13 @@ void rawCopyWinApi(const Zstring& sourceFile,
//
// struct ManageCtxt //manage context for BackupRead()/BackupWrite()
// {
-// ManageCtxt() : read(NULL), write(NULL) {}
+// ManageCtxt() : read(nullptr), write(nullptr) {}
// ~ManageCtxt()
// {
-// if (read != NULL)
-// ::BackupRead (0, NULL, 0, NULL, true, false, &read);
-// if (write != NULL)
-// ::BackupWrite(0, NULL, 0, NULL, true, false, &write);
+// if (read != nullptr)
+// ::BackupRead (0, nullptr, 0, nullptr, true, false, &read);
+// if (write != nullptr)
+// ::BackupWrite(0, nullptr, 0, nullptr, true, false, &write);
// }
//
// LPVOID read;
@@ -1919,19 +1926,19 @@ void rawCopyWinApi(const Zstring& sourceFile,
// false, //__in BOOL bAbort,
// false, //__in BOOL bProcessSecurity,
// &context.read)) //__out LPVOID *lpContext
-// throw FileError(_("Error reading file:") + "\n\"" + sourceFile + "\"" +
+// throw FileError(Error reading file:") + "\n\"" + sourceFile + "\"" +
// "\n\n" + getLastErrorFormatted());
// }
// else if (!::ReadFile(hFileIn, //__in HANDLE hFile,
// &buffer[0], //__out LPVOID lpBuffer,
// BUFFER_SIZE, //__in DWORD nNumberOfBytesToRead,
// &bytesRead, //__out_opt LPDWORD lpNumberOfBytesRead,
-// NULL)) //__inout_opt LPOVERLAPPED lpOverlapped
-// throw FileError(_("Error reading file:") + "\n\"" + sourceFile + "\"" +
+// nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
+// throw FileError(Error reading file:") + "\n\"" + sourceFile + "\"" +
// "\n\n" + getLastErrorFormatted());
//
// if (bytesRead > BUFFER_SIZE)
-// throw FileError(_("Error reading file:") + "\n\"" + sourceFile + "\"" +
+// throw FileError(Error reading file:") + "\n\"" + sourceFile + "\"" +
// "\n\n" + "buffer overflow");
//
// if (bytesRead < BUFFER_SIZE)
@@ -1948,19 +1955,17 @@ void rawCopyWinApi(const Zstring& sourceFile,
// false, //__in BOOL bAbort,
// false, //__in BOOL bProcessSecurity,
// &context.write)) //__out LPVOID *lpContext
-// throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" +
-// "\n\n" + getLastErrorFormatted() + " (w)"); //w -> distinguish from fopen error message!
+// throw FileError(ddd" (w)"); //w -> distinguish from fopen error message!
// }
// else if (!::WriteFile(hFileOut, //__in HANDLE hFile,
// &buffer[0], //__out LPVOID lpBuffer,
// bytesRead, //__in DWORD nNumberOfBytesToWrite,
// &bytesWritten, //__out_opt LPDWORD lpNumberOfBytesWritten,
-// NULL)) //__inout_opt LPOVERLAPPED lpOverlapped
-// throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" +
-// "\n\n" + getLastErrorFormatted() + " (w)"); //w -> distinguish from fopen error message!
+// nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
+// throw FileError(ddd" (w)"); //w -> distinguish from fopen error message!
//
// if (bytesWritten != bytesRead)
-// throw FileError(_("Error writing file:") + "\n\"" + targetFile + "\"" + "\n\n" + "incomplete write");
+// throw FileError(ddd + "incomplete write");
//
// totalBytesTransferred += bytesRead;
//
@@ -1969,15 +1974,15 @@ void rawCopyWinApi(const Zstring& sourceFile,
//#endif
//
// //invoke callback method to update progress indicators
-// if (callback != NULL)
+// if (callback != nullptr)
// switch (callback->updateCopyStatus(totalBytesTransferred))
// {
// case CallbackCopyFile::CONTINUE:
// break;
//
// case CallbackCopyFile::CANCEL: //a user aborted operation IS an error condition!
-// throw FileError(_("Error copying file:") + "\n\"" + sourceFile + "\" ->\n\"" +
-// targetFile + "\"\n\n" + _("Operation aborted!"));
+// throw FileError(Error copying file:") + "\n\"" + sourceFile + "\" ->\n\"" +
+// targetFile + "\"\n\n" + Operation aborted!"));
// }
// }
// while (!eof);
@@ -1987,18 +1992,18 @@ void rawCopyWinApi(const Zstring& sourceFile,
// {
// LARGE_INTEGER inputSize = {};
// if (!::GetFileSizeEx(hFileIn, &inputSize))
-// throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
+// throw FileError(Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted());
//
// if (inputSize.QuadPart != 0)
-// throw FileError(_("Error reading file:") + "\n\"" + sourceFile + "\"" + "\n\n" + "unknown error");
+// throw FileError(Error reading file:") + "\n\"" + sourceFile + "\"" + "\n\n" + "unknown error");
// }
//
// //time needs to be set at the end: BackupWrite() changes file time
// if (!::SetFileTime(hFileOut,
// &infoFileIn.ftCreationTime,
-// NULL,
+// nullptr,
// &infoFileIn.ftLastWriteTime))
-// throw FileError(_("Error changing modification time:") + "\n\"" + targetFile + "\"" + "\n\n" + getLastErrorFormatted());
+// throw FileError(Error changing modification time:") + "\n\"" + targetFile + "\"" + "\n\n" + getLastErrorFormatted());
//
//
//#ifndef NDEBUG //dst hack: verify data written
@@ -2024,15 +2029,15 @@ void rawCopyWinApi(const Zstring& sourceFile,
// 0,
// CREATE_NEW,
// FILE_FLAG_SEQUENTIAL_SCAN,
-// NULL);
+// nullptr);
// DWORD br = 0;
-// if (!::DeviceIoControl(hSparse, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &br,NULL))
+// if (!::DeviceIoControl(hSparse, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &br,nullptr))
// throw 1;
//
// LARGE_INTEGER liDistanceToMove = {};
// liDistanceToMove.QuadPart = 1024 * 1024 * 1024; //create 5 TB sparse file
// liDistanceToMove.QuadPart *= 5 * 1024; //
-// if (!::SetFilePointerEx(hSparse, liDistanceToMove, NULL, FILE_BEGIN))
+// if (!::SetFilePointerEx(hSparse, liDistanceToMove, nullptr, FILE_BEGIN))
// throw 1;
//
// if (!SetEndOfFile(hSparse))
@@ -2040,7 +2045,7 @@ void rawCopyWinApi(const Zstring& sourceFile,
//
// FILE_ZERO_DATA_INFORMATION zeroInfo = {};
// zeroInfo.BeyondFinalZero.QuadPart = liDistanceToMove.QuadPart;
-// if (!::DeviceIoControl(hSparse, FSCTL_SET_ZERO_DATA, &zeroInfo, sizeof(zeroInfo), NULL, 0, &br, NULL))
+// if (!::DeviceIoControl(hSparse, FSCTL_SET_ZERO_DATA, &zeroInfo, sizeof(zeroInfo), nullptr, 0, &br, nullptr))
// throw 1;
//
// ::CloseHandle(hSparse);
@@ -2054,7 +2059,7 @@ void rawCopyStream(const Zstring& sourceFile,
CallbackCopyFile* callback,
FileAttrib* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting
{
- zen::ScopeGuard guardTarget = zen::makeGuard([&] { removeFile(targetFile); }); //transactional behavior: place guard before lifetime of FileOutput
+ zen::ScopeGuard guardTarget = zen::makeGuard([&] { try { removeFile(targetFile); } catch (...) {} }); //transactional behavior: place guard before lifetime of FileOutput
try
{
//open sourceFile for reading
diff --git a/zen/file_handling.h b/zen/file_handling.h
index 80350731..b0d97a6c 100644
--- a/zen/file_handling.h
+++ b/zen/file_handling.h
@@ -48,7 +48,7 @@ UInt64 getFilesize(const Zstring& filename); //throw FileError
//file handling
bool removeFile(const Zstring& filename); //return "true" if file was actually deleted; throw FileError
-void removeDirectory(const Zstring& directory, CallbackRemoveDir* callback = NULL); //throw FileError
+void removeDirectory(const Zstring& directory, CallbackRemoveDir* callback = nullptr); //throw FileError
//rename file or directory: no copying!!!
@@ -80,8 +80,8 @@ void copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPathMissi
const Zstring& targetFile, //symlink handling: dereference source
bool copyFilePermissions,
bool transactionalCopy,
- CallbackCopyFile* callback, //may be NULL
- FileAttrib* newAttrib = NULL); //return current attributes at the time of copy
+ CallbackCopyFile* callback, //may be nullptr
+ FileAttrib* newAttrib = nullptr); //return current attributes at the time of copy
//Note: it MAY happen that copyFile() leaves temp files behind, e.g. temporary network drop.
// => clean them up at an appropriate time (automatically set sync directions to delete them). They have the following ending:
const Zstring TEMP_FILE_ENDING = Zstr(".ffs_tmp");
diff --git a/zen/file_id.cpp b/zen/file_id.cpp
index 4f9e3600..40efa373 100644
--- a/zen/file_id.cpp
+++ b/zen/file_id.cpp
@@ -27,13 +27,13 @@ zen::FileId zen::getFileID(const Zstring& filename)
const HANDLE hFile = ::CreateFile(zen::applyLongPathPrefix(filename).c_str(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory
- NULL);
+ nullptr);
if (hFile != INVALID_HANDLE_VALUE)
{
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hFile));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
BY_HANDLE_FILE_INFORMATION fileInfo = {};
if (::GetFileInformationByHandle(hFile, &fileInfo))
diff --git a/zen/file_id_def.h b/zen/file_id_def.h
index b65496be..c51a0ecc 100644
--- a/zen/file_id_def.h
+++ b/zen/file_id_def.h
@@ -21,7 +21,7 @@
namespace zen
{
#ifdef FFS_WIN
-typedef std::pair<decltype(BY_HANDLE_FILE_INFORMATION().dwVolumeSerialNumber), decltype(ULARGE_INTEGER().QuadPart)> FileId; //(volume serial number, file ID)
+typedef std::pair<DWORD, ULONGLONG> FileId; //(volume serial number, file ID)
inline
FileId extractFileID(const BY_HANDLE_FILE_INFORMATION& fileInfo)
@@ -41,16 +41,10 @@ FileId extractFileID(DWORD dwVolumeSerialNumber, ULARGE_INTEGER fileId)
FileId(dwVolumeSerialNumber, fileId.QuadPart) : FileId();
}
-namespace impl
-{
-inline
-void validate(const FileId& id, const BY_HANDLE_FILE_INFORMATION& fileInfo)
-{
- assert_static(sizeof(id.second) == sizeof(fileInfo.nFileIndexHigh) + sizeof(fileInfo.nFileIndexLow));
- assert_static(sizeof(id.first ) == sizeof(DWORD));
- assert_static(sizeof(id.second) == sizeof(ULARGE_INTEGER));
-}
-}
+assert_static(sizeof(FileId().first ) == sizeof(BY_HANDLE_FILE_INFORMATION().dwVolumeSerialNumber));
+assert_static(sizeof(FileId().second) == sizeof(BY_HANDLE_FILE_INFORMATION().nFileIndexHigh) + sizeof(BY_HANDLE_FILE_INFORMATION().nFileIndexLow));
+assert_static(sizeof(FileId().second) == sizeof(ULARGE_INTEGER));
+
#elif defined FFS_LINUX
namespace impl { typedef struct ::stat StatDummy; } //sigh...
@@ -58,7 +52,7 @@ namespace impl { typedef struct ::stat StatDummy; } //sigh...
typedef std::pair<decltype(impl::StatDummy::st_dev), decltype(impl::StatDummy::st_ino)> FileId; //(device id, inode)
inline
-FileId extractFileID(const struct stat& fileInfo)
+FileId extractFileID(const struct ::stat& fileInfo)
{
return fileInfo.st_dev != 0 && fileInfo.st_ino != 0 ?
FileId(fileInfo.st_dev, fileInfo.st_ino) : FileId();
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index ad1ecd6b..4c38bb22 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -8,9 +8,6 @@
#ifdef FFS_WIN
#include "long_path_prefix.h"
-
-#elif defined FFS_LINUX
-#include <cerrno>
#endif
using namespace zen;
@@ -57,36 +54,21 @@ FileInput::FileInput(const Zstring& filename) : //throw FileError, ErrorNotExis
for FFS most comparisons are probably between different disks => let's use FILE_FLAG_SEQUENTIAL_SCAN
*/
- NULL);
+ nullptr);
if (fileHandle == INVALID_HANDLE_VALUE)
- {
- const DWORD lastError = ::GetLastError();
-
- std::wstring errorMessage = _("Error opening file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted(lastError);
-
- if (lastError == ERROR_FILE_NOT_FOUND ||
- lastError == ERROR_PATH_NOT_FOUND ||
- lastError == ERROR_BAD_NETPATH ||
- lastError == ERROR_NETNAME_DELETED)
- throw ErrorNotExisting(errorMessage);
-
- throw FileError(errorMessage);
- }
-
#elif defined FFS_LINUX
fileHandle = ::fopen(filename.c_str(), "r,type=record,noseek"); //utilize UTF-8 filename
- if (fileHandle == NULL)
+ if (!fileHandle)
+#endif
{
- const int lastError = errno;
-
- std::wstring errorMessage = _("Error opening file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted(lastError);
+ const ErrorCode lastError = getLastError();
+ std::wstring errorMessage = _("Error reading file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted(lastError) + L" (open)";
- if (lastError == ENOENT)
+ if (errorCodeForNotExisting(lastError))
throw ErrorNotExisting(errorMessage);
throw FileError(errorMessage);
}
-#endif
}
@@ -95,7 +77,7 @@ FileInput::~FileInput()
#ifdef FFS_WIN
::CloseHandle(fileHandle);
#elif defined FFS_LINUX
- ::fclose(fileHandle); //NEVER allow passing NULL to fclose! -> crash!; fileHandle != NULL in this context!
+ ::fclose(fileHandle); //NEVER allow passing nullptr to fclose! -> crash!; fileHandle != nullptr in this context!
#endif
}
@@ -108,15 +90,15 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number
buffer, //__out LPVOID lpBuffer,
static_cast<DWORD>(bytesToRead), //__in DWORD nNumberOfBytesToRead,
&bytesRead, //__out_opt LPDWORD lpNumberOfBytesRead,
- NULL)) //__inout_opt LPOVERLAPPED lpOverlapped
+ nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
#elif defined FFS_LINUX
const size_t bytesRead = ::fread(buffer, 1, bytesToRead, fileHandle);
if (::ferror(fileHandle) != 0)
#endif
- throw FileError(_("Error reading file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted() + L" (r)");
+ throw FileError(_("Error reading file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted() + L" (read)");
#ifdef FFS_WIN
- if (bytesRead < bytesToRead) //falsify only!
+ if (bytesRead < bytesToRead) //verify only!
#elif defined FFS_LINUX
if (::feof(fileHandle) != 0)
#endif
@@ -153,11 +135,11 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil
0,
access == ACC_OVERWRITE ? CREATE_ALWAYS : CREATE_NEW,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
- NULL);
+ nullptr);
if (fileHandle == INVALID_HANDLE_VALUE)
{
const DWORD lastError = ::GetLastError();
- std::wstring errorMessage = _("Error writing file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted(lastError);
+ std::wstring errorMessage = _("Error writing file:") + L"\n\"" + filename_ + L"\"" L"\n\n" + zen::getLastErrorFormatted(lastError);
if (lastError == ERROR_FILE_EXISTS)
throw ErrorTargetExisting(errorMessage);
@@ -172,10 +154,10 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil
fileHandle = ::fopen(filename.c_str(),
//GNU extension: https://www.securecoding.cert.org/confluence/display/cplusplus/FIO03-CPP.+Do+not+make+assumptions+about+fopen()+and+file+creation
access == ACC_OVERWRITE ? "w,type=record,noseek" : "wx,type=record,noseek");
- if (fileHandle == NULL)
+ if (!fileHandle)
{
const int lastError = errno;
- std::wstring errorMessage = _("Error writing file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted(lastError);
+ std::wstring errorMessage = _("Error writing file:") + L"\n\"" + filename_ + L"\"" L"\n\n" + zen::getLastErrorFormatted(lastError);
if (lastError == EEXIST)
throw ErrorTargetExisting(errorMessage);
@@ -193,7 +175,7 @@ FileOutput::~FileOutput()
#ifdef FFS_WIN
::CloseHandle(fileHandle);
#elif defined FFS_LINUX
- ::fclose(fileHandle); //NEVER allow passing NULL to fclose! -> crash!
+ ::fclose(fileHandle); //NEVER allow passing nullptr to fclose! -> crash!
#endif
}
@@ -206,13 +188,13 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro
buffer, //__out LPVOID lpBuffer,
static_cast<DWORD>(bytesToWrite), //__in DWORD nNumberOfBytesToWrite,
&bytesWritten, //__out_opt LPDWORD lpNumberOfBytesWritten,
- NULL)) //__inout_opt LPOVERLAPPED lpOverlapped
+ nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
#elif defined FFS_LINUX
const size_t bytesWritten = ::fwrite(buffer, 1, bytesToWrite, fileHandle);
if (::ferror(fileHandle) != 0)
#endif
- throw FileError(_("Error writing file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + zen::getLastErrorFormatted() + L" (w)"); //w -> distinguish from fopen error message!
+ throw FileError(_("Error writing file:") + L"\n\"" + filename_ + L"\"" L"\n\n" + zen::getLastErrorFormatted() + L" (w)"); //w -> distinguish from fopen error message!
if (bytesWritten != bytesToWrite) //must be fulfilled for synchronous writes!
- throw FileError(_("Error writing file:") + L"\n\"" + filename_ + L"\"" + L"\n\n" + L"incomplete write");
+ throw FileError(_("Error writing file:") + L"\n\"" + filename_ + L"\"" L"\n\n" + L"incomplete write");
}
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index a0979c49..c3536825 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -21,7 +21,6 @@
#elif defined FFS_LINUX
#include <sys/stat.h>
#include <dirent.h>
-#include <cerrno>
#endif
using namespace zen;
@@ -67,10 +66,10 @@ bool extractFileInfoFromSymlink(const Zstring& linkName, zen::TraverseCallback::
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
+ nullptr);
if (hFile == INVALID_HANDLE_VALUE)
return false;
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hFile));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
BY_HANDLE_FILE_INFORMATION fileInfoByHandle = {};
if (!::GetFileInformationByHandle(hFile, &fileInfoByHandle))
@@ -92,11 +91,10 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //returns 0 on error or if s
//- indirection: subst S: %USERPROFILE%
// -> GetVolumePathName() on the other hand resolves "S:\Desktop\somedir" to "S:\Desktop\" - nice try...
- //dynamically load windows API function (existing since Windows XP)
typedef BOOL (WINAPI* GetFileInformationByHandleFunc)(HANDLE hFile,
LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
- const SysDllFun<GetFileInformationByHandleFunc> getFileInformationByHandle(L"kernel32.dll", "GetFileInformationByHandle");
+ const SysDllFun<GetFileInformationByHandleFunc> getFileInformationByHandle(L"kernel32.dll", "GetFileInformationByHandle"); //available since Windows XP
if (!getFileInformationByHandle)
{
assert(false);
@@ -106,13 +104,13 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //returns 0 on error or if s
const HANDLE hDir = ::CreateFile(zen::applyLongPathPrefix(pathName).c_str(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
+ nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS /*needed to open a directory*/ /*| FILE_FLAG_OPEN_REPARSE_POINT -> no, we follow symlinks!*/ ,
- NULL);
+ nullptr);
if (hDir == INVALID_HANDLE_VALUE)
return 0;
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hDir));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
BY_HANDLE_FILE_INFORMATION fileInfo = {};
if (!getFileInformationByHandle(hDir, //__in HANDLE hFile,
@@ -143,12 +141,12 @@ DWORD retrieveVolumeSerial(const Zstring& pathName) //returns 0 on error!
DWORD volumeSerial = 0;
if (!::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
- NULL, //__out LPTSTR lpVolumeNameBuffer,
+ nullptr, //__out LPTSTR lpVolumeNameBuffer,
0, //__in DWORD nVolumeNameSize,
&volumeSerial, //__out_opt LPDWORD lpVolumeSerialNumber,
- NULL, //__out_opt LPDWORD lpMaximumComponentLength,
- NULL, //__out_opt LPDWORD lpFileSystemFlags,
- NULL, //__out LPTSTR lpFileSystemNameBuffer,
+ nullptr, //__out_opt LPDWORD lpMaximumComponentLength,
+ nullptr, //__out_opt LPDWORD lpFileSystemFlags,
+ nullptr, //__out LPTSTR lpFileSystemNameBuffer,
0)) //__in DWORD nFileSystemNameSize
return 0;
@@ -194,7 +192,7 @@ struct Win32Traverser
{
struct DirHandle
{
- DirHandle() : searchHandle(NULL), firstRead(true) {}
+ DirHandle() : searchHandle(nullptr), firstRead(true) {}
HANDLE searchHandle;
bool firstRead;
@@ -276,7 +274,7 @@ struct FilePlusTraverser
{
struct DirHandle
{
- DirHandle() : searchHandle(NULL) {}
+ DirHandle() : searchHandle(nullptr) {}
findplus::FindHandle searchHandle;
};
@@ -286,7 +284,7 @@ struct FilePlusTraverser
static void create(const Zstring& directory, DirHandle& hnd) //throw FileError
{
hnd.searchHandle = ::openDir(applyLongPathPrefix(directory).c_str());
- if (hnd.searchHandle == NULL)
+ if (hnd.searchHandle == nullptr)
throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
}
@@ -315,10 +313,12 @@ struct FilePlusTraverser
STATUS_UNSUCCESSFUL | ERROR_GEN_FAILURE
STATUS_ACCESS_VIOLATION | ERROR_NOACCESS ->FileIdBothDirectoryInformation on XP accessing UDF
*/
+
if (lastError == ERROR_INVALID_LEVEL ||
lastError == ERROR_NOT_SUPPORTED ||
lastError == ERROR_INVALID_PARAMETER ||
lastError == ERROR_BAD_NET_RESP ||
+ lastError == ERROR_UNEXP_NET_ERR || //traverse network drive hosted by Win98
lastError == ERROR_GEN_FAILURE ||
lastError == ERROR_NOACCESS)
{
@@ -407,7 +407,7 @@ private:
if (!openSuccess)
return; //ignored error
- ZEN_ON_BLOCK_EXIT(typedef Trav Trav; Trav::destroy(searchHandle));
+ ZEN_ON_SCOPE_EXIT(typedef Trav Trav; Trav::destroy(searchHandle));
typename Trav::FindData fileInfo = {};
@@ -456,8 +456,7 @@ private:
}
else if (Trav::isDirectory(fileInfo)) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!)
{
- const std::shared_ptr<TraverseCallback> rv = sink.onDir(shortName, fullName);
- if (rv)
+ if (const std::shared_ptr<TraverseCallback> rv = sink.onDir(shortName, fullName))
traverse<Trav>(fullName, *rv, level + 1);
}
else //a file or symlink that is followed...
@@ -471,7 +470,7 @@ private:
}
else
{
- Trav::extractFileInfo(fileInfo, volumeSerial, details); //make optional character of volumeSerial explicit in the interface
+ Trav::extractFileInfo(fileInfo, volumeSerial, details);
//####################################### DST hack ###########################################
if (isFatFileSystem)
@@ -508,15 +507,15 @@ private:
const dst::RawTime encodedTime = dst::fatEncodeUtcTime(i->second); //throw (std::runtime_error)
{
//may need to remove the readonly-attribute (e.g. FAT usb drives)
- FileUpdateHandle updateHandle(i->first, [=]()
+ FileUpdateHandle updateHandle(i->first, [=]
{
return ::CreateFile(zen::applyLongPathPrefix(i->first).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,
- 0,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
+ 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,
+ 0,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ nullptr);
});
if (updateHandle.get() == INVALID_HANDLE_VALUE)
{
@@ -527,7 +526,7 @@ private:
if (!::SetFileTime(updateHandle.get(),
&encodedTime.createTimeRaw,
- NULL,
+ nullptr,
&encodedTime.writeTimeRaw))
{
++failedAttempts;
@@ -604,27 +603,27 @@ private:
}, sink);
- DIR* dirObj = NULL;
+ DIR* dirObj = nullptr;
tryReportingError([&]
{
dirObj = ::opendir(directory.c_str()); //directory must NOT end with path separator, except "/"
- if (dirObj == NULL)
+ if (!dirObj)
throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
}, sink);
- if (dirObj == NULL)
+ if (!dirObj)
return; //ignored error
- ZEN_ON_BLOCK_EXIT(::closedir(dirObj)); //never close NULL handles! -> crash
+ ZEN_ON_SCOPE_EXIT(::closedir(dirObj)); //never close nullptr handles! -> crash
while (true)
{
- struct ::dirent* dirEntry = NULL;
+ struct ::dirent* dirEntry = nullptr;
tryReportingError([&]
{
if (::readdir_r(dirObj, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0)
throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted());
}, sink);
- if (dirEntry == NULL) //no more items or ignore error
+ if (!dirEntry) //no more items or ignore error
return;
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index d6b69f86..ab46621f 100644
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -66,7 +66,7 @@ struct DstHackCallback; //DST hack not required on Linux
void traverseFolder(const Zstring& directory, //throw();
bool followSymlinks,
TraverseCallback& sink,
- DstHackCallback* dstCallback = NULL); //apply DST hack if callback is supplied
+ DstHackCallback* dstCallback = nullptr); //apply DST hack if callback is supplied
//followSymlinks:
//"true": Symlinks dereferenced and reported via onFile() and onDir() => onSymlink not used!
//"false": Symlinks directly reported via onSymlink(), directory symlinks are not followed
diff --git a/zen/fixed_list.h b/zen/fixed_list.h
index 1b2af5bf..eedbfab9 100644
--- a/zen/fixed_list.h
+++ b/zen/fixed_list.h
@@ -18,13 +18,13 @@ class FixedList
{
struct Node
{
- Node() : next(NULL), val() {}
- template <class A> Node(A&& a) : next(NULL), val(a) {}
- template <class A, class B> Node(A&& a, B&& b) : next(NULL), val(a, b) {}
- template <class A, class B, class C> Node(A&& a, B&& b, C&& c) : next(NULL), val(a, b, c) {}
- template <class A, class B, class C, class D> Node(A&& a, B&& b, C&& c, D&& d) : next(NULL), val(a, b, c, d) {}
- template <class A, class B, class C, class D, class E> Node(A&& a, B&& b, C&& c, D&& d, E&& e) : next(NULL), val(a, b, c, d, e) {}
- template <class A, class B, class C, class D, class E, class F> Node(A&& a, B&& b, C&& c, D&& d, E&& e, F&& f) : next(NULL), val(a, b, c, d, e, f) {}
+ Node() : next(nullptr), val() {}
+ template <class A> Node(A&& a) : next(nullptr), val(a) {}
+ template <class A, class B> Node(A&& a, B&& b) : next(nullptr), val(a, b) {}
+ template <class A, class B, class C> Node(A&& a, B&& b, C&& c) : next(nullptr), val(a, b, c) {}
+ template <class A, class B, class C, class D> Node(A&& a, B&& b, C&& c, D&& d) : next(nullptr), val(a, b, c, d) {}
+ template <class A, class B, class C, class D, class E> Node(A&& a, B&& b, C&& c, D&& d, E&& e) : next(nullptr), val(a, b, c, d, e) {}
+ template <class A, class B, class C, class D, class E, class F> Node(A&& a, B&& b, C&& c, D&& d, E&& e, F&& f) : next(nullptr), val(a, b, c, d, e, f) {}
Node* next; //singly linked list is sufficient
T val;
@@ -32,8 +32,8 @@ class FixedList
public:
FixedList() :
- first(NULL),
- lastInsert(NULL),
+ first(nullptr),
+ lastInsert(nullptr),
sz(0) {}
~FixedList()
@@ -51,7 +51,7 @@ public:
class ListIterator : public std::iterator<std::forward_iterator_tag, U>
{
public:
- ListIterator(NodeT* it = NULL) : iter(it) {}
+ ListIterator(NodeT* it = nullptr) : iter(it) {}
ListIterator& operator++() { iter = iter->next; return *this; }
inline friend bool operator==(const ListIterator& lhs, const ListIterator& rhs) { return lhs.iter == rhs.iter; }
inline friend bool operator!=(const ListIterator& lhs, const ListIterator& rhs) { return !(lhs == rhs); }
@@ -90,7 +90,7 @@ public:
template <class Predicate>
void remove_if(Predicate pred)
{
- Node* prev = NULL;
+ Node* prev = nullptr;
Node* ptr = first;
while (ptr)
@@ -102,7 +102,7 @@ public:
prev->next = ptr = tmp;
else
first = ptr = tmp;
- if (tmp == NULL)
+ if (!tmp)
lastInsert = prev;
}
else
@@ -113,7 +113,7 @@ public:
}
void clear() { remove_if([](T&) { return true; }); }
- bool empty() const { return first == NULL; }
+ bool empty() const { return first == nullptr; }
size_t size() const { return sz; }
private:
@@ -123,14 +123,14 @@ private:
void pushNode(Node* newNode)
{
++sz;
- if (lastInsert == NULL)
+ if (lastInsert == nullptr)
{
- assert(first == NULL);
+ assert(first == nullptr);
first = lastInsert = newNode;
}
else
{
- assert(lastInsert->next == NULL);
+ assert(lastInsert->next == nullptr);
lastInsert->next = newNode;
lastInsert = newNode;
}
diff --git a/zen/i18n.h b/zen/i18n.h
index 6c050601..cea4340d 100644
--- a/zen/i18n.h
+++ b/zen/i18n.h
@@ -33,7 +33,7 @@ struct TranslationHandler
virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, int n) = 0;
};
-void setTranslator(TranslationHandler* newHandler = NULL); //takes ownership
+void setTranslator(TranslationHandler* newHandler = nullptr); //takes ownership
TranslationHandler* getTranslator();
std::wstring getThousandsSeparator();
diff --git a/zen/int64.h b/zen/int64.h
index a5140ffd..ea51b23b 100644
--- a/zen/int64.h
+++ b/zen/int64.h
@@ -49,13 +49,15 @@ class Int64
{
public:
//safe implicit conversions
- Int64() : value(0) {}
- Int64(const Int64& rhs) : value(rhs.value) {}
- template <class T>
- Int64(T rhs, typename EnableIf<IsSignedInt<T>::result && sizeof(T) <= sizeof(std::int64_t)>::Result* = NULL) : value(static_cast<std::int64_t>(rhs)) {}
+ Int64() : value(0) {}
+ Int64(const Int64& rhs) : value(rhs.value) {}
+ template <class T>
+ Int64(T rhs, typename EnableIf<IsSignedInt<T>::value && sizeof(T) <= sizeof(std::int64_t)>::Type* = nullptr) :
+ value(static_cast<std::int64_t>(rhs)) {}
//unsafe explicit but checked conversion for all other integer types
- template <class T> explicit Int64(T rhs, typename EnableIf<!(IsSignedInt<T>::result && sizeof(T) <= sizeof(std::int64_t))>::Result* = NULL) : value(static_cast<std::int64_t>(rhs)) { checkRange<std::int64_t>(rhs); }
+ template <class T> explicit Int64(T rhs, typename EnableIf<!(IsSignedInt<T>::value && sizeof(T) <= sizeof(std::int64_t))>::Type* = nullptr) :
+ value(static_cast<std::int64_t>(rhs)) { checkRange<std::int64_t>(rhs); }
Int64& operator=(const Int64& rhs) { value = rhs.value; return *this; }
@@ -126,13 +128,15 @@ class UInt64
{
public:
//safe implicit conversions
- UInt64() : value(0) {}
- UInt64(const UInt64& rhs) : value(rhs.value) {}
- template <class T>
- UInt64(T rhs, typename EnableIf<IsUnsignedInt<T>::result && sizeof(T) <= sizeof(std::uint64_t)>::Result* = NULL) : value(static_cast<std::uint64_t>(rhs)) {}
+ UInt64() : value(0) {}
+ UInt64(const UInt64& rhs) : value(rhs.value) {}
+ template <class T>
+ UInt64(T rhs, typename EnableIf<IsUnsignedInt<T>::value && sizeof(T) <= sizeof(std::uint64_t)>::Type* = nullptr) :
+ value(static_cast<std::uint64_t>(rhs)) {}
//unsafe explicit but checked conversion for all other integer types
- template <class T> explicit UInt64(T rhs, typename EnableIf<!(IsUnsignedInt<T>::result && sizeof(T) <= sizeof(std::uint64_t))>::Result* = NULL) : value(static_cast<std::uint64_t>(rhs)) { checkRange<std::uint64_t>(rhs); }
+ template <class T> explicit UInt64(T rhs, typename EnableIf<!(IsUnsignedInt<T>::value && sizeof(T) <= sizeof(std::uint64_t))>::Type* = nullptr) :
+ value(static_cast<std::uint64_t>(rhs)) { checkRange<std::uint64_t>(rhs); }
UInt64& operator=(const UInt64& rhs) { value = rhs.value; return *this; }
@@ -248,8 +252,8 @@ public:
//specialize zen type trait
namespace zen -> we cannot mix signed/unsigned in general arithmetic operations -> we'll use the ostream-approach
{
-template <> struct IsUnsignedInt<UInt64> { enum { result = true }; };
-template <> struct IsSignedInt <Int64> { enum { result = true }; };
+template <> struct IsUnsignedInt<UInt64> : StaticBool<true> {};
+template <> struct IsSignedInt <Int64> : StaticBool<true> {};
}
*/
#endif //FFS_LARGE_64_BIT_INTEGER_H_INCLUDED
diff --git a/zen/last_error.h b/zen/last_error.h
index 6f701992..28982b63 100644
--- a/zen/last_error.h
+++ b/zen/last_error.h
@@ -20,16 +20,25 @@
#endif
-
namespace zen
{
//evaluate GetLastError()/errno and assemble specific error message
#ifdef FFS_WIN
-std::wstring getLastErrorFormatted(DWORD lastError = 0);
+typedef DWORD ErrorCode;
#elif defined FFS_LINUX
-std::wstring getLastErrorFormatted(int lastError = 0);
+typedef int ErrorCode;
#endif
+std::wstring getLastErrorFormatted(ErrorCode lastError = 0);
+ErrorCode getLastError();
+
+bool errorCodeForNotExisting(ErrorCode lastError); //check for "not existing" aliases
+
+
+
+
+
+
@@ -56,24 +65,37 @@ std::wstring getLastErrorFormatted(int lastError = 0);
-//######################## Implementation ########################
+
+
+
+//######################## implementation ########################
+inline
+ErrorCode getLastError()
+{
#ifdef FFS_WIN
+ return ::GetLastError();
+#elif defined FFS_LINUX
+ return errno;
+#endif
+}
+
inline
-std::wstring getLastErrorFormatted(DWORD lastError) //try to get additional Windows error information
+std::wstring getLastErrorFormatted(ErrorCode lastError)
{
+#ifdef FFS_WIN
//determine error code if none was specified
if (lastError == 0)
lastError = ::GetLastError();
std::wstring output = _("Windows Error Code %x:");
- replace(output, L"%x", toString<std::wstring>(lastError));
+ replace(output, L"%x", numberTo<std::wstring>(lastError));
- LPWSTR buffer = NULL;
+ LPWSTR buffer = nullptr;
if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_MAX_WIDTH_MASK |
FORMAT_MESSAGE_IGNORE_INSERTS | //important: without this flag ::FormatMessage() will fail if message contains placeholders
- FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, lastError, 0, reinterpret_cast<LPWSTR>(&buffer), 0, NULL) != 0)
+ FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, lastError, 0, reinterpret_cast<LPWSTR>(&buffer), 0, nullptr) != 0)
{
if (buffer) //just to be sure
{
@@ -84,27 +106,37 @@ std::wstring getLastErrorFormatted(DWORD lastError) //try to get additional Wind
}
::SetLastError(lastError); //restore last error
return output;
-}
#elif defined FFS_LINUX
-inline
-std::wstring getLastErrorFormatted(int lastError) //try to get additional Linux error information
-{
//determine error code if none was specified
if (lastError == 0)
lastError = errno; //don't use "::", errno is a macro!
std::wstring output = _("Linux Error Code %x:");
- replace(output, L"%x", toString<std::wstring>(lastError));
+ replace(output, L"%x", numberTo<std::wstring>(lastError));
output += L" ";
output += utf8CvrtTo<std::wstring>(::strerror(lastError));
errno = lastError; //restore errno
return output;
-}
#endif
}
+inline
+bool errorCodeForNotExisting(ErrorCode lastError)
+{
+#ifdef FFS_WIN
+ return lastError == ERROR_FILE_NOT_FOUND ||
+ lastError == ERROR_PATH_NOT_FOUND ||
+ lastError == ERROR_BAD_NETPATH ||
+ lastError == ERROR_NETNAME_DELETED;
+
+#elif defined FFS_LINUX
+ return lastError == ENOENT;
+#endif
+}
+}
+
#endif // SYSTEMFUNCTIONS_H_INCLUDED
diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h
index d6255b85..83643906 100644
--- a/zen/long_path_prefix.h
+++ b/zen/long_path_prefix.h
@@ -55,7 +55,7 @@ template <size_t max_path> inline
Zstring applyLongPathPrefixImpl(const Zstring& path)
{
assert(!path.empty()); //nicely check almost all WinAPI accesses!
- assert(!zen::cStringIsWhiteSpace(path[0]));
+ assert(!zen::isWhiteSpace(path[0]));
if (path.length() >= max_path && //maximum allowed path length without prefix is (MAX_PATH - 1)
!zen::startsWith(path, LONG_PATH_PREFIX))
diff --git a/zen/notify_removal.cpp b/zen/notify_removal.cpp
index 661822cb..d8657ea2 100644
--- a/zen/notify_removal.cpp
+++ b/zen/notify_removal.cpp
@@ -91,10 +91,10 @@ LRESULT CALLBACK topWndProc(HWND hwnd, //handle to window
MessageProvider::MessageProvider() :
- process(::GetModuleHandle(NULL)), //get program's module handle
- windowHandle(NULL)
+ process(::GetModuleHandle(nullptr)), //get program's module handle
+ windowHandle(nullptr)
{
- if (process == NULL)
+ if (!process)
throw zen::FileError(std::wstring(L"Could not start monitoring window notifications:") + L"\n\n" + getLastErrorFormatted() + L" (GetModuleHandle)");
//register the main window class
@@ -110,17 +110,17 @@ MessageProvider::MessageProvider() :
//create dummy-window
windowHandle = ::CreateWindow(WINDOW_NAME, //LPCTSTR lpClassName OR ATOM in low-order word!
- NULL, //LPCTSTR lpWindowName,
+ nullptr, //LPCTSTR lpWindowName,
0, //DWORD dwStyle,
0, //int x,
0, //int y,
0, //int nWidth,
0, //int nHeight,
0, //note: we need a toplevel window to receive device arrival events, not a message-window (HWND_MESSAGE)!
- NULL, //HMENU hMenu,
- process, //HINSTANCE hInstance,
- NULL); //LPVOID lpParam
- if (windowHandle == NULL)
+ nullptr, //HMENU hMenu,
+ process, //HINSTANCE hInstance,
+ nullptr); //LPVOID lpParam
+ if (!windowHandle)
throw zen::FileError(std::wstring(L"Could not start monitoring window notifications:") + L"\n\n" + getLastErrorFormatted() + L" (CreateWindow)");
guardClass.dismiss();
@@ -161,7 +161,7 @@ public:
hNotification = ::RegisterDeviceNotification(MessageProvider::instance().getWnd(), //__in HANDLE hRecipient,
&filter, //__in LPVOID NotificationFilter,
DEVICE_NOTIFY_WINDOW_HANDLE); //__in DWORD Flags
- if (hNotification == NULL)
+ if (!hNotification)
{
const DWORD lastError = ::GetLastError();
if (lastError != ERROR_CALL_NOT_IMPLEMENTED && //fail on SAMBA share: this shouldn't be a showstopper!
diff --git a/zen/optional.h b/zen/optional.h
index 1e04f52c..2bd272ae 100644
--- a/zen/optional.h
+++ b/zen/optional.h
@@ -34,9 +34,13 @@ template <class T>
class Opt
{
public:
- Opt() : valid(false), value() {}
- Opt(NoValue) : valid(false), value() {}
- Opt(const T& val) : valid(true ), value(val) {}
+ Opt() : value() , valid(false) {}
+ Opt(NoValue) : value() , valid(false) {}
+ Opt(const T& val) : value(val), valid(true ) {}
+
+ //rvalue optimization: only basic exception safety:
+ Opt(Opt&& tmp) : value(std::move(tmp.value)), valid(tmp.valid) {}
+ Opt& operator=(const Opt& tmp) { value = std::move(tmp.value); valid = tmp.valid; }
#ifdef _MSC_VER
private:
@@ -52,9 +56,11 @@ public:
const T* operator->() const { return &value; }
/**/ T* operator->() { return &value; }
+
+ void reset() { valid = false; }
private:
- const bool valid;
T value;
+ bool valid;
};
}
diff --git a/zen/perf.h b/zen/perf.h
index 874e6093..ea8991a8 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -7,14 +7,21 @@
#ifndef DEBUG_PERF_HEADER
#define DEBUG_PERF_HEADER
-#include <sstream>
#include "deprecate.h"
+
+#ifdef FFS_WIN
+#include <sstream>
#include "win.h" //includes "windows.h"
+#else
+#include <iostream>
+#include <time.h>
+#endif
//two macros for quick performance measurements
#define PERF_START CpuTimer perfTest;
#define PERF_STOP perfTest.showResult();
+#ifdef FFS_WIN
class CpuTimer
{
public:
@@ -24,8 +31,10 @@ public:
CpuTimer() : frequency(), startTime(), resultShown(false)
{
SetThreadAffinity dummy;
- if (!::QueryPerformanceFrequency(&frequency)) throw TimerError();
- if (!::QueryPerformanceCounter (&startTime)) throw TimerError();
+ if (!::QueryPerformanceFrequency(&frequency))
+ throw TimerError();
+ if (!::QueryPerformanceCounter (&startTime))
+ throw TimerError();
}
~CpuTimer()
@@ -38,16 +47,18 @@ public:
{
SetThreadAffinity dummy;
LARGE_INTEGER currentTime = {};
- if (!::QueryPerformanceCounter(&currentTime)) throw TimerError();
+ if (!::QueryPerformanceCounter(&currentTime))
+ throw TimerError();
- const long delta = static_cast<long>(1000.0 * (currentTime.QuadPart - startTime.QuadPart) / frequency.QuadPart);
+ const auto delta = static_cast<long>(1000.0 * (currentTime.QuadPart - startTime.QuadPart) / frequency.QuadPart);
std::ostringstream ss;
ss << delta << " ms";
- ::MessageBoxA(NULL, ss.str().c_str(), "Timer", 0);
+ ::MessageBoxA(nullptr, ss.str().c_str(), "Timer", 0);
resultShown = true;
- if (!::QueryPerformanceCounter(&startTime)) throw TimerError(); //don't include call to MessageBox()!
+ if (!::QueryPerformanceCounter(&startTime))
+ throw TimerError(); //don't include call to MessageBox()!
}
private:
@@ -57,6 +68,8 @@ private:
SetThreadAffinity() : oldmask(::SetThreadAffinityMask(::GetCurrentThread(), 1)) { if (oldmask == 0) throw TimerError(); }
~SetThreadAffinity() { ::SetThreadAffinityMask(::GetCurrentThread(), oldmask); }
private:
+ SetThreadAffinity(const SetThreadAffinity&);
+ SetThreadAffinity& operator=(const SetThreadAffinity&);
const DWORD_PTR oldmask;
};
@@ -65,4 +78,46 @@ private:
bool resultShown;
};
+
+#else
+class CpuTimer
+{
+public:
+ class TimerError {};
+
+ ZEN_DEPRECATE
+ CpuTimer() : startTime(), resultShown(false)
+ {
+ //clock() seems to give grossly incorrect results: multi core issue?
+ //gettimeofday() seems fine but is deprecated
+ if (::clock_gettime(CLOCK_MONOTONIC_RAW, &startTime) != 0) //CLOCK_MONOTONIC measures time reliably across processors!
+ throw TimerError();
+ }
+
+ ~CpuTimer()
+ {
+ if (!resultShown)
+ showResult();
+ }
+
+ void showResult()
+ {
+ timespec currentTime = {};
+ if (::clock_gettime(CLOCK_MONOTONIC_RAW, &currentTime) != 0)
+ throw TimerError();
+
+ const auto delta = static_cast<long>((currentTime.tv_sec - startTime.tv_sec) * 1000.0 + (currentTime.tv_nsec - startTime.tv_nsec) / 1000000.0);
+ std::clog << "Perf: duration: " << delta << " ms\n";
+ resultShown = true;
+
+ if (::clock_gettime(CLOCK_MONOTONIC_RAW, &startTime) != 0)
+ throw TimerError();
+ }
+
+private:
+ timespec startTime;
+ bool resultShown;
+};
+#endif
+
#endif //DEBUG_PERF_HEADER
diff --git a/zen/privilege.cpp b/zen/privilege.cpp
index 3b7e9cc5..23a55bd8 100644
--- a/zen/privilege.cpp
+++ b/zen/privilege.cpp
@@ -11,15 +11,15 @@ namespace
{
bool privilegeIsActive(LPCTSTR privilege) //throw FileError
{
- HANDLE hToken = NULL;
+ HANDLE hToken = nullptr;
if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
TOKEN_QUERY, //__in DWORD DesiredAccess,
&hToken)) //__out PHANDLE TokenHandle
throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hToken));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
LUID luid = {};
- if (!::LookupPrivilegeValue(NULL, //__in_opt LPCTSTR lpSystemName,
+ if (!::LookupPrivilegeValue(nullptr, //__in_opt LPCTSTR lpSystemName,
privilege, //__in LPCTSTR lpName,
&luid )) //__out PLUID lpLuid
throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
@@ -42,15 +42,15 @@ bool privilegeIsActive(LPCTSTR privilege) //throw FileError
void setPrivilege(LPCTSTR privilege, bool enable) //throw FileError
{
- HANDLE hToken = NULL;
+ HANDLE hToken = nullptr;
if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
TOKEN_ADJUST_PRIVILEGES, //__in DWORD DesiredAccess,
&hToken)) //__out PHANDLE TokenHandle
throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hToken));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
LUID luid = {};
- if (!::LookupPrivilegeValue(NULL, //__in_opt LPCTSTR lpSystemName,
+ if (!::LookupPrivilegeValue(nullptr, //__in_opt LPCTSTR lpSystemName,
privilege, //__in LPCTSTR lpName,
&luid )) //__out PLUID lpLuid
throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
@@ -60,12 +60,12 @@ void setPrivilege(LPCTSTR privilege, bool enable) //throw FileError
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
- if (!::AdjustTokenPrivileges(hToken, //__in HANDLE TokenHandle,
- false, //__in BOOL DisableAllPrivileges,
- &tp, //__in_opt PTOKEN_PRIVILEGES NewState,
- 0, //__in DWORD BufferLength,
- NULL, //__out_opt PTOKEN_PRIVILEGES PreviousState,
- NULL)) //__out_opt PDWORD ReturnLength
+ if (!::AdjustTokenPrivileges(hToken, //__in HANDLE TokenHandle,
+ false, //__in BOOL DisableAllPrivileges,
+ &tp, //__in_opt PTOKEN_PRIVILEGES NewState,
+ 0, //__in DWORD BufferLength,
+ nullptr, //__out_opt PTOKEN_PRIVILEGES PreviousState,
+ nullptr)) //__out_opt PDWORD ReturnLength
throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted());
if (::GetLastError() == ERROR_NOT_ALL_ASSIGNED) //check although previous function returned with success!
diff --git a/zen/privilege.h b/zen/privilege.h
index 97d0d201..b940279a 100644
--- a/zen/privilege.h
+++ b/zen/privilege.h
@@ -15,5 +15,4 @@ namespace zen
void activatePrivilege(LPCTSTR privilege); //throw FileError; thread-safe!!!
}
-
#endif // PRIVILEGE_H_INCLUDED
diff --git a/zen/scope_guard.h b/zen/scope_guard.h
index cc2f31e6..86d22c91 100644
--- a/zen/scope_guard.h
+++ b/zen/scope_guard.h
@@ -8,6 +8,8 @@
#ifndef ZEN_SCOPEGUARD_8971632487321434
#define ZEN_SCOPEGUARD_8971632487321434
+#include <cassert>
+
//best of Zen, Loki and C++11
namespace zen
@@ -21,7 +23,7 @@ namespace zen
//Scope Exit
/*
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hDir));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
*/
class ScopeGuardBase
@@ -56,7 +58,7 @@ public:
{
fun_();
}
- catch (...) {}
+ catch (...) { assert(false); }
}
private:
@@ -72,6 +74,6 @@ ScopeGuardImpl<F> makeGuard(F fun) { return ScopeGuardImpl<F>(fun); }
#define ZEN_CONCAT_SUB(X, Y) X ## Y
#define ZEN_CONCAT(X, Y) ZEN_CONCAT_SUB(X, Y)
-#define ZEN_ON_BLOCK_EXIT(X) zen::ScopeGuard ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard([&](){X;}); (void)ZEN_CONCAT(dummy, __LINE__);
+#define ZEN_ON_SCOPE_EXIT(X) zen::ScopeGuard ZEN_CONCAT(dummy, __LINE__) = zen::makeGuard([&]{ X; }); (void)ZEN_CONCAT(dummy, __LINE__);
#endif //ZEN_SCOPEGUARD_8971632487321434
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 03a10f96..e9fe149a 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -9,6 +9,7 @@
#define STL_TOOLS_HEADER_84567184321434
#include <memory>
+#include <algorithm>
#if defined _MSC_VER && _MSC_VER <= 1600
#include <set>
#include <map>
@@ -111,17 +112,14 @@ ForwardIterator binary_search(ForwardIterator first, ForwardIterator last, const
template <class BidirectionalIterator, class T> inline
BidirectionalIterator find_last(const BidirectionalIterator first, BidirectionalIterator last, const T& value)
{
- //reverse iteration: 1. check 2. decrement 3. evaluate
- const BidirectionalIterator iterNotFound = last;
- for (;;) //VS 2010 doesn't like "while (true)"
+ for (BidirectionalIterator iter = last; iter != first;) //reverse iteration: 1. check 2. decrement 3. evaluate
{
- if (last == first)
- return iterNotFound;
- --last;
+ --iter; //
- if (*last == value)
- return last;
+ if (*iter == value)
+ return iter;
}
+ return last;
}
diff --git a/zen/string_base.h b/zen/string_base.h
index ef0d9059..82793a49 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -118,11 +118,7 @@ class StorageRefCountThreadSafe : public AP
protected:
~StorageRefCountThreadSafe() {}
- static Char* create(size_t size)
- {
- return create(size, size);
- }
-
+ static Char* create(size_t size) { return create(size, size); }
static Char* create(size_t size, size_t minCapacity)
{
const size_t newCapacity = AP::calcCapacity(minCapacity);
@@ -157,23 +153,24 @@ protected:
return descr(ptr)->refCount == 1 && minCapacity <= descr(ptr)->capacity;
}
- static size_t length(const Char* ptr)
- {
- return descr(ptr)->length;
- }
+ static size_t length(const Char* ptr) { return descr(ptr)->length; }
static void setLength(Char* ptr, size_t newLength)
{
assert(canWrite(ptr, newLength));
- descr(ptr)->length = newLength;
+ descr(ptr)->length = static_cast<std::uint32_t>(newLength);
}
private:
struct Descriptor
{
- Descriptor(long rc, size_t len, size_t cap) : refCount(rc), length(len), capacity(cap) {}
+ Descriptor(long rc, size_t len, size_t cap) :
+ refCount(rc),
+ length(static_cast<std::uint32_t>(len)),
+ capacity(static_cast<std::uint32_t>(cap)) {}
boost::detail::atomic_count refCount; //practically no perf loss: ~0.2%! (FFS comparison)
+ //replace by #include <atomic> std::atomic_int when finally getting rid of VS2010
std::uint32_t length;
std::uint32_t capacity; //allocated size without null-termination
};
@@ -197,7 +194,7 @@ public:
Zbase(const Char* source, size_t length);
Zbase(const Zbase& source);
Zbase(Zbase&& tmp);
- explicit Zbase(Char source); //dangerous if implicit: Char buffer[]; Zbase name = buffer; ups...
+ explicit Zbase(Char source); //dangerous if implicit: Char buffer[]; return buffer[0]; ups...
//allow explicit construction from different string type, prevent ambiguity via SFINAE
template <class S> explicit Zbase(const S& other, typename S::value_type = 0);
~Zbase();
@@ -217,15 +214,15 @@ public:
//std::string functions
size_t length() const;
- size_t size() const;
- const Char* c_str() const; //C-string format with NULL-termination
- const Char* data() const; //internal representation, NULL-termination not guaranteed
+ size_t size () const { return length(); }
+ const Char* c_str() const { return rawStr; }; //C-string format with 0-termination
+ const Char* data() const { return rawStr; }; //internal representation, 0-termination not guaranteed
const Char operator[](size_t pos) const;
- bool empty() const;
+ bool empty() const { return length() == 0; }
void clear();
size_t find (const Zbase& str, size_t pos = 0) const; //
- size_t find (const Char* str, size_t pos = 0) const; //returns "npos" if not found
- size_t find (Char ch, size_t pos = 0) const; //
+ size_t find (const Char* str, size_t pos = 0) const; //
+ size_t find (Char ch, size_t pos = 0) const; //returns "npos" if not found
size_t rfind(Char ch, size_t pos = npos) const; //
size_t rfind(const Char* str, size_t pos = npos) const; //
Zbase& replace(size_t pos1, size_t n1, const Zbase& str);
@@ -234,7 +231,7 @@ public:
Zbase& append(const Char* source, size_t len);
void resize(size_t newSize, Char fillChar = 0);
void swap(Zbase& other);
- void push_back(Char val); //STL access
+ void push_back(Char val) { operator+=(val); } //STL access
Zbase& operator=(Zbase source);
Zbase& operator=(const Char* source);
@@ -254,27 +251,24 @@ private:
Char* rawStr;
};
-template <class Char, template <class, class> class SP, class AP> bool operator==(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs);
-template <class Char, template <class, class> class SP, class AP> bool operator==(const Zbase<Char, SP, AP>& lhs, const Char* rhs);
-template <class Char, template <class, class> class SP, class AP> bool operator==(const Char* lhs, const Zbase<Char, SP, AP>& rhs);
-
-template <class Char, template <class, class> class SP, class AP> bool operator!=(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs);
-template <class Char, template <class, class> class SP, class AP> bool operator!=(const Zbase<Char, SP, AP>& lhs, const Char* rhs);
-template <class Char, template <class, class> class SP, class AP> bool operator!=(const Char* lhs, const Zbase<Char, SP, AP>& rhs);
-
-template <class Char, template <class, class> class SP, class AP> bool operator< (const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs);
-template <class Char, template <class, class> class SP, class AP> bool operator< (const Zbase<Char, SP, AP>& lhs, const Char* rhs);
-template <class Char, template <class, class> class SP, class AP> bool operator< (const Char* lhs, const Zbase<Char, SP, AP>& rhs);
-
-template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs);
-template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, const Char* rhs);
-template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+(const Char* lhs, const Zbase<Char, SP, AP>& rhs);
-template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+( Char lhs, const Zbase<Char, SP, AP>& rhs);
-template <class Char, template <class, class> class SP, class AP> const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, Char rhs);
-
+template <class Char, template <class, class> class SP, class AP> bool operator==(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs);
+template <class Char, template <class, class> class SP, class AP> bool operator==(const Zbase<Char, SP, AP>& lhs, const Char* rhs);
+template <class Char, template <class, class> class SP, class AP> inline bool operator==(const Char* lhs, const Zbase<Char, SP, AP>& rhs) { return operator==(rhs, lhs); }
+template <class Char, template <class, class> class SP, class AP> inline bool operator!=(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs) { return !operator==(lhs, rhs); }
+template <class Char, template <class, class> class SP, class AP> inline bool operator!=(const Zbase<Char, SP, AP>& lhs, const Char* rhs) { return !operator==(lhs, rhs); }
+template <class Char, template <class, class> class SP, class AP> inline bool operator!=(const Char* lhs, const Zbase<Char, SP, AP>& rhs) { return !operator==(lhs, rhs); }
+template <class Char, template <class, class> class SP, class AP> bool operator<(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs);
+template <class Char, template <class, class> class SP, class AP> bool operator<(const Zbase<Char, SP, AP>& lhs, const Char* rhs);
+template <class Char, template <class, class> class SP, class AP> bool operator<(const Char* lhs, const Zbase<Char, SP, AP>& rhs);
+//rvalue references: unified first argument!
+template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+(Zbase<Char, SP, AP> lhs, const Zbase<Char, SP, AP>& rhs) { return lhs += rhs; }
+template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+(Zbase<Char, SP, AP> lhs, const Char* rhs) { return lhs += rhs; }
+template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+(Zbase<Char, SP, AP> lhs, Char rhs) { return lhs += rhs; }
+template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+( Char lhs, const Zbase<Char, SP, AP>& rhs) { return Zbase<Char, SP, AP>(lhs) += rhs; }
+template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+(const Char* lhs, const Zbase<Char, SP, AP>& rhs) { return Zbase<Char, SP, AP>(lhs) += rhs; }
@@ -302,13 +296,7 @@ template <class Char, template <class, class> class SP, class AP> const Zbase<Ch
-
-
-
-
-
-
-//################################# inline implementation ########################################
+//################################# implementation ########################################
template <class Char, template <class, class> class SP, class AP> inline
Zbase<Char, SP, AP>::Zbase()
{
@@ -355,7 +343,16 @@ Zbase<Char, SP, AP>::Zbase(const Zbase<Char, SP, AP>& source)
template <class Char, template <class, class> class SP, class AP> inline
Zbase<Char, SP, AP>::Zbase(Zbase<Char, SP, AP>&& tmp)
{
- rawStr = this->clone(tmp.rawStr); //for a ref-counting string there probably isn't a faster way, even with r-value references
+ //rawStr = this->clone(tmp.rawStr); NO! do not increment ref-count of a potentially unshared string! We'd lose optimization opportunity of reusing it!
+ //instead create a dummy string and swap:
+ if (canWrite(tmp.rawStr, 0)) //perf: this check saves about 4%
+ {
+ rawStr = this->create(0); //no perf issue! see comment in default constructor
+ rawStr[0] = 0;
+ swap(tmp);
+ }
+ else //shared representation: yet another "add ref" won't hurt
+ rawStr = this->clone(tmp.rawStr);
}
@@ -524,34 +521,6 @@ bool operator==(const Zbase<Char, SP, AP>& lhs, const Char* rhs)
template <class Char, template <class, class> class SP, class AP> inline
-bool operator==(const Char* lhs, const Zbase<Char, SP, AP>& rhs)
-{
- return operator==(rhs, lhs);
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-bool operator!=(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs)
-{
- return !operator==(lhs, rhs);
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-bool operator!=(const Zbase<Char, SP, AP>& lhs, const Char* rhs)
-{
- return !operator==(lhs, rhs);
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-bool operator!=(const Char* lhs, const Zbase<Char, SP, AP>& rhs)
-{
- return !operator==(lhs, rhs);
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
bool operator<(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0
@@ -583,27 +552,6 @@ size_t Zbase<Char, SP, AP>::length() const
template <class Char, template <class, class> class SP, class AP> inline
-size_t Zbase<Char, SP, AP>::size() const
-{
- return length();
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-const Char* Zbase<Char, SP, AP>::c_str() const
-{
- return rawStr;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-const Char* Zbase<Char, SP, AP>::data() const
-{
- return rawStr;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
const Char Zbase<Char, SP, AP>::operator[](size_t pos) const
{
assert(pos < length());
@@ -641,20 +589,6 @@ Char* Zbase<Char, SP, AP>::end()
template <class Char, template <class, class> class SP, class AP> inline
-void Zbase<Char, SP, AP>::push_back(Char val)
-{
- operator+=(val);
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-bool Zbase<Char, SP, AP>::empty() const
-{
- return length() == 0;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
void Zbase<Char, SP, AP>::clear()
{
if (!empty())
@@ -671,41 +605,6 @@ void Zbase<Char, SP, AP>::clear()
template <class Char, template <class, class> class SP, class AP> inline
-const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, const Zbase<Char, SP, AP>& rhs)
-{
- return Zbase<Char, SP, AP>(lhs) += rhs;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, const Char* rhs)
-{
- return Zbase<Char, SP, AP>(lhs) += rhs;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-const Zbase<Char, SP, AP> operator+(const Char* lhs, const Zbase<Char, SP, AP>& rhs)
-{
- return Zbase<Char, SP, AP>(lhs) += rhs;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-const Zbase<Char, SP, AP> operator+(Char lhs, const Zbase<Char, SP, AP>& rhs)
-{
- return Zbase<Char, SP, AP>(lhs) += rhs;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
-const Zbase<Char, SP, AP> operator+(const Zbase<Char, SP, AP>& lhs, Char rhs)
-{
- return Zbase<Char, SP, AP>(lhs) += rhs;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
void Zbase<Char, SP, AP>::swap(Zbase<Char, SP, AP>& other)
{
std::swap(rawStr, other.rawStr);
@@ -719,7 +618,7 @@ void Zbase<Char, SP, AP>::reserve(size_t minCapacity) //make unshared and check
{
//allocate a new string
Char* newStr = create(length(), std::max(minCapacity, length())); //reserve() must NEVER shrink the string: logical const!
- std::copy(rawStr, rawStr + length() + 1, newStr); //include NULL-termination
+ std::copy(rawStr, rawStr + length() + 1, newStr); //include 0-termination
destroy(rawStr);
rawStr = newStr;
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 602c4258..85eef5df 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -23,9 +23,8 @@
//enhance arbitray string class with useful non-member functions:
namespace zen
{
-template <class Char> bool cStringIsWhiteSpace(Char ch);
-template <class Char> bool cStringIsDigit (Char ch); //not exactly the same as "std::isdigit" -> we consider '0'-'9' only!
-
+template <class Char> bool isWhiteSpace(Char ch);
+template <class Char> bool isDigit (Char ch); //not exactly the same as "std::isdigit" -> we consider '0'-'9' only!
template <class S, class T> bool startsWith(const S& str, const T& prefix); //both S and T can be strings or char/wchar_t arrays or simple char/wchar_t
template <class S, class T> bool endsWith (const S& str, const T& postfix); //
@@ -36,7 +35,6 @@ template <class S, class T> S afterFirst (const S& str, const T& ch); //returns
template <class S, class T> S beforeFirst(const S& str, const T& ch); //returns the whole string if ch not found
template <class S, class T> std::vector<S> split(const S& str, const T& delimiter);
-template <class S> void truncate(S& str, size_t newLen);
template <class S> void trim(S& str, bool fromLeft = true, bool fromRight = true);
template <class S, class T, class U> void replace ( S& str, const T& oldOne, const U& newOne, bool replaceAll = true);
template <class S, class T, class U> S replaceCpy(const S& str, const T& oldOne, const U& newOne, bool replaceAll = true);
@@ -44,8 +42,8 @@ template <class S, class T, class U> S replaceCpy(const S& str, const T& oldO
//high-performance conversion between numbers and strings
template <class S, class T, class Num> S printNumber(const T& format, const Num& number); //format a single number using std::snprintf()
-template <class S, class Num> S toString(const Num& number);
-template <class Num, class S > Num toNumber(const S& str);
+template <class S, class Num> S numberTo(const Num& number);
+template <class Num, class S > Num stringTo(const S& str);
//string to string conversion: converts string-like type into char-compatible target string class
template <class T, class S> T copyStringTo(const S& str);
@@ -83,7 +81,7 @@ template <class T, class S> T copyStringTo(const S& str);
//---------------------- implementation ----------------------
template <> inline
-bool cStringIsWhiteSpace(char ch)
+bool isWhiteSpace(char ch)
{
//caveat 1: std::isspace() takes an int, but expects an unsigned char
//caveat 2: some parts of UTF-8 chars are erroneously seen as whitespace, e.g. the a0 from "\xec\x8b\xa0" (MSVC)
@@ -91,13 +89,13 @@ bool cStringIsWhiteSpace(char ch)
std::isspace(static_cast<unsigned char>(ch)) != 0;
}
-template <> inline bool cStringIsWhiteSpace(wchar_t ch) { return std::iswspace(ch) != 0; }
+template <> inline bool isWhiteSpace(wchar_t ch) { return std::iswspace(ch) != 0; }
template <class Char> inline
-bool cStringIsDigit(Char ch) //similar to implmenetation of std::::isdigit()!
+bool isDigit(Char ch) //similar to implmenetation of std::::isdigit()!
{
- assert_static((IsSameType<Char, char>::result || IsSameType<Char, wchar_t>::result));
+ assert_static((IsSameType<Char, char>::value || IsSameType<Char, wchar_t>::value));
return static_cast<Char>('0') <= ch && ch <= static_cast<Char>('9');
}
@@ -105,9 +103,8 @@ bool cStringIsDigit(Char ch) //similar to implmenetation of std::::isdigit()!
template <class S, class T> inline
bool startsWith(const S& str, const T& prefix)
{
- assert_static(IsStringLike<S>::result);
- assert_static(IsStringLike<T>::result);
- typedef typename GetCharType<S>::Result CharType;
+ assert_static(IsStringLike<S>::value && IsStringLike<T>::value);
+ typedef typename GetCharType<S>::Type CharType;
const size_t pfLength = strLength(prefix);
if (strLength(str) < pfLength)
@@ -122,9 +119,8 @@ bool startsWith(const S& str, const T& prefix)
template <class S, class T> inline
bool endsWith(const S& str, const T& postfix)
{
- assert_static(IsStringLike<S>::result);
- assert_static(IsStringLike<T>::result);
- typedef typename GetCharType<S>::Result CharType;
+ assert_static(IsStringLike<S>::value && IsStringLike<T>::value);
+ typedef typename GetCharType<S>::Type CharType;
const size_t strLen = strLength(str);
const size_t pfLen = strLength(postfix);
@@ -141,8 +137,8 @@ bool endsWith(const S& str, const T& postfix)
template <class S, class T> inline
S afterLast(const S& str, const T& ch)
{
- assert_static(IsStringLike<T>::result);
- typedef typename GetCharType<S>::Result CharType;
+ assert_static(IsStringLike<T>::value);
+ typedef typename GetCharType<S>::Type CharType;
const size_t chLen = strLength(ch);
@@ -164,8 +160,8 @@ S afterLast(const S& str, const T& ch)
template <class S, class T> inline
S beforeLast(const S& str, const T& ch)
{
- assert_static(IsStringLike<T>::result);
- typedef typename GetCharType<S>::Result CharType;
+ assert_static(IsStringLike<T>::value);
+ typedef typename GetCharType<S>::Type CharType;
const CharType* const strFirst = strBegin(str);
const CharType* const strLast = strFirst + strLength(str);
@@ -184,8 +180,8 @@ S beforeLast(const S& str, const T& ch)
template <class S, class T> inline
S afterFirst(const S& str, const T& ch)
{
- assert_static(IsStringLike<T>::result);
- typedef typename GetCharType<S>::Result CharType;
+ assert_static(IsStringLike<T>::value);
+ typedef typename GetCharType<S>::Type CharType;
const size_t chLen = strLength(ch);
const CharType* const strFirst = strBegin(str);
@@ -206,8 +202,8 @@ S afterFirst(const S& str, const T& ch)
template <class S, class T> inline
S beforeFirst(const S& str, const T& ch)
{
- assert_static(IsStringLike<T>::result);
- typedef typename GetCharType<S>::Result CharType;
+ assert_static(IsStringLike<T>::value);
+ typedef typename GetCharType<S>::Type CharType;
const CharType* const strFirst = strBegin(str);
const CharType* const chFirst = strBegin(ch);
@@ -220,8 +216,8 @@ S beforeFirst(const S& str, const T& ch)
template <class S, class T> inline
std::vector<S> split(const S& str, const T& delimiter)
{
- assert_static(IsStringLike<T>::result);
- typedef typename GetCharType<S>::Result CharType;
+ assert_static(IsStringLike<T>::value);
+ typedef typename GetCharType<S>::Type CharType;
std::vector<S> output;
@@ -252,34 +248,25 @@ std::vector<S> split(const S& str, const T& delimiter)
}
-template <class S> inline
-void truncate(S& str, size_t newLen)
-{
- if (newLen < str.length())
- str.resize(newLen);
-}
-
-
namespace implementation
{
ZEN_INIT_DETECT_MEMBER(append);
//either call operator+=(S(str, len)) or append(str, len)
template <class S, class Char> inline
-typename EnableIf<HasMember_append<S>::result>::Result stringAppend(S& str, const Char* other, size_t len) { str.append(other, len); }
+typename EnableIf<HasMember_append<S>::value>::Type stringAppend(S& str, const Char* other, size_t len) { str.append(other, len); }
template <class S, class Char> inline
-typename EnableIf<!HasMember_append<S>::result>::Result stringAppend(S& str, const Char* other, size_t len) { str += S(other, len); }
+typename EnableIf<!HasMember_append<S>::value>::Type stringAppend(S& str, const Char* other, size_t len) { str += S(other, len); }
}
template <class S, class T, class U> inline
S replaceCpy(const S& str, const T& oldOne, const U& newOne, bool replaceAll)
{
- assert_static(IsStringLike<T>::result);
- assert_static(IsStringLike<U>::result);
+ assert_static(IsStringLike<T>::value && IsStringLike<U>::value);
- typedef typename GetCharType<S>::Result CharType;
+ typedef typename GetCharType<S>::Type CharType;
const size_t oldLen = strLength(oldOne);
const size_t newLen = strLength(newOne);
@@ -324,29 +311,24 @@ template <class S> inline
void trim(S& str, bool fromLeft, bool fromRight)
{
assert(fromLeft || fromRight);
-
- typedef typename GetCharType<S>::Result CharType; //don't use value_type! (wxString, Glib::ustring)
+ typedef typename GetCharType<S>::Type CharType; //don't use value_type! (wxString, Glib::ustring)
const CharType* const oldBegin = str.c_str();
const CharType* newBegin = oldBegin;
const CharType* newEnd = oldBegin + str.length();
if (fromRight)
- while (newBegin != newEnd && cStringIsWhiteSpace(newEnd[-1]))
+ while (newBegin != newEnd && isWhiteSpace(newEnd[-1]))
--newEnd;
if (fromLeft)
- while (newBegin != newEnd && cStringIsWhiteSpace(*newBegin))
+ while (newBegin != newEnd && isWhiteSpace(*newBegin))
++newBegin;
- const size_t newLength = newEnd - newBegin;
- if (newLength != str.length())
- {
- if (newBegin != oldBegin)
- str = S(newBegin, newLength); //minor inefficiency: in case "str" is not shared, we could save an allocation and do a memory move only
- else
- str.resize(newLength);
- }
+ if (newBegin != oldBegin)
+ str = S(newBegin, newEnd - newBegin); //minor inefficiency: in case "str" is not shared, we could save an allocation and do a memory move only
+ else
+ str.resize(newEnd - newBegin);
}
@@ -374,8 +356,8 @@ namespace implementation
template <class Num> inline
int saferPrintf(char* buffer, size_t bufferSize, const char* format, const Num& number) //there is no such thing as a "safe" printf ;)
{
-#ifdef _MSC_VER
- return ::_snprintf(buffer, bufferSize, format, number); //VS2010 doesn't respect ISO C
+#if defined _MSC_VER || defined __MINGW32__
+ return ::_snprintf(buffer, bufferSize, format, number); //by factor 10 faster than "std::snprintf" on Mingw and on par with std::sprintf()!!!
#else
return std::snprintf(buffer, bufferSize, format, number); //C99
#endif
@@ -385,7 +367,7 @@ template <class Num> inline
int saferPrintf(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const Num& number)
{
#ifdef __MINGW32__
- return ::snwprintf(buffer, bufferSize, format, number); //MinGW doesn't respect ISO C
+ return ::_snwprintf(buffer, bufferSize, format, number); //MinGW doesn't respect ISO C
#else
return std::swprintf(buffer, bufferSize, format, number); //C99
#endif
@@ -395,12 +377,12 @@ int saferPrintf(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const
template <class S, class T, class Num> inline
S printNumber(const T& format, const Num& number) //format a single number using ::sprintf
{
- assert_static(IsStringLike<T>::result);
+ assert_static(IsStringLike<T>::value);
assert_static((IsSameType<
- typename GetCharType<S>::Result,
- typename GetCharType<T>::Result>::result));
+ typename GetCharType<S>::Type,
+ typename GetCharType<T>::Type>::value));
- typedef typename GetCharType<S>::Result CharType;
+ typedef typename GetCharType<S>::Type CharType;
const int BUFFER_SIZE = 128;
CharType buffer[BUFFER_SIZE];
@@ -422,9 +404,9 @@ enum NumberType
template <class S, class Num> inline
-S toString(const Num& number, Int2Type<NUM_TYPE_OTHER>) //default number to string conversion using streams: convenient, but SLOW, SLOW, SLOW!!!! (~ factor of 20)
+S numberTo(const Num& number, Int2Type<NUM_TYPE_OTHER>) //default number to string conversion using streams: convenient, but SLOW, SLOW, SLOW!!!! (~ factor of 20)
{
- typedef typename GetCharType<S>::Result CharType;
+ typedef typename GetCharType<S>::Type CharType;
std::basic_ostringstream<CharType> ss;
ss << number;
@@ -436,9 +418,9 @@ template <class S, class Num> inline S floatToString(const Num& number, char )
template <class S, class Num> inline S floatToString(const Num& number, wchar_t) { return printNumber<S>(L"%g", static_cast<double>(number)); }
template <class S, class Num> inline
-S toString(const Num& number, Int2Type<NUM_TYPE_FLOATING_POINT>)
+S numberTo(const Num& number, Int2Type<NUM_TYPE_FLOATING_POINT>)
{
- return floatToString<S>(number, typename GetCharType<S>::Result());
+ return floatToString<S>(number, typename GetCharType<S>::Type());
}
@@ -452,32 +434,37 @@ perf: integer to string: (executed 10 mio. times)
template <class S, class Num> inline
S formatInteger(Num n, bool hasMinus)
{
- typedef typename GetCharType<S>::Result CharType;
-
assert(n >= 0);
- S output;
+ typedef typename GetCharType<S>::Type CharType;
+
+ const size_t bufferSize = 100; //sufficient for signed 256-bit numbers
+ CharType buffer[bufferSize]; //it's generally faster to use a buffer than to rely on String::operator+=() (in)efficiency
+ assert_static(2 + 5 * sizeof(n) / 2 <= bufferSize);
+ //minimum required chars (+ sign char): 1 + ceil(ln_10 (256^sizeof(n))) =~ 1 + ceil(sizeof(n) * 2.4082) <= 2 + floor(sizeof(n) * 2.5)
+
+ size_t startPos = bufferSize;
do
{
- output += static_cast<CharType>('0' + n % 10);
+ buffer[--startPos] = static_cast<char>('0' + n % 10);
n /= 10;
}
while (n != 0);
+
if (hasMinus)
- output += static_cast<CharType>('-');
+ buffer[--startPos] = static_cast<CharType>('-');
- std::reverse(output.begin(), output.end());
- return output;
+ return S(buffer + startPos, bufferSize - startPos);
}
template <class S, class Num> inline
-S toString(const Num& number, Int2Type<NUM_TYPE_SIGNED_INT>)
+S numberTo(const Num& number, Int2Type<NUM_TYPE_SIGNED_INT>)
{
return formatInteger<S>(number < 0 ? -number : number, number < 0);
}
template <class S, class Num> inline
-S toString(const Num& number, Int2Type<NUM_TYPE_UNSIGNED_INT>)
+S numberTo(const Num& number, Int2Type<NUM_TYPE_UNSIGNED_INT>)
{
return formatInteger<S>(number, false);
}
@@ -486,20 +473,20 @@ S toString(const Num& number, Int2Type<NUM_TYPE_UNSIGNED_INT>)
template <class Num, class S> inline
-Num toNumber(const S& str, Int2Type<NUM_TYPE_OTHER>) //default string to number conversion using streams: convenient, but SLOW
+Num stringTo(const S& str, Int2Type<NUM_TYPE_OTHER>) //default string to number conversion using streams: convenient, but SLOW
{
- typedef typename GetCharType<S>::Result CharType;
+ typedef typename GetCharType<S>::Type CharType;
Num number = 0;
std::basic_istringstream<CharType>(copyStringTo<std::basic_string<CharType> >(str)) >> number;
return number;
}
-template <class Num> inline Num stringToFloat(const char* str) { return std::strtod(str, NULL); }
-template <class Num> inline Num stringToFloat(const wchar_t* str) { return std::wcstod(str, NULL); }
+template <class Num> inline Num stringToFloat(const char* str) { return std::strtod(str, nullptr); }
+template <class Num> inline Num stringToFloat(const wchar_t* str) { return std::wcstod(str, nullptr); }
template <class Num, class S> inline
-Num toNumber(const S& str, Int2Type<NUM_TYPE_FLOATING_POINT>)
+Num stringTo(const S& str, Int2Type<NUM_TYPE_FLOATING_POINT>)
{
return stringToFloat<Num>(strBegin(str));
}
@@ -507,12 +494,12 @@ Num toNumber(const S& str, Int2Type<NUM_TYPE_FLOATING_POINT>)
template <class Num, class S>
Num extractInteger(const S& str, bool& hasMinusSign) //very fast conversion to integers: slightly faster than std::atoi, but more importantly: generic
{
- typedef typename GetCharType<S>::Result CharType;
+ typedef typename GetCharType<S>::Type CharType;
const CharType* first = strBegin(str);
const CharType* last = first + strLength(str);
- while (first != last && cStringIsWhiteSpace(*first)) //skip leading whitespace
+ while (first != last && isWhiteSpace(*first)) //skip leading whitespace
++first;
//handle minus sign
@@ -540,7 +527,7 @@ Num extractInteger(const S& str, bool& hasMinusSign) //very fast conversion to i
else
{
//rest of string should contain whitespace only
- //assert(std::find_if(iter, last, std::not1(std::ptr_fun(&cStringIsWhiteSpace<CharType>))) == last); -> this is NO assert situation
+ //assert(std::all_of(iter, last, &isWhiteSpace<CharType>)); -> this is NO assert situation
break;
}
}
@@ -549,7 +536,7 @@ Num extractInteger(const S& str, bool& hasMinusSign) //very fast conversion to i
template <class Num, class S> inline
-Num toNumber(const S& str, Int2Type<NUM_TYPE_SIGNED_INT>)
+Num stringTo(const S& str, Int2Type<NUM_TYPE_SIGNED_INT>)
{
bool hasMinusSign = false; //handle minus sign
const Num number = extractInteger<Num>(str, hasMinusSign);
@@ -558,7 +545,7 @@ Num toNumber(const S& str, Int2Type<NUM_TYPE_SIGNED_INT>)
template <class Num, class S> inline
-Num toNumber(const S& str, Int2Type<NUM_TYPE_UNSIGNED_INT>) //very fast conversion to integers: slightly faster than std::atoi, but more importantly: generic
+Num stringTo(const S& str, Int2Type<NUM_TYPE_UNSIGNED_INT>) //very fast conversion to integers: slightly faster than std::atoi, but more importantly: generic
{
bool hasMinusSign = false; //handle minus sign
const Num number = extractInteger<Num>(str, hasMinusSign);
@@ -573,28 +560,28 @@ Num toNumber(const S& str, Int2Type<NUM_TYPE_UNSIGNED_INT>) //very fast conversi
template <class S, class Num> inline
-S toString(const Num& number) //convert number to string the C++ way
+S numberTo(const Num& number)
{
typedef Int2Type<
- IsSignedInt <Num>::result ? implementation::NUM_TYPE_SIGNED_INT :
- IsUnsignedInt<Num>::result ? implementation::NUM_TYPE_UNSIGNED_INT :
- IsFloat <Num>::result ? implementation::NUM_TYPE_FLOATING_POINT :
+ IsSignedInt <Num>::value ? implementation::NUM_TYPE_SIGNED_INT :
+ IsUnsignedInt<Num>::value ? implementation::NUM_TYPE_UNSIGNED_INT :
+ IsFloat <Num>::value ? implementation::NUM_TYPE_FLOATING_POINT :
implementation::NUM_TYPE_OTHER> TypeTag;
- return implementation::toString<S>(number, TypeTag());
+ return implementation::numberTo<S>(number, TypeTag());
}
template <class Num, class S> inline
-Num toNumber(const S& str) //convert string to number the C++ way
+Num stringTo(const S& str)
{
typedef Int2Type<
- IsSignedInt <Num>::result ? implementation::NUM_TYPE_SIGNED_INT :
- IsUnsignedInt<Num>::result ? implementation::NUM_TYPE_UNSIGNED_INT :
- IsFloat <Num>::result ? implementation::NUM_TYPE_FLOATING_POINT :
+ IsSignedInt <Num>::value ? implementation::NUM_TYPE_SIGNED_INT :
+ IsUnsignedInt<Num>::value ? implementation::NUM_TYPE_UNSIGNED_INT :
+ IsFloat <Num>::value ? implementation::NUM_TYPE_FLOATING_POINT :
implementation::NUM_TYPE_OTHER> TypeTag;
- return implementation::toNumber<Num>(str, TypeTag());
+ return implementation::stringTo<Num>(str, TypeTag());
}
}
diff --git a/zen/string_traits.h b/zen/string_traits.h
index c06aa6e3..cfcf78bb 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -9,7 +9,6 @@
#define STRING_TRAITS_HEADER_813274321443234
#include "type_tools.h"
-#include "type_traits.h"
#include "assert_static.h"
@@ -17,13 +16,13 @@
namespace zen
{
/*
-IsStringLike<>::result:
- IsStringLike<const wchar_t*>::result; //equals "true"
- IsStringLike<const int*> ::result; //equals "false"
+IsStringLike<>::value:
+ IsStringLike<const wchar_t*>::value; //equals "true"
+ IsStringLike<const int*> ::value; //equals "false"
-GetCharType<>::Result:
- GetCharType<std::wstring>::Result //equals wchar_t
- GetCharType<wchar_t[5]> ::Result //equals wchar_t
+GetCharType<>::Type:
+ GetCharType<std::wstring>::Type //equals wchar_t
+ GetCharType<wchar_t[5]> ::Type //equals wchar_t
strBegin():
std::wstring str(L"dummy");
@@ -67,21 +66,6 @@ private:
//---------------------- implementation ----------------------
namespace implementation
{
-ZEN_INIT_DETECT_MEMBER(c_str) //we don't know the exact declaration of the member attribute and it may be in a base class!
-ZEN_INIT_DETECT_MEMBER(length) //
-
-template<typename T, bool isClassType>
-struct HasStringMembers { enum { result = false }; };
-
-template<typename T>
-struct HasStringMembers<T, true> //Note: we can apply non-typed member-check on class types only!
-{
- enum { result = HasMember_c_str <T>::result &&
- HasMember_length<T>::result
- };
-};
-
-
template<class S, class Char> //test if result of S::c_str() can convert to const Char*
class HasConversion
{
@@ -91,63 +75,69 @@ class HasConversion
static Yes& hasConversion(const Char*);
static No& hasConversion(...);
- static S createInstance();
+ static S& createInstance();
public:
- enum { result = sizeof(hasConversion(createInstance().c_str())) == sizeof(Yes) };
+ enum { value = sizeof(hasConversion(createInstance().c_str())) == sizeof(Yes) };
};
-template <class S, bool isStringClass> struct GetCharTypeImpl { typedef EmptyType Result; };
-template <class S> struct GetCharTypeImpl<S, true >
+template <class S, bool isStringClass> struct GetCharTypeImpl : ResultType<NullType> {};
+template <class S>
+struct GetCharTypeImpl<S, true> :
+ ResultType<
+ typename SelectIf<HasConversion<S, wchar_t>::value, wchar_t,
+ typename SelectIf<HasConversion<S, char >::value, char, NullType>::Type
+ >::Type>
{
- //typedef typename S::value_type Result;
+ //typedef typename S::value_type Type;
/*DON'T use S::value_type:
1. support Glib::ustring: value_type is "unsigned int" but c_str() returns "const char*"
2. wxString, wxWidgets v2.9, has some questionable string design: wxString::c_str() returns a proxy (wxCStrData) which
is implicitly convertible to *both* "const char*" and "const wchar_t*" while wxString::value_type is a wrapper around an unsigned int
*/
- typedef typename SelectIf<HasConversion<S, wchar_t>::result, wchar_t,
- typename SelectIf<HasConversion<S, char>::result, char, EmptyType>::Result
- >::Result Result;
};
-
-template <> struct GetCharTypeImpl<char, false> { typedef char Result; };
-template <> struct GetCharTypeImpl<wchar_t, false> { typedef wchar_t Result; };
+template <> struct GetCharTypeImpl<char, false> : ResultType<char > {};
+template <> struct GetCharTypeImpl<wchar_t, false> : ResultType<wchar_t> {};
ZEN_INIT_DETECT_MEMBER_TYPE(value_type);
+ZEN_INIT_DETECT_MEMBER(c_str); //we don't know the exact declaration of the member attribute and it may be in a base class!
+ZEN_INIT_DETECT_MEMBER(length); //
template <class S>
class StringTraits
{
- typedef typename RemoveRef <S >::Result NonRefType;
- typedef typename RemoveConst <NonRefType >::Result NonConstType;
- typedef typename RemoveArray <NonConstType>::Result NonArrayType;
- typedef typename RemovePointer<NonArrayType>::Result NonPtrType;
- typedef typename RemoveConst <NonPtrType >::Result UndecoratedType; //handle "const char* const"
+ typedef typename RemoveRef <S >::Type NonRefType;
+ typedef typename RemoveConst <NonRefType >::Type NonConstType;
+ typedef typename RemoveArray <NonConstType>::Type NonArrayType;
+ typedef typename RemovePointer<NonArrayType>::Type NonPtrType;
+ typedef typename RemoveConst <NonPtrType >::Type UndecoratedType; //handle "const char* const"
public:
enum
{
- isStringClass = HasStringMembers<NonConstType, HasMemberType_value_type<NonConstType>::result>::result
+ isStringClass = HasMemberType_value_type<NonConstType>::value &&
+ HasMember_c_str <NonConstType>::value &&
+ HasMember_length <NonConstType>::value
};
- typedef typename GetCharTypeImpl<UndecoratedType, isStringClass>::Result CharType;
+ typedef typename GetCharTypeImpl<UndecoratedType, isStringClass>::Type CharType;
enum
{
- isStringLike = IsSameType<CharType, char>::result ||
- IsSameType<CharType, wchar_t>::result
+ isStringLike =
+ IsSameType<CharType, char >::value ||
+ IsSameType<CharType, wchar_t>::value
};
};
}
template <class T>
-struct IsStringLike { enum { result = implementation::StringTraits<T>::isStringLike }; };
+struct IsStringLike : StaticBool<implementation::StringTraits<T>::isStringLike> {};
template <class T>
-struct GetCharType { typedef typename implementation::StringTraits<T>::CharType Result; };
+struct GetCharType : ResultType<typename implementation::StringTraits<T>::CharType> {};
namespace implementation
@@ -155,7 +145,7 @@ namespace implementation
template <class C> inline
size_t cStringLength(const C* str) //strlen()
{
- assert_static((IsSameType<C, char>::result || IsSameType<C, wchar_t>::result));
+ assert_static((IsSameType<C, char>::value || IsSameType<C, wchar_t>::value));
size_t len = 0;
while (*str++ != 0)
++len;
@@ -165,7 +155,7 @@ size_t cStringLength(const C* str) //strlen()
template <class S> inline
-const typename GetCharType<S>::Result* strBegin(const S& str, typename EnableIf<implementation::StringTraits<S>::isStringClass>::Result* = NULL) //SFINAE: T must be a "string"
+const typename GetCharType<S>::Type* strBegin(const S& str, typename EnableIf<implementation::StringTraits<S>::isStringClass>::Type* = nullptr) //SFINAE: T must be a "string"
{
return str.c_str();
}
@@ -177,7 +167,7 @@ inline const wchar_t* strBegin(const wchar_t& ch) { return &ch; }
template <class S> inline
-size_t strLength(const S& str, typename EnableIf<implementation::StringTraits<S>::isStringClass>::Result* = NULL) //SFINAE: T must be a "string"
+size_t strLength(const S& str, typename EnableIf<implementation::StringTraits<S>::isStringClass>::Type* = nullptr) //SFINAE: T must be a "string"
{
return str.length();
}
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index 20433b43..006e4ea0 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -76,10 +76,10 @@ Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw FileError
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
+ nullptr);
if (hLink == INVALID_HANDLE_VALUE)
throw FileError(_("Error resolving symbolic link:") + L"\n\"" + linkPath + L"\"" + L"\n\n" + getLastErrorFormatted());
- ZEN_ON_BLOCK_EXIT(::CloseHandle(hLink));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hLink));
//respect alignment issues...
const DWORD bufferSize = REPARSE_DATA_BUFFER_HEADER_SIZE + MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
@@ -88,12 +88,12 @@ Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw FileError
DWORD bytesReturned; //dummy value required by FSCTL_GET_REPARSE_POINT!
if (!::DeviceIoControl(hLink, //__in HANDLE hDevice,
FSCTL_GET_REPARSE_POINT, //__in DWORD dwIoControlCode,
- NULL, //__in_opt LPVOID lpInBuffer,
+ nullptr, //__in_opt LPVOID lpInBuffer,
0, //__in DWORD nInBufferSize,
&buffer[0], //__out_opt LPVOID lpOutBuffer,
bufferSize, //__in DWORD nOutBufferSize,
&bytesReturned, //__out_opt LPDWORD lpBytesReturned,
- NULL)) //__inout_opt LPOVERLAPPED lpOverlapped
+ nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
throw FileError(_("Error resolving symbolic link:") + L"\n\"" + linkPath + L"\"" + L"\n\n" + getLastErrorFormatted());
REPARSE_DATA_BUFFER& reparseData = *reinterpret_cast<REPARSE_DATA_BUFFER*>(&buffer[0]); //REPARSE_DATA_BUFFER needs to be artificially enlarged!
diff --git a/zen/time.h b/zen/time.h
index f7b64367..b26fb0ad 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -25,16 +25,16 @@ struct TimeComp //replaces "struct std::tm" and SYSTEMTIME
int second; //0-61
};
-TimeComp localTime (time_t utc = std::time(NULL)); //convert time_t (UTC) to local time components
+TimeComp localTime (time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components
time_t localToTimeT(const TimeComp& comp); //convert local time components to time_t (UTC), returns -1 on error
//----------------------------------------------------------------------------------------------------------------------------------
/*
format (current) date and time; example:
- formatTime<std::wstring>(L"%Y*%m*%d"); -> "2011*10*29"
- formatTime<std::wstring>(FORMAT_DATE); -> "2011-10-29"
- formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34"
+ formatTime<std::wstring>(L"%Y*%m*%d"); -> "2011*10*29"
+ formatTime<std::wstring>(FORMAT_DATE); -> "2011-10-29"
+ formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34"
*/
template <class String, class String2>
String formatTime(const String2& format, const TimeComp& comp = localTime()); //format as specified by "std::strftime", returns empty string on failure
@@ -82,6 +82,12 @@ namespace implementation
inline
struct std::tm toClibTimeComponents(const TimeComp& comp)
{
+ assert(1 <= comp.month && comp.month <= 12 &&
+ 1 <= comp.day && comp.day <= 31 &&
+ 0 <= comp.hour && comp.hour <= 23 &&
+ 0 <= comp.minute && comp.minute <= 59 &&
+ 0 <= comp.second && comp.second <= 61);
+
struct std::tm ctc = {};
ctc.tm_year = comp.year - 1900; //years since 1900
ctc.tm_mon = comp.month - 1; //0-11
@@ -90,6 +96,7 @@ struct std::tm toClibTimeComponents(const TimeComp& comp)
ctc.tm_min = comp.minute; //0-59
ctc.tm_sec = comp.second; //0-61
ctc.tm_isdst = -1; //> 0 if DST is active, == 0 if DST is not active, < 0 if the information is not available
+
return ctc;
}
@@ -132,14 +139,14 @@ struct GetFormat<FormatDateTimeTag> //%c - locale dependent date and time:
};
template <>
-struct GetFormat<FormatIsoDateTag> //%Y-%m-%d - e.g. 2001-08-23
+struct GetFormat<FormatIsoDateTag> //%Y-%m-%d - e.g. 2001-08-23
{
const char* format(char) const { return "%Y-%m-%d"; }
const wchar_t* format(wchar_t) const { return L"%Y-%m-%d"; }
};
template <>
-struct GetFormat<FormatIsoTimeTag> //%H:%M:%S - e.g. 14:55:02
+struct GetFormat<FormatIsoTimeTag> //%H:%M:%S - e.g. 14:55:02
{
const char* format(char) const { return "%H:%M:%S"; }
const wchar_t* format(wchar_t) const { return L"%H:%M:%S"; }
@@ -173,10 +180,10 @@ struct PredefinedFormatTag {};
template <class String, class String2> inline
String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure
{
- typedef typename GetCharType<String>::Result CharType;
+ typedef typename GetCharType<String>::Type CharType;
struct std::tm ctc = toClibTimeComponents(comp);
- std::mktime (&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday
+ std::mktime(&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday
//note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent
CharType buffer[256];
@@ -187,7 +194,7 @@ String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormat
template <class String, class FormatType> inline
String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag)
{
- typedef typename GetCharType<String>::Result CharType;
+ typedef typename GetCharType<String>::Type CharType;
return formatTime<String>(GetFormat<FormatType>().format(CharType()), comp, UserDefinedFormatTag());
}
}
@@ -196,7 +203,14 @@ String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag)
inline
TimeComp localTime(time_t utc)
{
- return implementation::toZenTimeComponents(*std::localtime (&utc));
+#ifdef _MSC_VER
+ struct tm lt = {};
+ /*errno_t rv = */
+ ::localtime_s(&lt, &utc); //more secure?
+ return implementation::toZenTimeComponents(lt);
+#else
+ return implementation::toZenTimeComponents(*std::localtime(&utc));
+#endif
}
@@ -212,12 +226,12 @@ template <class String, class String2> inline
String formatTime(const String2& format, const TimeComp& comp)
{
typedef typename SelectIf<
- IsSameType<String2, FormatDateTag >::result ||
- IsSameType<String2, FormatTimeTag >::result ||
- IsSameType<String2, FormatDateTimeTag >::result ||
- IsSameType<String2, FormatIsoDateTag >::result ||
- IsSameType<String2, FormatIsoTimeTag >::result ||
- IsSameType<String2, FormatIsoDateTimeTag>::result, implementation::PredefinedFormatTag, implementation::UserDefinedFormatTag>::Result FormatTag;
+ IsSameType<String2, FormatDateTag >::value ||
+ IsSameType<String2, FormatTimeTag >::value ||
+ IsSameType<String2, FormatDateTimeTag >::value ||
+ IsSameType<String2, FormatIsoDateTag >::value ||
+ IsSameType<String2, FormatIsoTimeTag >::value ||
+ IsSameType<String2, FormatIsoDateTimeTag>::value, implementation::PredefinedFormatTag, implementation::UserDefinedFormatTag>::Type FormatTag;
return implementation::formatTime<String>(format, comp, FormatTag());
}
@@ -226,7 +240,7 @@ String formatTime(const String2& format, const TimeComp& comp)
template <class String>
bool parseTime(const String& format, const String& str, TimeComp& comp) //return true on success
{
- typedef typename GetCharType<String>::Result CharType;
+ typedef typename GetCharType<String>::Type CharType;
const CharType* iterFmt = strBegin(format);
const CharType* const fmtLast = iterFmt + strLength(format);
@@ -239,10 +253,10 @@ bool parseTime(const String& format, const String& str, TimeComp& comp) //return
if (strLast - iterStr < digitCount)
return false;
- if (std::find_if(iterStr, iterStr + digitCount, [](CharType c) { return !cStringIsDigit(c); }) != str.end())
+ if (std::any_of(iterStr, iterStr + digitCount, [](CharType c) { return !isDigit(c); }))
return false;
- result = zen::toNumber<int>(StringProxy<CharType>(iterStr, digitCount));
+ result = zen::stringTo<int>(StringProxy<CharType>(iterStr, digitCount));
iterStr += digitCount;
return true;
};
@@ -287,9 +301,9 @@ bool parseTime(const String& format, const String& str, TimeComp& comp) //return
return false;
}
}
- else if (cStringIsWhiteSpace(fmt)) //single whitespace in format => skip 0..n whitespace chars
+ else if (isWhiteSpace(fmt)) //single whitespace in format => skip 0..n whitespace chars
{
- while (iterStr != strLast && cStringIsWhiteSpace(*iterStr))
+ while (iterStr != strLast && isWhiteSpace(*iterStr))
++iterStr;
}
else
diff --git a/zen/type_tools.h b/zen/type_tools.h
index 03105ac8..b221954c 100644
--- a/zen/type_tools.h
+++ b/zen/type_tools.h
@@ -8,11 +8,12 @@
#ifndef TYPE_TOOLS_HEADER_45237590734254545
#define TYPE_TOOLS_HEADER_45237590734254545
+#include "type_traits.h"
+
namespace zen
{
//########## Strawman Classes ##########################
-struct EmptyType {};
-struct NullType {};
+struct NullType {}; //:= no type here
//########## Type Mapping ##############################
template <int n>
@@ -23,61 +24,47 @@ struct Type2Type {};
//########## Control Structures ########################
template <bool flag, class T, class U>
-struct SelectIf
-{
- typedef T Result;
-};
+struct SelectIf : ResultType<T> {};
+
template <class T, class U>
-struct SelectIf<false, T, U>
-{
- typedef U Result;
-};
+struct SelectIf<false, T, U> : ResultType<U> {};
//------------------------------------------------------
template <class T, class U>
-struct IsSameType
-{
- enum { result = false };
-};
+struct IsSameType : StaticBool<false> {};
template <class T>
-struct IsSameType<T, T>
-{
- enum { result = true };
-};
+struct IsSameType<T, T> : StaticBool<true> {};
//------------------------------------------------------
template <bool, class T = void>
struct EnableIf {};
-template <class T>
-struct EnableIf<true, T>
-{
- typedef T Result;
-};
+template <class T>
+struct EnableIf<true, T> : ResultType<T> {};
//########## Type Cleanup ##############################
template <class T>
-struct RemoveRef { typedef T Result; };
+struct RemoveRef : ResultType<T> {};
template <class T>
-struct RemoveRef<T&> { typedef T Result; };
+struct RemoveRef<T&> : ResultType<T> {};
//------------------------------------------------------
template <class T>
-struct RemoveConst { typedef T Result; };
+struct RemoveConst : ResultType<T> {};
template <class T>
-struct RemoveConst<const T> { typedef T Result; };
+struct RemoveConst<const T> : ResultType<T> {};
//------------------------------------------------------
template <class T>
-struct RemovePointer { typedef T Result; };
+struct RemovePointer : ResultType<T> {};
template <class T>
-struct RemovePointer<T*> { typedef T Result; };
+struct RemovePointer<T*> : ResultType<T> {};
//------------------------------------------------------
template <class T>
-struct RemoveArray { typedef T Result; };
+struct RemoveArray : ResultType<T> {};
template <class T, int N>
-struct RemoveArray<T[N]> { typedef T Result; };
+struct RemoveArray<T[N]> : ResultType<T> {};
//########## Sorting ##############################
/*
diff --git a/zen/type_traits.h b/zen/type_traits.h
index d9b28525..0b15eef1 100644
--- a/zen/type_traits.h
+++ b/zen/type_traits.h
@@ -8,10 +8,34 @@
#ifndef TYPE_TRAITS_HEADER_3425628658765467
#define TYPE_TRAITS_HEADER_3425628658765467
+#include <type_traits> //all we need is std::is_class!!
+
namespace zen
{
+//################# TMP compile time return values: "inherit to return compile-time result" ##############
+template <int i>
+struct StaticInt
+{
+ enum { value = i };
+};
+
+template <bool b>
+struct StaticBool : StaticInt<b> {};
+
+template <class EnumType, EnumType val>
+struct StaticEnum
+{
+ static const EnumType value = val;
+};
+//---------------------------------------------------------
+template <class T>
+struct ResultType
+{
+ typedef T Type;
+};
+
//################# Built-in Types ########################
-//Example: "IsSignedInt<int>::result" evaluates to "true"
+//Example: "IsSignedInt<int>::value" evaluates to "true"
template <class T> struct IsUnsignedInt;
template <class T> struct IsSignedInt;
@@ -22,27 +46,25 @@ template <class T> struct IsArithmetic; //IsInteger or IsFloat
//remaining non-arithmetic types: bool, char, wchar_t
//optional: specialize new types like:
-//template <> struct IsUnsignedInt<UInt64> { enum { result = true }; };
+//template <> struct IsUnsignedInt<UInt64> : StaticBool<true> {};
//################# Class Members ########################
/* Detect data or function members of a class by name: ZEN_INIT_DETECT_MEMBER + HasMember_
- !!! Note: this may ONLY be used for class types: fails to compile for non-class types !!!
-
Example: 1. ZEN_INIT_DETECT_MEMBER(c_str);
- 2. HasMember_c_str<T>::result -> use as boolean
+ 2. HasMember_c_str<T>::value -> use as boolean
*/
-/* Detect data or function members of a class by name and type: ZEN_INIT_DETECT_MEMBER2 + HasMember_
+/* Detect data or function members of a class by name *and* type: ZEN_INIT_DETECT_MEMBER2 + HasMember_
Example: 1. ZEN_INIT_DETECT_MEMBER2(size, size_t (T::*)() const);
- 2. HasMember_size<T>::result -> use as boolean
+ 2. HasMember_size<T>::value -> use as boolean
*/
/* Detect member type of a class: ZEN_INIT_DETECT_MEMBER_TYPE + HasMemberType_
Example: 1. ZEN_INIT_DETECT_MEMBER_TYPE(value_type);
- 2. HasMemberType_value_type<T>::result -> use as boolean
+ 2. HasMemberType_value_type<T>::value -> use as boolean
*/
@@ -65,10 +87,10 @@ template <class T> struct IsArithmetic; //IsInteger or IsFloat
//################ implementation ######################
-#define ZEN_SPECIALIZE_TRAIT(X, Y) template <> struct X<Y> { enum { result = true }; };
+#define ZEN_SPECIALIZE_TRAIT(X, Y) template <> struct X<Y> : StaticBool<true> {};
template <class T>
-struct IsUnsignedInt { enum { result = false }; };
+struct IsUnsignedInt : StaticBool<false> {};
ZEN_SPECIALIZE_TRAIT(IsUnsignedInt, unsigned char);
ZEN_SPECIALIZE_TRAIT(IsUnsignedInt, unsigned short int);
@@ -78,7 +100,7 @@ ZEN_SPECIALIZE_TRAIT(IsUnsignedInt, unsigned long long int); //new with C++11 -
//------------------------------------------------------
template <class T>
-struct IsSignedInt { enum { result = false }; };
+struct IsSignedInt : StaticBool<false> {};
ZEN_SPECIALIZE_TRAIT(IsSignedInt, signed char);
ZEN_SPECIALIZE_TRAIT(IsSignedInt, short int);
@@ -88,7 +110,7 @@ ZEN_SPECIALIZE_TRAIT(IsSignedInt, long long int); //new with C++11 - same type a
//------------------------------------------------------
template <class T>
-struct IsFloat { enum { result = false }; };
+struct IsFloat : StaticBool<false> {};
ZEN_SPECIALIZE_TRAIT(IsFloat, float);
ZEN_SPECIALIZE_TRAIT(IsFloat, double);
@@ -98,31 +120,40 @@ ZEN_SPECIALIZE_TRAIT(IsFloat, long double);
#undef ZEN_SPECIALIZE_TRAIT
template <class T>
-struct IsInteger { enum { result = IsUnsignedInt<T>::result || IsSignedInt<T>::result }; };
+struct IsInteger : StaticBool<IsUnsignedInt<T>::value || IsSignedInt<T>::value> {};
template <class T>
-struct IsArithmetic { enum { result = IsInteger<T>::result || IsFloat<T>::result }; };
+struct IsArithmetic : StaticBool<IsInteger<T>::value || IsFloat<T>::value> {};
//####################################################################
#define ZEN_INIT_DETECT_MEMBER(NAME) \
\
- template<typename T> \
- class HasMember_##NAME \
- { \
+ template<bool isClass, class T> \
+ struct HasMemberImpl_##NAME \
+ { \
+ private: \
typedef char Yes[1]; \
typedef char No [2]; \
\
- template <typename U, U t> class Helper {}; \
- struct Fallback { int NAME; }; \
+ template <typename U, U t> \
+ class Helper {}; \
+ struct Fallback { int NAME; }; \
\
- template <class U> \
- struct Helper2 : public U, public Fallback {}; \
+ template <class U> \
+ struct Helper2 : public U, public Fallback {}; /*this works only for class types!!!*/ \
\
template <class U> static No& hasMember(Helper<int Fallback::*, &Helper2<U>::NAME>*); \
template <class U> static Yes& hasMember(...); \
public: \
- enum { result = sizeof(hasMember<T>(NULL)) == sizeof(Yes) }; \
- };
+ enum { value = sizeof(hasMember<T>(nullptr)) == sizeof(Yes) }; \
+ }; \
+ \
+ template<class T> \
+ struct HasMemberImpl_##NAME<false, T> : StaticBool<false> {}; \
+ \
+ template<typename T> \
+ struct HasMember_##NAME : StaticBool<HasMemberImpl_##NAME<std::is_class<T>::value, T>::value> {};
+
//####################################################################
#define ZEN_INIT_DETECT_MEMBER2(NAME, TYPE) \
@@ -138,7 +169,7 @@ struct IsArithmetic { enum { result = IsInteger<T>::result || IsFloat<T>::result
template <class T> static Yes& hasMember(Helper<TYPE, &T::NAME>*); \
template <class T> static No& hasMember(...); \
public: \
- enum { result = sizeof(hasMember<U>(NULL)) == sizeof(Yes) }; \
+ enum { value = sizeof(hasMember<U>(nullptr)) == sizeof(Yes) }; \
};
//####################################################################
@@ -155,7 +186,7 @@ struct IsArithmetic { enum { result = IsInteger<T>::result || IsFloat<T>::result
template <class U> static Yes& hasMemberType(Helper<typename U::TYPENAME>*); \
template <class U> static No& hasMemberType(...); \
public: \
- enum { result = sizeof(hasMemberType<T>(NULL)) == sizeof(Yes) }; \
+ enum { value = sizeof(hasMemberType<T>(nullptr)) == sizeof(Yes) }; \
};
}
diff --git a/zen/utf8.h b/zen/utf8.h
index 3d97ca7a..242b729f 100644
--- a/zen/utf8.h
+++ b/zen/utf8.h
@@ -8,13 +8,15 @@
#ifndef STRING_UTF8_HEADER_01832479146991573473545
#define STRING_UTF8_HEADER_01832479146991573473545
+#include <cstdint>
#include <iterator>
#include "string_tools.h" //copyStringTo
namespace zen
{
//convert any(!) "string-like" object into target string by applying a UTF8 conversion (but only if necessary!)
-template <class TargetString, class SourceString> TargetString utf8CvrtTo(const SourceString& str);
+template <class TargetString, class SourceString>
+TargetString utf8CvrtTo(const SourceString& str);
//convert wide to utf8 string; example: std::string tmp = toUtf8<std::string>(L"abc");
template <class CharString, class WideString>
@@ -62,7 +64,9 @@ const char BYTE_ORDER_MARK_UTF8[] = "\xEF\xBB\xBF";
//----------------------- implementation ----------------------------------
namespace implementation
{
-typedef unsigned int CodePoint; //must be at least four bytes
+typedef std::uint_fast32_t CodePoint; //must be at least four bytes
+typedef std::uint_fast16_t Char16; //we need an unsigned type
+typedef unsigned char Char8;
const CodePoint CODE_POINT_MAX = 0x10ffff;
@@ -73,31 +77,28 @@ const CodePoint LOW_SURROGATE = 0xdc00;
const CodePoint LOW_SURROGATE_MAX = 0xdfff;
-template <class OutputIterator> inline
-OutputIterator codePointToUtf16(CodePoint cp, OutputIterator result) //http://en.wikipedia.org/wiki/UTF-16
+template <class Function> inline
+void codePointToUtf16(CodePoint cp, Function writeOutput) //"writeOutput" is a unary function taking a Char16
{
- typedef unsigned short Char16; //this isn't necessarily 16 bit, but all we need is an unsigned type
-
+ //http://en.wikipedia.org/wiki/UTF-16
assert(cp < HIGH_SURROGATE || LOW_SURROGATE_MAX < cp); //code points [0xd800, 0xdfff] are not allowed for UTF-16
assert(cp <= CODE_POINT_MAX);
if (cp < 0x10000)
- *result++ = static_cast<Char16>(cp);
+ writeOutput(static_cast<Char16>(cp));
else
{
cp -= 0x10000;
- *result++ = static_cast<Char16>((cp >> 10) + HIGH_SURROGATE);
- *result++ = static_cast<Char16>((cp & 0x3ff) + LOW_SURROGATE);
+ writeOutput(static_cast<Char16>((cp >> 10) + HIGH_SURROGATE));
+ writeOutput(static_cast<Char16>((cp & 0x3ff) + LOW_SURROGATE));
}
- return result;
}
template <class CharIterator, class Function> inline
-Function utf16ToCodePoint(CharIterator first, CharIterator last, Function f) //f is a unary function taking a CodePoint as single parameter
+void utf16ToCodePoint(CharIterator first, CharIterator last, Function writeOutput) //"writeOutput" is a unary function taking a CodePoint
{
assert_static(sizeof(typename std::iterator_traits<CharIterator>::value_type) == 2);
- typedef unsigned short Char16; //this isn't necessarily 16 bit, but all we need is an unsigned type
for ( ; first != last; ++first)
{
@@ -107,7 +108,7 @@ Function utf16ToCodePoint(CharIterator first, CharIterator last, Function f) //f
if (++first == last)
{
assert(false); //low surrogate expected
- break;
+ return;
}
assert(LOW_SURROGATE <= static_cast<Char16>(*first) && static_cast<Char16>(*first) <= LOW_SURROGATE_MAX); //low surrogate expected
cp = ((cp - HIGH_SURROGATE) << 10) + static_cast<Char16>(*first) - LOW_SURROGATE + 0x10000;
@@ -115,40 +116,37 @@ Function utf16ToCodePoint(CharIterator first, CharIterator last, Function f) //f
else
assert(cp < LOW_SURROGATE || LOW_SURROGATE_MAX < cp); //NO low surrogate expected
- f(cp);
+ writeOutput(cp);
}
- return f;
}
-template <class OutputIterator> inline
-OutputIterator codePointToUtf8(CodePoint cp, OutputIterator result) //http://en.wikipedia.org/wiki/UTF-8
+template <class Function> inline
+void codePointToUtf8(CodePoint cp, Function writeOutput) //"writeOutput" is a unary function taking a Char8
{
- typedef unsigned char Char8;
-
- assert(cp <= CODE_POINT_MAX);
+ //http://en.wikipedia.org/wiki/UTF-8
if (cp < 0x80)
- *result++ = static_cast<Char8>(cp);
+ writeOutput(static_cast<Char8>(cp));
else if (cp < 0x800)
{
- *result++ = static_cast<Char8>((cp >> 6 ) | 0xc0);
- *result++ = static_cast<Char8>((cp & 0x3f) | 0x80);
+ writeOutput(static_cast<Char8>((cp >> 6 ) | 0xc0));
+ writeOutput(static_cast<Char8>((cp & 0x3f) | 0x80));
}
else if (cp < 0x10000)
{
- *result++ = static_cast<Char8>((cp >> 12 ) | 0xe0);
- *result++ = static_cast<Char8>(((cp >> 6) & 0x3f) | 0x80);
- *result++ = static_cast<Char8>((cp & 0x3f ) | 0x80);
+ writeOutput(static_cast<Char8>((cp >> 12 ) | 0xe0));
+ writeOutput(static_cast<Char8>(((cp >> 6) & 0x3f) | 0x80));
+ writeOutput(static_cast<Char8>((cp & 0x3f ) | 0x80));
}
else
{
- *result++ = static_cast<Char8>((cp >> 18 ) | 0xf0);
- *result++ = static_cast<Char8>(((cp >> 12) & 0x3f) | 0x80);
- *result++ = static_cast<Char8>(((cp >> 6) & 0x3f) | 0x80);
- *result++ = static_cast<Char8>((cp & 0x3f ) | 0x80);
+ assert(cp <= CODE_POINT_MAX);
+ writeOutput(static_cast<Char8>((cp >> 18 ) | 0xf0));
+ writeOutput(static_cast<Char8>(((cp >> 12) & 0x3f) | 0x80));
+ writeOutput(static_cast<Char8>(((cp >> 6) & 0x3f) | 0x80));
+ writeOutput(static_cast<Char8>((cp & 0x3f ) | 0x80));
}
- return result;
}
@@ -170,14 +168,13 @@ size_t getUtf8Len(unsigned char ch)
template <class CharIterator, class Function> inline
-Function utf8ToCodePoint(CharIterator first, CharIterator last, Function f) //f is a unary function taking a CodePoint as single parameter
+void utf8ToCodePoint(CharIterator first, CharIterator last, Function writeOutput) //"writeOutput" is a unary function taking a CodePoint
{
assert_static(sizeof(typename std::iterator_traits<CharIterator>::value_type) == 1);
- typedef unsigned char Char8;
for ( ; first != last; ++first)
{
- auto getChar = [&](Char8 & ch) -> bool
+ auto getChar = [&](Char8& ch) -> bool
{
if (++first == last)
{
@@ -189,71 +186,55 @@ Function utf8ToCodePoint(CharIterator first, CharIterator last, Function f) //f
return true;
};
- CodePoint cp = static_cast<Char8>(*first);
- switch (getUtf8Len(static_cast<Char8>(cp)))
+ Char8 ch = static_cast<Char8>(*first);
+ switch (getUtf8Len(ch))
{
case 1:
+ writeOutput(ch);
break;
case 2:
{
- cp = (cp & 0x1f) << 6;
- Char8 ch;
- if (!getChar(ch)) continue;
+ CodePoint cp = (ch & 0x1f) << 6;
+ if (!getChar(ch)) return;
cp += ch & 0x3f;
+ writeOutput(cp);
}
break;
case 3:
{
- cp = (cp & 0xf) << 12;
- Char8 ch;
- if (!getChar(ch)) continue;
+ CodePoint cp = (ch & 0xf) << 12;
+ if (!getChar(ch)) return;
cp += (ch & 0x3f) << 6;
- if (!getChar(ch)) continue;
+ if (!getChar(ch)) return;
cp += ch & 0x3f;
-
+ writeOutput(cp);
}
break;
case 4:
{
- cp = (cp & 0x7) << 18;
- Char8 ch;
- if (!getChar(ch)) continue;
+ CodePoint cp = (ch & 0x7) << 18;
+ if (!getChar(ch)) return;
cp += (ch & 0x3f) << 12;
- if (!getChar(ch)) continue;
+ if (!getChar(ch)) return;
cp += (ch & 0x3f) << 6;
- if (!getChar(ch)) continue;
+ if (!getChar(ch)) return;
cp += ch & 0x3f;
+ writeOutput(cp);
}
break;
default:
assert(false);
}
- f(cp);
}
- return f;
}
-template <class String>
-class AppendStringIterator: public std::iterator<std::output_iterator_tag, void, void, void, void>
-{
-public:
- explicit AppendStringIterator (String& x) : str(&x) {}
- AppendStringIterator& operator= (typename String::value_type value) { *str += value; return *this; }
- AppendStringIterator& operator* () { return *this; }
- AppendStringIterator& operator++ () { return *this; }
- AppendStringIterator operator++ (int) { return *this; }
-private:
- String* str;
-};
-
-
template <class WideString, class CharString> inline
WideString utf8ToWide(const CharString& str, Int2Type<2>) //windows: convert utf8 to utf16 wchar_t
{
WideString output;
utf8ToCodePoint(strBegin(str), strBegin(str) + strLength(str),
- [&](CodePoint cp) { codePointToUtf16(cp, AppendStringIterator<WideString>(output)); });
+ [&](CodePoint cp) { codePointToUtf16(cp, [&](Char16 c) { output += static_cast<wchar_t>(c); }); });
return output;
}
@@ -273,7 +254,7 @@ CharString wideToUtf8(const WideString& str, Int2Type<2>) //windows: convert utf
{
CharString output;
utf16ToCodePoint(strBegin(str), strBegin(str) + strLength(str),
- [&](CodePoint cp) { codePointToUtf8(cp, AppendStringIterator<CharString>(output)); });
+ [&](CodePoint cp) { codePointToUtf8(cp, [&](char c) { output += c; }); });
return output;
}
@@ -283,7 +264,7 @@ CharString wideToUtf8(const WideString& str, Int2Type<4>) //other OS: convert ut
{
CharString output;
std::for_each(strBegin(str), strBegin(str) + strLength(str),
- [&](CodePoint cp) { codePointToUtf8(cp, AppendStringIterator<CharString>(output)); });
+ [&](CodePoint cp) { codePointToUtf8(cp, [&](char c) { output += c; }); });
return output;
}
}
@@ -292,8 +273,8 @@ CharString wideToUtf8(const WideString& str, Int2Type<4>) //other OS: convert ut
template <class WideString, class CharString> inline
WideString utf8ToWide(const CharString& str)
{
- assert_static((IsSameType<typename GetCharType<CharString>::Result, char >::result));
- assert_static((IsSameType<typename GetCharType<WideString>::Result, wchar_t>::result));
+ assert_static((IsSameType<typename GetCharType<CharString>::Type, char >::value));
+ assert_static((IsSameType<typename GetCharType<WideString>::Type, wchar_t>::value));
return implementation::utf8ToWide<WideString>(str, Int2Type<sizeof(wchar_t)>());
}
@@ -302,8 +283,8 @@ WideString utf8ToWide(const CharString& str)
template <class CharString, class WideString> inline
CharString wideToUtf8(const WideString& str)
{
- assert_static((IsSameType<typename GetCharType<CharString>::Result, char >::result));
- assert_static((IsSameType<typename GetCharType<WideString>::Result, wchar_t>::result));
+ assert_static((IsSameType<typename GetCharType<CharString>::Type, char >::value));
+ assert_static((IsSameType<typename GetCharType<WideString>::Type, wchar_t>::value));
return implementation::wideToUtf8<CharString>(str, Int2Type<sizeof(wchar_t)>());
}
@@ -326,8 +307,8 @@ template <class TargetString, class SourceString> inline
TargetString utf8CvrtTo(const SourceString& str)
{
return utf8CvrtTo<TargetString>(str,
- typename GetCharType<SourceString>::Result(),
- typename GetCharType<TargetString>::Result());
+ typename GetCharType<SourceString>::Type(),
+ typename GetCharType<TargetString>::Type());
}
}
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index d17e860c..d37fa522 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -35,7 +35,7 @@ LeakChecker::~LeakChecker()
const std::string message = std::string("Memory leak detected!") + "\n\n"
+ "Candidates:\n" + leakingStrings;
#ifdef FFS_WIN
- MessageBoxA(NULL, message.c_str(), "Error", 0);
+ MessageBoxA(nullptr, message.c_str(), "Error", 0);
#else
std::cerr << message;
std::abort();
@@ -70,7 +70,7 @@ std::string LeakChecker::rawMemToString(const void* ptr, size_t size)
void LeakChecker::reportProblem(const std::string& message) //throw (std::logic_error)
{
#ifdef FFS_WIN
- ::MessageBoxA(NULL, message.c_str(), "Error", 0);
+ ::MessageBoxA(nullptr, message.c_str(), "Error", 0);
#else
std::cerr << message;
#endif
@@ -100,20 +100,20 @@ typedef int (WINAPI* CompareStringOrdinalFunc)(LPCWSTR lpString1,
LPCWSTR lpString2,
int cchCount2,
BOOL bIgnoreCase);
-const SysDllFun<CompareStringOrdinalFunc> ordinalCompare = SysDllFun<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal");
+const SysDllFun<CompareStringOrdinalFunc> compareStringOrdinal = SysDllFun<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal");
}
-int z_impl::compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA, size_t sizeB)
+int z_impl::compareFilenamesWin(const wchar_t* lhs, const wchar_t* rhs, size_t sizeLhs, size_t sizeRhs)
{
//caveat: function scope static initialization is not thread-safe in VS 2010!
- if (ordinalCompare) //this additional test has no noticeable performance impact
+ if (compareStringOrdinal) //this additional test has no noticeable performance impact
{
- const int rv = ordinalCompare(a, //pointer to first string
- static_cast<int>(sizeA), //size, in bytes or characters, of first string
- b, //pointer to second string
- static_cast<int>(sizeB), //size, in bytes or characters, of second string
- true); //ignore case
+ const int rv = compareStringOrdinal(lhs, //__in LPCWSTR lpString1,
+ static_cast<int>(sizeLhs), //__in int cchCount1,
+ rhs, //__in LPCWSTR lpString2,
+ static_cast<int>(sizeRhs), //__in int cchCount2,
+ true); //__in BOOL bIgnoreCase
if (rv == 0)
throw std::runtime_error("Error comparing strings (ordinal)!");
else
@@ -124,26 +124,26 @@ int z_impl::compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA
//do NOT use "CompareString"; this function is NOT accurate (even with LOCALE_INVARIANT and SORT_STRINGSORT): for example "weiß" == "weiss"!!!
//the only reliable way to compare filenames (with XP) is to call "CharUpper" or "LCMapString":
- const int minSize = std::min<int>(sizeA, sizeB);
+ const auto minSize = static_cast<unsigned int>(std::min(sizeLhs, sizeRhs));
int rv = 0;
- if (minSize != 0) //LCMapString does not allow input sizes of 0!
+ if (minSize >= 0) //LCMapString does not allow input sizes of 0!
{
- if (minSize <= 5000) //performance optimization: stack
+ if (minSize <= MAX_PATH) //performance optimization: stack
{
- wchar_t bufferA[5000];
- wchar_t bufferB[5000];
+ wchar_t bufferA[MAX_PATH];
+ wchar_t bufferB[MAX_PATH];
//faster than CharUpperBuff + wmemcpy or CharUpper + wmemcpy and same speed like ::CompareString()
if (::LCMapString(ZSTRING_INVARIANT_LOCALE, //__in LCID Locale,
LCMAP_UPPERCASE, //__in DWORD dwMapFlags,
- a, //__in LPCTSTR lpSrcStr,
+ lhs, //__in LPCTSTR lpSrcStr,
minSize, //__in int cchSrc,
bufferA, //__out LPTSTR lpDestStr,
- 5000) == 0) //__in int cchDest
+ MAX_PATH) == 0) //__in int cchDest
throw std::runtime_error("Error comparing strings! (LCMapString)");
- if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, b, minSize, bufferB, 5000) == 0)
+ if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, rhs, minSize, bufferB, MAX_PATH) == 0)
throw std::runtime_error("Error comparing strings! (LCMapString)");
rv = ::wmemcmp(bufferA, bufferB, minSize);
@@ -153,10 +153,10 @@ int z_impl::compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA
std::vector<wchar_t> bufferA(minSize);
std::vector<wchar_t> bufferB(minSize);
- if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, a, minSize, &bufferA[0], minSize) == 0)
+ if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, lhs, minSize, &bufferA[0], minSize) == 0)
throw std::runtime_error("Error comparing strings! (LCMapString: FS)");
- if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, b, minSize, &bufferB[0], minSize) == 0)
+ if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, rhs, minSize, &bufferB[0], minSize) == 0)
throw std::runtime_error("Error comparing strings! (LCMapString: FS)");
rv = ::wmemcmp(&bufferA[0], &bufferB[0], minSize);
@@ -164,7 +164,7 @@ int z_impl::compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA
}
return rv == 0 ?
- static_cast<int>(sizeA) - static_cast<int>(sizeB) :
+ static_cast<int>(sizeLhs) - static_cast<int>(sizeRhs) :
rv;
}
diff --git a/zen/zstring.h b/zen/zstring.h
index a53c1bb0..cb6974e5 100644
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -151,7 +151,7 @@ typedef zen::Zbase<Zchar, zen::StorageRefCountThreadSafe, AllocatorFreeStoreChec
#if defined(FFS_WIN) || defined(FFS_LINUX)
namespace z_impl
{
-int compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA, size_t sizeB);
+int compareFilenamesWin(const wchar_t* lhs, const wchar_t* rhs, size_t sizeLhs, size_t sizeRhs);
void makeUpperCaseWin(wchar_t* str, size_t size);
}
bgstack15