From 8bf668665b107469086f16cb8ad23e47d479d2b4 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:14:37 +0200 Subject: 4.0 --- shared/FindFilePlus/FindFilePlus.vcxproj | 245 +++ shared/FindFilePlus/dll_main.cpp | 25 + shared/FindFilePlus/find_file_plus.cpp | 305 ++++ shared/FindFilePlus/find_file_plus.h | 78 + shared/FindFilePlus/load_dll.cpp | 25 + shared/FindFilePlus/load_dll.h | 39 + shared/IFileOperation/FileOperation_Vista.vcxproj | 6 +- shared/IFileOperation/file_op.cpp | 13 +- shared/IFileOperation/file_op.h | 7 + shared/ShadowCopy/Shadow_2003.vcxproj | 6 +- shared/ShadowCopy/Shadow_XP.vcxproj | 6 +- shared/ShadowCopy/shadow.h | 39 + shared/Taskbar_Seven/Taskbar_Seven.vcxproj | 5 +- shared/Taskbar_Seven/taskbar.cpp | 8 +- shared/Taskbar_Seven/taskbar.h | 7 + shared/Thumbnail/Thumbnail.vcxproj | 235 +++ shared/Thumbnail/dll_main.cpp | 25 + shared/Thumbnail/thumbnail.cpp | 167 +++ shared/Thumbnail/thumbnail.h | 68 + shared/check_exist.h | 2 +- shared/com_error.h | 178 ++- shared/custom_button.cpp | 32 +- shared/custom_combo_box.cpp | 111 -- shared/custom_combo_box.h | 42 - shared/custom_tooltip.cpp | 4 +- shared/debug_new.h | 2 +- shared/dir_name.cpp | 156 +- shared/dir_name.h | 52 +- shared/dir_watcher.cpp | 139 +- shared/dll_loader.cpp | 83 -- shared/dll_loader.h | 69 +- shared/dst_hack.cpp | 62 +- shared/dst_hack.h | 2 + shared/file_handling.cpp | 974 ++++++------ shared/file_handling.h | 50 +- shared/file_id.cpp | 35 +- shared/file_id_internal.h | 48 + shared/file_io.cpp | 19 +- shared/file_io.h | 8 +- shared/file_traverser.cpp | 255 +++- shared/file_traverser.h | 2 +- shared/fixed_list.h | 142 ++ shared/folder_history_box.cpp | 139 ++ shared/folder_history_box.h | 109 ++ shared/global_func.h | 99 +- shared/help_provider.cpp | 4 +- shared/i18n.cpp | 1 + shared/image_tools.h | 157 ++ shared/int64.h | 23 +- shared/localization.cpp | 4 +- shared/loki/AbstractFactory.h | 4 +- shared/loki/AssocVector.h | 4 +- shared/loki/CachedFactory.h | 190 +-- shared/loki/Factory.h | 298 ++-- shared/loki/Function.h | 298 ++-- shared/loki/Functor.h | 220 +-- shared/loki/HierarchyGenerators.h | 26 +- shared/loki/Key.h | 558 +++---- shared/loki/MultiMethods.h | 96 +- shared/loki/OrderedStatic.h | 14 +- shared/loki/Pimpl.h | 6 +- shared/loki/Register.h | 12 +- shared/loki/SPCachedFactory.h | 4 +- shared/loki/SafeBits.h | 4 +- shared/loki/SafeFormat.h | 14 +- shared/loki/ScopeGuard.h | 29 +- shared/loki/Sequence.h | 12 +- shared/loki/Singleton.h | 36 +- shared/loki/SmallObj.cpp | 4 +- shared/loki/SmallObj.h | 10 +- shared/loki/SmartPtr.h | 16 +- shared/loki/StrongPtr.h | 4 +- shared/loki/Threads.h | 354 ++--- shared/loki/TypeManip.h | 4 +- shared/loki/TypeTraits.h | 1640 ++++++++++----------- shared/loki/Typelist.h | 44 +- shared/loki/TypelistMacros.h | 416 +++--- shared/loki/Visitor.h | 8 +- shared/long_path_prefix.h | 2 +- shared/parse_lng.h | 10 +- shared/parse_plural.h | 4 +- shared/parse_txt.h | 4 +- shared/privilege.cpp | 13 +- shared/privilege.h | 4 +- shared/recycler.cpp | 26 +- shared/resolve_path.cpp | 262 +++- shared/resolve_path.h | 5 + shared/serialize.cpp | 4 +- shared/serialize.h | 32 +- shared/shadow.cpp | 77 +- shared/shell_execute.h | 6 +- shared/stl_tools.h | 49 + shared/string_tools.h | 16 +- shared/string_utf8.h | 20 +- shared/symlink_target.h | 23 +- shared/taskbar.cpp | 28 +- shared/taskbar.h | 2 +- shared/util.cpp | 14 +- shared/util.h | 2 +- shared/warn_static.h | 6 +- shared/wx_choice_enum.h | 2 +- shared/wx_timespan.h | 6 +- shared/xml_base.cpp | 25 +- shared/zbase.h | 20 +- shared/zstring.cpp | 28 +- shared/zstring.h | 4 +- 106 files changed, 5744 insertions(+), 3587 deletions(-) create mode 100644 shared/FindFilePlus/FindFilePlus.vcxproj create mode 100644 shared/FindFilePlus/dll_main.cpp create mode 100644 shared/FindFilePlus/find_file_plus.cpp create mode 100644 shared/FindFilePlus/find_file_plus.h create mode 100644 shared/FindFilePlus/load_dll.cpp create mode 100644 shared/FindFilePlus/load_dll.h create mode 100644 shared/Thumbnail/Thumbnail.vcxproj create mode 100644 shared/Thumbnail/dll_main.cpp create mode 100644 shared/Thumbnail/thumbnail.cpp create mode 100644 shared/Thumbnail/thumbnail.h delete mode 100644 shared/custom_combo_box.cpp delete mode 100644 shared/custom_combo_box.h delete mode 100644 shared/dll_loader.cpp create mode 100644 shared/file_id_internal.h create mode 100644 shared/fixed_list.h create mode 100644 shared/folder_history_box.cpp create mode 100644 shared/folder_history_box.h create mode 100644 shared/image_tools.h create mode 100644 shared/stl_tools.h (limited to 'shared') diff --git a/shared/FindFilePlus/FindFilePlus.vcxproj b/shared/FindFilePlus/FindFilePlus.vcxproj new file mode 100644 index 00000000..a49e99ba --- /dev/null +++ b/shared/FindFilePlus/FindFilePlus.vcxproj @@ -0,0 +1,245 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {70394AEF-5897-4911-AFA1-82EAF0581EFA} + ShadowDll + Win32Proj + + + + DynamicLibrary + Unicode + true + Windows7.1SDK + + + DynamicLibrary + Unicode + Windows7.1SDK + + + DynamicLibrary + Unicode + true + Windows7.1SDK + + + DynamicLibrary + Unicode + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + OBJ\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + OBJ\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + .\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + .\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + FindFilePlus_$(Platform) + FindFilePlus_$(Platform) + FindFilePlus_$(Platform) + FindFilePlus_$(Platform) + D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include + D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include + D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include + D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include + + + + $(IntDir)Build.html + + + Disabled + _X86_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100 + C:\Program Files\C++\Projects\FreeFileSync\shared + + + $(OutDir)$(TargetName)$(TargetExt) + true + true + $(IntDir)$(TargetName).pdb + Windows + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + $(IntDir)Build.html + + + X64 + + + Disabled + _AMD64_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + 4100 + C:\Program Files\C++\Projects\FreeFileSync\shared + + + $(OutDir)$(TargetName)$(TargetExt) + true + true + $(IntDir)$(TargetName).pdb + Windows + + + $(IntDir)$(TargetName).lib + MachineX64 + + + + + $(IntDir)Build.html + + + MaxSpeed + true + _X86_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level4 + true + ProgramDatabase + 4100 + Speed + C:\Program Files\C++\Projects\FreeFileSync\shared + + + $(OutDir)$(TargetName)$(TargetExt) + true + false + Windows + true + true + UseLinkTimeCodeGeneration + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + $(IntDir)Build.html + + + X64 + + + MaxSpeed + true + _AMD64_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level4 + true + ProgramDatabase + 4100 + Speed + C:\Program Files\C++\Projects\FreeFileSync\shared + + + $(OutDir)$(TargetName)$(TargetExt) + true + false + Windows + true + true + UseLinkTimeCodeGeneration + + + $(IntDir)$(TargetName).lib + MachineX64 + + + + + + + false + + + false + + + false + + + false + + + + + + + + + + + + \ No newline at end of file diff --git a/shared/FindFilePlus/dll_main.cpp b/shared/FindFilePlus/dll_main.cpp new file mode 100644 index 00000000..3805c99d --- /dev/null +++ b/shared/FindFilePlus/dll_main.cpp @@ -0,0 +1,25 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + + +#define WIN32_LEAN_AND_MEAN +#include + +//optional: add init/teardown logic here +BOOL APIENTRY DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} diff --git a/shared/FindFilePlus/find_file_plus.cpp b/shared/FindFilePlus/find_file_plus.cpp new file mode 100644 index 00000000..8b29efa2 --- /dev/null +++ b/shared/FindFilePlus/find_file_plus.cpp @@ -0,0 +1,305 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#include "find_file_plus.h" +//#include //these two don't play nice with each other + +#include "load_dll.h" +#include + +using namespace dll; +using namespace findplus; + + +namespace +{ +//-------------------------------------------------------------------------------------------------------------- +typedef NTSTATUS (NTAPI* NtOpenFileFunc)(PHANDLE fileHandle, + ACCESS_MASK desiredAccess, + POBJECT_ATTRIBUTES objectAttributes, + PIO_STATUS_BLOCK ioStatusBlock, + ULONG shareAccess, + ULONG openOptions); + +typedef NTSTATUS (NTAPI* NtCloseFunc)(HANDLE handle); + +typedef NTSTATUS (NTAPI* NtQueryDirectoryFileFunc)(HANDLE fileHandle, + HANDLE event, + PIO_APC_ROUTINE apcRoutine, + PVOID apcContext, + PIO_STATUS_BLOCK ioStatusBlock, + PVOID fileInformation, + ULONG length, + FILE_INFORMATION_CLASS fileInformationClass, + BOOLEAN ReturnSingleEntry, + PUNICODE_STRING fileMask, + BOOLEAN restartScan); + +typedef ULONG (NTAPI* RtlNtStatusToDosErrorFunc)(NTSTATUS /*__in status*/); + +typedef struct _RTL_RELATIVE_NAME_U +{ + UNICODE_STRING RelativeName; + HANDLE ContainingDirectory; + PVOID /*PRTLP_CURDIR_REF*/ CurDirRef; +} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U; + +typedef BOOLEAN (NTAPI* RtlDosPathNameToNtPathName_UFunc)(PCWSTR, //__in dosFileName, + PUNICODE_STRING, //__out ntFileName, + PCWSTR*, //__out_optFilePart, + PRTL_RELATIVE_NAME_U); //__out_opt relativeName + +typedef BOOLEAN (NTAPI* RtlDosPathNameToRelativeNtPathName_UFunc)(PCWSTR, //__in dosFileName, + PUNICODE_STRING, //__out ntFileName, + PWSTR*, //__out_optFilePart, + PRTL_RELATIVE_NAME_U); //__out_opt relativeName + +typedef VOID (NTAPI* RtlFreeUnicodeStringFunc)(PUNICODE_STRING); //__inout unicodeString + +//-------------------------------------------------------------------------------------------------------------- + +//it seems we cannot use any of the ntoskrnl.lib files in WinDDK as they produce access violations +//fortunately dynamic binding works fine: +NtOpenFileFunc ntOpenFile; +NtCloseFunc ntClose; +NtQueryDirectoryFileFunc ntQueryDirectoryFile; +RtlNtStatusToDosErrorFunc rtlNtStatusToDosError; +RtlFreeUnicodeStringFunc rtlFreeUnicodeString; +RtlDosPathNameToNtPathName_UFunc rtlDosPathNameToNtPathName_U; + + +template inline +void initDllFun(FunType& fun, const char* functionName) //throw FileError +{ + if (!fun) + { + fun = getSystemDllFun(L"ntdll.dll", functionName); + if (!fun) + throw FileError(182); //== ERROR_INVALID_ORDINAL, verified at compile time in "load_dll.cpp"; we better not use rtlNtStatusToDosError(STATUS_ORDINAL_NOT_FOUND) here ;) + } +} + + +struct FileError +{ + FileError(ULONG errorCode) : win32Error(errorCode) {} + ULONG win32Error; +}; +} + +class findplus::FileSearcher +{ +public: + FileSearcher(const wchar_t* dirname); //throw FileError + ~FileSearcher(); + + void readdir(FileInformation& output); //throw FileError + +private: + UNICODE_STRING ntPathName; //it seems hDir implicitly keeps a reference to this, at least ::FindFirstFile() does no cleanup before ::FindClose()! + HANDLE hDir; + + ULONG nextEntryOffset; //!= 0 if entry is waiting in buffer + //::FindNextFileW() uses 0x1000 = 4096 = sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 + //=> let's use the same, even if our header is 16 byte larger; maybe there is some packet size advantage for networks? Note that larger buffers seem to degrade performance. + static const ULONG BUFFER_SIZE = 4096; + LONGLONG buffer[BUFFER_SIZE / sizeof(LONGLONG)]; //buffer needs to be aligned at LONGLONG boundary + + static_assert(BUFFER_SIZE % sizeof(LONGLONG) == 0, "ups, our buffer is trimmed!"); +}; + + +FileSearcher::FileSearcher(const wchar_t* dirname) : + hDir(NULL), + nextEntryOffset(0) +{ + UNICODE_STRING cleanDummy = {}; + ntPathName = cleanDummy; + + Loki::ScopeGuard guardConstructor = Loki::MakeGuard([&]() { this->~FileSearcher(); }); + + //NT/ZwXxx Routines + //http://msdn.microsoft.com/en-us/library/ff567122(v=VS.85).aspx + + //Run-Time Library (RTL) Routines + //http://msdn.microsoft.com/en-us/library/ff563638(v=VS.85).aspx + + //init static dll functions + initDllFun(ntOpenFile, "NtOpenFile"); //throw FileError + initDllFun(ntClose, "NtClose"); + initDllFun(ntQueryDirectoryFile, "NtQueryDirectoryFile"); + initDllFun(rtlNtStatusToDosError, "RtlNtStatusToDosError"); + initDllFun(rtlFreeUnicodeString, "RtlFreeUnicodeString"); + try + { + initDllFun(rtlDosPathNameToNtPathName_U, "RtlDosPathNameToRelativeNtPathName_U"); //use the newer version if available + } + catch (const FileError&) + { + initDllFun(rtlDosPathNameToNtPathName_U, "RtlDosPathNameToNtPathName_U"); //fallback for XP + } + //-------------------------------------------------------------------------------------------------------------- + + //convert dosFileName, e.g. C:\Users or \\?\C:\Users to ntFileName \??\C:\Users + //in contrast to ::FindFirstFile() we don't evaluate the relativeName, however tests indicate ntFileName is *always* filled with an absolute name, even if dosFileName is relative + + //NOTE: RtlDosPathNameToNtPathName_U may be used on all XP/Win7/Win8 for compatibility + // RtlDosPathNameToNtPathName_U: used by Windows XP available with OS version 3.51 (Windows NT) and higher + // RtlDosPathNameToRelativeNtPathName_U: used by Win7/Win8 available with OS version 5.2 (Windows Server 2003) and higher + if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName, + &ntPathName, //__out ntFileName, + NULL, //__out_optFilePart, + NULL)) //__out_opt relativeName - empty if dosFileName is absolute + throw FileError(rtlNtStatusToDosError(STATUS_OBJECT_PATH_NOT_FOUND)); //translates to ERROR_PATH_NOT_FOUND, same behavior like ::FindFirstFileEx() + + OBJECT_ATTRIBUTES objAttr = {}; + InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes, + &ntPathName, //[in] PUNICODE_STRING objectName, + OBJ_CASE_INSENSITIVE, //[in] ULONG attributes, + NULL, //[in] HANDLE rootDirectory, + NULL); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor + + { + IO_STATUS_BLOCK status = {}; + NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle, + FILE_LIST_DIRECTORY | SYNCHRONIZE, //__in ACCESS_MASK desiredAccess, - 100001 used by ::FindFirstFile() on all XP/Win7/Win8 + &objAttr, //__in POBJECT_ATTRIBUTES objectAttributes, + &status, //__out PIO_STATUS_BLOCK ioStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //__in ULONG shareAccess, - 7 on Win7/Win8, 3 on XP + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); //__in ULONG openOptions - 4021 used on all XP/Win7/Win8 + if (!NT_SUCCESS(rv)) + throw FileError(rtlNtStatusToDosError(rv)); + } + + guardConstructor.Dismiss(); +} + + +FileSearcher::~FileSearcher() +{ + //cleanup in reverse order + if (hDir) + ntClose(hDir); + + if (ntPathName.Buffer) + rtlFreeUnicodeString(&ntPathName); //cleanup identical to ::FindFirstFile() + //note that most if this function seems inlined by the linker, so that its assembly looks equivalent to "RtlFreeHeap(GetProcessHeap(), 0, ntPathName.Buffer)" +} + + +void FileSearcher::readdir(FileInformation& output) +{ + //although FILE_ID_FULL_DIR_INFORMATION should suffice for our purposes, there are problems on Windows XP for certain directories, e.g. "\\Vboxsvr\build" + //making NtQueryDirectoryFile() return with STATUS_INVALID_PARAMETER while other directories, e.g. "C:\" work fine for some reason + //FILE_ID_BOTH_DIR_INFORMATION on the other hand works on XP/Win7/Win8 + //performance: there is no noticable difference between FILE_ID_BOTH_DIR_INFORMATION and FILE_ID_FULL_DIR_INFORMATION + + /* 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, + &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, + false); //__in BOOLEAN restartScan + */ + + //analog to ::FindNextFileW() with performance optimized access (in contrast to first access in ::FindFirstFileW()) + if (nextEntryOffset == 0) + { + 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, + &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 + FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" + false, //__in BOOLEAN returnSingleEntry, + NULL, //__in_opt PUNICODE_STRING mask, + false); //__in BOOLEAN restartScan + if (!NT_SUCCESS(rv)) + throw FileError(rtlNtStatusToDosError(rv)); //throws STATUS_NO_MORE_FILES when finished + + if (status.Information == 0) //except for the first call to call ::NtQueryDirectoryFile(): + throw FileError(rtlNtStatusToDosError(STATUS_BUFFER_OVERFLOW)); //if buffer size is too small, return value is STATUS_SUCCESS and Information == 0 -> we don't expect this! + } + + const FILE_ID_BOTH_DIR_INFORMATION& dirInfo = *reinterpret_cast(reinterpret_cast(buffer) + nextEntryOffset); + + if (dirInfo.NextEntryOffset == 0) + nextEntryOffset = 0; //our offset is relative to the beginning of the buffer + else + nextEntryOffset += dirInfo.NextEntryOffset; + + + auto toFileTime = [](const LARGE_INTEGER & rawTime) -> FILETIME + { + FILETIME tmp = { rawTime.LowPart, rawTime.HighPart }; + return tmp; + }; + + output.creationTime = toFileTime(dirInfo.CreationTime); + output.lastWriteTime = toFileTime(dirInfo.LastWriteTime); + output.fileSize.QuadPart = dirInfo.EndOfFile.QuadPart; + output.fileId.QuadPart = dirInfo.FileId.QuadPart; + output.fileAttributes = dirInfo.FileAttributes; + output.shortNameLength = dirInfo.FileNameLength / sizeof(TCHAR); //FileNameLength is in bytes! + + if (dirInfo.FileNameLength + sizeof(TCHAR) > sizeof(output.shortName)) //this may actually happen if ::NtQueryDirectoryFile() decides to return a + throw FileError(rtlNtStatusToDosError(STATUS_BUFFER_OVERFLOW)); //short name of length MAX_PATH + 1, 0-termination is not required! + + ::memcpy(output.shortName, dirInfo.FileName, dirInfo.FileNameLength); + output.shortName[output.shortNameLength] = 0; //NOTE: FILE_ID_BOTH_DIR_INFORMATION::FileName in general is NOT 0-terminated! It is on XP/Win7, but NOT on Win8! + + static_assert(sizeof(output.creationTime) == sizeof(dirInfo.CreationTime), "dang!"); + static_assert(sizeof(output.lastWriteTime) == sizeof(dirInfo.LastWriteTime), "dang!"); + static_assert(sizeof(output.fileSize) == sizeof(dirInfo.EndOfFile), "dang!"); + static_assert(sizeof(output.fileId) == sizeof(dirInfo.FileId), "dang!"); + static_assert(sizeof(output.fileAttributes) == sizeof(dirInfo.FileAttributes), "dang!"); +} + + +FindHandle findplus::openDir(const wchar_t* dirname) +{ + try + { + return new FileSearcher(dirname); //throw FileError + } + catch (const FileError& err) + { + setWin32Error(err.win32Error); + return NULL; + } +} + + +bool findplus::readDir(FindHandle hnd, FileInformation& output) +{ + try + { + hnd->readdir(output); //throw FileError + return true; + } + catch (const FileError& err) + { + setWin32Error(err.win32Error); + return false; + } +} + + +void findplus::closeDir(FindHandle hnd) +{ + if (hnd) //play a little "nice" + delete static_cast(hnd); +} diff --git a/shared/FindFilePlus/find_file_plus.h b/shared/FindFilePlus/find_file_plus.h new file mode 100644 index 00000000..88cb13af --- /dev/null +++ b/shared/FindFilePlus/find_file_plus.h @@ -0,0 +1,78 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef FIND_FIRST_FILE_PLUS_HEADER_087483434 +#define FIND_FIRST_FILE_PLUS_HEADER_087483434 + +#ifdef FIND_FILE_PLUS_DLL_EXPORTS +#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllexport) +#else +#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllimport) +#endif + + +#ifdef FIND_FILE_PLUS_DLL_EXPORTS +#include //driver level headers must be included *before* windows api headers! +#endif +#include // +#undef min +#undef max + +#include "../build_info.h" + +namespace findplus +{ +/*-------------- + |declarations| + --------------*/ + +struct FileInformation +{ + FILETIME creationTime; + FILETIME lastWriteTime; + ULARGE_INTEGER fileSize; + ULARGE_INTEGER fileId; + DWORD fileAttributes; + DWORD shortNameLength; + WCHAR shortName[MAX_PATH + 1]; //shortName is 0-terminated +}; + +class FileSearcher; +typedef FileSearcher* FindHandle; + +DLL_FUNCTION_DECLARATION +FindHandle openDir(const wchar_t* dirname); //returns NULL on error, call ::GetLastError(); returns ERROR_INVALID_ORDINAL if ntdll-libraries could not be loaded +//note do NOT place an asterisk at end, e.g. C:\SomeDir\*, as one would do for ::FindFirstFile() + +DLL_FUNCTION_DECLARATION +bool readDir(FindHandle hnd, FileInformation& output); //returns false on error or if there are no more files; ::GetLastError() returns ERROR_NO_MORE_FILES + +DLL_FUNCTION_DECLARATION +void closeDir(FindHandle hnd); + +/*---------- + |typedefs| + ----------*/ +typedef FindHandle (*OpenDirFunc )(const wchar_t* dirname); +typedef bool (*ReadDirFunc )(FindHandle hnd, FileInformation& dirInfo); +typedef void (*CloseDirFunc)(FindHandle hnd); + +/*-------------- + |symbol names| + --------------*/ +//const pointers ensure internal linkage +const char openDirFuncName [] = "openDir"; +const char readDirFuncName [] = "readDir"; +const char closeDirFuncName[] = "closeDir"; + +/*--------------- + |library names| + ---------------*/ +inline const wchar_t* getDllName() { return util::is64BitBuild ? L"FindFilePlus_x64.dll" : L"FindFilePlus_Win32.dll"; } +} + + +#endif //FIND_FIRST_FILE_PLUS_HEADER_087483434 diff --git a/shared/FindFilePlus/load_dll.cpp b/shared/FindFilePlus/load_dll.cpp new file mode 100644 index 00000000..51ec1f0c --- /dev/null +++ b/shared/FindFilePlus/load_dll.cpp @@ -0,0 +1,25 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#define WIN32_LEAN_AND_MEAN +#include // yes, this sequence is mad, but ddk and api headers contain plenty of redefinitions +#include "load_dll.h" // + +void* /*FARPROC*/ dll::loadSymbol(const wchar_t* libraryName, const char* functionName) +{ + return ::GetProcAddress(::GetModuleHandle(libraryName), functionName); + //cleanup neither required nor allowed (::FreeLibrary()) + +} +//note: void* and FARPROC function pointer have same binary size on Windows + + +void dll::setWin32Error(unsigned long lastError) +{ + ::SetLastError(lastError); +} + +static_assert(ERROR_INVALID_ORDINAL == 182, "dang!"); \ No newline at end of file diff --git a/shared/FindFilePlus/load_dll.h b/shared/FindFilePlus/load_dll.h new file mode 100644 index 00000000..f152dd74 --- /dev/null +++ b/shared/FindFilePlus/load_dll.h @@ -0,0 +1,39 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef LOAD_DLL_HEADER_0312463214872163832174 +#define LOAD_DLL_HEADER_0312463214872163832174 + +namespace dll +{ +template +FunctionType getSystemDllFun(const wchar_t* libraryName, const char* functionName); //NOTE: uses ::GetModuleHandle => call for system DLLs only! + +void setWin32Error(unsigned long lastError); + + + + + + + + + + + + + +void* /*FARPROC*/ loadSymbol(const wchar_t* libraryName, const char* functionName); + +template inline +FunctionType getSystemDllFun(const wchar_t* libraryName, const char* functionName) +{ + return reinterpret_cast(loadSymbol(libraryName, functionName)); +} +} + +#endif //LOAD_DLL_HEADER_0312463214872163832174 + diff --git a/shared/IFileOperation/FileOperation_Vista.vcxproj b/shared/IFileOperation/FileOperation_Vista.vcxproj index 9f9a9c28..5de402f4 100644 --- a/shared/IFileOperation/FileOperation_Vista.vcxproj +++ b/shared/IFileOperation/FileOperation_Vista.vcxproj @@ -29,10 +29,12 @@ DynamicLibrary Unicode true + Windows7.1SDK DynamicLibrary Unicode + Windows7.1SDK DynamicLibrary @@ -63,10 +65,10 @@ <_ProjectFileVersion>10.0.30319.1 - .\ + OBJ\ OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ false - .\ + OBJ\ OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ false .\ diff --git a/shared/IFileOperation/file_op.cpp b/shared/IFileOperation/file_op.cpp index a2cf9413..8b632972 100644 --- a/shared/IFileOperation/file_op.cpp +++ b/shared/IFileOperation/file_op.cpp @@ -61,13 +61,15 @@ bool fileop::moveToRecycleBin(const wchar_t* fileNames[], return false; } + int operationCount = 0; + for (size_t i = 0; i < fileNo; ++i) { //create file/folder item object ComPtr psiFile; - hr = SHCreateItemFromParsingName(fileNames[i], - NULL, - IID_PPV_ARGS(psiFile.init())); + hr = ::SHCreateItemFromParsingName(fileNames[i], + NULL, + IID_PPV_ARGS(psiFile.init())); if (FAILED(hr)) { if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || //file not existing anymore @@ -87,8 +89,13 @@ bool fileop::moveToRecycleBin(const wchar_t* fileNames[], lastErrorMessage = generateErrorMsg(L"Error calling \"DeleteItem\".", hr); return false; } + + ++operationCount; } + if (operationCount == 0) //calling PerformOperations() without anything to do results in E_UNEXPECTED + return true; + //perform actual operations hr = fileOp->PerformOperations(); if (FAILED(hr)) diff --git a/shared/IFileOperation/file_op.h b/shared/IFileOperation/file_op.h index c1bb26a2..dbe00196 100644 --- a/shared/IFileOperation/file_op.h +++ b/shared/IFileOperation/file_op.h @@ -13,6 +13,8 @@ #define FILE_OP_DLL_API extern "C" __declspec(dllimport) #endif +#include "../build_info.h" + namespace fileop { @@ -48,6 +50,11 @@ typedef void (*GetLastErrorFct)(wchar_t* errorMessage, size_t errorBufferLen); const char moveToRecycleBinFctName[] = "moveToRecycleBin"; const char copyFileFctName[] = "copyFile"; const char getLastErrorFctName[] = "getLastError"; + +/*--------------- + |library names| + ---------------*/ +inline const wchar_t* getDllName() { return util::is64BitBuild ? L"FileOperation_x64.dll" : L"FileOperation_Win32.dll"; } } diff --git a/shared/ShadowCopy/Shadow_2003.vcxproj b/shared/ShadowCopy/Shadow_2003.vcxproj index 5351cc1d..710b65bf 100644 --- a/shared/ShadowCopy/Shadow_2003.vcxproj +++ b/shared/ShadowCopy/Shadow_2003.vcxproj @@ -30,10 +30,12 @@ Unicode true false + Windows7.1SDK DynamicLibrary Unicode + Windows7.1SDK DynamicLibrary @@ -64,10 +66,10 @@ <_ProjectFileVersion>10.0.30319.1 - .\ + OBJ\ OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ false - .\ + OBJ\ OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ false .\ diff --git a/shared/ShadowCopy/Shadow_XP.vcxproj b/shared/ShadowCopy/Shadow_XP.vcxproj index d096297a..6211afd5 100644 --- a/shared/ShadowCopy/Shadow_XP.vcxproj +++ b/shared/ShadowCopy/Shadow_XP.vcxproj @@ -29,10 +29,12 @@ DynamicLibrary Unicode true + Windows7.1SDK DynamicLibrary Unicode + Windows7.1SDK DynamicLibrary @@ -63,10 +65,10 @@ <_ProjectFileVersion>10.0.30319.1 - .\ + OBJ\ OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ false - .\ + OBJ\ OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ false .\ diff --git a/shared/ShadowCopy/shadow.h b/shared/ShadowCopy/shadow.h index b21395da..8721b906 100644 --- a/shared/ShadowCopy/shadow.h +++ b/shared/ShadowCopy/shadow.h @@ -13,6 +13,8 @@ #define SHADOWDLL_API extern "C" __declspec(dllimport) #endif +#include "../build_info.h" + namespace shadow { @@ -60,6 +62,43 @@ typedef void (*ReleaseShadowCopyFct)(ShadowHandle handle); //(use const pointers to ensure internal linkage) const char createShadowCopyFctName[] = "createShadowCopy"; const char releaseShadowCopyFctName[] = "releaseShadowCopy"; + +/*--------------- + |library names| + ---------------*/ +namespace impl +{ +bool newerThanXP() +{ + OSVERSIONINFO osvi = {}; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if (::GetVersionEx(&osvi)) + return osvi.dwMajorVersion > 5 || + (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 1) ; + //XP has majorVersion == 5, minorVersion == 1 + //Server 2003 has majorVersion == 5, minorVersion == 2 + //version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + return false; +} +} + +inline +const wchar_t* getDllName() +{ + /* + distinguish a bunch of VSS builds: we use XP and Server 2003 implementations... + VSS version and compatibility overview: http://msdn.microsoft.com/en-us/library/aa384627(VS.85).aspx + */ + return impl::newerThanXP() ? + (util::is64BitBuild ? + L"Shadow_Server2003_x64.dll" : + L"Shadow_Server2003_Win32.dll") : + + (util::is64BitBuild ? + L"Shadow_XP_x64.dll" : + L"Shadow_XP_Win32.dll"); +} } diff --git a/shared/Taskbar_Seven/Taskbar_Seven.vcxproj b/shared/Taskbar_Seven/Taskbar_Seven.vcxproj index 5b04a98c..8437bc09 100644 --- a/shared/Taskbar_Seven/Taskbar_Seven.vcxproj +++ b/shared/Taskbar_Seven/Taskbar_Seven.vcxproj @@ -32,6 +32,7 @@ DynamicLibrary Unicode + Windows7.1SDK DynamicLibrary @@ -62,10 +63,10 @@ <_ProjectFileVersion>10.0.30319.1 - .\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ false - .\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ false .\ diff --git a/shared/Taskbar_Seven/taskbar.cpp b/shared/Taskbar_Seven/taskbar.cpp index bbbaaf7d..2a739e6c 100644 --- a/shared/Taskbar_Seven/taskbar.cpp +++ b/shared/Taskbar_Seven/taskbar.cpp @@ -30,10 +30,10 @@ ComPtr getInstance() static ComPtr taskbarlist; if (!taskbarlist) { - HRESULT hr = CoCreateInstance(CLSID_TaskbarList, - NULL, - CLSCTX_ALL, - IID_PPV_ARGS(taskbarlist.init())); + HRESULT hr = ::CoCreateInstance(CLSID_TaskbarList, + NULL, + CLSCTX_ALL, + IID_PPV_ARGS(taskbarlist.init())); if (FAILED(hr)) lastErrorMessage = generateErrorMsg(L"Error calling \"CoCreateInstance\".", hr); } diff --git a/shared/Taskbar_Seven/taskbar.h b/shared/Taskbar_Seven/taskbar.h index 3bae28a9..507920c7 100644 --- a/shared/Taskbar_Seven/taskbar.h +++ b/shared/Taskbar_Seven/taskbar.h @@ -13,6 +13,8 @@ #define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllimport) #endif +#include "../build_info.h" + namespace tbseven { @@ -60,6 +62,11 @@ typedef void (*GetLastErrorFct)(wchar_t* errorMessage, size_t errorBufferLen); const char setStatusFctName[] = "setStatus"; const char setProgressFctName[] = "setProgress"; const char getLastErrorFctName[] = "getLastError"; + +/*--------------- + |library names| + ---------------*/ +inline const wchar_t* getDllName() { return util::is64BitBuild ? L"Taskbar7_x64.dll" : L"Taskbar7_Win32.dll"; } } #endif //TASKBAR_SEVEN_DLL_H diff --git a/shared/Thumbnail/Thumbnail.vcxproj b/shared/Thumbnail/Thumbnail.vcxproj new file mode 100644 index 00000000..05196e0a --- /dev/null +++ b/shared/Thumbnail/Thumbnail.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {70394AEF-5897-4911-AFA1-82EAF0581EFA} + ShadowDll + Win32Proj + + + + DynamicLibrary + Unicode + true + Windows7.1SDK + + + DynamicLibrary + Unicode + Windows7.1SDK + + + DynamicLibrary + Unicode + true + Windows7.1SDK + + + DynamicLibrary + Unicode + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + OBJ\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + OBJ\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + .\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + .\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + Thumbnail_$(Platform) + Thumbnail_$(Platform) + Thumbnail_$(Platform) + Thumbnail_$(Platform) + + + + $(IntDir)Build.html + + + Disabled + _DEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100 + + + $(OutDir)$(TargetName)$(TargetExt) + true + true + $(IntDir)$(TargetName).pdb + Windows + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + $(IntDir)Build.html + + + X64 + + + Disabled + _DEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + 4100 + + + $(OutDir)$(TargetName)$(TargetExt) + true + true + $(IntDir)$(TargetName).pdb + Windows + + + $(IntDir)$(TargetName).lib + MachineX64 + + + + + $(IntDir)Build.html + + + MaxSpeed + true + NDEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level4 + true + ProgramDatabase + 4100 + Speed + + + $(OutDir)$(TargetName)$(TargetExt) + true + false + Windows + true + true + UseLinkTimeCodeGeneration + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + $(IntDir)Build.html + + + X64 + + + MaxSpeed + true + NDEBUG;_WINDOWS;_USRDLL;THUMBNAIL_DLL_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level4 + true + ProgramDatabase + 4100 + Speed + + + $(OutDir)$(TargetName)$(TargetExt) + true + false + Windows + true + true + UseLinkTimeCodeGeneration + + + $(IntDir)$(TargetName).lib + MachineX64 + + + + + + + false + + + false + + + false + + + false + + + + + + + + + + \ No newline at end of file diff --git a/shared/Thumbnail/dll_main.cpp b/shared/Thumbnail/dll_main.cpp new file mode 100644 index 00000000..3805c99d --- /dev/null +++ b/shared/Thumbnail/dll_main.cpp @@ -0,0 +1,25 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + + +#define WIN32_LEAN_AND_MEAN +#include + +//optional: add init/teardown logic here +BOOL APIENTRY DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} diff --git a/shared/Thumbnail/thumbnail.cpp b/shared/Thumbnail/thumbnail.cpp new file mode 100644 index 00000000..51635ff9 --- /dev/null +++ b/shared/Thumbnail/thumbnail.cpp @@ -0,0 +1,167 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#include "thumbnail.h" + +#define WIN32_LEAN_AND_MEAN +#include "windows.h" + +#define STRICT_TYPED_ITEMIDS //better type safety for IDLists +#include + +#include +#include +#include "../com_ptr.h" +#include "../string_tools.h" +#include "../loki/ScopeGuard.h" +//#include "../perf.h" + +using namespace zen; + + +thumb::HICON thumb::getThumbnail(const wchar_t* filename, int requestedSize) //return 0 on failure, caller takes ownership! +{ + const std::wstring filenameStr(filename); + + util::ComPtr shellFolder; + { + HRESULT hr = ::SHGetDesktopFolder(shellFolder.init()); + if (FAILED(hr) || !shellFolder) + return NULL; + } + + PIDLIST_RELATIVE pidlFolder = NULL; + { + const std::wstring pathName = beforeLast(filenameStr, '\\'); + HRESULT hr = shellFolder->ParseDisplayName(NULL, // [in] HWND hwnd, + NULL, // [in] IBindCtx *pbc, + const_cast(pathName.c_str()), // [in] LPWSTR pszDisplayName, + NULL, // [out] ULONG *pchEaten, + &pidlFolder, // [out] PIDLIST_RELATIVE* ppidl, + NULL); // [in, out] ULONG *pdwAttributes + if (FAILED(hr) || !pidlFolder) + return NULL; + } + LOKI_ON_BLOCK_EXIT2(::ILFree(pidlFolder)); //older version: ::CoTaskMemFree + + util::ComPtr imageFolder; + { + HRESULT hr = shellFolder->BindToObject(pidlFolder, // [in] PCUIDLIST_RELATIVE pidl, + NULL, + IID_PPV_ARGS(imageFolder.init())); + if (FAILED(hr) || !imageFolder) + return NULL; + } + + PIDLIST_RELATIVE pidImage = NULL; + { + const std::wstring shortName = afterLast(filenameStr, '\\'); + HRESULT hr = imageFolder->ParseDisplayName(NULL, // [in] HWND hwnd, + NULL, // [in] IBindCtx *pbc, + const_cast(shortName.c_str()), // [in] LPWSTR pszDisplayName, + NULL, // [out] ULONG *pchEaten, + &pidImage, // [out] PIDLIST_RELATIVE *ppidl, + NULL); // [in, out] ULONG *pdwAttributes + if (FAILED(hr) || !pidImage) + return NULL; + } + LOKI_ON_BLOCK_EXIT2(::ILFree(pidImage)); //older version: ::CoTaskMemFree + + util::ComPtr extractImage; + { + PCUITEMID_CHILD_ARRAY pidlIn = reinterpret_cast(&pidImage); + //this is where STRICT_TYPED_ITEMIDS gets us ;) + + HRESULT hr = imageFolder->GetUIObjectOf(NULL, // [in] HWND hwndOwner, + 1, // [in] UINT cidl, + pidlIn, // [in] PCUITEMID_CHILD_ARRAY apidl, + IID_IExtractImage, // [in] REFIID riid, + NULL, // [in, out] UINT *rgfReserved, + reinterpret_cast(extractImage.init())); // [out] void **ppv + if (FAILED(hr) || !extractImage) + return NULL; + } + + { + wchar_t pathBuffer[MAX_PATH]; + DWORD priority = 0; + const SIZE prgSize = { requestedSize, requestedSize }; //preferred size only! + DWORD clrDepth = 32; + DWORD flags = IEIFLAG_SCREEN | IEIFLAG_OFFLINE; + + HRESULT hr = extractImage->GetLocation(pathBuffer, // [out] LPWSTR pszPathBuffer, + MAX_PATH, // [in] DWORD cchMax, + &priority, // [out] DWORD *pdwPriority, + &prgSize, // [in] const SIZE *prgSize, + clrDepth, // [in] DWORD dwRecClrDepth, + &flags); // [in, out] DWORD *pdwFlags + if (FAILED(hr)) + return NULL; + } + + HBITMAP bitmap = NULL; + { + HRESULT hr = extractImage->Extract(&bitmap); + if (FAILED(hr) || !bitmap) + return NULL; + } + LOKI_ON_BLOCK_EXIT2(::DeleteObject(bitmap)); + + + BITMAP bmpInfo = {}; + if (::GetObject(bitmap, //__in HGDIOBJ hgdiobj, + sizeof(bmpInfo), //__in int cbBuffer, + &bmpInfo) == 0) //__out LPVOID lpvObject + return NULL; + + HBITMAP bitmapMask = ::CreateCompatibleBitmap(::GetDC(NULL), bmpInfo.bmWidth, bmpInfo.bmHeight); + if (bitmapMask == 0) + return NULL; + LOKI_ON_BLOCK_EXIT2(::DeleteObject(bitmapMask)); + + ICONINFO iconInfo = {}; + iconInfo.fIcon = true; + iconInfo.hbmColor = bitmap; + iconInfo.hbmMask = bitmapMask; + + return ::CreateIconIndirect(&iconInfo); +} + + +thumb::HICON thumb::getIconByIndex(int iconIndex, int shilIconType) //return 0 on failure, caller takes ownership! +{ + //Note: using IExtractIcon::Extract is *no* alternative, just as ::SHGetFileInfo(), it only supports small (16x16) and large (32x32) icons + + util::ComPtr imageList; //perf: 0,12 µs only to get the image list + { + HRESULT hr = ::SHGetImageList(shilIconType, //__in int iImageList, + IID_PPV_ARGS(imageList.init())); + if (FAILED(hr) || !imageList) + return NULL; + } + + bool hasAlpha = false; //perf: 0,14 µs + { + DWORD flags = 0; + HRESULT hr = imageList->GetItemFlags(iconIndex, //[in] int i, + &flags); //[out] DWORD *dwFlags + if (SUCCEEDED(hr)) + hasAlpha = flags & ILIF_ALPHA; + } + + ::HICON hIcon = NULL; //perf: 1,5 ms - the dominant block + { + HRESULT hr = imageList->GetIcon(iconIndex, // [in] int i, + hasAlpha ? ILD_IMAGE : ILD_NORMAL, // [in] UINT flags, + //ILD_IMAGE -> do not draw mask - fixes glitch with ILD_NORMAL where both mask *and* alpha channel are applied, e.g. for ffs_batch and folder icon + //other flags: http://msdn.microsoft.com/en-us/library/windows/desktop/bb775230(v=vs.85).aspx + &hIcon); // [out] HICON *picon + if (FAILED(hr) || !hIcon) + return NULL; + } + + return hIcon; +} \ No newline at end of file diff --git a/shared/Thumbnail/thumbnail.h b/shared/Thumbnail/thumbnail.h new file mode 100644 index 00000000..ae62cf5d --- /dev/null +++ b/shared/Thumbnail/thumbnail.h @@ -0,0 +1,68 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef TASKBAR_SEVEN_DLL_H +#define TASKBAR_SEVEN_DLL_H + +#ifdef THUMBNAIL_DLL_EXPORTS +#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllexport) +#else +#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllimport) +#endif + +#include "../build_info.h" +//#include + +namespace thumb +{ +/* +PREREQUISITES: + +1. COM must be initialized for the current thread via ::CoInitialize(NULL) or ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED), + but NOT ::CoInitializeEx(NULL, COINIT_MULTITHREADED) -> internal access violation crash! +2. call ::FileIconInit() on app start to remedy obscure errors like SHELL_E_WRONG_BITDEPTH (0x80270102) + for certain file types, e.g. lnk, mpg - required on Windows 7 see http://msdn.microsoft.com/en-us/library/ms683212(v=VS.85).aspx +*/ + +/*-------------- + |declarations| + --------------*/ +typedef void* HICON; + +DLL_FUNCTION_DECLARATION +HICON getThumbnail(const wchar_t* filename, int requestedSize); //return 0 on failure, caller takes ownership! +//Note: not all file types support thumbnails! make sure to implement fallback to file icon! + +DLL_FUNCTION_DECLARATION +HICON getIconByIndex(int iconIndex, int shilIconType); //return 0 on failure, caller takes ownership! +/* +"iconType" refers to parameter "iImageList" of ::SHGetImageList(); sample values: + SHIL_SMALL - 16x16, but the size can be customized by the user. + SHIL_EXTRALARGE - 48x48, but the size can be customized by the user. + SHIL_JUMBO - Vista and later; normally 256x256 pixels +"iconIndex" as returned by ::SHGetFileInfo() +*/ + +/*---------- + |typedefs| + ----------*/ +typedef HICON (*GetThumbnailFct )(const wchar_t* filename, int requestedSize); +typedef HICON (*GetIconByIndexFct)(int iconIndex, int shilIconType); + +/*-------------- + |symbol names| + --------------*/ +//(use const pointers to ensure internal linkage) +const char getThumbnailFctName [] = "getThumbnail"; +const char getIconByIndexFctName [] = "getIconByIndex"; + +/*--------------- + |library names| + ---------------*/ +inline const wchar_t* getDllName() { return util::is64BitBuild ? L"Thumbnail_x64.dll" : L"Thumbnail_Win32.dll"; } +} + +#endif //TASKBAR_SEVEN_DLL_H diff --git a/shared/check_exist.h b/shared/check_exist.h index 14a8a3f8..8078d388 100644 --- a/shared/check_exist.h +++ b/shared/check_exist.h @@ -48,7 +48,7 @@ boost::unique_future objExistsAsync(const Zstring& objname) { //thread safety: make it a pure value type for use in the thread! const Zstring objnameVal = objname; //atomic ref-count => binary value-type semantics! - boost::packaged_task pt([=] { return (*fun)(objnameVal); }); + boost::packaged_task pt([ = ] { return (*fun)(objnameVal); }); auto fut = pt.get_future(); boost::thread(std::move(pt)); return std::move(fut); diff --git a/shared/com_error.h b/shared/com_error.h index 39f26555..e3d51d4b 100644 --- a/shared/com_error.h +++ b/shared/com_error.h @@ -9,31 +9,22 @@ #include #include -#include +#include +#undef min +#undef max namespace util { std::wstring generateErrorMsg(const std::wstring& input, HRESULT hr); +std::wstring formatWin32Msg(DWORD dwMessageId); //return empty string on error + + + -class ComException -{ -public: - ComException(const std::wstring& message, HRESULT hr = NO_ERROR) - : message_(message), hr_(hr) {} - std::wstring show() const - { - return hr_ != NO_ERROR ? generateErrorMsg(message_, hr_) : message_; - } -private: - ComException(const ComException&); - ComException& operator=(const ComException&); - const std::wstring message_; - const HRESULT hr_; -}; @@ -56,6 +47,144 @@ private: //################# implementation ##################### +std::wstring formatWin32Msg(DWORD dwMessageId) //return empty string on error +{ + std::wstring output; + LPWSTR buffer = NULL; + 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(&buffer), 0, NULL) != 0) + { + if (buffer) //just to be sure + { + output = buffer; + ::LocalFree(buffer); + } + } + return output; +} + +namespace +{ +std::wstring formatFacility(HRESULT hr) +{ + switch (HRESULT_FACILITY(hr)) + { + case FACILITY_XPS: + return L"XPS"; + case FACILITY_WINRM: + return L"Windows Resource Manager"; + case FACILITY_WINDOWSUPDATE: + return L"Windows Update"; + case FACILITY_WINDOWS_DEFENDER: + return L"Windows Defender Component"; + case FACILITY_WINDOWS_CE: + return L"Windows CE"; + case FACILITY_WINDOWS: + return L"Windows Subsystem"; + case FACILITY_USERMODE_VOLMGR: + return L"User Mode Volume Manager"; + case FACILITY_USERMODE_VIRTUALIZATION: + return L"User Mode Virtualization Subsystem"; + case FACILITY_USERMODE_VHD: + return L"User Mode Virtual Hard Disk Support"; + case FACILITY_URT: + return L".NET CLR"; + case FACILITY_UMI: + return L"Ubiquitous Memoryintrospection Service"; + case FACILITY_UI: + return L"UI"; + case FACILITY_TPM_SOFTWARE: + return L"Trusted Platform Module Applications"; + case FACILITY_TPM_SERVICES: + return L"Trusted Platform Module Services"; + case FACILITY_SXS: + return L"Side-by-side Servicing"; + case FACILITY_STORAGE: + return L"OLE Storage"; + case FACILITY_STATE_MANAGEMENT: + return L"State Management Services"; + case FACILITY_SCARD: + return L"Smart-card Subsystem"; + case FACILITY_SHELL: + return L"User Shell"; + case FACILITY_SETUPAPI: + return L"Setup API"; + case FACILITY_SECURITY: + return L"Security API Layer"; + case FACILITY_SDIAG: + return L"System Diagnostics"; + case FACILITY_RPC: + return L"RPC Subsystem"; + case FACILITY_RAS: + return L"RAS"; + case FACILITY_PLA: + return L"Performance Logs and Alerts"; + case FACILITY_OPC: + return L"Open Connectivity Service"; + case FACILITY_WIN32: + return L"Win32"; + case FACILITY_CONTROL: + return L"Control Mechanism"; + case FACILITY_WEBSERVICES: + return L"Web Services"; + case FACILITY_NDIS: + return L"Network Driver Interface"; + case FACILITY_METADIRECTORY: + return L"Microsoft Identity Server"; + case FACILITY_MSMQ: + return L"Microsoft Message Queue"; + case FACILITY_MEDIASERVER: + return L"Windows Media Server"; + case FACILITY_MBN: + return L"MBN"; + case FACILITY_INTERNET: + return L"Wininet"; + case FACILITY_ITF: + return L"COM/OLE Interface Management"; + case FACILITY_USERMODE_HYPERVISOR: + return L"Usermode Hypervisor Components"; + case FACILITY_HTTP: + return L"HTTP Support"; + case FACILITY_GRAPHICS: + return L"Graphics Drivers"; + case FACILITY_FWP: + return L"Firewall Platform"; + case FACILITY_FVE: + return L"Full volume encryption"; + case FACILITY_USERMODE_FILTER_MANAGER: + return L"User Mode Filter Manager"; + case FACILITY_DPLAY: + return L"Direct Play"; + case FACILITY_DISPATCH: + return L"COM Dispatch"; + case FACILITY_DIRECTORYSERVICE: + return L"Active Directory"; + case FACILITY_CONFIGURATION: + return L"Configuration Services"; + case FACILITY_COMPLUS: + return L"COM+"; + case FACILITY_USERMODE_COMMONLOG: + return L"Common Logging Support"; + case FACILITY_CMI: + return L"Configuration Management Infrastructure"; + case FACILITY_CERT: + return L"Certificate"; + case FACILITY_BCD: + return L"Boot Configuration Database"; + case FACILITY_BACKGROUNDCOPY: + return L"Background Copy Control"; + case FACILITY_ACS: + return L"Audit Collection Service"; + case FACILITY_AAF: + return L"Microsoft Agent"; + default: + return L"Unknown"; + } +} +} + inline std::wstring numberToHexString(long number) { @@ -69,11 +198,18 @@ inline std::wstring generateErrorMsg(const std::wstring& input, HRESULT hr) { std::wstring output(input); - output += L" ("; - output += numberToHexString(hr); - output += L": "; - output += _com_error(hr).ErrorMessage(); - output += L")"; + output += L"\n"; + output += L"HRESULT: " + numberToHexString(hr) + L",\n"; + + //don't use _com_error(hr).ErrorMessage(), this is nothing more than a call to ::FormatMessage() + std::wstring win32Msg = formatWin32Msg(hr); + if (!win32Msg.empty()) //empty string on error + output += win32Msg; + else + { + output += L"Facility: " + formatFacility(hr) + L",\n"; + output += L"Win32 Error: " + formatWin32Msg(HRESULT_CODE(hr)); //interpet hr as a Win32 code; this is often useful + } return output; } } diff --git a/shared/custom_button.cpp b/shared/custom_button.cpp index 0c4c3019..606db4f2 100644 --- a/shared/custom_button.cpp +++ b/shared/custom_button.cpp @@ -10,37 +10,9 @@ #include #include #include +#include "image_tools.h" - -namespace -{ -bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs) -{ - if (lhs.IsOk() != rhs.IsOk()) - return false; - - if (!lhs.IsOk()) - return true; - - const int pixelCount = lhs.GetWidth() * lhs.GetHeight(); - if (pixelCount != rhs.GetWidth() * rhs.GetHeight()) - return false; - - wxImage imLhs = lhs.ConvertToImage(); - wxImage imRhs = rhs.ConvertToImage(); - - if (imLhs.HasAlpha() != imRhs.HasAlpha()) - return false; - - if (imLhs.HasAlpha()) - { - if (!std::equal(imLhs.GetAlpha(), imLhs.GetAlpha() + pixelCount, imRhs.GetAlpha())) - return false; - } - - return std::equal(imLhs.GetData(), imLhs.GetData() + pixelCount * 3, imRhs.GetData()); -} -} +using namespace zen; void setBitmapLabel(wxBitmapButton& button, const wxBitmap& bmp) diff --git a/shared/custom_combo_box.cpp b/shared/custom_combo_box.cpp deleted file mode 100644 index fb16a303..00000000 --- a/shared/custom_combo_box.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "custom_combo_box.h" - - -CustomComboBox::CustomComboBox(wxWindow* parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - int n, - const wxString choices[], - long style, - const wxValidator& validator, - const wxString& name) : - wxComboBox(parent, id, value, pos, size, n, choices, style, validator, name) -#if wxCHECK_VERSION(2, 9, 1) - , dropDownShown(false) -#endif -{ - //register key event to enable item deletion - this->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(CustomComboBox::OnKeyEvent), NULL, this ); - -#if wxCHECK_VERSION(2, 9, 1) - this->Connect(wxEVT_COMMAND_COMBOBOX_DROPDOWN, wxCommandEventHandler(CustomComboBox::OnShowDropDown), NULL, this ); - this->Connect(wxEVT_COMMAND_COMBOBOX_CLOSEUP, wxCommandEventHandler(CustomComboBox::OnHideDropDown), NULL, this ); -#endif -} - - -#if wxCHECK_VERSION(2, 9, 1) -void CustomComboBox::OnShowDropDown(wxCommandEvent& event) -{ - dropDownShown = true; - event.Skip(); -} - - -void CustomComboBox::OnHideDropDown(wxCommandEvent& event) -{ - dropDownShown = false; - event.Skip(); -} -#endif - - -void CustomComboBox::OnKeyEvent(wxKeyEvent& event) -{ - const int keyCode = event.GetKeyCode(); - if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE) - { - //try to delete the currently selected config history item - const int selectedItem = this->GetCurrentSelection(); - if (0 <= selectedItem && selectedItem < static_cast(this->GetCount()) && -#if wxCHECK_VERSION(2, 9, 1) - dropDownShown) -#else - //what a mess...: - (GetValue() != GetString(selectedItem) || //avoid problems when a character shall be deleted instead of list item - GetValue() == wxEmptyString)) //exception: always allow removing empty entry -#endif - { - //save old (selected) value: deletion seems to have influence on this - const wxString currentVal = this->GetValue(); - this->SetSelection(wxNOT_FOUND); - - //delete selected row - this->Delete(selectedItem); - - //(re-)set value - this->SetValue(currentVal); - - //eat up key event - return; - } - } - event.Skip(); -} - - -void CustomComboBox::addPairToFolderHistory(const wxString& newFolder, unsigned int maxHistSize) -{ - //don't add empty directories - if (newFolder.empty()) - return; - - const wxString oldVal = this->GetValue(); - - //insert new folder or put it to the front if already existing -#ifdef FFS_WIN //don't respect case in windows build - const int pos = FindString(newFolder, false); -#elif defined FFS_LINUX - const int pos = FindString(newFolder, true); -#endif - if (pos != wxNOT_FOUND) - this->Delete(pos); - - this->Insert(newFolder, 0); - - //keep maximal size of history list - if (this->GetCount() > maxHistSize) - this->Delete(maxHistSize); - - this->SetSelection(wxNOT_FOUND); //don't select anything - this->SetValue(oldVal); //but preserve main text! -} - diff --git a/shared/custom_combo_box.h b/shared/custom_combo_box.h deleted file mode 100644 index 3ddd73b0..00000000 --- a/shared/custom_combo_box.h +++ /dev/null @@ -1,42 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef CUSTOMCOMBOBOX_H_INCLUDED -#define CUSTOMCOMBOBOX_H_INCLUDED - -#include - -//combobox with history function + functionality to delete items (DEL) - -class CustomComboBox : public wxComboBox -{ -public: - CustomComboBox(wxWindow* parent, - wxWindowID id, - const wxString& value = wxEmptyString, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - int n = 0, - const wxString choices[] = NULL, - long style = 0, - const wxValidator& validator = wxDefaultValidator, - const wxString& name = wxComboBoxNameStr); - - void addPairToFolderHistory(const wxString& newFolder, unsigned int maxHistSize); - -private: - void OnKeyEvent(wxKeyEvent& event); - -#if wxCHECK_VERSION(2, 9, 1) - void OnShowDropDown(wxCommandEvent& event); - void OnHideDropDown(wxCommandEvent& event); - - bool dropDownShown; -#endif -}; - - -#endif // CUSTOMCOMBOBOX_H_INCLUDED diff --git a/shared/custom_tooltip.cpp b/shared/custom_tooltip.cpp index 184c2716..0e1c5172 100644 --- a/shared/custom_tooltip.cpp +++ b/shared/custom_tooltip.cpp @@ -17,7 +17,7 @@ public: wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxSize( -1,-1 ), + const wxSize& size = wxSize( -1, -1 ), long style = wxFRAME_NO_TASKBAR | wxSTAY_ON_TOP | wxSTATIC_BORDER); wxStaticText* m_staticTextMain; @@ -41,7 +41,7 @@ CustomTooltip::PopupFrameGenerated::PopupFrameGenerated( bSizer158 = new wxBoxSizer( wxHORIZONTAL ); m_bitmapLeft = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); - bSizer158->Add( m_bitmapLeft, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer158->Add( m_bitmapLeft, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5 ); m_staticTextMain = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); bSizer158->Add( m_staticTextMain, 0, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5 ); diff --git a/shared/debug_new.h b/shared/debug_new.h index b8911b4d..ba31e489 100644 --- a/shared/debug_new.h +++ b/shared/debug_new.h @@ -21,7 +21,7 @@ Usage: - Include everywhere before any other file: $(ProjectDir)\shared\debug_new.h For Minidumps: - Compile "debug_new.cpp" -- Compile in Debug build (need Symbols and less restrictive Optimization) +- Compile with debugging symbols and optimization deactivated */ namespace mem_check diff --git a/shared/dir_name.cpp b/shared/dir_name.cpp index f1b0c3c2..a14367c9 100644 --- a/shared/dir_name.cpp +++ b/shared/dir_name.cpp @@ -15,6 +15,7 @@ #include "check_exist.h" #include "util.h" #include "i18n.h" +#include "folder_history_box.h" using namespace zen; @@ -37,7 +38,7 @@ void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, w staticBox->GetStaticBox()->SetLabel(dirNormalized == dirFormatted ? wxString(_("Drag && drop")) : dirFormatted); } - + if (dirPicker) { if (!dirFormatted.empty() && @@ -61,162 +62,113 @@ void setDirectoryName(const wxString& dirname, void setDirectoryName(const wxString& dirname, - wxComboBox* comboBox, + FolderHistoryBox* comboBox, wxDirPickerCtrl* dirPicker, wxWindow& tooltipWnd, - wxStaticBoxSizer& staticBox, + wxStaticBoxSizer* staticBox, size_t timeout = 200) //pointers are optional { if (comboBox) - { - comboBox->SetSelection(wxNOT_FOUND); - comboBox->SetValue(dirname); - } - setDirectoryNameImpl(dirname, dirPicker, tooltipWnd, &staticBox, timeout); + comboBox->setValue(dirname); + setDirectoryNameImpl(dirname, dirPicker, tooltipWnd, staticBox, timeout); } } - - //############################################################################################################## -using zen::DirectoryNameMainDlg; - -DirectoryNameMainDlg::DirectoryNameMainDlg(wxWindow& dropWindow1, - wxWindow& dropWindow2, - wxDirPickerCtrl& dirPicker, - wxComboBox& dirName, - wxStaticBoxSizer& staticBox) : - dropWindow1_(dropWindow1), + +template +DirectoryName::DirectoryName(wxWindow& dropWindow, + wxDirPickerCtrl& dirPicker, + NameControl& dirName, + wxStaticBoxSizer* staticBox, + wxWindow* dropWindow2) : + dropWindow_(dropWindow), dropWindow2_(dropWindow2), dirPicker_(dirPicker), dirName_(dirName), staticBox_(staticBox) { //prepare drag & drop - setupFileDrop(dropWindow1); - setupFileDrop(dropWindow2); + setupFileDrop(dropWindow); + if (dropWindow2) + setupFileDrop(*dropWindow2); //redirect drag & drop event back to this class - dropWindow1.Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryNameMainDlg::OnFilesDropped), NULL, this); - dropWindow2.Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryNameMainDlg::OnFilesDropped), NULL, this); + dropWindow.Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryName::OnFilesDropped), NULL, this); + if (dropWindow2) + dropWindow2->Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryName::OnFilesDropped), NULL, this); //keep dirPicker and dirName synchronous - dirName .Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DirectoryNameMainDlg::OnWriteDirManually), NULL, this ); - dirPicker.Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(DirectoryNameMainDlg::OnDirSelected), NULL, this ); + dirName_ .Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DirectoryName::OnWriteDirManually), NULL, this); + dirPicker_.Connect(wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(DirectoryName::OnDirSelected ), NULL, this); +} + + +template +DirectoryName::~DirectoryName() +{ + dirName_ .Disconnect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DirectoryName::OnWriteDirManually), NULL, this); + dirPicker_.Disconnect(wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler(DirectoryName::OnDirSelected ), NULL, this); } -void DirectoryNameMainDlg::OnFilesDropped(FFSFileDropEvent& event) +template +void DirectoryName::OnFilesDropped(FFSFileDropEvent& event) { if (event.getFiles().empty()) return; - if (AcceptDrop(event.getFiles())) + if (acceptDrop(event.getFiles())) { - wxString fileName = event.getFiles()[0]; + const wxString fileName = event.getFiles()[0]; if (dirExists(toZ(fileName))) setDirectoryName(fileName, &dirName_, &dirPicker_, dirName_, staticBox_); else { - fileName = beforeLast(fileName, FILE_NAME_SEPARATOR); - if (dirExists(toZ(fileName))) + wxString parentName = beforeLast(fileName, FILE_NAME_SEPARATOR); //returns empty string if ch not found +#ifdef FFS_WIN + if (endsWith(parentName, L":")) //volume name + parentName += FILE_NAME_SEPARATOR; +#endif + if (dirExists(toZ(parentName))) + setDirectoryName(parentName, &dirName_, &dirPicker_, dirName_, staticBox_); + else //set original name unconditionally: usecase: inactive mapped network shares setDirectoryName(fileName, &dirName_, &dirPicker_, dirName_, staticBox_); } } } -void DirectoryNameMainDlg::OnWriteDirManually(wxCommandEvent& event) +template +void DirectoryName::OnWriteDirManually(wxCommandEvent& event) { - setDirectoryName(event.GetString(), NULL, &dirPicker_, dirName_, staticBox_, 100); //potentially slow network access: wait 100 ms at most + setDirectoryName(event.GetString(), static_cast(NULL), &dirPicker_, dirName_, staticBox_, 100); //potentially slow network access: wait 100 ms at most event.Skip(); } -void DirectoryNameMainDlg::OnDirSelected(wxFileDirPickerEvent& event) +template +void DirectoryName::OnDirSelected(wxFileDirPickerEvent& event) { const wxString newPath = event.GetPath(); setDirectoryName(newPath, &dirName_, NULL, dirName_, staticBox_); - event.Skip(); } -wxString DirectoryNameMainDlg::getName() const +template +wxString DirectoryName::getName() const { return dirName_.GetValue(); } -void DirectoryNameMainDlg::setName(const wxString& dirname) +template +void DirectoryName::setName(const wxString& dirname) { setDirectoryName(dirname, &dirName_, &dirPicker_, dirName_, staticBox_); } -//############################################################################################################## -using zen::DirectoryName; - -DirectoryName::DirectoryName(wxWindow& dropWindow, - wxDirPickerCtrl& dirPicker, - wxTextCtrl& dirName, - wxStaticBoxSizer* staticBox) : - dropWindow_(dropWindow), - dirPicker_(dirPicker), - dirName_(dirName), - staticBox_(staticBox) -{ - //prepare drag & drop - setupFileDrop(dropWindow); - - //redirect drag & drop event back to this class - dropWindow.Connect(FFS_DROP_FILE_EVENT, FFSFileDropEventHandler(DirectoryName::OnFilesDropped), NULL, this); - - //keep dirPicker and dirName synchronous - dirName.Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DirectoryName::OnWriteDirManually ), NULL, this ); - dirPicker.Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( DirectoryName::OnDirSelected ), NULL, this ); -} - - -void DirectoryName::OnFilesDropped(FFSFileDropEvent& event) -{ - if (event.getFiles().empty()) - return; - - wxString fileName = event.getFiles()[0]; - if (dirExists(toZ(fileName))) - setDirectoryName(fileName, &dirName_, &dirPicker_, dirName_, staticBox_); - else - { - fileName = beforeLast(fileName, FILE_NAME_SEPARATOR); - if (dirExists(toZ(fileName))) - setDirectoryName(fileName, &dirName_, &dirPicker_, dirName_, staticBox_); - } -} - - -void DirectoryName::OnWriteDirManually(wxCommandEvent& event) -{ - setDirectoryName(event.GetString(), NULL, &dirPicker_, dirName_, staticBox_, 100); //potentially slow network access: wait 100 ms at most - event.Skip(); -} - - -void DirectoryName::OnDirSelected(wxFileDirPickerEvent& event) -{ - const wxString newPath = event.GetPath(); - setDirectoryName(newPath, &dirName_, NULL, dirName_, staticBox_); - - event.Skip(); -} - - -wxString DirectoryName::getName() const -{ - return dirName_.GetValue(); -} - - -void DirectoryName::setName(const wxString& dirname) -{ - setDirectoryName(dirname, &dirName_, &dirPicker_, dirName_, staticBox_); -} +//explicit template instantiation +template class DirectoryName; +template class DirectoryName; diff --git a/shared/dir_name.h b/shared/dir_name.h index 6e783d75..7c7b3bc4 100644 --- a/shared/dir_name.h +++ b/shared/dir_name.h @@ -11,64 +11,38 @@ #include #include #include -#include #include "file_drop.h" - -class wxFileDirPickerEvent; - namespace zen { //handle drag and drop, tooltip, label and manual input, coordinating a wxWindow, wxDirPickerCtrl, and wxComboBox/wxTextCtrl -class DirectoryNameMainDlg : private wxEvtHandler +template //NameControl may be wxTextCtrl, FolderHistoryBox +class DirectoryName: private wxEvtHandler { public: - DirectoryNameMainDlg(wxWindow& dropWindow1, - wxWindow& dropWindow2, - wxDirPickerCtrl& dirPicker, - wxComboBox& dirName, - wxStaticBoxSizer& staticBox); + DirectoryName(wxWindow& dropWindow, + wxDirPickerCtrl& dirPicker, + NameControl& dirName, + wxStaticBoxSizer* staticBox = NULL, + wxWindow* dropWindow2 = NULL); //optional - virtual ~DirectoryNameMainDlg() {} + ~DirectoryName(); wxString getName() const; void setName(const wxString& dirname); - virtual bool AcceptDrop(const std::vector& droppedFiles) = 0; //return true if drop should be processed - private: - void OnFilesDropped(FFSFileDropEvent& event); - void OnWriteDirManually(wxCommandEvent& event); - void OnDirSelected(wxFileDirPickerEvent& event); - - const wxWindow& dropWindow1_; - const wxWindow& dropWindow2_; - wxDirPickerCtrl& dirPicker_; - wxComboBox& dirName_; - wxStaticBoxSizer& staticBox_; -}; + virtual bool acceptDrop(const std::vector& droppedFiles) { return true; }; //return true if drop should be processed - -class DirectoryName: private wxEvtHandler -{ -public: - DirectoryName(wxWindow& dropWindow, - wxDirPickerCtrl& dirPicker, - wxTextCtrl& dirName, - wxStaticBoxSizer* staticBox = NULL); //optional - - wxString getName() const; - void setName(const wxString& dirname); - -private: void OnFilesDropped(FFSFileDropEvent& event); void OnWriteDirManually(wxCommandEvent& event); void OnDirSelected(wxFileDirPickerEvent& event); - const wxWindow& dropWindow_; - wxDirPickerCtrl& dirPicker_; - wxTextCtrl& dirName_; + const wxWindow& dropWindow_; + const wxWindow* dropWindow2_; + wxDirPickerCtrl& dirPicker_; + NameControl& dirName_; wxStaticBoxSizer* staticBox_; //optional }; } diff --git a/shared/dir_watcher.cpp b/shared/dir_watcher.cpp index 9c3a00c7..5d178734 100644 --- a/shared/dir_watcher.cpp +++ b/shared/dir_watcher.cpp @@ -28,77 +28,88 @@ using namespace zen; - #ifdef FFS_WIN namespace { -typedef Zbase BasicWString; //thread safe string class for UI texts - - -struct SharedData +class SharedData { - boost::mutex lockAccess; - std::set changedFiles; //get rid of duplicate entries (actually occur!) - BasicWString errorMsg; //non-empty if errors occured in thread -}; - - -void addChanges(SharedData& shared, const char* buffer, DWORD bytesWritten, const Zstring& dirname) //throw () -{ - boost::lock_guard dummy(shared.lockAccess); +public: + //context of worker thread + void addChanges(const char* buffer, DWORD bytesWritten, const Zstring& dirname) //throw () + { + boost::lock_guard dummy(lockAccess); - std::set& output = shared.changedFiles; + std::set& output = changedFiles; - if (bytesWritten == 0) //according to docu this may happen in case of internal buffer overflow: report some "dummy" change - output.insert(L"Overflow!"); - else - { - const char* bufPos = &buffer[0]; - while (true) + if (bytesWritten == 0) //according to docu this may happen in case of internal buffer overflow: report some "dummy" change + output.insert(L"Overflow!"); + else { - const FILE_NOTIFY_INFORMATION& notifyInfo = reinterpret_cast(*bufPos); + const char* bufPos = &buffer[0]; + while (true) + { + const FILE_NOTIFY_INFORMATION& notifyInfo = reinterpret_cast(*bufPos); - const Zstring fullname = dirname + Zstring(notifyInfo.FileName, notifyInfo.FileNameLength / sizeof(WCHAR)); + const Zstring fullname = dirname + Zstring(notifyInfo.FileName, notifyInfo.FileNameLength / sizeof(WCHAR)); - //skip modifications sent by changed directories: reason for change, child element creation/deletion, will notify separately! - bool skip = false; - if (notifyInfo.Action == FILE_ACTION_MODIFIED) - { - //note: this check will not work if top watched directory has been renamed - const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(fullname).c_str()); - bool isDir = ret != INVALID_FILE_ATTRIBUTES && (ret & FILE_ATTRIBUTE_DIRECTORY); //returns true for (dir-)symlinks also - skip = isDir; - } + //skip modifications sent by changed directories: reason for change, child element creation/deletion, will notify separately! + bool skip = false; + if (notifyInfo.Action == FILE_ACTION_RENAMED_OLD_NAME) //FILE_ACTION_RENAMED_NEW_NAME should suffice + skip = true; + else if (notifyInfo.Action == FILE_ACTION_MODIFIED) + { + //note: this check will not work if top watched directory has been renamed + const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(fullname).c_str()); + bool isDir = ret != INVALID_FILE_ATTRIBUTES && (ret & FILE_ATTRIBUTE_DIRECTORY); //returns true for (dir-)symlinks also + skip = isDir; + } - if (!skip) - output.insert(fullname); + if (!skip) + output.insert(fullname); - if (notifyInfo.NextEntryOffset == 0) - break; - bufPos += notifyInfo.NextEntryOffset; + if (notifyInfo.NextEntryOffset == 0) + break; + bufPos += notifyInfo.NextEntryOffset; + } } } -} + //context of main thread + void addChange(const Zstring& dirname) //throw () + { + boost::lock_guard dummy(lockAccess); + changedFiles.insert(dirname); + } -void getChanges(SharedData& shared, std::vector& output) //throw FileError -{ - boost::lock_guard dummy(shared.lockAccess); - //first check whether errors occured in thread - if (!shared.errorMsg.empty()) - throw zen::FileError(shared.errorMsg.c_str()); + //context of main thread + void getChanges(std::vector& output) //throw FileError + { + boost::lock_guard dummy(lockAccess); - output.assign(shared.changedFiles.begin(), shared.changedFiles.end()); - shared.changedFiles.clear(); -} + //first check whether errors occured in thread + if (!errorMsg.empty()) + throw zen::FileError(errorMsg.c_str()); + output.assign(changedFiles.begin(), changedFiles.end()); + changedFiles.clear(); + } -void reportError(SharedData& shared, const BasicWString& errorMsg) //throw () -{ - boost::lock_guard dummy(shared.lockAccess); - shared.errorMsg = errorMsg; -} + + //context of worker thread + void reportError(const std::wstring& msg) //throw () + { + boost::lock_guard dummy(lockAccess); + errorMsg = cvrtString(msg); + } + +private: + typedef Zbase BasicWString; //thread safe string class for UI texts + + boost::mutex lockAccess; + std::set changedFiles; //get rid of duplicate entries (actually occur!) + BasicWString errorMsg; //non-empty if errors occured in thread +}; class ReadChangesAsync @@ -129,7 +140,7 @@ public: OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); - if(hDir == INVALID_HANDLE_VALUE ) + if (hDir == INVALID_HANDLE_VALUE ) throw FileError(_("Could not initialize directory monitoring:") + "\n\"" + utf8CvrtTo(dirname) + "\"" + "\n\n" + zen::getLastErrorFormatted()); //Loki::ScopeGuard guardDir = Loki::MakeGuard(::CloseHandle, hDir); @@ -146,7 +157,7 @@ public: { try { - std::vector buffer(64 * 1024); //maximum buffer size restricted by some networks protocols (according to docu) + std::vector buffer(64 * 1024); //needs to be aligned on a DWORD boundary; maximum buffer size restricted by some networks protocols (according to docu) while (true) { @@ -159,7 +170,7 @@ public: false, //__in BOOL bInitialState, NULL); //__in_opt LPCTSTR lpName if (overlapped.hEvent == NULL) - return ::reportError(*shared_, BasicWString(_("Error when monitoring directories.") + "\n\n" + getLastErrorFormatted())); //throw () + quit thread + return shared_->reportError(_("Error when monitoring directories.") + " (CreateEvent)" + "\n\n" + getLastErrorFormatted()); //throw () + quit thread Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, overlapped.hEvent); (void)dummy; @@ -176,14 +187,13 @@ public: NULL, // __out_opt LPDWORD lpBytesReturned, &overlapped, // __inout_opt LPOVERLAPPED lpOverlapped, NULL)) // __in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine - return ::reportError(*shared_, BasicWString(_("Error when monitoring directories.") + "\n\n" + getLastErrorFormatted())); //throw () + quit thread + return shared_->reportError(_("Error when monitoring directories.") + " (ReadDirectoryChangesW)" + "\n\n" + getLastErrorFormatted()); //throw () + quit thread //async I/O is a resource that needs to be guarded since it will write to local variable "buffer"! Loki::ScopeGuard lockAio = Loki::MakeGuard([&]() { //http://msdn.microsoft.com/en-us/library/aa363789(v=vs.85).aspx - bool cancelSuccess = ::CancelIo(hDir) == TRUE; //cancel all async I/O related to this handle and thread - if (cancelSuccess) + if (::CancelIo(hDir) == TRUE) //cancel all async I/O related to this handle and thread { DWORD bytesWritten = 0; ::GetOverlappedResult(hDir, &overlapped, &bytesWritten, true); //wait until cancellation is complete @@ -199,7 +209,7 @@ public: false)) //__in BOOL bWait { if (::GetLastError() != ERROR_IO_INCOMPLETE) - return ::reportError(*shared_, BasicWString(_("Error when monitoring directories.") + "\n\n" + getLastErrorFormatted())); //throw () + quit thread + return shared_->reportError(_("Error when monitoring directories.") + " (GetOverlappedResult)" + "\n\n" + getLastErrorFormatted()); //throw () + quit thread //execute asynchronous procedure calls (APC) queued on this thread ::SleepEx(50, // __in DWORD dwMilliseconds, @@ -209,7 +219,7 @@ public: } lockAio.Dismiss(); - ::addChanges(*shared_, &buffer[0], bytesWritten, dirname); //throw () + shared_->addChanges(&buffer[0], bytesWritten, dirname); //throw () } } catch (boost::thread_interrupted&) @@ -222,7 +232,7 @@ public: } } - ReadChangesAsync(ReadChangesAsync&& other) : + ReadChangesAsync(ReadChangesAsync && other) : hDir(INVALID_HANDLE_VALUE) { shared_ = std::move(other.shared_); @@ -269,10 +279,7 @@ private: //now hDir should have been released //report removal as change to main directory - { - boost::lock_guard dummy(shared_->lockAccess); - shared_->changedFiles.insert(dirname_); - } + shared_->addChange(dirname_); removalRequested = true; } //don't throw! @@ -327,7 +334,7 @@ DirWatcher::~DirWatcher() std::vector DirWatcher::getChanges() //throw FileError { std::vector output; - ::getChanges(*pimpl_->shared, output); //throw FileError + pimpl_->shared->getChanges(output); //throw FileError return output; } diff --git a/shared/dll_loader.cpp b/shared/dll_loader.cpp deleted file mode 100644 index 4e2c0e65..00000000 --- a/shared/dll_loader.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "dll_loader.h" -#include - -namespace -{ -class DllHandler -{ -public: - static DllHandler& getInstance() - { - static DllHandler instance; - return instance; - } - - HMODULE getHandle(const std::wstring& libraryName) - { - if (libraryName.empty()) - return ::GetModuleHandle(NULL); //return handle to calling executable - - HandleMap::const_iterator iter = handles.find(libraryName); - if (iter != handles.end()) - return iter->second; - - HMODULE newHandle = ::LoadLibrary(libraryName.c_str()); - if (newHandle != NULL) - handles.insert(std::make_pair(libraryName, newHandle)); - - return newHandle; - } - -private: - DllHandler() {} - DllHandler(const DllHandler&); - DllHandler& operator=(const DllHandler&); - - ~DllHandler() - { - for (HandleMap::const_iterator i = handles.begin(); i != handles.end(); ++i) - ::FreeLibrary(i->second); - } - - typedef std::map HandleMap; - HandleMap handles; //only valid handles here! -}; -} - - -FARPROC util::loadSymbol(const std::wstring& libraryName, const std::string& functionName) -{ - const HMODULE libHandle = DllHandler::getInstance().getHandle(libraryName); - return libHandle != NULL ? ::GetProcAddress(libHandle, functionName.c_str()) : NULL; -} - - -std::string util::getResourceStream(const std::wstring& libraryName, size_t resourceId) -{ - std::string output; - const HMODULE module = DllHandler::getInstance().getHandle(libraryName); - if (module) - { - const HRSRC res = ::FindResource(module, MAKEINTRESOURCE(resourceId), RT_RCDATA); - if (res != NULL) - { - const HGLOBAL resHandle = ::LoadResource(module, res); - if (resHandle != NULL) - { - const char* stream = static_cast(::LockResource(resHandle)); - if (stream) - { - const DWORD streamSize = ::SizeofResource(module, res); - output.assign(stream, streamSize); - } - } - } - } - return output; -} diff --git a/shared/dll_loader.h b/shared/dll_loader.h index 252e7598..e34fc4a9 100644 --- a/shared/dll_loader.h +++ b/shared/dll_loader.h @@ -7,7 +7,9 @@ #ifndef DLLLOADER_H_INCLUDED #define DLLLOADER_H_INCLUDED +#include #include +#include "loki\ScopeGuard.h" #ifdef __WXMSW__ //we have wxWidgets #include //includes "windows.h" @@ -20,13 +22,35 @@ namespace util { - /* -load function from a DLL library, e.g. from kernel32.dll -NOTE: you're allowed to take a static reference to the return value! :) +Manage DLL function and library ownership + - thread safety: like built-in type + - full value semantics + + Usage: + typedef BOOL (WINAPI *IsWow64ProcessFun)(HANDLE hProcess, PBOOL Wow64Process); + const util::DllFun isWow64Process(L"kernel32.dll", "IsWow64Process"); + if (isWow64Process) */ -template -FunctionType getDllFun(const std::wstring& libraryName, const std::string& functionName); + +template +class DllFun +{ +public: + DllFun() : fun(NULL) {} + + DllFun(const wchar_t* libraryName, const char* functionName) : + hLibRef(new HMODULE(::LoadLibrary(libraryName)), deleter), + fun(*hLibRef ? reinterpret_cast(::GetProcAddress(*hLibRef, functionName)) : NULL) {} + + operator Func() const { return fun; } + +private: + static void deleter(HMODULE* ptr) { if (*ptr) ::FreeLibrary(*ptr); delete ptr; } + + std::shared_ptr hLibRef; + Func fun; +}; /* extract binary resources from .exe/.dll: @@ -48,13 +72,38 @@ std::string getResourceStream(const std::wstring& libraryName, size_t resourceId -//---------------Inline Implementation--------------------------------------------------- -FARPROC loadSymbol(const std::wstring& libraryName, const std::string& functionName); -template inline -FunctionType getDllFun(const std::wstring& libraryName, const std::string& functionName) + + + + + +//---------------Inline Implementation--------------------------------------------------- +inline +std::string getResourceStream(const wchar_t* libraryName, size_t resourceId) { - return reinterpret_cast(loadSymbol(libraryName, functionName)); + std::string output; + HMODULE module = ::LoadLibrary(libraryName); + if (module) + { + LOKI_ON_BLOCK_EXIT2(::FreeLibrary(module)); + + const HRSRC res = ::FindResource(module, MAKEINTRESOURCE(resourceId), RT_RCDATA); + if (res != NULL) + { + const HGLOBAL resHandle = ::LoadResource(module, res); + if (resHandle != NULL) + { + const char* stream = static_cast(::LockResource(resHandle)); + if (stream) + { + const DWORD streamSize = ::SizeofResource(module, res); + output.assign(stream, streamSize); + } + } + } + } + return output; } } diff --git a/shared/dst_hack.cpp b/shared/dst_hack.cpp index d52a335f..aa7a0f3e 100644 --- a/shared/dst_hack.cpp +++ b/shared/dst_hack.cpp @@ -9,6 +9,7 @@ #include #include "int64.h" #include "file_error.h" +#include "dll_loader.h" using namespace zen; @@ -78,11 +79,64 @@ bool dst::isFatDrive(const Zstring& fileName) //throw() assert(false); //shouldn't happen return false; } - const Zstring fileSystem = fsName; + //DST hack seems to be working equally well for FAT and FAT32 (in particular creation time has 10^-2 s precision as advertised) + return fsName == Zstring(L"FAT") || + fsName == Zstring(L"FAT32"); +} + + +bool dst::vistaOrLater() +{ + OSVERSIONINFO osvi = {}; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + //IFileOperation is supported with Vista and later + if (::GetVersionEx(&osvi)) + return osvi.dwMajorVersion > 5; + //XP has majorVersion == 5, minorVersion == 1 + //Vista has majorVersion == 6, minorVersion == 0 + //version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + return false; +} + +bool dst::isFatDrive(HANDLE hFile) //throw() +{ + //dynamically load windows API function + typedef BOOL (WINAPI *GetVolumeInformationByHandleWFunc)(HANDLE hFile, + LPWSTR lpVolumeNameBuffer, + DWORD nVolumeNameSize, + LPDWORD lpVolumeSerialNumber, + LPDWORD lpMaximumComponentLength, + LPDWORD lpFileSystemFlags, + LPWSTR lpFileSystemNameBuffer, + DWORD nFileSystemNameSize); + + const util::DllFun getVolumeInformationByHandle(L"kernel32.dll", "GetVolumeInformationByHandleW"); + if (!getVolumeInformationByHandle) + { + assert(false); + return false; + } + + const size_t BUFFER_SIZE = MAX_PATH + 1; + wchar_t fsName[BUFFER_SIZE]; + + if (!getVolumeInformationByHandle(hFile, //__in HANDLE hFile, + NULL, //__out LPTSTR lpVolumeNameBuffer, + 0, //__in DWORD nVolumeNameSize, + NULL, //__out_opt LPDWORD lpVolumeSerialNumber, + NULL, //__out_opt LPDWORD lpMaximumComponentLength, + NULL, //__out_opt LPDWORD lpFileSystemFlags, + fsName, //__out LPTSTR lpFileSystemNameBuffer, + BUFFER_SIZE)) //__in DWORD nFileSystemNameSize + { + assert(false); //shouldn't happen + return false; + } //DST hack seems to be working equally well for FAT and FAT32 (in particular creation time has 10^-2 s precision as advertised) - return fileSystem == Zstr("FAT") || - fileSystem == Zstr("FAT32"); + return fsName == Zstring(L"FAT") || + fsName == Zstring(L"FAT32"); } @@ -244,7 +298,7 @@ std::bitset getUtcLocalShift() const int absValue = common::abs(timeShiftQuarter); //MSVC C++0x bug: std::bitset<>(unsigned long) is ambiguous - if (std::bitset(absValue).to_ulong() != static_cast(absValue) || //time shifts that big shouldn't be possible! + if (std::bitset < UTC_LOCAL_OFFSET_BITS - 1 > (absValue).to_ulong() != static_cast(absValue) || //time shifts that big shouldn't be possible! timeShiftSec % (60 * 15) != 0) //all known time shift have at least 15 minute granularity! { const std::wstring errorMessage = _("Conversion error:") + " Unexpected UTC <-> local time shift: " + diff --git a/shared/dst_hack.h b/shared/dst_hack.h index 550098a2..2e25cf81 100644 --- a/shared/dst_hack.h +++ b/shared/dst_hack.h @@ -19,6 +19,8 @@ Solve DST +-1h and time zone shift issues on FAT drives */ bool isFatDrive(const Zstring& fileName); //throw () +bool isFatDrive(HANDLE hFile); //throw() -> call ONLY if vistaOrLater() == true! +bool vistaOrLater(); //all subsequent functions may throw the std::runtime_error exception! diff --git a/shared/file_handling.cpp b/shared/file_handling.cpp index 8fa8568a..c9e85c15 100644 --- a/shared/file_handling.cpp +++ b/shared/file_handling.cpp @@ -17,6 +17,7 @@ #include "assert_static.h" #include #include +#include "file_id_internal.h" #ifdef FFS_WIN #include "privilege.h" @@ -98,63 +99,99 @@ bool zen::somethingExists(const Zstring& objname) //throw() check whether } -#ifdef FFS_WIN namespace { -zen::UInt64 getFileSizeSymlink(const Zstring& linkName) //throw (FileError) -{ - //open handle to target of symbolic link - const HANDLE hFile = ::CreateFile(applyLongPathPrefix(linkName).c_str(), - 0, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); - if (hFile == INVALID_HANDLE_VALUE) - throw FileError(_("Error reading file attributes:") + "\n\"" + linkName + "\"" + "\n\n" + getLastErrorFormatted()); - - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hFile); - (void)dummy; //silence warning "unused variable" - - BY_HANDLE_FILE_INFORMATION fileInfo = {}; - if (!::GetFileInformationByHandle(hFile, &fileInfo)) - throw FileError(_("Error reading file attributes:") + "\n\"" + linkName + "\"" + "\n\n" + getLastErrorFormatted()); - - return UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); -} -} -#endif - - -UInt64 zen::getFilesize(const Zstring& filename) //throw (FileError) +void getFileAttrib(const Zstring& filename, FileAttrib& attr, ProcSymlink procSl) //throw FileError { #ifdef FFS_WIN WIN32_FIND_DATA fileInfo = {}; - const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo); - if (searchHandle == INVALID_HANDLE_VALUE) - throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); - - ::FindClose(searchHandle); + { + const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo); + if (searchHandle == INVALID_HANDLE_VALUE) + throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); + ::FindClose(searchHandle); + } + // WIN32_FILE_ATTRIBUTE_DATA sourceAttr = {}; + // if (!::GetFileAttributesEx(applyLongPathPrefix(sourceObj).c_str(), //__in LPCTSTR lpFileName, + // GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId, + // &sourceAttr)) //__out LPVOID lpFileInformation const bool isSymbolicLink = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; - if (isSymbolicLink) - return getFileSizeSymlink(filename); //throw (FileError) + if (!isSymbolicLink || procSl == SYMLINK_DIRECT) + { + //####################################### DST hack ########################################### + const bool isDirectory = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + if (!isDirectory && dst::isFatDrive(filename)) //throw() + { + const dst::RawTime rawTime(fileInfo.ftCreationTime, fileInfo.ftLastWriteTime); + if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error) + { + fileInfo.ftLastWriteTime = dst::fatDecodeUtcTime(rawTime); //return last write time in real UTC, throw (std::runtime_error) + ::GetSystemTimeAsFileTime(&fileInfo.ftCreationTime); //real creation time information is not available... + } + } + //####################################### DST hack ########################################### - return UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + attr.fileSize = UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + attr.modificationTime = toTimeT(fileInfo.ftLastWriteTime); + } + else + { + const HANDLE hFile = ::CreateFile(applyLongPathPrefix(filename).c_str(), //open handle to target of symbolic link + 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); + LOKI_ON_BLOCK_EXIT2(::CloseHandle(hFile)); + + BY_HANDLE_FILE_INFORMATION fileInfoHnd = {}; + if (!::GetFileInformationByHandle(hFile, &fileInfoHnd)) + throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); + + attr.fileSize = UInt64(fileInfoHnd.nFileSizeLow, fileInfoHnd.nFileSizeHigh); + attr.modificationTime = toTimeT(fileInfoHnd.ftLastWriteTime); + } #elif defined FFS_LINUX struct stat fileInfo = {}; - if (::stat(filename.c_str(), &fileInfo) != 0) //follow symbolic links + + const int rv = procSl == SYMLINK_FOLLOW ? + :: stat(filename.c_str(), &fileInfo) : + ::lstat(filename.c_str(), &fileInfo); + if (rv != 0) //follow symbolic links throw FileError(_("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); - return UInt64(fileInfo.st_size); + attr.fileSize = UInt64(fileInfo.st_size); + attr.modificationTime = fileInfo.st_mtime; #endif } +} + + +UInt64 zen::getFilesize(const Zstring& filename) //throw FileError +{ + FileAttrib attr; + getFileAttrib(filename, attr, SYMLINK_FOLLOW); //throw FileError + return attr.fileSize; +} + + +Int64 zen::getFileTime(const Zstring& filename, ProcSymlink procSl) //throw FileError +{ + FileAttrib attr; + getFileAttrib(filename, attr, procSl); //throw FileError + return attr.modificationTime; +} namespace { + + #ifdef FFS_WIN DWORD retrieveVolumeSerial(const Zstring& pathName) //return 0 on error! { @@ -218,7 +255,7 @@ zen::ResponseSame zen::onSameVolume(const Zstring& folderLeft, const Zstring& fo } -bool zen::removeFile(const Zstring& filename) //throw (FileError); +bool zen::removeFile(const Zstring& filename) //throw FileError; { #ifdef FFS_WIN //remove file, support for \\?\-prefix @@ -261,16 +298,15 @@ namespace { DEFINE_NEW_FILE_ERROR(ErrorDifferentVolume); -/* Usage overview: +/* Usage overview: (avoid circular pattern!) - renameFile() --> renameFileInternal() + renameFile() --> renameFile_sub() | /|\ \|/ | - fix8Dot3NameClash() + Fix8Dot3NameClash() */ //wrapper for file system rename function: -//throw (FileError); ErrorDifferentVolume if it is due to moving file to another volume -void renameFileInternal(const Zstring& oldName, const Zstring& newName) //throw (FileError: ErrorDifferentVolume, ErrorTargetExisting) +void renameFile_sub(const Zstring& oldName, const Zstring& newName) //throw FileError, ErrorDifferentVolume, ErrorTargetExisting { #ifdef FFS_WIN const Zstring oldNameFmt = applyLongPathPrefix(oldName); @@ -361,12 +397,12 @@ Zstring getFilenameFmt(const Zstring& filename, Function fun) //throw(); returns } -Zstring createTemp8Dot3Name(const Zstring& fileName) //find a unique 8.3 short name +Zstring findUnused8Dot3Name(const Zstring& filename) //find a unique 8.3 short name { - const Zstring pathPrefix = fileName.find(FILE_NAME_SEPARATOR) != Zstring::npos ? - (fileName.BeforeLast(FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR) : Zstring(); + const Zstring pathPrefix = filename.find(FILE_NAME_SEPARATOR) != Zstring::npos ? + (filename.BeforeLast(FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR) : Zstring(); - Zstring extension = fileName.AfterLast(FILE_NAME_SEPARATOR).AfterLast(Zchar('.')); //extension needn't contain reasonable data + Zstring extension = filename.AfterLast(FILE_NAME_SEPARATOR).AfterLast(Zchar('.')); //extension needn't contain reasonable data if (extension.empty()) extension = Zstr("FFS"); extension.Truncate(3); @@ -382,63 +418,82 @@ Zstring createTemp8Dot3Name(const Zstring& fileName) //find a unique 8.3 short n } -//try to handle issues with already existing short 8.3 file names on Windows 7 -bool fix8Dot3NameClash(const Zstring& oldName, const Zstring& newName) //throw (FileError); return "true" if rename operation succeeded +bool have8dot3NameClash(const Zstring& filename) { - using namespace zen; - - if (newName.find(FILE_NAME_SEPARATOR) == Zstring::npos) + if (filename.find(FILE_NAME_SEPARATOR) == Zstring::npos) return false; - if (somethingExists(newName)) //name OR directory! + if (somethingExists(filename)) //name OR directory! { - const Zstring fileNameOrig = newName.AfterLast(FILE_NAME_SEPARATOR); //returns the whole string if ch not found - const Zstring fileNameShort = getFilenameFmt(newName, ::GetShortPathName).AfterLast(FILE_NAME_SEPARATOR); //throw() returns empty string on error - const Zstring fileNameLong = getFilenameFmt(newName, ::GetLongPathName) .AfterLast(FILE_NAME_SEPARATOR); //throw() returns empty string on error - - if (!fileNameShort.empty() && - !fileNameLong.empty() && - EqualFilename() (fileNameOrig, fileNameShort) && - !EqualFilename()(fileNameShort, fileNameLong)) + const Zstring origName = filename.AfterLast(FILE_NAME_SEPARATOR); //returns the whole string if ch not found + const Zstring shortName = getFilenameFmt(filename, ::GetShortPathName).AfterLast(FILE_NAME_SEPARATOR); //throw() returns empty string on error + const Zstring longName = getFilenameFmt(filename, ::GetLongPathName) .AfterLast(FILE_NAME_SEPARATOR); // + + if (!shortName.empty() && + !longName.empty() && + EqualFilename()(origName, shortName) && + !EqualFilename()(shortName, longName)) { - //we detected an event where newName is in shortname format (although it is intended to be a long name) and - //writing target file failed because another unrelated file happens to have the same short name + //for filename short and long file name are equal and another unrelated file happens to have the same short name + //e.g. filename == "TESTWE~1", but another file is existing named "TestWeb" with short name ""TESTWE~1" + return true; + } + } + return false; +} - const Zstring unrelatedPathLong = newName.BeforeLast(FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileNameLong; +class Fix8Dot3NameClash +{ +public: + Fix8Dot3NameClash(const Zstring& filename) + { + const Zstring longName = getFilenameFmt(filename, ::GetLongPathName).AfterLast(FILE_NAME_SEPARATOR); //throw() returns empty string on error - //find another name in short format: this ensures the actual short name WILL be renamed as well! - const Zstring parkedTarget = createTemp8Dot3Name(newName); + unrelatedFile = filename.BeforeLast(FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + longName; - //move already existing short name out of the way for now - renameFileInternal(unrelatedPathLong, parkedTarget); //throw (FileError: ErrorDifferentVolume); - //DON'T call renameFile() to avoid reentrance! + //find another name in short format: this ensures the actual short name WILL be renamed as well! + unrelatedFileParked = findUnused8Dot3Name(filename); - //schedule cleanup; the file system should assign this unrelated file a new (unique) short name - Loki::ScopeGuard guard = Loki::MakeGuard(renameFileInternal, parkedTarget, unrelatedPathLong);//equivalent to Boost.ScopeExit in this case - (void)guard; //silence warning "unused variable" + //move already existing short name out of the way for now + renameFile_sub(unrelatedFile, unrelatedFileParked); //throw FileError, ErrorDifferentVolume + //DON'T call renameFile() to avoid reentrance! + } - renameFileInternal(oldName, newName); //the short filename name clash is solved, this should work now - return true; + ~Fix8Dot3NameClash() + { + //the file system should assign this unrelated file a new (unique) short name + try + { + renameFile_sub(unrelatedFileParked, unrelatedFile); //throw FileError, ErrorDifferentVolume } + catch (...) {} } - return false; //issue not fixed -} +private: + Zstring unrelatedFile; + Zstring unrelatedFileParked; +}; #endif } //rename file: no copying!!! -void zen::renameFile(const Zstring& oldName, const Zstring& newName) //throw (FileError: ErrorDifferentVolume, ErrorTargetExisting); +void zen::renameFile(const Zstring& oldName, const Zstring& newName) //throw FileError, ErrorDifferentVolume, ErrorTargetExisting { try { - renameFileInternal(oldName, newName); //throw (FileError: ErrorDifferentVolume, ErrorTargetExisting) + renameFile_sub(oldName, newName); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting } catch (const FileError&) { #ifdef FFS_WIN - if (fix8Dot3NameClash(oldName, newName)) //throw (FileError); try to handle issues with already existing short 8.3 file names on Windows 7 + //try to handle issues with already existing short 8.3 file names on Windows + if (have8dot3NameClash(newName)) + { + Fix8Dot3NameClash dummy(newName); //move clashing filename to the side + //now try again... + renameFile_sub(oldName, newName); //throw FileError return; + } #endif throw; } @@ -458,12 +513,15 @@ public: } private: + CopyCallbackImpl(const CopyCallbackImpl&); + CopyCallbackImpl& operator=(const CopyCallbackImpl&); + const Zstring sourceFile_; CallbackMoveFile& moveCallback; }; -void zen::moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ignoreExisting, CallbackMoveFile* callback) //throw (FileError); +void zen::moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError; { //call back once per file (moveFile() is called by moveDirectory()) if (callback) @@ -480,24 +538,24 @@ void zen::moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ig //try to move the file directly without copying try { - renameFile(sourceFile, targetFile); //throw (FileError: ErrorDifferentVolume); + renameFile(sourceFile, targetFile); //throw FileError, ErrorDifferentVolume return; //great, we get away cheaply! } //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file) catch (const ErrorDifferentVolume&) {} //file is on a different volume: let's copy it - std::auto_ptr copyCallback(callback != NULL ? new CopyCallbackImpl(sourceFile, *callback) : NULL); + std::unique_ptr copyCallback(callback != NULL ? new CopyCallbackImpl(sourceFile, *callback) : NULL); if (symlinkExists(sourceFile)) - copySymlink(sourceFile, targetFile, SYMLINK_TYPE_FILE, false); //throw (FileError) dont copy filesystem permissions + copySymlink(sourceFile, targetFile, false); //throw FileError; don't copy filesystem permissions else - copyFile(sourceFile, targetFile, false, true, copyCallback.get()); //throw (FileError); + copyFile(sourceFile, targetFile, false, true, copyCallback.get()); //throw FileError; //attention: if copy-operation was cancelled an exception is thrown => sourcefile is not deleted, as we wish! } - removeFile(sourceFile); //throw (FileError) + removeFile(sourceFile); //throw FileError //note: copying file is NOT undone in case of exception: currently this function is called in context of user-defined deletion dir, where this behavior is fine } @@ -535,6 +593,9 @@ public: virtual HandleError onError(const std::wstring& errorText) { throw FileError(errorText); } private: + TraverseOneLevel(const TraverseOneLevel&); + TraverseOneLevel& operator=(const TraverseOneLevel&); + NameList& files_; NameList& dirs_; }; @@ -547,22 +608,21 @@ struct RemoveCallbackImpl : public CallbackRemoveDir sourceDir_(sourceDir), moveCallback_(moveCallback) {} - virtual void notifyDeletion(const Zstring& currentObject) - { - moveCallback_.requestUiRefresh(sourceDir_); - } + virtual void notifyFileDeletion(const Zstring& filename) { moveCallback_.requestUiRefresh(sourceDir_); } + virtual void notifyDirDeletion(const Zstring& dirname) { moveCallback_.requestUiRefresh(sourceDir_); } private: + RemoveCallbackImpl(const RemoveCallbackImpl&); + RemoveCallbackImpl& operator=(const RemoveCallbackImpl&); + const Zstring sourceDir_; CallbackMoveFile& moveCallback_; }; } -void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw (FileError); +void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError; { - using namespace zen; - //call back once per folder if (callback) callback->requestUiRefresh(sourceDir); @@ -580,7 +640,7 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool //first try to move the directory directly without copying try { - renameFile(sourceDir, targetDir); //throw (FileError: ErrorDifferentVolume, ErrorTargetExisting); + renameFile(sourceDir, targetDir); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting return; //great, we get away cheaply! } //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the directory) @@ -588,9 +648,9 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool //create target if (isSymlink) - copySymlink(sourceDir, targetDir, SYMLINK_TYPE_DIR, false); //throw (FileError) -> don't copy permissions + copySymlink(sourceDir, targetDir, false); //throw FileError -> don't copy permissions else - createDirectory(targetDir, sourceDir, false); //throw (FileError) + createDirectory(targetDir, sourceDir, false); //throw FileError } if (!isSymlink) //handle symbolic links @@ -609,7 +669,7 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool //move files for (TraverseOneLevel::NameList::const_iterator i = fileList.begin(); i != fileList.end(); ++i) - moveFile(i->second, targetDirFormatted + i->first, ignoreExisting, callback); //throw (FileError: ErrorTargetExisting); + moveFile(i->second, targetDirFormatted + i->first, ignoreExisting, callback); //throw FileError, ErrorTargetExisting //move directories for (TraverseOneLevel::NameList::const_iterator i = dirList.begin(); i != dirList.end(); ++i) @@ -619,12 +679,12 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool } //delete source - std::auto_ptr removeCallback(callback != NULL ? new RemoveCallbackImpl(sourceDir, *callback) : NULL); - removeDirectory(sourceDir, removeCallback.get()); //throw (FileError); + std::unique_ptr removeCallback(callback != NULL ? new RemoveCallbackImpl(sourceDir, *callback) : NULL); + removeDirectory(sourceDir, removeCallback.get()); //throw FileError; } -void zen::moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw (FileError); +void zen::moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError; { #ifdef FFS_WIN const Zstring& sourceDirFormatted = sourceDir; @@ -671,6 +731,9 @@ public: virtual HandleError onError(const std::wstring& errorText) { throw FileError(errorText); } private: + FilesDirsOnlyTraverser(const FilesDirsOnlyTraverser&); + FilesDirsOnlyTraverser& operator=(const FilesDirsOnlyTraverser&); + std::vector& m_files; std::vector& m_dirs; }; @@ -699,7 +762,8 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback) #endif throw FileError(_("Error deleting directory:") + "\n\"" + directory + "\"" + "\n\n" + getLastErrorFormatted()); - if (callback) callback->notifyDeletion(directory); //once per symlink + if (callback) + callback->notifyDirDeletion(directory); //once per symlink return; } @@ -714,7 +778,8 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback) for (std::vector::const_iterator i = fileList.begin(); i != fileList.end(); ++i) { const bool workDone = removeFile(*i); - if (callback && workDone) callback->notifyDeletion(*i); //call once per file + if (callback && workDone) + callback->notifyFileDeletion(*i); //call once per file } //delete directories recursively @@ -730,76 +795,25 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback) { throw FileError(_("Error deleting directory:") + "\n\"" + directory + "\"" + "\n\n" + getLastErrorFormatted()); } - if (callback) callback->notifyDeletion(directory); //and once per folder + if (callback) + callback->notifyDirDeletion(directory); //and once per folder } -void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool deRefSymlinks) //throw (FileError) +void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, ProcSymlink procSl) //throw FileError { #ifdef FFS_WIN - FILETIME creationTime = {}; - FILETIME lastWriteTime = {}; + FILETIME creationTime = {}; + FILETIME lastWriteTime = tofiletime(modificationTime); + //####################################### DST hack ########################################### + if (dst::isFatDrive(filename)) //throw() { - WIN32_FILE_ATTRIBUTE_DATA sourceAttr = {}; - if (!::GetFileAttributesEx(applyLongPathPrefix(sourceObj).c_str(), //__in LPCTSTR lpFileName, - GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId, - &sourceAttr)) //__out LPVOID lpFileInformation - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); - - const bool isReparsePoint = (sourceAttr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; - const bool isDirectory = (sourceAttr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - - if (isReparsePoint && deRefSymlinks) //we have a symlink AND need to dereference... - { - HANDLE hSource = ::CreateFile(applyLongPathPrefix(sourceObj).c_str(), - FILE_READ_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory; no FILE_FLAG_OPEN_REPARSE_POINT => deref symlinks - NULL); - if (hSource == INVALID_HANDLE_VALUE) - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); - - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hSource); - (void)dummy; //silence warning "unused variable" - - if (!::GetFileTime(hSource, //__in HANDLE hFile, - &creationTime, //__out_opt LPFILETIME lpCreationTime, - NULL, //__out_opt LPFILETIME lpLastAccessTime, - &lastWriteTime)) //__out_opt LPFILETIME lpLastWriteTime - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); - } - else - { - creationTime = sourceAttr.ftCreationTime; - lastWriteTime = sourceAttr.ftLastWriteTime; - } - - //####################################### DST hack ########################################### - if (!isDirectory) //dst hack not (yet) required for directories (symlinks implicitly checked by isFatDrive()) - { - if (dst::isFatDrive(sourceObj)) //throw() - { - const dst::RawTime rawTime(creationTime, lastWriteTime); - if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error) - { - lastWriteTime = dst::fatDecodeUtcTime(rawTime); //return last write time in real UTC, throw (std::runtime_error) - ::GetSystemTimeAsFileTime(&creationTime); //real creation time information is not available... - } - } - - if (dst::isFatDrive(targetObj)) //throw() - { - const dst::RawTime encodedTime = dst::fatEncodeUtcTime(lastWriteTime); //throw (std::runtime_error) - creationTime = encodedTime.createTimeRaw; - lastWriteTime = encodedTime.writeTimeRaw; - } - } - //####################################### DST hack ########################################### + const dst::RawTime encodedTime = dst::fatEncodeUtcTime(lastWriteTime); //throw (std::runtime_error) + creationTime = encodedTime.createTimeRaw; + lastWriteTime = encodedTime.writeTimeRaw; } - + //####################################### DST hack ########################################### //privilege SE_BACKUP_NAME doesn't seem to be required here for symbolic links //note: setting privileges requires admin rights! @@ -815,20 +829,20 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool */ //may need to remove the readonly-attribute (e.g. FAT usb drives) - FileUpdateHandle targetHandle(targetObj, [=]() + FileUpdateHandle targetHandle(filename, [ = ]() { - return ::CreateFile(applyLongPathPrefix(targetObj).c_str(), - FILE_GENERIC_WRITE, //ATTENTION: although FILE_WRITE_ATTRIBUTES should(!) be sufficient, this may leads to access denied on NAS shares, unless we specify FILE_GENERIC_WRITE + return ::CreateFile(applyLongPathPrefix(filename).c_str(), + GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | //needed to open a directory - (deRefSymlinks ? 0 : FILE_FLAG_OPEN_REPARSE_POINT), //process symlinks + (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //process symlinks NULL); }); if (targetHandle.get() == INVALID_HANDLE_VALUE) - throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + getLastErrorFormatted()); + throw FileError(_("Error changing modification time:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); /* if (hTarget == INVALID_HANDLE_VALUE && ::GetLastError() == ERROR_SHARING_VIOLATION) @@ -838,17 +852,19 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool } */ + auto isNullTime = [](const FILETIME & ft) { return ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0; }; + if (!::SetFileTime(targetHandle.get(), - &creationTime, + isNullTime(creationTime) ? NULL : &creationTime, NULL, &lastWriteTime)) - throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + getLastErrorFormatted()); + throw FileError(_("Error changing modification time:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); #ifndef NDEBUG //dst hack: verify data written - if (dst::isFatDrive(targetObj) && !dirExists(targetObj)) //throw() + if (dst::isFatDrive(filename) && !dirExists(filename)) //throw() { WIN32_FILE_ATTRIBUTE_DATA debugeAttr = {}; - assert(::GetFileAttributesEx(applyLongPathPrefix(targetObj).c_str(), //__in LPCTSTR lpFileName, + assert(::GetFileAttributesEx(applyLongPathPrefix(filename).c_str(), //__in LPCTSTR lpFileName, GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId, &debugeAttr)); //__out LPVOID lpFileInformation @@ -858,35 +874,27 @@ void zen::copyFileTimes(const Zstring& sourceObj, const Zstring& targetObj, bool #endif #elif defined FFS_LINUX - if (deRefSymlinks) + if (procSl == SYMLINK_FOLLOW) { - struct stat objInfo = {}; - if (::stat(sourceObj.c_str(), &objInfo) != 0) //read file attributes from source directory - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); - struct utimbuf newTimes = {}; - newTimes.actime = objInfo.st_atime; - newTimes.modtime = objInfo.st_mtime; + newTimes.actime = ::time(NULL); + newTimes.modtime = to(modificationTime); - //(try to) set new "last write time" - if (::utime(targetObj.c_str(), &newTimes) != 0) //return value not evaluated! - throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + getLastErrorFormatted()); + // set new "last write time" + if (::utime(filename.c_str(), &newTimes) != 0) + throw FileError(_("Error changing modification time:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); } else { - struct stat objInfo = {}; - if (::lstat(sourceObj.c_str(), &objInfo) != 0) //read file attributes from source directory - throw FileError(_("Error reading file attributes:") + "\n\"" + sourceObj + "\"" + "\n\n" + getLastErrorFormatted()); - struct timeval newTimes[2] = {}; - newTimes[0].tv_sec = objInfo.st_atime; /* seconds */ - newTimes[0].tv_usec = 0; /* microseconds */ + newTimes[0].tv_sec = ::time(NULL); /* seconds */ + newTimes[0].tv_usec = 0; /* microseconds */ - newTimes[1].tv_sec = objInfo.st_mtime; /* seconds */ - newTimes[1].tv_usec = 0; /* microseconds */ + newTimes[1].tv_sec = to(modificationTime); + newTimes[1].tv_usec = 0; - if (::lutimes(targetObj.c_str(), newTimes) != 0) //return value not evaluated! - throw FileError(_("Error changing modification time:") + "\n\"" + targetObj + "\"" + "\n\n" + getLastErrorFormatted()); + if (::lutimes(filename.c_str(), newTimes) != 0) + throw FileError(_("Error changing modification time:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted()); } #endif } @@ -901,56 +909,50 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa const HANDLE hDir = ::CreateFile(applyLongPathPrefix(dirLinkName).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory NULL); if (hDir == INVALID_HANDLE_VALUE) throw FileError(_("Error resolving symbolic link:") + "\n\"" + dirLinkName + "\"" + "\n\n" + getLastErrorFormatted()); + LOKI_ON_BLOCK_EXIT2(::CloseHandle(hDir)); - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hDir); - (void)dummy; //silence warning "unused variable" - - const size_t BUFFER_SIZE = 10000; - TCHAR targetPath[BUFFER_SIZE]; + const DWORD BUFFER_SIZE = 10000; + std::vector targetPath(BUFFER_SIZE); //dynamically load windows API function - typedef DWORD (WINAPI *GetFinalPathNameByHandleWFunc)( - HANDLE hFile, - LPTSTR lpszFilePath, - DWORD cchFilePath, - DWORD dwFlags); - const GetFinalPathNameByHandleWFunc getFinalPathNameByHandle = - util::getDllFun(L"kernel32.dll", "GetFinalPathNameByHandleW"); - - if (getFinalPathNameByHandle == NULL) + typedef DWORD (WINAPI *GetFinalPathNameByHandleWFunc)(HANDLE hFile, + LPTSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); + const util::DllFun getFinalPathNameByHandle(L"kernel32.dll", "GetFinalPathNameByHandleW"); + if (!getFinalPathNameByHandle) throw FileError(_("Error loading library function:") + "\n\"" + "GetFinalPathNameByHandleW" + "\""); - const DWORD rv = getFinalPathNameByHandle( - hDir, //__in HANDLE hFile, - targetPath, //__out LPTSTR lpszFilePath, - BUFFER_SIZE,//__in DWORD cchFilePath, - 0); //__in DWORD dwFlags - if (rv >= BUFFER_SIZE || rv == 0) + const DWORD charsWritten = getFinalPathNameByHandle(hDir, //__in HANDLE hFile, + &targetPath[0], //__out LPTSTR lpszFilePath, + BUFFER_SIZE, //__in DWORD cchFilePath, + FILE_NAME_NORMALIZED); //__in DWORD dwFlags + if (charsWritten >= BUFFER_SIZE || charsWritten == 0) { std::wstring errorMessage = _("Error resolving symbolic link:") + "\n\"" + dirLinkName + "\""; - if (rv == 0) + if (charsWritten == 0) errorMessage += L"\n\n" + getLastErrorFormatted(); throw FileError(errorMessage); } - return targetPath; + return Zstring(&targetPath[0], charsWritten); } #endif #ifdef HAVE_SELINUX //copy SELinux security context -void copySecurityContext(const Zstring& source, const Zstring& target, bool derefSymlinks) //throw (FileError) +void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymlink procSl) //throw FileError { security_context_t contextSource = NULL; - const int rv = derefSymlinks ? - ::getfilecon (source.c_str(), &contextSource) : + const int rv = procSl == SYMLINK_FOLLOW ? + ::getfilecon(source.c_str(), &contextSource) : ::lgetfilecon(source.c_str(), &contextSource); if (rv < 0) { @@ -960,13 +962,12 @@ void copySecurityContext(const Zstring& source, const Zstring& target, bool dere throw FileError(_("Error reading security context:") + "\n\"" + source + "\"" + "\n\n" + getLastErrorFormatted()); } - Loki::ScopeGuard dummy1 = Loki::MakeGuard(::freecon, contextSource); - (void)dummy1; //silence warning "unused variable" + LOKI_ON_BLOCK_EXIT2(::freecon(contextSource)); { security_context_t contextTarget = NULL; - const int rv2 = derefSymlinks ? - ::getfilecon (target.c_str(), &contextTarget) : + const int rv2 = procSl == SYMLINK_FOLLOW ? + ::getfilecon(target.c_str(), &contextTarget) : ::lgetfilecon(target.c_str(), &contextTarget); if (rv2 < 0) { @@ -976,16 +977,15 @@ void copySecurityContext(const Zstring& source, const Zstring& target, bool dere } else { - Loki::ScopeGuard dummy2 = Loki::MakeGuard(::freecon, contextTarget); - (void)dummy2; //silence warning "unused variable" + LOKI_ON_BLOCK_EXIT2(::freecon(contextTarget)); if (::strcmp(contextSource, contextTarget) == 0) //nothing to do return; } } - const int rv3 = derefSymlinks ? - ::setfilecon (target.c_str(), contextSource) : + const int rv3 = procSl == SYMLINK_FOLLOW ? + ::setfilecon(target.c_str(), contextSource) : ::lsetfilecon(target.c_str(), contextSource); if (rv3 < 0) throw FileError(_("Error writing security context:") + "\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted()); @@ -994,7 +994,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, bool dere //copy permissions for files, directories or symbolic links: requires admin rights -void copyObjectPermissions(const Zstring& source, const Zstring& target, bool derefSymlinks) //throw (FileError); +void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSymlink procSl) //throw FileError; { #ifdef FFS_WIN //setting privileges requires admin rights! @@ -1024,15 +1024,13 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de const HANDLE hSource = ::CreateFile(applyLongPathPrefix(source).c_str(), READ_CONTROL | ACCESS_SYSTEM_SECURITY, //ACCESS_SYSTEM_SECURITY required for SACL access FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, + 0, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | (derefSymlinks ? 0 : FILE_FLAG_OPEN_REPARSE_POINT), //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory + FILE_FLAG_BACKUP_SEMANTICS | (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory NULL); if (hSource == INVALID_HANDLE_VALUE) throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted() + " (OR)"); - - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hSource); - (void)dummy; //silence warning "unused variable" + LOKI_ON_BLOCK_EXIT2(::CloseHandle(hSource)); // DWORD rc = ::GetNamedSecurityInfo(const_cast(applyLongPathPrefix(source).c_str()), -> does NOT dereference symlinks! DWORD rc = ::GetSecurityInfo(hSource, //__in LPTSTR pObjectName, @@ -1045,20 +1043,17 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de &buffer); //__out_opt PSECURITY_DESCRIPTOR *ppSecurityDescriptor if (rc != ERROR_SUCCESS) throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted(rc) + " (R)"); - - Loki::ScopeGuard dummy4 = Loki::MakeGuard(::LocalFree, buffer); - (void)dummy4; //silence warning "unused variable" - + LOKI_ON_BLOCK_EXIT2(::LocalFree(buffer)); //may need to remove the readonly-attribute (e.g. FAT usb drives) - FileUpdateHandle targetHandle(target, [=]() + FileUpdateHandle targetHandle(target, [ = ]() { - return ::CreateFile(applyLongPathPrefix(target).c_str(), // lpFileName - FILE_GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY, // dwDesiredAccess: all four seem to be required!!! - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // dwShareMode - NULL, // lpSecurityAttributes + return ::CreateFile(applyLongPathPrefix(target).c_str(), // lpFileName + GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY, // dwDesiredAccess: all four seem to be required!!! + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // dwShareMode + 0, // lpSecurityAttributes OPEN_EXISTING, // dwCreationDisposition - FILE_FLAG_BACKUP_SEMANTICS | (derefSymlinks ? 0 : FILE_FLAG_OPEN_REPARSE_POINT), // dwFlagsAndAttributes + FILE_FLAG_BACKUP_SEMANTICS | (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), // dwFlagsAndAttributes NULL); // hTemplateFile }); @@ -1066,14 +1061,13 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted() + " (OW)"); // rc = ::SetNamedSecurityInfo(const_cast(applyLongPathPrefix(target).c_str()), //__in LPTSTR pObjectName, -> does NOT dereference symlinks! - rc = ::SetSecurityInfo( - targetHandle.get(), //__in LPTSTR pObjectName, - SE_FILE_OBJECT, //__in SE_OBJECT_TYPE ObjectType, - OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, //__in SECURITY_INFORMATION SecurityInfo, - owner, //__in_opt PSID psidOwner, - group, //__in_opt PSID psidGroup, - dacl, //__in_opt PACL pDacl, - sacl); //__in_opt PACL pSacl + rc = ::SetSecurityInfo(targetHandle.get(), //__in LPTSTR pObjectName, + SE_FILE_OBJECT, //__in SE_OBJECT_TYPE ObjectType, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, //__in SECURITY_INFORMATION SecurityInfo, + owner, //__in_opt PSID psidOwner, + group, //__in_opt PSID psidGroup, + dacl, //__in_opt PACL pDacl, + sacl); //__in_opt PACL pSacl if (rc != ERROR_SUCCESS) throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted(rc) + " (W)"); @@ -1081,21 +1075,20 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de #elif defined FFS_LINUX #ifdef HAVE_SELINUX //copy SELinux security context - copySecurityContext(source, target, derefSymlinks); //throw (FileError) + copySecurityContext(source, target, procSl); //throw FileError #endif - if (derefSymlinks) + struct stat fileInfo = {}; + if (procSl == SYMLINK_FOLLOW) { - struct stat fileInfo = {}; - if (::stat (source.c_str(), &fileInfo) != 0 || + if (::stat(source.c_str(), &fileInfo) != 0 || ::chown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0 || // may require admin rights! ::chmod(target.c_str(), fileInfo.st_mode) != 0) throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted() + " (R)"); } else { - struct stat fileInfo = {}; - if (::lstat (source.c_str(), &fileInfo) != 0 || + if (::lstat(source.c_str(), &fileInfo) != 0 || ::lchown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0 || // may require admin rights! (!symlinkExists(target) && ::chmod(target.c_str(), fileInfo.st_mode) != 0)) //setting access permissions doesn't make sense for symlinks on Linux: there is no lchmod() throw FileError(_("Error copying file permissions:") + "\n\"" + source + "\" ->\n\"" + target + "\"" + "\n\n" + getLastErrorFormatted() + " (W)"); @@ -1104,35 +1097,8 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, bool de } -namespace -{ -//provide uniform binary interface: -void removeDirSimple(const Zstring& directory) { removeDirectory(directory); } //throw (FileError) -void removeFileSimple(const Zstring& filename) { removeFile(filename); } //throw (FileError) -} - - -void createDirectoryRecursively(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions, int level) +void createDirectory_straight(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions, int level) { - using namespace zen; - - if (dirExists(directory)) - return; - - if (level == 100) //catch endless recursion - return; - - //try to create parent folders first - const Zstring dirParent = directory.BeforeLast(FILE_NAME_SEPARATOR); - if (!dirParent.empty() && !dirExists(dirParent)) - { - //call function recursively - const Zstring templateParent = templateDir.BeforeLast(FILE_NAME_SEPARATOR); - createDirectoryRecursively(dirParent, templateParent, copyFilePermissions, level + 1); - } - - //now creation should be possible - //default directory creation #ifdef FFS_WIN //don't use ::CreateDirectoryEx: @@ -1159,11 +1125,11 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat try { //get target directory of symbolic link - sourcePath = resolveDirectorySymlink(templateDir); //throw (FileError) + sourcePath = resolveDirectorySymlink(templateDir); //throw FileError } catch (FileError&) {} //dereferencing a symbolic link usually fails if it is located on network drive or client is XP: NOT really an error... } - else //no symbolic link + else //no symbolic link sourcePath = templateDir; //try to copy file attributes @@ -1185,14 +1151,13 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat HANDLE hDir = ::CreateFile(applyLongPathPrefix(directory).c_str(), GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hDir != INVALID_HANDLE_VALUE) { - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hDir); - (void)dummy; //silence warning "unused variable" + LOKI_ON_BLOCK_EXIT2(::CloseHandle(hDir)); USHORT cmpState = COMPRESSION_FORMAT_DEFAULT; @@ -1210,23 +1175,51 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat } } #endif - - //try to copy file times: NOT mission critical for a directory, since modification time is changed on each added, deleted file, however creation time will stay - try - { - copyFileTimes(templateDir, directory, true); //throw (FileError) - } - catch (FileError&) {} - - Loki::ScopeGuard guardNewDir = Loki::MakeGuard(&removeDirSimple, directory); //ensure cleanup: + Loki::ScopeGuard guardNewDir = Loki::MakeGuard([&]() { removeDirectory(directory); }); //ensure cleanup: //enforce copying file permissions: it's advertized on GUI... if (copyFilePermissions) - copyObjectPermissions(templateDir, directory, true); //throw (FileError) + copyObjectPermissions(templateDir, directory, SYMLINK_FOLLOW); //throw FileError guardNewDir.Dismiss(); //target has been created successfully! } } + + +void createDirectoryRecursively(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions, int level) +{ + if (level == 100) //catch endless recursion + return; + +#ifdef FFS_WIN + std::unique_ptr fnc; + if (somethingExists(directory)) + { + //handle issues with already existing short 8.3 file names on Windows + if (have8dot3NameClash(directory)) + fnc.reset(new Fix8Dot3NameClash(directory)); //move clashing object to the side + else if (dirExists(directory)) + return; + } +#elif defined FFS_LINUX + if (dirExists(directory)) + return; +#endif + else //if "somethingExists" we needn't create the parent directory + { + //try to create parent folders first + const Zstring dirParent = directory.BeforeLast(FILE_NAME_SEPARATOR); + if (!dirParent.empty() && !dirExists(dirParent)) + { + //call function recursively + const Zstring templateParent = templateDir.BeforeLast(FILE_NAME_SEPARATOR); //returns empty string if ch not found + createDirectoryRecursively(dirParent, templateParent, copyFilePermissions, level + 1); + } + } + + //now creation should be possible + createDirectory_straight(directory, templateDir, copyFilePermissions, level); //throw FileError +} } @@ -1251,38 +1244,51 @@ void zen::createDirectory(const Zstring& directory) } -void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, zen::SymlinkType type, bool copyFilePermissions) //throw (FileError) +void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool copyFilePermissions) //throw FileError { - const Zstring linkPath = getSymlinkRawTargetString(sourceLink); //accept broken symlinks; throw (FileError) + const Zstring linkPath = getSymlinkRawTargetString(sourceLink); //accept broken symlinks; throw FileError #ifdef FFS_WIN + const bool isDirLink = [&]() -> bool + { + const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(sourceLink).c_str()); + return ret != INVALID_FILE_ATTRIBUTES && (ret& FILE_ATTRIBUTE_DIRECTORY); + }(); + //dynamically load windows API function typedef BOOLEAN (WINAPI *CreateSymbolicLinkFunc)(LPCTSTR lpSymlinkFileName, LPCTSTR lpTargetFileName, DWORD dwFlags); - const CreateSymbolicLinkFunc createSymbolicLink = util::getDllFun(L"kernel32.dll", "CreateSymbolicLinkW"); - if (createSymbolicLink == NULL) - throw FileError(_("Error loading library function:") + "\n\"" + "CreateSymbolicLinkW" + "\""); - if (!createSymbolicLink( //seems no long path prefix is required... - targetLink.c_str(), //__in LPTSTR lpSymlinkFileName, - linkPath.c_str(), //__in LPTSTR lpTargetFileName, - (type == SYMLINK_TYPE_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))) //__in DWORD dwFlags - throw FileError(_("Error copying symbolic link:") + "\n\"" + sourceLink + "\" ->\n\"" + targetLink + "\"" + "\n\n" + getLastErrorFormatted()); + const util::DllFun createSymbolicLink(L"kernel32.dll", "CreateSymbolicLinkW"); + if (!createSymbolicLink) + throw FileError(_("Error loading library function:") + "\n\"" + "CreateSymbolicLinkW" + "\""); + if (!createSymbolicLink(targetLink.c_str(), //__in LPTSTR lpSymlinkFileName, - seems no long path prefix is required... + linkPath.c_str(), //__in LPTSTR lpTargetFileName, + (isDirLink ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))) //__in DWORD dwFlags #elif defined FFS_LINUX if (::symlink(linkPath.c_str(), targetLink.c_str()) != 0) - throw FileError(_("Error copying symbolic link:") + "\n\"" + sourceLink + "\" ->\n\"" + targetLink + "\"" + "\n\n" + getLastErrorFormatted()); #endif + throw FileError(_("Error copying symbolic link:") + "\n\"" + sourceLink + "\" ->\n\"" + targetLink + "\"" + "\n\n" + getLastErrorFormatted()); //allow only consistent objects to be created -> don't place before ::symlink, targetLink may already exist - Loki::ScopeGuard guardNewDir = type == SYMLINK_TYPE_DIR ? - Loki::MakeGuard(&removeDirSimple, targetLink) : - Loki::MakeGuard(&removeFileSimple, targetLink); + Loki::ScopeGuard guardNewDir = Loki::MakeGuard([&]() + { +#ifdef FFS_WIN + if (isDirLink) + removeDirectory(targetLink); + else +#endif + removeFile(targetLink); + }); //file times: essential for a symlink: enforce this! (don't just try!) - copyFileTimes(sourceLink, targetLink, false); //throw (FileError) + { + const Int64 modTime = getFileTime(sourceLink, SYMLINK_DIRECT); //throw FileError + setFileTime(targetLink, modTime, SYMLINK_DIRECT); //throw FileError + } if (copyFilePermissions) - copyObjectPermissions(sourceLink, targetLink, false); //throw (FileError) + copyObjectPermissions(sourceLink, targetLink, SYMLINK_DIRECT); //throw FileError guardNewDir.Dismiss(); //target has been created successfully! } @@ -1302,16 +1308,57 @@ Zstring createTempName(const Zstring& filename) } #ifdef FFS_WIN -struct CallbackData +class CallbackData { - CallbackData(CallbackCopyFile& cb) : - callback(cb), - callNr(0), - exceptionCaught(false) {} - - CallbackCopyFile& callback; - size_t callNr; - bool exceptionCaught; +public: + CallbackData(CallbackCopyFile* cb, //may be NULL + const Zstring& sourceFile, + const Zstring& targetFile, + bool osIsvistaOrLater) : + userCallback(cb), + sourceFile_(sourceFile), + targetFile_(targetFile), + osIsvistaOrLater_(osIsvistaOrLater), + exceptionInUserCallback(false) {} + + CallbackCopyFile* userCallback; //optional! + const Zstring& sourceFile_; + const Zstring& targetFile_; + const bool osIsvistaOrLater_; + + //there is some mixed responsibility in this class, pure read-only data and abstraction for error reporting + //however we need to keep it at one place as ::CopyFileEx() requires! + + void reportUserException(const UInt64& bytesTransferred) + { + exceptionInUserCallback = true; + bytesTransferredOnException = bytesTransferred; + } + + void reportError(const std::wstring& message) { errorMsg = message; } + + void evaluateErrors() //throw + { + if (exceptionInUserCallback) + { + assert(userCallback); + if (userCallback) + userCallback->updateCopyStatus(bytesTransferredOnException); //rethrow (hopefully!) + } + if (!errorMsg.empty()) + throw FileError(errorMsg); + } + + void setSrcAttr(const FileAttrib& attr) { sourceAttr = attr; } + FileAttrib getSrcAttr() const { assert(sourceAttr.modificationTime != 0); return sourceAttr; } + +private: + CallbackData(const CallbackData&); + CallbackData& operator=(const CallbackData&); + + FileAttrib sourceAttr; + std::wstring errorMsg; // + bool exceptionInUserCallback; //these two are exclusive! UInt64 bytesTransferredOnException; }; @@ -1327,36 +1374,81 @@ DWORD CALLBACK copyCallbackInternal( HANDLE hDestinationFile, LPVOID lpData) { - if (lpData) + //this callback is invoked for block sizes managed by Windows, these may vary from e.g. 64 kB up to 1MB. It seems this is dependent from file size amongst others. + + //symlink handling: + //if source is a symlink and COPY_FILE_COPY_SYMLINK is specified, this callback is NOT invoked! + //if source is a symlink and COPY_FILE_COPY_SYMLINK is NOT specified, this callback is called and hSourceFile is a handle to the *target* of the link! + + //file time handling: + //::CopyFileEx() will copy file modification time (only) over from source file AFTER the last inocation of this callback + //=> it is possible to adapt file creation time of target in here, but NOT file modification time! + + CallbackData& cbd = *static_cast(lpData); + + //#################### return source file attributes ################################ + if (dwCallbackReason == CALLBACK_STREAM_SWITCH) //called up front for every file (even if 0-sized) { - CallbackData& cbd = *static_cast(lpData); + BY_HANDLE_FILE_INFORMATION fileInfo = {}; + if (!::GetFileInformationByHandle(hSourceFile, &fileInfo)) + { + cbd.reportError(_("Error reading file attributes:") + "\n\"" + cbd.sourceFile_ + "\"" + "\n\n" + getLastErrorFormatted()); + return PROGRESS_CANCEL; + } + + const FileAttrib attr = { UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh), + toTimeT(fileInfo.ftLastWriteTime) + }; + //extractFileID(fileInfo)); + + cbd.setSrcAttr(attr); + + //#################### copy file creation time ################################ + FILETIME creationTime = {}; + + if (!::GetFileTime(hSourceFile, //__in HANDLE hFile, + &creationTime, //__out_opt LPFILETIME lpCreationTime, + NULL, //__out_opt LPFILETIME lpLastAccessTime, + NULL)) //__out_opt LPFILETIME lpLastWriteTime + { + cbd.reportError(_("Error reading file attributes:") + "\n\"" + cbd.sourceFile_ + "\"" + "\n\n" + getLastErrorFormatted()); + return PROGRESS_CANCEL; + } - //small performance optimization: it seems this callback function is called for every 64 kB (depending on cluster size). - if (++cbd.callNr % 4 == 0) //executing callback every 256 kB should suffice + if (!::SetFileTime(hDestinationFile, + &creationTime, + NULL, + NULL)) { - //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\ + cbd.reportError(_("Error changing modification time:") + "\n\"" + cbd.targetFile_ + "\"" + "\n\n" + getLastErrorFormatted()); + return PROGRESS_CANCEL; + } + //############################################################################## + } + + //if (totalFileSize.QuadPart == totalBytesTransferred.QuadPart) {} //called after copy operation is finished - note: for 0-sized files this callback is invoked just ONCE! + + if (cbd.userCallback) + { + //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\ 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); - try - { - cbd.callback.updateCopyStatus(UInt64(totalBytesTransferred.QuadPart)); - } - catch (...) - { -#ifndef _MSC_VER -#warning migrate to std::exception_ptr when available -#endif - cbd.exceptionCaught = true; - cbd.bytesTransferredOnException = UInt64(totalBytesTransferred.QuadPart); - return PROGRESS_CANCEL; - } + NULL, 0); + try + { + cbd.userCallback->updateCopyStatus(UInt64(totalBytesTransferred.QuadPart)); } - } + catch (...) + { +//#warning migrate to std::exception_ptr when available + cbd.reportUserException(UInt64(totalBytesTransferred.QuadPart)); + return PROGRESS_CANCEL; + } + } return PROGRESS_CONTINUE; } @@ -1379,36 +1471,43 @@ bool supportForNonEncryptedDestination() } -void rawCopyWinApi(const Zstring& sourceFile, - const Zstring& targetFile, - CallbackCopyFile* callback) //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked) +void rawCopyWinApi_sub(const Zstring& sourceFile, + const Zstring& targetFile, + CallbackCopyFile* callback, + FileAttrib* sourceAttr) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked { - Loki::ScopeGuard guardTarget = Loki::MakeGuard(&removeFile, targetFile); //transactional behavior: guard just before starting copy! + Loki::ScopeGuard guardTarget = Loki::MakeGuard(&removeFile, targetFile); //transactional behavior: guard just before starting copy, we don't trust ::CopyFileEx(), do we ;) DWORD copyFlags = COPY_FILE_FAIL_IF_EXISTS; //allow copying from encrypted to non-encrytped location - static bool nonEncSupported = false; - static boost::once_flag once = BOOST_ONCE_INIT; //caveat: function scope static initialization is not thread-safe in VS 2010! - boost::call_once(once, []() { nonEncSupported = supportForNonEncryptedDestination(); }); - + { + 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 = supportForNonEncryptedDestination(); }); + } if (nonEncSupported) copyFlags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION; - std::unique_ptr cbd(callback ? new CallbackData(*callback) : NULL); - - if (!::CopyFileEx( //same performance like CopyFile() - applyLongPathPrefix(sourceFile).c_str(), - applyLongPathPrefix(targetFile).c_str(), - callback ? copyCallbackInternal : NULL, - cbd.get(), - NULL, - copyFlags)) + static bool osIsvistaOrLater = false; { - if (cbd.get() && cbd->exceptionCaught) - callback->updateCopyStatus(cbd->bytesTransferredOnException); //rethrow (hopefully!) + 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 = dst::vistaOrLater(); }); + } + + CallbackData cbd(callback, sourceFile, targetFile, osIsvistaOrLater); + const bool success = ::CopyFileEx( //same performance like CopyFile() + applyLongPathPrefix(sourceFile).c_str(), + applyLongPathPrefix(targetFile).c_str(), + copyCallbackInternal, + &cbd, + NULL, + copyFlags) == TRUE; //silence x64 perf warning + + cbd.evaluateErrors(); //throw ?, process errors in callback first! + if (!success) + { const DWORD lastError = ::GetLastError(); //don't suppress "lastError == ERROR_REQUEST_ABORTED": a user aborted operation IS an error condition! @@ -1439,38 +1538,56 @@ void rawCopyWinApi(const Zstring& sourceFile, //trying to copy > 4GB file to FAT/FAT32 volume gives obscure ERROR_INVALID_PARAMETER (FAT can indeed handle files up to 4 Gig, tested!) if (lastError == ERROR_INVALID_PARAMETER && dst::isFatDrive(targetFile) && - getFilesize(sourceFile) >= 4U * UInt64(1024U * 1024 * 1024)) //throw (FileError) + getFilesize(sourceFile) >= 4U * UInt64(1024U * 1024 * 1024)) //throw FileError errorMessage += L"\nFAT volume cannot store files larger than 4 gigabyte!"; //note: ERROR_INVALID_PARAMETER can also occur when copying to a SharePoint server or MS SkyDrive and the target filename is of a restricted type. } - catch(...) {} + catch (...) {} throw FileError(errorMessage); } - try //adapt file modification time - { - //this is optional, since ::CopyFileEx already copies modification time (but not creation time) - //chances are good this also avoids a number of unnecessary access-denied errors on NAS shares! - //(one is: missing permission to change file attributes, remove read-only in particular) - copyFileTimes(sourceFile, targetFile, true); //throw FileError - } - catch (FileError&) + if (sourceAttr) + *sourceAttr = cbd.getSrcAttr(); + { - //CAVEAT: in case one of the drives is FAT, we still(!) need copyFileTimes to apply the DST hack! - if (dst::isFatDrive(sourceFile) || dst::isFatDrive(targetFile)) //throw() - throw; - assert(false); //maybe this catches some test-case left-overs? + const Int64 modTime = getFileTime(sourceFile, SYMLINK_FOLLOW); //throw FileError + setFileTime(targetFile, modTime, SYMLINK_FOLLOW); //throw FileError + //note: this sequence leads to a loss of precision of up to 1 sec! + //perf-loss on USB sticks with many small files of about 30%! damn! } guardTarget.Dismiss(); //target has been created successfully! } +inline +void rawCopyWinApi(const Zstring& sourceFile, + const Zstring& targetFile, + CallbackCopyFile* callback, + FileAttrib* sourceAttr) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked +{ + try + { + rawCopyWinApi_sub(sourceFile, targetFile, callback, sourceAttr); // throw ... + } + catch (ErrorTargetExisting&) + { + //try to handle issues with already existing short 8.3 file names on Windows + if (have8dot3NameClash(targetFile)) + { + Fix8Dot3NameClash dummy(targetFile); //move clashing filename to the side + rawCopyWinApi_sub(sourceFile, targetFile, callback, sourceAttr); //throw FileError; the short filename name clash is solved, this should work now + return; + } + throw; + } +} + //void rawCopyWinOptimized(const Zstring& sourceFile, // const Zstring& targetFile, -// CallbackCopyFile* callback) //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked) +// CallbackCopyFile* callback) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked //{ // /* // BackupRead() FileRead() CopyFileEx() @@ -1491,7 +1608,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // 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 -// NULL, +// 0, // OPEN_EXISTING, // FILE_FLAG_SEQUENTIAL_SCAN, // NULL); @@ -1507,8 +1624,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // // throw FileError(errorMessage); // } -// Loki::ScopeGuard dummy1 = Loki::MakeGuard(::CloseHandle, hFileIn); -// (void)dummy1; //silence warning "unused variable" +// LOKI_ON_BLOCK_EXIT2(::CloseHandle, hFileIn); // // // BY_HANDLE_FILE_INFORMATION infoFileIn = {}; @@ -1545,7 +1661,7 @@ 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, -// NULL, +// 0, // CREATE_NEW, // (infoFileIn.dwFileAttributes & validAttribs) | FILE_FLAG_SEQUENTIAL_SCAN, // NULL); @@ -1565,8 +1681,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // } // Loki::ScopeGuard guardTarget = Loki::MakeGuard(&removeFile, targetFile); //transactional behavior: guard just after opening target and before managing hFileOut // -// Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hFileOut); -// (void)dummy; //silence warning "unused variable" +// LOKI_ON_BLOCK_EXIT2(::CloseHandle, hFileOut); // // //#ifndef _MSC_VER @@ -1773,7 +1888,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // HANDLE hSparse = ::CreateFile(L"C:\\sparse.file", // GENERIC_READ | GENERIC_WRITE, //read access required for FSCTL_SET_COMPRESSION // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, -// NULL, +// 0, // CREATE_NEW, // FILE_FLAG_SEQUENTIAL_SCAN, // NULL); @@ -1800,19 +1915,20 @@ void rawCopyWinApi(const Zstring& sourceFile, //} #endif - +#ifdef FFS_LINUX void rawCopyStream(const Zstring& sourceFile, const Zstring& targetFile, - CallbackCopyFile* callback) //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting) + CallbackCopyFile* callback, + FileAttrib* sourceAttr) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting { Loki::ScopeGuard guardTarget = Loki::MakeGuard(&removeFile, targetFile); //transactional behavior: place guard before lifetime of FileOutput try { //open sourceFile for reading - FileInput fileIn(sourceFile); //throw (FileError) + FileInput fileIn(sourceFile); //throw FileError //create targetFile and open it for writing - FileOutput fileOut(targetFile, FileOutput::ACC_CREATE_NEW); //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting) + FileOutput fileOut(targetFile, FileOutput::ACC_CREATE_NEW); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting static boost::thread_specific_ptr> cpyBuf; if (!cpyBuf.get()) @@ -1823,35 +1939,55 @@ void rawCopyStream(const Zstring& sourceFile, UInt64 totalBytesTransferred; do { - const size_t bytesRead = fileIn.read(&buffer[0], buffer.size()); //throw (FileError) + const size_t bytesRead = fileIn.read(&buffer[0], buffer.size()); //throw FileError - fileOut.write(&buffer[0], bytesRead); //throw (FileError) + fileOut.write(&buffer[0], bytesRead); //throw FileError totalBytesTransferred += bytesRead; //invoke callback method to update progress indicators - if (callback != NULL) + if (callback) callback->updateCopyStatus(totalBytesTransferred); } while (!fileIn.eof()); } - catch(ErrorTargetExisting&) + catch (ErrorTargetExisting&) { guardTarget.Dismiss(); //don't delete file that existed previously! throw; } //adapt file modification time: - copyFileTimes(sourceFile, targetFile, true); //throw (FileError) + { + struct stat srcInfo = {}; + if (::stat(sourceFile.c_str(), &srcInfo) != 0) //read file attributes from source directory + throw FileError(_("Error reading file attributes:") + "\n\"" + sourceFile + "\"" + "\n\n" + getLastErrorFormatted()); + + if (sourceAttr) + { + sourceAttr->fileSize = UInt64(srcInfo.st_size); + sourceAttr->modificationTime = srcInfo.st_mtime; + } + + struct utimbuf newTimes = {}; + newTimes.actime = srcInfo.st_atime; + newTimes.modtime = srcInfo.st_mtime; + + //set new "last write time" + if (::utime(targetFile.c_str(), &newTimes) != 0) + throw FileError(_("Error changing modification time:") + "\n\"" + targetFile + "\"" + "\n\n" + getLastErrorFormatted()); + } guardTarget.Dismiss(); //target has been created successfully! } +#endif inline void copyFileImpl(const Zstring& sourceFile, const Zstring& targetFile, - CallbackCopyFile* callback) //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked) + CallbackCopyFile* callback, + FileAttrib* sourceAttr) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked { #ifdef FFS_WIN /* @@ -1867,21 +2003,22 @@ void copyFileImpl(const Zstring& sourceFile, SAMBA, ect. YES UNKNOWN! -> issues writing ADS to Samba, issues reading from NAS, error copying files having "blocked" state... ect. damn! */ - rawCopyWinApi(sourceFile, targetFile, callback); //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked) - //rawCopyWinOptimized(sourceFile, targetFile, callback); //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked) ->about 8% faster + rawCopyWinApi(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + //rawCopyWinOptimized(sourceFile, targetFile, callback); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked ->about 8% faster #elif defined FFS_LINUX - rawCopyStream(sourceFile, targetFile, callback); //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting) + rawCopyStream(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting #endif } } -void zen::copyFile(const Zstring& sourceFile, //throw (FileError: ErrorTargetPathMissing, ErrorFileLocked); +void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPathMissing, ErrorFileLocked const Zstring& targetFile, bool copyFilePermissions, bool transactionalCopy, - CallbackCopyFile* callback) + CallbackCopyFile* callback, + FileAttrib* sourceAttr) { if (transactionalCopy) { @@ -1891,7 +2028,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw (FileError: ErrorTargetPat //raw file copy try { - copyFileImpl(sourceFile, temporary, callback); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + copyFileImpl(sourceFile, temporary, callback, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked } catch (ErrorTargetExisting&) { @@ -1900,40 +2037,39 @@ void zen::copyFile(const Zstring& sourceFile, //throw (FileError: ErrorTargetPat temporary = createTempName(targetFile); //retry - copyFileImpl(sourceFile, temporary, callback); //throw FileError + copyFileImpl(sourceFile, temporary, callback, sourceAttr); //throw FileError } //have target file deleted (after read access on source and target has been confirmed) => allow for almost transactional overwrite - if (callback) callback->deleteTargetFile(targetFile); + if (callback) + callback->deleteTargetFile(targetFile); //rename temporary file: //perf: this call is REALLY expensive on unbuffered volumes! ~40% performance decrease on FAT USB stick! - renameFile(temporary, targetFile); //throw (FileError) + renameFile(temporary, targetFile); //throw FileError guardTempFile.Dismiss(); - - //perf: interestingly it is much faster to apply file times BEFORE renaming temporary! } else { //have target file deleted if (callback) callback->deleteTargetFile(targetFile); - copyFileImpl(sourceFile, targetFile, callback); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + copyFileImpl(sourceFile, targetFile, callback, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked } -/* - Note: non-transactional file copy solves at least four problems: - -> skydrive - doesn't allow for .ffs_tmp extension and returns ERROR_INVALID_PARAMETER - -> network renaming issues - -> allow for true delete before copy to handle low disk space problems - -> higher performance on non-buffered drives (e.g. usb sticks) -*/ + /* + Note: non-transactional file copy solves at least four problems: + -> skydrive - doesn't allow for .ffs_tmp extension and returns ERROR_INVALID_PARAMETER + -> network renaming issues + -> allow for true delete before copy to handle low disk space problems + -> higher performance on non-buffered drives (e.g. usb sticks) + */ //set file permissions if (copyFilePermissions) { Loki::ScopeGuard guardTargetFile = Loki::MakeGuard(&removeFile, targetFile); - copyObjectPermissions(sourceFile, targetFile, true); //throw (FileError) + copyObjectPermissions(sourceFile, targetFile, SYMLINK_FOLLOW); //throw FileError guardTargetFile.Dismiss(); //target has been created successfully! } } diff --git a/shared/file_handling.h b/shared/file_handling.h index bdd73bea..f1ed2d98 100644 --- a/shared/file_handling.h +++ b/shared/file_handling.h @@ -33,52 +33,55 @@ enum ResponseSame }; ResponseSame onSameVolume(const Zstring& folderLeft, const Zstring& folderRight); //throw() -void checkthis(const Zstring& folderLeft); //throw() +enum ProcSymlink +{ + SYMLINK_DIRECT, + SYMLINK_FOLLOW +}; -//copy file or directory create/last change date, -void copyFileTimes(const Zstring& sourceDir, const Zstring& targetDir, bool derefSymlinks); //throw (FileError) +Int64 getFileTime(const Zstring& filename, ProcSymlink procSl); //throw FileError +void setFileTime(const Zstring& filename, const Int64& modificationTime, ProcSymlink procSl); //throw FileError //symlink handling: always evaluate target -UInt64 getFilesize(const Zstring& filename); //throw (FileError) - +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 = NULL); //throw FileError //rename file or directory: no copying!!! -void renameFile(const Zstring& oldName, const Zstring& newName); //throw (FileError); +void renameFile(const Zstring& oldName, const Zstring& newName); //throw FileError; //move source to target; expectations: all super-directories of target exist //"ignoreExisting": if target already exists, source is deleted -void moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ignoreExisting, CallbackMoveFile* callback); //throw (FileError); +void moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ignoreExisting, CallbackMoveFile* callback); //throw FileError; //move source to target including subdirectories //"ignoreExisting": existing directories and files will be enriched -void moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback); //throw (FileError); +void moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback); //throw FileError; //creates superdirectories automatically: -void createDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions); //throw (FileError); -void createDirectory(const Zstring& directory); //throw (FileError); -> function overload avoids default parameter ambiguity issues! +void createDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions); //throw FileError; +void createDirectory(const Zstring& directory); //throw FileError; -> function overload avoids default parameter ambiguity issues! +struct FileAttrib +{ + UInt64 fileSize; + Int64 modificationTime; //size_t UTC compatible +}; -void copyFile(const Zstring& sourceFile, //throw (FileError: ErrorTargetPathMissing, ErrorFileLocked (Windows-only)); - const Zstring& targetFile, +void copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPathMissing, ErrorFileLocked (Windows-only) + const Zstring& targetFile, //symlink handling: dereference source bool copyFilePermissions, bool transactionalCopy, - CallbackCopyFile* callback); //may be NULL + CallbackCopyFile* callback, //may be NULL + FileAttrib* sourceAttr = NULL); //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"); -enum SymlinkType -{ - SYMLINK_TYPE_FILE, - SYMLINK_TYPE_DIR -}; -void copySymlink(const Zstring& sourceLink, const Zstring& targetLink, SymlinkType type, bool copyFilePermissions); //throw (FileError) - +void copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool copyFilePermissions); //throw FileError @@ -87,7 +90,8 @@ void copySymlink(const Zstring& sourceLink, const Zstring& targetLink, SymlinkTy struct CallbackRemoveDir { virtual ~CallbackRemoveDir() {} - virtual void notifyDeletion(const Zstring& currentObject) = 0; + virtual void notifyFileDeletion(const Zstring& filename) = 0; + virtual void notifyDirDeletion(const Zstring& dirname) = 0; }; @@ -101,7 +105,7 @@ struct CallbackCopyFile //callback functionality //may throw: //Linux: unconditionally - //Windows: first exception is swallowed, requestUiRefresh() is then called again where it may throw again and exception will propagate as expected + //Windows: first exception is swallowed, requestUiRefresh() is then called again where it should throw again and exception will propagate as expected virtual void updateCopyStatus(UInt64 totalBytesTransferred) = 0; }; diff --git a/shared/file_id.cpp b/shared/file_id.cpp index e6c016e7..198598b4 100644 --- a/shared/file_id.cpp +++ b/shared/file_id.cpp @@ -5,6 +5,7 @@ // ************************************************************************** #include "file_id.h" +#include "file_id_internal.h" #ifdef FFS_WIN #include //includes "windows.h" @@ -16,21 +17,8 @@ #endif -namespace -{ -template inline -std::string numberToBytes(T number) -{ - const char* rawBegin = reinterpret_cast(&number); - return std::string(rawBegin, rawBegin + sizeof(number)); -} -} - - std::string util::retrieveFileID(const Zstring& filename) { - std::string fileID; - #ifdef FFS_WIN //WARNING: CreateFile() is SLOW, while GetFileInformationByHandle() is cheap! //http://msdn.microsoft.com/en-us/library/aa363788(VS.85).aspx @@ -40,34 +28,27 @@ std::string util::retrieveFileID(const Zstring& filename) const HANDLE hFile = ::CreateFile(zen::applyLongPathPrefix(filename).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, + 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, //FILE_FLAG_BACKUP_SEMANTICS needed to open a directory NULL); if (hFile != INVALID_HANDLE_VALUE) { - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hFile); - (void)dummy; //silence warning "unused variable" + LOKI_ON_BLOCK_EXIT2(::CloseHandle(hFile)); BY_HANDLE_FILE_INFORMATION fileInfo = {}; if (::GetFileInformationByHandle(hFile, &fileInfo)) - { - fileID += numberToBytes(fileInfo.dwVolumeSerialNumber); - fileID += numberToBytes(fileInfo.nFileIndexHigh); - fileID += numberToBytes(fileInfo.nFileIndexLow); - } + return extractFileID(fileInfo); } #elif defined FFS_LINUX struct stat fileInfo = {}; if (::lstat(filename.c_str(), &fileInfo) == 0) //lstat() does not follow symlinks - { - fileID += numberToBytes(fileInfo.st_dev); - fileID += numberToBytes(fileInfo.st_ino); - } + return extractFileID(fileInfo); #endif - assert(!fileID.empty()); - return fileID; + + assert(false); + return std::string(); } diff --git a/shared/file_id_internal.h b/shared/file_id_internal.h new file mode 100644 index 00000000..a8a7042d --- /dev/null +++ b/shared/file_id_internal.h @@ -0,0 +1,48 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef FILE_ID_INTERNAL_HEADER_013287632486321493 +#define FILE_ID_INTERNAL_HEADER_013287632486321493 + +#include + +#ifdef FFS_WIN +#include //includes "windows.h" + +#elif defined FFS_LINUX +#include +#endif + +namespace +{ +template inline +std::string numberToBytes(T number) +{ + const char* rawBegin = reinterpret_cast(&number); + return std::string(rawBegin, rawBegin + sizeof(number)); +} + +#ifdef FFS_WIN +inline +std::string extractFileID(const BY_HANDLE_FILE_INFORMATION& fileInfo) +{ + return numberToBytes(fileInfo.dwVolumeSerialNumber) + + numberToBytes(fileInfo.nFileIndexHigh) + + numberToBytes(fileInfo.nFileIndexLow); +} +#elif defined FFS_LINUX +inline +std::string extractFileID(const struct stat& fileInfo) +{ + return numberToBytes(fileInfo.st_dev) + + numberToBytes(fileInfo.st_ino); +} +#endif + +} + + +#endif //FILE_ID_INTERNAL_HEADER_013287632486321493 diff --git a/shared/file_io.cpp b/shared/file_io.cpp index 2614ac06..59b78044 100644 --- a/shared/file_io.cpp +++ b/shared/file_io.cpp @@ -23,7 +23,7 @@ FileInput::FileInput(FileHandle handle, const Zstring& filename) : filename_(filename) {} -FileInput::FileInput(const Zstring& filename) : //throw (FileError, ErrorNotExisting) +FileInput::FileInput(const Zstring& filename) : //throw FileError, ErrorNotExisting eofReached(false), filename_(filename) { @@ -31,7 +31,7 @@ FileInput::FileInput(const Zstring& filename) : //throw (FileError, ErrorNotExi fileHandle = ::CreateFile(zen::applyLongPathPrefix(filename).c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //all shared modes are required to read open files that are shared by other applications - NULL, + 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, /* possible values: (Reference http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx#caching_behavior) @@ -112,7 +112,7 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number const size_t bytesRead = ::fread(buffer, 1, bytesToRead, fileHandle); if (::ferror(fileHandle) != 0) #endif - throw FileError(_("Error reading file:") + "\n\"" + filename_ + "\"" + "\n\n" + zen::getLastErrorFormatted()); + throw FileError(_("Error reading file:") + "\n\"" + filename_ + "\"" + "\n\n" + zen::getLastErrorFormatted() + " (r)"); #ifdef FFS_WIN if (bytesRead < bytesToRead) //falsify only! @@ -137,14 +137,19 @@ bool FileInput::eof() //end of file reached FileOutput::FileOutput(FileHandle handle, const Zstring& filename) : fileHandle(handle), filename_(filename) {} -FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw (FileError, ErrorTargetPathMissing, ErrorTargetExisting) +FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting filename_(filename) { #ifdef FFS_WIN fileHandle = ::CreateFile(zen::applyLongPathPrefix(filename).c_str(), - GENERIC_WRITE, + GENERIC_READ | GENERIC_WRITE, + /* http://msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx + quote: When an application creates a file across a network, it is better + to use GENERIC_READ | GENERIC_WRITE for dwDesiredAccess than to use GENERIC_WRITE alone. + The resulting code is faster, because the redirector can use the cache manager and send fewer SMBs with more data. + This combination also avoids an issue where writing to a file across a network can occasionally return ERROR_ACCESS_DENIED. */ FILE_SHARE_READ | FILE_SHARE_DELETE, //note: FILE_SHARE_DELETE is required to rename file while handle is open! - NULL, + 0, access == ACC_OVERWRITE ? CREATE_ALWAYS : CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); @@ -192,7 +197,7 @@ FileOutput::~FileOutput() } -void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw (FileError) +void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileError { #ifdef FFS_WIN DWORD bytesWritten = 0; diff --git a/shared/file_io.h b/shared/file_io.h index 6f87845b..76713e5b 100644 --- a/shared/file_io.h +++ b/shared/file_io.h @@ -29,11 +29,11 @@ typedef FILE* FileHandle; class FileInput { public: - FileInput(const Zstring& filename); //throw (FileError: ErrorNotExisting) + FileInput(const Zstring& filename); //throw FileError, ErrorNotExisting FileInput(FileHandle handle, const Zstring& filename); //takes ownership! ~FileInput(); - size_t read(void* buffer, size_t bytesToRead); //throw (FileError); returns actual number of bytes read + size_t read(void* buffer, size_t bytesToRead); //throw FileError; returns actual number of bytes read bool eof(); //end of file reached private: @@ -54,11 +54,11 @@ public: ACC_OVERWRITE, ACC_CREATE_NEW }; - FileOutput(const Zstring& filename, AccessFlag access); //throw (FileError: ErrorTargetPathMissing, ErrorTargetExisting) + FileOutput(const Zstring& filename, AccessFlag access); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting FileOutput(FileHandle handle, const Zstring& filename); //takes ownership! ~FileOutput(); - void write(const void* buffer, size_t bytesToWrite); //throw (FileError) + void write(const void* buffer, size_t bytesToWrite); //throw FileError private: FileOutput(const FileOutput&); diff --git a/shared/file_traverser.cpp b/shared/file_traverser.cpp index 595b2768..eb79b0e7 100644 --- a/shared/file_traverser.cpp +++ b/shared/file_traverser.cpp @@ -15,6 +15,8 @@ #include "long_path_prefix.h" #include "dst_hack.h" #include "file_update_handle.h" +#include "dll_loader.h" +#include "FindFilePlus/find_file_plus.h" #elif defined FFS_LINUX #include @@ -54,16 +56,6 @@ bool tryReportingError(Command cmd, zen::TraverseCallback& callback) #ifdef FFS_WIN -inline -zen::Int64 filetimeToTimeT(const FILETIME& lastWriteTime) -{ - //convert UTC FILETIME to ANSI C format (number of seconds since Jan. 1st 1970 UTC) - zen::Int64 writeTimeLong = to(zen::UInt64(lastWriteTime.dwLowDateTime, lastWriteTime.dwHighDateTime) / 10000000U); //reduce precision to 1 second (FILETIME has unit 10^-7 s) - writeTimeLong -= zen::Int64(3054539008UL, 2); //timeshift between ansi C time and FILETIME in seconds == 11644473600s - return writeTimeLong; -} - - inline bool setWin32FileInformationFromSymlink(const Zstring& linkName, zen::TraverseCallback::FileInfo& output) { @@ -71,25 +63,30 @@ bool setWin32FileInformationFromSymlink(const Zstring& linkName, zen::TraverseCa HANDLE hFile = ::CreateFile(zen::applyLongPathPrefix(linkName).c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) return false; - - Loki::ScopeGuard dummy = Loki::MakeGuard(::CloseHandle, hFile); - (void)dummy; //silence warning "unused variable" + LOKI_ON_BLOCK_EXIT2(::CloseHandle(hFile)); BY_HANDLE_FILE_INFORMATION fileInfoByHandle = {}; if (!::GetFileInformationByHandle(hFile, &fileInfoByHandle)) return false; //write output - output.lastWriteTimeRaw = filetimeToTimeT(fileInfoByHandle.ftLastWriteTime); + output.lastWriteTimeRaw = toTimeT(fileInfoByHandle.ftLastWriteTime); output.fileSize = zen::UInt64(fileInfoByHandle.nFileSizeLow, fileInfoByHandle.nFileSizeHigh); return true; } + +/* +warn_static("finish") + util::DllFun openDir (findplus::getDllName(), findplus::openDirFuncName); + util::DllFun readDir (findplus::getDllName(), findplus::readDirFuncName); + util::DllFun closeDir(findplus::getDllName(), findplus::closeDirFuncName); +*/ #endif } @@ -102,8 +99,8 @@ public: : isFatFileSystem(dst::isFatDrive(baseDirectory)) #endif { - //format base directory name #ifdef FFS_WIN + //format base directory name const Zstring& directoryFormatted = baseDirectory; #elif defined FFS_LINUX @@ -143,57 +140,75 @@ private: return true; }, sink); - #ifdef FFS_WIN +/* //ensure directoryPf ends with backslash const Zstring& directoryPf = directory.EndsWith(FILE_NAME_SEPARATOR) ? directory : directory + FILE_NAME_SEPARATOR; - WIN32_FIND_DATA fileInfo = {}; - HANDLE searchHandle = INVALID_HANDLE_VALUE; + FindHandle searchHandle = NULL; tryReportingError([&](std::wstring& errorMsg) -> bool { - searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryPf + L'*').c_str(), &fileInfo); + searchHandle = this->openDir(applyLongPathPrefix(directoryPf).c_str()); //no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH - if (searchHandle == INVALID_HANDLE_VALUE) + if (searchHandle == NULL) { - const DWORD lastError = ::GetLastError(); - if (lastError == ERROR_FILE_NOT_FOUND) - return true; //fine: empty directory + //const DWORD lastError = ::GetLastError(); + //if (lastError == ERROR_FILE_NOT_FOUND) -> actually NOT okay, even for an empty directory this should not occur (., ..) + //return true; //fine: empty directory //else: we have a problem... report it: - errorMsg = _("Error traversing directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted(lastError); + errorMsg = _("Error traversing directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted(); return false; } return true; }, sink); - if (searchHandle == INVALID_HANDLE_VALUE) + if (searchHandle == NULL) return; //empty dir or ignore error + LOKI_ON_BLOCK_EXIT2(this->closeDir(searchHandle)); - Loki::ScopeGuard dummy = Loki::MakeGuard(::FindClose, searchHandle); - (void)dummy; //silence warning "unused variable" - - do + FileInformation fileInfo = {}; + for (;;) { + bool moreData = false; + tryReportingError([&](std::wstring& errorMsg) -> bool + { + if (!this->readDir(searchHandle, fileInfo)) + { + if (::GetLastError() == ERROR_NO_MORE_FILES) //this is fine + return true; + + //else we have a problem... report it: + errorMsg = _("Error traversing directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted(); + return false; + } + + moreData = true; + return true; + }, sink); + if (!moreData) //no more items or ignore error + return; + + //don't return "." and ".." - const Zchar* const shortName = fileInfo.cFileName; + const Zchar* const shortName = fileInfo.shortName; if (shortName[0] == L'.' && (shortName[1] == L'\0' || (shortName[1] == L'.' && shortName[2] == L'\0'))) continue; const Zstring& fullName = directoryPf + shortName; - const bool isSymbolicLink = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + const bool isSymbolicLink = (fileInfo.fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; if (isSymbolicLink && !followSymlinks) //evaluate symlink directly { TraverseCallback::SymlinkInfo details; try { - details.targetPath = getSymlinkRawTargetString(fullName); //throw (FileError) + details.targetPath = getSymlinkRawTargetString(fullName); //throw FileError } catch (FileError& e) { @@ -203,11 +218,11 @@ private: #endif } - details.lastWriteTimeRaw = filetimeToTimeT(fileInfo.ftLastWriteTime); - details.dirLink = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows + details.lastWriteTimeRaw = toTimeT(fileInfo.lastWriteTime); + details.dirLink = (fileInfo.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows sink.onSymlink(shortName, fullName, details); } - else if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!) + else if (fileInfo.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!) { const TraverseCallback::ReturnValDir rv = sink.onDir(shortName, fullName); switch (rv.returnCode) @@ -238,45 +253,155 @@ private: //####################################### DST hack ########################################### if (isFatFileSystem) { - const dst::RawTime rawTime(fileInfo.ftCreationTime, fileInfo.ftLastWriteTime); + const dst::RawTime rawTime(fileInfo.creationTime, fileInfo.lastWriteTime); if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error) - fileInfo.ftLastWriteTime = dst::fatDecodeUtcTime(rawTime); //return real UTC time; throw (std::runtime_error) + fileInfo.lastWriteTime = dst::fatDecodeUtcTime(rawTime); //return real UTC time; throw (std::runtime_error) else - markForDstHack.push_back(std::make_pair(fullName, fileInfo.ftLastWriteTime)); + markForDstHack.push_back(std::make_pair(fullName, fileInfo.lastWriteTime)); } //####################################### DST hack ########################################### - details.lastWriteTimeRaw = filetimeToTimeT(fileInfo.ftLastWriteTime); - details.fileSize = zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + + details.lastWriteTimeRaw = toTimeT(fileInfo.lastWriteTime); + details.fileSize = fileInfo.fileSize.QuadPart; } sink.onFile(shortName, fullName, details); } } - while ([&]() -> bool - { - bool moreData = false; +*/ - tryReportingError([&](std::wstring& errorMsg) -> bool - { - if (!::FindNextFile(searchHandle, // handle to search - &fileInfo)) // pointer to structure for data on found file + + + //ensure directoryPf ends with backslash + const Zstring& directoryPf = directory.EndsWith(FILE_NAME_SEPARATOR) ? + directory : + directory + FILE_NAME_SEPARATOR; + WIN32_FIND_DATA fileInfo = {}; + + HANDLE searchHandle = INVALID_HANDLE_VALUE; + tryReportingError([&](std::wstring& errorMsg) -> bool { - if (::GetLastError() == ERROR_NO_MORE_FILES) //this is fine - return true; + searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryPf + L'*').c_str(), &fileInfo); + //no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH - //else we have a problem... report it: - errorMsg = _("Error traversing directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted(); - return false; - } + if (searchHandle == INVALID_HANDLE_VALUE) + { + //const DWORD lastError = ::GetLastError(); + //if (lastError == ERROR_FILE_NOT_FOUND) -> actually NOT okay, even for an empty directory this should not occur (., ..) + //return true; //fine: empty directory - moreData = true; - return true; - }, sink); + //else: we have a problem... report it: + errorMsg = _("Error traversing directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted(); + return false; + } + return true; + }, sink); + + if (searchHandle == INVALID_HANDLE_VALUE) + return; //empty dir or ignore error + LOKI_ON_BLOCK_EXIT2(::FindClose(searchHandle)); - return moreData; - }()); + do + { + //don't return "." and ".." + const Zchar* const shortName = fileInfo.cFileName; + if (shortName[0] == L'.' && + (shortName[1] == L'\0' || (shortName[1] == L'.' && shortName[2] == L'\0'))) + continue; + const Zstring& fullName = directoryPf + shortName; + + const bool isSymbolicLink = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + + if (isSymbolicLink && !followSymlinks) //evaluate symlink directly + { + TraverseCallback::SymlinkInfo details; + try + { + details.targetPath = getSymlinkRawTargetString(fullName); //throw FileError + } + catch (FileError& e) + { + (void)e; + #ifndef NDEBUG //show broken symlink / access errors in debug build! + sink.onError(e.msg()); + #endif + } + + details.lastWriteTimeRaw = toTimeT(fileInfo.ftLastWriteTime); + details.dirLink = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows + sink.onSymlink(shortName, fullName, details); + } + else if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!) + { + const TraverseCallback::ReturnValDir rv = sink.onDir(shortName, fullName); + switch (rv.returnCode) + { + case TraverseCallback::ReturnValDir::TRAVERSING_DIR_IGNORE: + break; + + case TraverseCallback::ReturnValDir::TRAVERSING_DIR_CONTINUE: + traverse(fullName, *rv.subDirCb, level + 1); + break; + } + } + else //a file or symlink that is followed... + { + TraverseCallback::FileInfo details; + + if (isSymbolicLink) //dereference symlinks! + { + if (!setWin32FileInformationFromSymlink(fullName, details)) + { + //broken symlink... + details.lastWriteTimeRaw = 0; //we are not interested in the modification time of the link + details.fileSize = 0U; + } + } + else + { + //####################################### DST hack ########################################### + if (isFatFileSystem) + { + const dst::RawTime rawTime(fileInfo.ftCreationTime, fileInfo.ftLastWriteTime); + + if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error) + fileInfo.ftLastWriteTime = dst::fatDecodeUtcTime(rawTime); //return real UTC time; throw (std::runtime_error) + else + markForDstHack.push_back(std::make_pair(fullName, fileInfo.ftLastWriteTime)); + } + //####################################### DST hack ########################################### + details.lastWriteTimeRaw = toTimeT(fileInfo.ftLastWriteTime); + details.fileSize = zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + } + + sink.onFile(shortName, fullName, details); + } + } + while ([&]() -> bool + { + bool moreData = false; + + tryReportingError([&](std::wstring& errorMsg) -> bool + { + if (!::FindNextFile(searchHandle, // handle to search + &fileInfo)) // pointer to structure for data on found file + { + if (::GetLastError() == ERROR_NO_MORE_FILES) //this is fine + return true; + + //else we have a problem... report it: + errorMsg = _("Error traversing directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted(); + return false; + } + + moreData = true; + return true; + }, sink); + + return moreData; + }()); #elif defined FFS_LINUX DIR* dirObj = NULL; @@ -291,9 +416,7 @@ private: return true; }, sink)) return; - - Loki::ScopeGuard dummy = Loki::MakeGuard(::closedir, dirObj); //never close NULL handles! -> crash - (void)dummy; //silence warning "unused variable" + LOKI_ON_BLOCK_EXIT2(::closedir(dirObj)); //never close NULL handles! -> crash while (true) { @@ -357,7 +480,7 @@ private: TraverseCallback::SymlinkInfo details; try { - details.targetPath = getSymlinkRawTargetString(fullName); //throw (FileError) + details.targetPath = getSymlinkRawTargetString(fullName); //throw FileError } catch (FileError& e) { @@ -418,12 +541,12 @@ 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_WRITE, //just FILE_WRITE_ATTRIBUTES may not be enough for some NAS shares! + GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); diff --git a/shared/file_traverser.h b/shared/file_traverser.h index aa9dffad..7da86c3a 100644 --- a/shared/file_traverser.h +++ b/shared/file_traverser.h @@ -44,7 +44,7 @@ public: ReturnValDir(Loki::Int2Type) : returnCode(TRAVERSING_DIR_IGNORE), subDirCb(NULL) {} ReturnValDir(Loki::Int2Type, TraverseCallback& subDirCallback) : returnCode(TRAVERSING_DIR_CONTINUE), subDirCb(&subDirCallback) {} - const ReturnValueEnh returnCode; + ReturnValueEnh returnCode; TraverseCallback* subDirCb; }; diff --git a/shared/fixed_list.h b/shared/fixed_list.h new file mode 100644 index 00000000..97976149 --- /dev/null +++ b/shared/fixed_list.h @@ -0,0 +1,142 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef PTR_WRAP_012384670856841394535 +#define PTR_WRAP_012384670856841394535 + +#include + +namespace zen +{ +//std::list(C++11) compatible class supporting inplace element construction for non-copyable/movable types +//may be replaced by C++11 std::list when available +template +class FixedList +{ + struct Node + { + Node() : next(NULL) {} + template Node(A && a) : next(NULL), val(a) {} + template Node(A && a, B && b) : next(NULL), val(a, b) {} + template Node(A && a, B && b, C && c) : next(NULL), val(a, b, c) {} + template Node(A && a, B && b, C && c, D && d) : next(NULL), val(a, b, c, d) {} + template Node(A && a, B && b, C && c, D && d, E && e) : next(NULL), val(a, b, c, d, e) {} + template Node(A && a, B && b, C && c, D && d, E && e, F && f) : next(NULL), val(a, b, c, d, e, f) {} + + Node* next; //singly linked list is sufficient + T val; + }; + +public: + FixedList() : + first(NULL), + lastInsert(NULL), + sz(0) {} + + ~FixedList() { clear(); } + + template + class ListIterator : public std::iterator + { + public: + ListIterator(NodeT* it = NULL) : 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); } + U& operator* () { return iter->val; } + U* operator->() { return &iter->val; } + private: + NodeT* iter; + }; + + typedef T value_type; + typedef ListIterator iterator; + typedef ListIterator const_iterator; + typedef T& reference; + typedef const T& const_reference; + + iterator begin() { return first; } + iterator end() { return iterator(); } + + const_iterator begin() const { return first; } + const_iterator end () const { return const_iterator(); } + + reference front() { return first->val; } + const_reference front() const { return first->val; } + + reference& back() { return lastInsert->val; } + const_reference& back() const { return lastInsert->val; } + + void emplace_back() { pushNode(new Node); } + template void emplace_back(A && a) { pushNode(new Node(std::forward(a))); } + template void emplace_back(A && a, B && b) { pushNode(new Node(std::forward(a), std::forward(b))); } + template void emplace_back(A && a, B && b, C && c) { pushNode(new Node(std::forward(a), std::forward(b), std::forward(c))); } + template void emplace_back(A && a, B && b, C && c, D && d) { pushNode(new Node(std::forward(a), std::forward(b), std::forward(c), std::forward(d))); } + template void emplace_back(A && a, B && b, C && c, D && d, E && e) { pushNode(new Node(std::forward(a), std::forward(b), std::forward(c), std::forward(d), std::forward(e))); } + template void emplace_back(A && a, B && b, C && c, D && d, E && e, F && f) { pushNode(new Node(std::forward(a), std::forward(b), std::forward(c), std::forward(d), std::forward(e), std::forward(f))); } + + template + void remove_if(Predicate pred) + { + Node* prev = NULL; + for (auto ptr = first; ptr;) + if (pred(ptr->val)) + { + Node* tmp = ptr->next; + deleteNode(ptr); + if (prev) + prev->next = ptr = tmp; + else + first = ptr = tmp; + if (tmp == NULL) + lastInsert = prev; + } + else + { + prev = ptr; + ptr = ptr->next; + } + } + + void clear() { remove_if([](T&) { return true; }); } + bool empty() const { return first == NULL; } + size_t size() const { return sz; } + +private: + FixedList(const FixedList&); + FixedList& operator=(const FixedList&); + + void pushNode(Node* newNode) + { + ++sz; + if (lastInsert == NULL) + { + assert(first == NULL); + first = lastInsert = newNode; + } + else + { + assert(lastInsert->next == NULL); + lastInsert->next = newNode; + lastInsert = newNode; + } + } + + void deleteNode(Node* oldNode) + { + assert(sz > 0); + --sz; + delete oldNode; + } + + Node* first; + Node* lastInsert; //point to last insertion; required by emplace_back() + size_t sz; +}; +} + + +#endif //PTR_WRAP_012384670856841394535 diff --git a/shared/folder_history_box.cpp b/shared/folder_history_box.cpp new file mode 100644 index 00000000..f787e2cb --- /dev/null +++ b/shared/folder_history_box.cpp @@ -0,0 +1,139 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#include "folder_history_box.h" +#include "resolve_path.h" +#include + +using namespace zen; + +FolderHistoryBox::FolderHistoryBox(wxWindow* parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + int n, + const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) : + wxComboBox(parent, id, value, pos, size, n, choices, style, validator, name) +#if wxCHECK_VERSION(2, 9, 1) + , dropDownShown(false) +#endif +{ + //##################################### + /*##*/ SetMinSize(wxSize(150, -1)); //## workaround yet another wxWidgets bug: default minimum size is much too large for a wxComboBox + //##################################### + + //register key event to enable item deletion + Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(FolderHistoryBox::OnKeyEvent), NULL, this); + + //refresh history list on mouse click + Connect(wxEVT_LEFT_DOWN, wxEventHandler(FolderHistoryBox::OnUpdateList), NULL, this); + + Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(FolderHistoryBox::OnSelection), NULL, this); + +#if wxCHECK_VERSION(2, 9, 1) + Connect(wxEVT_COMMAND_COMBOBOX_DROPDOWN, wxCommandEventHandler(FolderHistoryBox::OnShowDropDown), NULL, this); + Connect(wxEVT_COMMAND_COMBOBOX_CLOSEUP, wxCommandEventHandler(FolderHistoryBox::OnHideDropDown), NULL, this); +#endif +} + + +#if wxCHECK_VERSION(2, 9, 1) +void FolderHistoryBox::OnShowDropDown(wxCommandEvent& event) +{ + dropDownShown = true; + event.Skip(); +} + + +void FolderHistoryBox::OnHideDropDown(wxCommandEvent& event) +{ + dropDownShown = false; + event.Skip(); +} +#endif + + +void FolderHistoryBox::update() +{ + std::list dirList; + + //add some aliases to allow user changing to volume name and back, if possible +#ifdef FFS_WIN + const Zstring activePath = toZ(GetValue()); + std::vector aliases = getDirectoryAliases(activePath); + dirList.insert(dirList.end(), aliases.begin(), aliases.end()); +#endif + + if (sharedHistory_.get()) + { + auto tmp = sharedHistory_->getList(); + //std::sort(tmp.begin(), tmp.end(), LessFilename()); + + if (!dirList.empty() && !tmp.empty()) + dirList.push_back(FolderHistory::lineSeparator()); + + dirList.insert(dirList.end(), tmp.begin(), tmp.end()); + } + //########################################################################################### + + + //it may be a little lame to update the list on each mouse-button click, but it should be working and we dont't have to manipulate wxComboBox internals + const wxString oldVal = this->GetValue(); + + Clear(); + std::for_each(dirList.begin(), dirList.end(), + [&](const Zstring& dir) { this->Append(toWx(dir)); }); + + this->SetSelection(wxNOT_FOUND); //don't select anything + this->SetValue(oldVal); //but preserve main text! +} + + +void FolderHistoryBox::OnSelection(wxCommandEvent& event) +{ + event.Skip(); +} + + +void FolderHistoryBox::OnKeyEvent(wxKeyEvent& event) +{ + const int keyCode = event.GetKeyCode(); + if (keyCode == WXK_DELETE || keyCode == WXK_NUMPAD_DELETE) + { + //try to delete the currently selected config history item + int pos = this->GetCurrentSelection(); + if (0 <= pos && pos < static_cast(this->GetCount()) && +#if wxCHECK_VERSION(2, 9, 1) + dropDownShown) +#else + //what a mess...: + (GetValue() != GetString(pos) || //avoid problems when a character shall be deleted instead of list item + GetValue() == wxEmptyString)) //exception: always allow removing empty entry +#endif + { + //save old (selected) value: deletion seems to have influence on this + const wxString currentVal = this->GetValue(); + //this->SetSelection(wxNOT_FOUND); + + //delete selected row + if (sharedHistory_.get()) + sharedHistory_->delItem(toZ(GetString(pos))); + SetString(pos, wxString()); //in contrast to Delete(), this one does not kill the drop-down list and gives a nice visual feedback! + //Delete(pos); + + //(re-)set value + this->SetValue(currentVal); + + //eat up key event + return; + } + } + event.Skip(); +} diff --git a/shared/folder_history_box.h b/shared/folder_history_box.h new file mode 100644 index 00000000..3b4fd57e --- /dev/null +++ b/shared/folder_history_box.h @@ -0,0 +1,109 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef CUSTOMCOMBOBOX_H_INCLUDED +#define CUSTOMCOMBOBOX_H_INCLUDED + +#include +#include +#include "zstring.h" +#include "string_conv.h" +#include "stl_tools.h" + +//combobox with history function + functionality to delete items (DEL) +using namespace zen; + + +class FolderHistory +{ +public: + FolderHistory() : maxSize_(0) {} + + FolderHistory(const std::vector& dirnames, size_t maxSize) : + maxSize_(maxSize), + dirnames_(dirnames) + { + if (dirnames_.size() > maxSize_) //keep maximal size of history list + dirnames_.resize(maxSize_); + } + + const std::vector& getList() const { return dirnames_; } + + static const Zstring lineSeparator() { return Zstr("---------------------------------------------------------------------------------------------------------------"); } + + void addItem(const Zstring& dirname) + { + if (dirname.empty() || dirname == lineSeparator()) + return; + + Zstring nameTmp = dirname; + zen::trim(nameTmp); + + //insert new folder or put it to the front if already existing + auto iter = std::find_if(dirnames_.begin(), dirnames_.end(), + [&](const Zstring& entry) { return ::EqualFilename()(entry, nameTmp); }); + + if (iter != dirnames_.end()) + dirnames_.erase(iter); + dirnames_.insert(dirnames_.begin(), nameTmp); + + if (dirnames_.size() > maxSize_) //keep maximal size of history list + dirnames_.resize(maxSize_); + } + + void delItem(const Zstring& dirname) { vector_remove_if(dirnames_, [&](const Zstring& entry) { return ::EqualFilename()(entry, dirname); }); } + +private: + + size_t maxSize_; + std::vector dirnames_; +}; + + +class FolderHistoryBox : public wxComboBox +{ +public: + FolderHistoryBox(wxWindow* parent, + wxWindowID id, + const wxString& value = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + int n = 0, + const wxString choices[] = NULL, + long style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxComboBoxNameStr); + + void init(const std::shared_ptr& sharedHistory) { sharedHistory_ = sharedHistory; } + + void setValue(const wxString& dirname) + { + SetSelection(wxNOT_FOUND); + SetValue(dirname); + update(); //required for Linux to ensure the dropdown is shown as being populated + } + + // GetValue + +private: + void OnKeyEvent(wxKeyEvent& event); + void OnSelection(wxCommandEvent& event); + void OnUpdateList(wxEvent& event) { update(); event.Skip(); } + + void update(); + +#if wxCHECK_VERSION(2, 9, 1) + void OnShowDropDown(wxCommandEvent& event); + void OnHideDropDown(wxCommandEvent& event); + + bool dropDownShown; +#endif + + std::shared_ptr sharedHistory_; +}; + + +#endif // CUSTOMCOMBOBOX_H_INCLUDED diff --git a/shared/global_func.h b/shared/global_func.h index 861e2081..b3c13a24 100644 --- a/shared/global_func.h +++ b/shared/global_func.h @@ -7,106 +7,21 @@ #ifndef GLOBALFUNCTIONS_H_INCLUDED #define GLOBALFUNCTIONS_H_INCLUDED -#include -#include -#include -#include -#include +#include namespace common { //little rounding function -inline int round(double d) { return static_cast(d < 0 ? d - 0.5 : d + 0.5); } - -//absolute value -template inline T abs(const T& d) { return d < 0 ? -d : d; } - -size_t getDigitCount(size_t number); //count number of digits - -//Note: the following lines are a performance optimization for deleting elements from a vector: linear runtime at most! -template -void removeRowsFromVector(const std::set& rowsToRemove, std::vector& grid); - -//enhanced binary search template: returns an iterator -template -ForwardIterator custom_binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp = std::less()); -} - - -//############################################################################ - - - - - - - - - - - - - - - - - - - - - -//---------------Inline Implementation--------------------------------------------------- inline -size_t common::getDigitCount(size_t number) //count number of digits -{ - return number == 0 ? 1 : static_cast(::log10(static_cast(number))) + 1; -} - - -//Note: the following lines are a performance optimization for deleting elements from a vector: linear runtime at most! -template -void common::removeRowsFromVector(const std::set& rowsToRemove, std::vector& grid) -{ - if (rowsToRemove.empty()) - return; - - std::set::const_iterator rowToSkipIndex = rowsToRemove.begin(); - size_t rowToSkip = *rowToSkipIndex; - - if (rowToSkip >= grid.size()) - return; - - typename std::vector::iterator insertPos = grid.begin() + rowToSkip; - - for (size_t i = rowToSkip; i < grid.size(); ++i) - { - if (i != rowToSkip) - { - *insertPos = grid[i]; - ++insertPos; - } - else - { - ++rowToSkipIndex; - if (rowToSkipIndex != rowsToRemove.end()) - rowToSkip = *rowToSkipIndex; - } - } - grid.erase(insertPos, grid.end()); -} +int round(double d) { return static_cast(d < 0 ? d - 0.5 : d + 0.5); } +//absolute value +template inline +T abs(const T& d) { return d < 0 ? -d : d; } -//enhanced binary search template: returns an iterator -template inline -ForwardIterator common::custom_binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp) -{ - first = std::lower_bound(first, last, value, comp); - if (first != last && !comp(value, *first)) - return first; - else - return last; +size_t getDigitCount(size_t number) { return number == 0 ? 1 : static_cast(std::log10(static_cast(number))) + 1; } //count number of digits } -#endif // GLOBALFUNCTIONS_H_INCLUDED +#endif //GLOBALFUNCTIONS_H_INCLUDED diff --git a/shared/help_provider.cpp b/shared/help_provider.cpp index 7eb043cd..666482eb 100644 --- a/shared/help_provider.cpp +++ b/shared/help_provider.cpp @@ -18,9 +18,9 @@ public: { controller.Initialize(zen::getResourceDir() + #ifdef FFS_WIN - wxT("FreeFileSync.chm")); + L"FreeFileSync.chm"); #elif defined FFS_LINUX - wxT("Help/FreeFileSync.hhp")); + L"Help/FreeFileSync.hhp"); #endif } diff --git a/shared/i18n.cpp b/shared/i18n.cpp index f22dca56..a5fb32dd 100644 --- a/shared/i18n.cpp +++ b/shared/i18n.cpp @@ -3,6 +3,7 @@ using namespace zen; + namespace { std::unique_ptr globalHandler; diff --git a/shared/image_tools.h b/shared/image_tools.h new file mode 100644 index 00000000..e78e7ced --- /dev/null +++ b/shared/image_tools.h @@ -0,0 +1,157 @@ +// ************************************************************************** +// * 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) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef IMAGE_TOOLS_HEADER_45782456427634254 +#define IMAGE_TOOLS_HEADER_45782456427634254 + +#include +#include +#include + + +namespace zen +{ +wxBitmap greyScale(const wxBitmap& bmp); //greyscale + brightness adaption +wxBitmap layOver(const wxBitmap& foreground, const wxBitmap& background); //merge + +void move(wxImage& img, int up, int left = 0); +void adjustBrightness(wxImage& img, int targetLevel); +double getAvgBrightness(const wxImage& img); //in [0, 255] +void brighten(wxImage& img, int level); //level: delta per channel in points + +bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs); //pixel-wise equality (respecting alpha channel) + + + + + + + + + + + + + + + + + +//################################### implementation ################################### +inline +void move(wxImage& img, int up, int left) +{ + img = img.GetSubImage(wxRect(std::max(0, left), std::max(0, up), img.GetWidth() - abs(left), img.GetHeight() - abs(up))); + img.Resize(wxSize(img.GetWidth() + abs(left), img.GetHeight() + abs(up)), wxPoint(-std::min(0, left), -std::min(0, up))); +} + + +inline +wxBitmap greyScale(const wxBitmap& bmp) +{ + wxImage output = bmp.ConvertToImage().ConvertToGreyscale(1.0/3, 1.0/3, 1.0/3); //treat all channels equally! + //wxImage output = bmp.ConvertToImage().ConvertToGreyscale(); + adjustBrightness(output, 170); + return output; +} + + +inline +double getAvgBrightness(const wxImage& img) +{ + const int pixelCount = img.GetWidth() * img.GetHeight(); + auto pixBegin = img.GetData(); + if (pixBegin) + { + auto pixEnd = pixBegin + 3 * pixelCount; //RGB + + if (img.HasAlpha()) + { + const unsigned char* alphaFirst = img.GetAlpha(); + + //calculate average weighted by alpha channel + double dividend = 0; + for (auto iter = pixBegin; iter != pixEnd; ++iter) + dividend += *iter * static_cast(alphaFirst[(iter - pixBegin) / 3]); + + const int divisor = 3.0 * std::accumulate(alphaFirst, alphaFirst + pixelCount, 0.0); + + return dividend / divisor; + } + else + return std::accumulate(pixBegin, pixEnd, 0.0) / (3.0 * pixelCount); + } + return 0; +} + + +inline +void brighten(wxImage& img, int level) +{ + const int pixelCount = img.GetWidth() * img.GetHeight(); + auto pixBegin = img.GetData(); + if (pixBegin) + { + auto pixEnd = pixBegin + 3 * pixelCount; //RGB + if (level > 0) + std::for_each(pixBegin, pixEnd, [&](unsigned char& c) { c = std::min(255, c + level); }); + else + std::for_each(pixBegin, pixEnd, [&](unsigned char& c) { c = std::max(0, c + level); }); + } +} + + +inline +void adjustBrightness(wxImage& img, int targetLevel) +{ + brighten(img, targetLevel - getAvgBrightness(img)); +} + + +inline +wxBitmap layOver(const wxBitmap& foreground, const wxBitmap& background) +{ + wxBitmap output = background; + { + wxMemoryDC dc; + dc.SelectObject(output); + dc.DrawBitmap(foreground, 0, 0, true); + dc.SelectObject(wxNullBitmap); + } + return output; +} + + +inline +bool isEqual(const wxBitmap& lhs, const wxBitmap& rhs) +{ + if (lhs.IsOk() != rhs.IsOk()) + return false; + if (!lhs.IsOk()) + return true; + + const int pixelCount = lhs.GetWidth() * lhs.GetHeight(); + if (pixelCount != rhs.GetWidth() * rhs.GetHeight()) + return false; + + wxImage imLhs = lhs.ConvertToImage(); + wxImage imRhs = rhs.ConvertToImage(); + + if (imLhs.HasAlpha() != imRhs.HasAlpha()) + return false; + + if (imLhs.HasAlpha()) + { + if (!std::equal(imLhs.GetAlpha(), imLhs.GetAlpha() + pixelCount, imRhs.GetAlpha())) + return false; + } + + return std::equal(imLhs.GetData(), imLhs.GetData() + pixelCount * 3, imRhs.GetData()); +} +} + + +#endif //IMAGE_TOOLS_HEADER_45782456427634254 diff --git a/shared/int64.h b/shared/int64.h index 61ef1716..cfd3e3d1 100644 --- a/shared/int64.h +++ b/shared/int64.h @@ -120,7 +120,6 @@ inline Int64 operator<<(const Int64& lhs, int rhs) { return Int64(lhs) <<= rhs; inline Int64 operator>>(const Int64& lhs, int rhs) { return Int64(lhs) >>= rhs; } - class UInt64 { struct DummyClass { operator size_t() { return 0U; } }; @@ -201,6 +200,28 @@ inline UInt64 operator>>(const UInt64& lhs, int rhs) { return UInt64(lhs) >>= rh template <> inline UInt64 to(Int64 number) { checkRange(number.value); return UInt64(number.value); } template <> inline Int64 to(UInt64 number) { checkRange(number.value); return Int64(number.value); } + + +#ifdef FFS_WIN +//convert FILETIME (number of 100-nanosecond intervals since January 1, 1601 UTC) +// to time_t (number of seconds since Jan. 1st 1970 UTC) +// +//FAT32 time is preserved exactly: FAT32 -> toTimeT -> tofiletime -> FAT32 +inline +Int64 toTimeT(const FILETIME& ft) +{ + return to(UInt64(ft.dwLowDateTime, ft.dwHighDateTime) / 10000000U) - Int64(3054539008UL, 2); + //timeshift between ansi C time and FILETIME in seconds == 11644473600s +} + +inline +FILETIME tofiletime(const Int64& utcTime) +{ + const UInt64 fileTimeLong = to(utcTime + Int64(3054539008UL, 2)) * 10000000U; + const FILETIME output = { fileTimeLong.getLo(), fileTimeLong.getHi() }; + return output; +} +#endif } diff --git a/shared/localization.cpp b/shared/localization.cpp index 66b2d97b..73aa5b72 100644 --- a/shared/localization.cpp +++ b/shared/localization.cpp @@ -69,7 +69,7 @@ private: Translation transMapping; //map original text |-> translation TranslationPlural transMappingPl; - std::auto_ptr pluralParser; + std::unique_ptr pluralParser; wxLanguage langId_; }; @@ -385,7 +385,7 @@ void zen::setLanguage(int language) //handle RTL swapping: we need wxWidgets to do this - static std::auto_ptr dummy; + static std::unique_ptr dummy; dummy.reset(); //avoid global locale lifetime overlap! wxWidgets cannot handle this and will crash! dummy.reset(new CustomLocale(languageFile.empty() ? wxLANGUAGE_ENGLISH : language)); diff --git a/shared/loki/AbstractFactory.h b/shared/loki/AbstractFactory.h index 9a30583b..615652bd 100644 --- a/shared/loki/AbstractFactory.h +++ b/shared/loki/AbstractFactory.h @@ -170,8 +170,8 @@ class AbstractFact, class TList = typename AbstractFact::ProductList > class ConcreteFactory - : public GenLinearHierarchy< - typename TL::Reverse::Result, Creator, AbstractFact> + : public GenLinearHierarchy < + typename TL::Reverse::Result, Creator, AbstractFact > { public: typedef typename AbstractFact::ProductList ProductList; diff --git a/shared/loki/AssocVector.h b/shared/loki/AssocVector.h index ad43d152..7f259281 100644 --- a/shared/loki/AssocVector.h +++ b/shared/loki/AssocVector.h @@ -182,8 +182,8 @@ public: //http://developer.apple.com/documentation/DeveloperTools/gcc-3.3/libstdc++/23_containers/howto.html#4 iterator insert(iterator pos, const value_type& val) { - if( (pos == begin() || this->operator()(*(pos-1),val)) && - (pos == end() || this->operator()(val, *pos)) ) + if ( (pos == begin() || this->operator()(*(pos - 1), val)) && + (pos == end() || this->operator()(val, *pos)) ) { return Base::insert(pos, val); } diff --git a/shared/loki/CachedFactory.h b/shared/loki/CachedFactory.h index 567b035c..dc5a76ae 100644 --- a/shared/loki/CachedFactory.h +++ b/shared/loki/CachedFactory.h @@ -81,7 +81,7 @@ protected: AbstractProduct* release(ProductReturn& pProduct) { AbstractProduct* pPointer(pProduct); - pProduct=NULL; + pProduct = NULL; return pPointer; } const char* name() {return "pointer";} @@ -172,9 +172,9 @@ private: { using namespace std; clock_t currentTime = clock(); - D( cout << "currentTime = " << currentTime<< endl; ) - D( cout << "currentTime - lastUpdate = " << currentTime - lastUpdate<< endl; ) - if(currentTime - lastUpdate > timeValidity) + D( cout << "currentTime = " << currentTime << endl; ) + D( cout << "currentTime - lastUpdate = " << currentTime - lastUpdate << endl; ) + if (currentTime - lastUpdate > timeValidity) { m_vTimes.clear(); D( cout << " is less than time validity " << timeValidity; ) @@ -213,7 +213,7 @@ protected: bool canCreate() { cleanVector(); - if(m_vTimes.size()>maxCreation) + if (m_vTimes.size() > maxCreation) throw Exception(); else return true; @@ -233,10 +233,10 @@ public: // No more than maxCreation within byTime milliseconds void setRate(unsigned maxCreation, unsigned byTime) { - assert(byTime>0); + assert(byTime > 0); this->maxCreation = maxCreation; this->timeValidity = static_cast(byTime * CLOCKS_PER_SEC / 1000); - D( std::cout << "Setting no more than "<< maxCreation <<" creation within " << this->timeValidity <<" ms"<< std::endl; ) + D( std::cout << "Setting no more than " << maxCreation << " creation within " << this->timeValidity << " ms" << std::endl; ) } }; @@ -262,7 +262,7 @@ protected: bool canCreate() { - return !(created>=maxCreation); + return !(created >= maxCreation); } void onCreate() @@ -279,9 +279,9 @@ public: // set the creation max amount void setMaxCreation(unsigned maxCreation) { - assert(maxCreation>0); + assert(maxCreation > 0); this->maxCreation = maxCreation; - D( std::cout << "Setting no more than " << maxCreation <<" creation" << std::endl; ) + D( std::cout << "Setting no more than " << maxCreation << " creation" << std::endl; ) } }; @@ -324,9 +324,9 @@ protected: assert(!m_mHitCount.empty()); // inserting the swapped pair into a multimap SwappedHitMap copyMap; - for(HitMapItr itr = m_mHitCount.begin(); itr != m_mHitCount.end(); ++itr) + for (HitMapItr itr = m_mHitCount.begin(); itr != m_mHitCount.end(); ++itr) copyMap.insert(SwappedPair((*itr).second, (*itr).first)); - if((*copyMap.rbegin()).first == 0) // the higher score is 0 ... + if ((*copyMap.rbegin()).first == 0) // the higher score is 0 ... throw EvictionException(); // there is no key evict return (*copyMap.begin()).second; } @@ -381,7 +381,7 @@ protected: // this function is implemented in Cache and redirected // to the Storage Policy - virtual void remove(DT const key)=0; + virtual void remove(DT const key) = 0; // LRU Eviction policy void evict() @@ -422,7 +422,7 @@ private: updateCounter(const DT& key): key_(key) {} void operator()(T x) { - x.second = (x.first == key_ ? (x.second >> 1) | ( 1 << ((sizeof(ST)-1)*8) ) : x.second >> 1); + x.second = (x.first == key_ ? (x.second >> 1) | ( 1 << ((sizeof(ST) - 1) * 8) ) : x.second >> 1); D( std::cout << x.second << std::endl; ) } const DT& key_; @@ -461,7 +461,7 @@ protected: // this function is implemented in Cache and redirected // to the Storage Policy - virtual void remove(DT const key)=0; + virtual void remove(DT const key) = 0; // LRU with Aging Eviction policy void evict() @@ -515,15 +515,15 @@ protected: } // Implemented in Cache and redirected to the Storage Policy - virtual void remove(DT const key)=0; + virtual void remove(DT const key) = 0; // Random Eviction policy void evict() { - if(m_vKeys.empty()) + if (m_vKeys.empty()) throw EvictionException(); - size_type random = static_cast((m_vKeys.size()*rand())/(static_cast(RAND_MAX) + 1)); - remove(*(m_vKeys.begin()+random)); + size_type random = static_cast((m_vKeys.size() * rand()) / (static_cast(RAND_MAX) + 1)); + remove(*(m_vKeys.begin() + random)); } const char* name() {return "random";} }; @@ -592,9 +592,9 @@ protected: cout << "## + Currently allocated : " << allocated << endl; cout << "## + Currently out : " << out << endl; cout << "############################" << endl; - if(fetched!=0) + if (fetched != 0) { - cout << "## Overall efficiency " << 100*double(hit)/fetched <<"%"<< endl; + cout << "## Overall efficiency " << 100 * double(hit) / fetched << "%" << endl; cout << "############################" << endl; } cout << endl; @@ -629,7 +629,7 @@ public: unsigned getMissed() {return fetched - hit;} unsigned getAllocated() {return allocated;} unsigned getOut() {return out;} - unsigned getDestroyed() {return created-allocated;} + unsigned getDestroyed() {return created - allocated;} }; /////////////////////////////////////////////////////////////////////////// @@ -712,7 +712,7 @@ private: AbstractProduct* const getPointerToObjectInContainer(ObjVector& entry) { - if(entry.empty()) // No object available + if (entry.empty()) // No object available { // the object will be created in the calling function. // It has to be created in the calling function because of @@ -723,7 +723,7 @@ private: { // returning the found object AbstractProduct* pObject(entry.back()); - assert(pObject!=NULL); + assert(pObject != NULL); entry.pop_back(); return pObject; } @@ -731,9 +731,9 @@ private: bool shouldCreateObject(AbstractProduct* const pProduct) { - if(pProduct!=NULL) // object already exists + if (pProduct != NULL) // object already exists return false; - if(CP::canCreate()==false) // Are we allowed to Create ? + if (CP::canCreate() == false) // Are we allowed to Create ? EP::evict(); // calling Eviction Policy to clean up return true; } @@ -797,16 +797,16 @@ protected: virtual void remove(AbstractProduct* const pProduct) { typename FetchedObjToKeyMap::iterator fetchedItr = providedObjects.find(pProduct); - if(fetchedItr!=providedObjects.end()) // object is unreleased. + if (fetchedItr != providedObjects.end()) // object is unreleased. throw CacheException(); bool productRemoved = false; typename KeyToObjVectorMap::iterator objVectorItr; typename ObjVector::iterator objItr; - for(objVectorItr=fromKeyToObjVector.begin(); objVectorItr!=fromKeyToObjVector.end(); ++objVectorItr) + for (objVectorItr = fromKeyToObjVector.begin(); objVectorItr != fromKeyToObjVector.end(); ++objVectorItr) { ObjVector& v((*objVectorItr).second); objItr = remove_if(v.begin(), v.end(), std::bind2nd(std::equal_to(), pProduct)); - if(objItr != v.end()) // we found the vector containing pProduct and removed it + if (objItr != v.end()) // we found the vector containing pProduct and removed it { onDestroy(pProduct); // warning policies we are about to destroy an object v.erase(objItr, v.end()); // real removing @@ -814,7 +814,7 @@ protected: break; } } - if(productRemoved==false) + if (productRemoved == false) throw CacheException(); // the product is not in the cache ?! delete pProduct; // deleting it } @@ -833,14 +833,14 @@ public: for_each(fromKeyToObjVector.begin(), fromKeyToObjVector.end(), deleteVectorObjects< typename KeyToObjVectorMap::value_type >() ); - if(!providedObjects.empty()) + if (!providedObjects.empty()) { // The factory is responsible for the creation and destruction of objects. // If objects are out during the destruction of the Factory : deleting anyway. // This might not be a good idea. But throwing an exception in a destructor is // considered as a bad pratice and asserting might be too much. // What to do ? Leaking memory or corrupting in use pointers ? hmm... - D( cout << "====>> Cache destructor : deleting "<< providedObjects.size()<<" in use objects <<====" << endl << endl; ) + D( cout << "====>> Cache destructor : deleting " << providedObjects.size() << " in use objects <<====" << endl << endl; ) for_each(providedObjects.begin(), providedObjects.end(), deleteMapKeys< typename FetchedObjToKeyMap::value_type >() ); @@ -878,7 +878,7 @@ public: { MyKey key(id); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { pProduct = factory.CreateObject(key.id); onCreate(pProduct); @@ -891,11 +891,11 @@ public: ProductReturn CreateObject(const IdentifierType& id, Parm1 p1) { - MyKey key(id,p1); + MyKey key(id, p1); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1); + pProduct = factory.CreateObject(key.id, key.p1); onCreate(pProduct); } onFetch(pProduct); @@ -906,11 +906,11 @@ public: ProductReturn CreateObject(const IdentifierType& id, Parm1 p1, Parm2 p2) { - MyKey key(id,p1,p2); + MyKey key(id, p1, p2); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2); + pProduct = factory.CreateObject(key.id, key.p1, key.p2); onCreate(pProduct); } onFetch(pProduct); @@ -921,11 +921,11 @@ public: ProductReturn CreateObject(const IdentifierType& id, Parm1 p1, Parm2 p2, Parm3 p3) { - MyKey key(id,p1,p2,p3); + MyKey key(id, p1, p2, p3); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3); onCreate(pProduct); } onFetch(pProduct); @@ -936,12 +936,12 @@ public: ProductReturn CreateObject(const IdentifierType& id, Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) { - MyKey key(id,p1,p2,p3,p4); + MyKey key(id, p1, p2, p3, p4); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4); onCreate(pProduct); } onFetch(pProduct); @@ -952,12 +952,12 @@ public: ProductReturn CreateObject(const IdentifierType& id, Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) { - MyKey key(id,p1,p2,p3,p4,p5); + MyKey key(id, p1, p2, p3, p4, p5); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5); onCreate(pProduct); } onFetch(pProduct); @@ -969,12 +969,12 @@ public: Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6) { - MyKey key(id,p1,p2,p3,p4,p5,p6); + MyKey key(id, p1, p2, p3, p4, p5, p6); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6); onCreate(pProduct); } onFetch(pProduct); @@ -986,12 +986,12 @@ public: Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6, Parm7 p7 ) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7); onCreate(pProduct); } onFetch(pProduct); @@ -1003,12 +1003,12 @@ public: Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6, Parm7 p7, Parm8 p8) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7, p8); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7,key.p8); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7, key.p8); onCreate(pProduct); } onFetch(pProduct); @@ -1020,12 +1020,12 @@ public: Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7, p8, p9); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7, key.p8, key.p9); onCreate(pProduct); } onFetch(pProduct); @@ -1035,14 +1035,14 @@ public: ProductReturn CreateObject(const IdentifierType& id, Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, - Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9,Parm10 p10) + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7, key.p8, key.p9, key.p10); onCreate(pProduct); } onFetch(pProduct); @@ -1055,12 +1055,12 @@ public: Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7, key.p8, key.p9, key.p10, key.p11); onCreate(pProduct); } onFetch(pProduct); @@ -1073,12 +1073,12 @@ public: Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, Parm12 p12) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7, key.p8, key.p9, key.p10, key.p11, key.p12); onCreate(pProduct); } onFetch(pProduct); @@ -1091,13 +1091,13 @@ public: Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, Parm12 p12, Parm13 p13) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 - ,key.p13); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7, key.p8, key.p9, key.p10, key.p11, key.p12 + , key.p13); onCreate(pProduct); } onFetch(pProduct); @@ -1110,13 +1110,13 @@ public: Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, Parm12 p12, Parm13 p13, Parm14 p14) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 - ,key.p13,key.p14); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7, key.p8, key.p9, key.p10, key.p11, key.p12 + , key.p13, key.p14); onCreate(pProduct); } onFetch(pProduct); @@ -1129,13 +1129,13 @@ public: Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, Parm12 p12, Parm13 p13, Parm14 p14, Parm15 p15) { - MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15); + MyKey key(id, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); AbstractProduct* pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); - if(shouldCreateObject(pProduct)) + if (shouldCreateObject(pProduct)) { - pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 - ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 - ,key.p13,key.p14,key.p15); + pProduct = factory.CreateObject(key.id, key.p1, key.p2, key.p3 + , key.p4, key.p5, key.p6, key.p7, key.p8, key.p9, key.p10, key.p11, key.p12 + , key.p13, key.p14, key.p15); onCreate(pProduct); } onFetch(pProduct); @@ -1153,7 +1153,7 @@ public: { AbstractProduct* pProduct(NP::release(object)); typename FetchedObjToKeyMap::iterator itr = providedObjects.find(pProduct); - if(itr == providedObjects.end()) + if (itr == providedObjects.end()) throw CacheException(); onRelease(pProduct); ReleaseObjectFromContainer(getContainerFromKey((*itr).second), pProduct); diff --git a/shared/loki/Factory.h b/shared/loki/Factory.h index abf4ab3b..bf31afc5 100644 --- a/shared/loki/Factory.h +++ b/shared/loki/Factory.h @@ -140,25 +140,25 @@ struct FactoryImpl virtual AP* CreateObject(const Id& id ) = 0; }; template -struct FactoryImpl > +struct FactoryImpl > : public FactoryImplBase { typedef typename TypeTraits::ParameterType Parm1; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1 ) = 0; + virtual AP* CreateObject(const Id& id, Parm1 ) = 0; }; -template +template struct FactoryImpl > : public FactoryImplBase { typedef typename TypeTraits::ParameterType Parm1; typedef typename TypeTraits::ParameterType Parm2; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2 ) = 0; + virtual AP* CreateObject(const Id& id, Parm1, Parm2 ) = 0; }; -template +template struct FactoryImpl > : public FactoryImplBase { @@ -166,10 +166,10 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm2; typedef typename TypeTraits::ParameterType Parm3; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3 ) = 0; + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3 ) = 0; }; -template +template struct FactoryImpl > : public FactoryImplBase { @@ -178,11 +178,11 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm3; typedef typename TypeTraits::ParameterType Parm4; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4 ) = 0; + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4 ) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5 > struct FactoryImpl > : public FactoryImplBase { @@ -192,12 +192,12 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm4; typedef typename TypeTraits::ParameterType Parm5; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5 ) = 0; + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5 ) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6 > struct FactoryImpl > : public FactoryImplBase { @@ -208,14 +208,14 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm5; typedef typename TypeTraits::ParameterType Parm6; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, Parm6 ) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7 > struct FactoryImpl > : public FactoryImplBase { @@ -227,14 +227,14 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm6; typedef typename TypeTraits::ParameterType Parm7; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, Parm7 ) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8 > struct FactoryImpl > : public FactoryImplBase { @@ -247,14 +247,14 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm7; typedef typename TypeTraits::ParameterType Parm8; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, Parm7, Parm8) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9 > struct FactoryImpl > : public FactoryImplBase { @@ -268,14 +268,14 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm8; typedef typename TypeTraits::ParameterType Parm9; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, Parm7, Parm8, Parm9) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10 > struct FactoryImpl > : public FactoryImplBase { @@ -290,15 +290,15 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm9; typedef typename TypeTraits::ParameterType Parm10; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10) + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11 > struct FactoryImpl > : public FactoryImplBase { @@ -314,16 +314,16 @@ struct FactoryImpl > typedef typename TypeTraits::ParameterType Parm10; typedef typename TypeTraits::ParameterType Parm11; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10, + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10, Parm11) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11, typename P12 > struct FactoryImpl > : public FactoryImplBase { @@ -340,16 +340,16 @@ struct FactoryImpl::ParameterType Parm11; typedef typename TypeTraits::ParameterType Parm12; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10, - Parm11,Parm12) + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10, + Parm11, Parm12) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11, typename P12, typename P13 > struct FactoryImpl > : public FactoryImplBase { @@ -367,16 +367,16 @@ struct FactoryImpl::ParameterType Parm12; typedef typename TypeTraits::ParameterType Parm13; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10, - Parm11,Parm12,Parm13) + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10, + Parm11, Parm12, Parm13) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11, typename P12, typename P13, typename P14 > struct FactoryImpl > : public FactoryImplBase { @@ -395,16 +395,16 @@ struct FactoryImpl::ParameterType Parm13; typedef typename TypeTraits::ParameterType Parm14; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm8,Parm10, - Parm11,Parm12,Parm13,Parm14) + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm8, Parm10, + Parm11, Parm12, Parm13, Parm14) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15 > struct FactoryImpl > : public FactoryImplBase { @@ -424,34 +424,34 @@ struct FactoryImpl::ParameterType Parm14; typedef typename TypeTraits::ParameterType Parm15; virtual ~FactoryImpl() {} - virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10, - Parm11,Parm12,Parm13,Parm14,Parm15 ) + virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10, + Parm11, Parm12, Parm13, Parm14, Parm15 ) = 0; }; #ifndef LOKI_DISABLE_TYPELIST_MACROS template -struct FactoryImpl +struct FactoryImpl : public FactoryImplBase { typedef typename TypeTraits::ParameterType Parm1; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1 ) = 0; +virtual AP* CreateObject(const Id& id, Parm1 ) = 0; }; -template +template struct FactoryImpl : public FactoryImplBase { typedef typename TypeTraits::ParameterType Parm1; typedef typename TypeTraits::ParameterType Parm2; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2 ) = 0; +virtual AP* CreateObject(const Id& id, Parm1, Parm2 ) = 0; }; -template +template struct FactoryImpl : public FactoryImplBase { @@ -459,10 +459,10 @@ struct FactoryImpl typedef typename TypeTraits::ParameterType Parm2; typedef typename TypeTraits::ParameterType Parm3; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3 ) = 0; +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3 ) = 0; }; -template +template struct FactoryImpl : public FactoryImplBase { @@ -471,11 +471,11 @@ struct FactoryImpl typedef typename TypeTraits::ParameterType Parm3; typedef typename TypeTraits::ParameterType Parm4; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4 ) = 0; +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4 ) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5 > struct FactoryImpl : public FactoryImplBase { @@ -485,12 +485,12 @@ struct FactoryImpl typedef typename TypeTraits::ParameterType Parm4; typedef typename TypeTraits::ParameterType Parm5; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5 ) = 0; +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5 ) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6 > struct FactoryImpl : public FactoryImplBase { @@ -501,14 +501,14 @@ struct FactoryImpl typedef typename TypeTraits::ParameterType Parm5; typedef typename TypeTraits::ParameterType Parm6; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, Parm6 ) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7 > struct FactoryImpl : public FactoryImplBase { @@ -520,14 +520,14 @@ struct FactoryImpl typedef typename TypeTraits::ParameterType Parm6; typedef typename TypeTraits::ParameterType Parm7; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, Parm7 ) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8 > struct FactoryImpl : public FactoryImplBase { @@ -540,14 +540,14 @@ struct FactoryImpl typedef typename TypeTraits::ParameterType Parm7; typedef typename TypeTraits::ParameterType Parm8; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, Parm7, Parm8) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9 > struct FactoryImpl : public FactoryImplBase { @@ -561,14 +561,14 @@ struct FactoryImpl::ParameterType Parm8; typedef typename TypeTraits::ParameterType Parm9; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, Parm7, Parm8, Parm9) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10 > struct FactoryImpl : public FactoryImplBase { @@ -583,15 +583,15 @@ struct FactoryImpl::ParameterType Parm9; typedef typename TypeTraits::ParameterType Parm10; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10) +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11 > struct FactoryImpl : public FactoryImplBase { @@ -607,16 +607,16 @@ struct FactoryImpl::ParameterType Parm10; typedef typename TypeTraits::ParameterType Parm11; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10, +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10, Parm11) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11, typename P12 > struct FactoryImpl : public FactoryImplBase { @@ -633,16 +633,16 @@ struct FactoryImpl::ParameterType Parm11; typedef typename TypeTraits::ParameterType Parm12; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10, - Parm11,Parm12) +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10, + Parm11, Parm12) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11, typename P12, typename P13 > struct FactoryImpl : public FactoryImplBase { @@ -660,16 +660,16 @@ struct FactoryImpl::ParameterType Parm12; typedef typename TypeTraits::ParameterType Parm13; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10, - Parm11,Parm12,Parm13) +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10, + Parm11, Parm12, Parm13) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11, typename P12, typename P13, typename P14 > struct FactoryImpl : public FactoryImplBase { @@ -688,16 +688,16 @@ struct FactoryImpl::ParameterType Parm13; typedef typename TypeTraits::ParameterType Parm14; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm8,Parm10, - Parm11,Parm12,Parm13,Parm14) +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm8, Parm10, + Parm11, Parm12, Parm13, Parm14) = 0; }; -template +template < typename AP, typename Id, + typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7, typename P8, typename P9, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15 > struct FactoryImpl : public FactoryImplBase { @@ -717,9 +717,9 @@ struct FactoryImpl::ParameterType Parm14; typedef typename TypeTraits::ParameterType Parm15; virtual ~FactoryImpl() {} -virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, - Parm6, Parm7, Parm8, Parm9,Parm10, - Parm11,Parm12,Parm13,Parm14,Parm15 ) +virtual AP* CreateObject(const Id& id, Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9, Parm10, + Parm11, Parm12, Parm13, Parm14, Parm15 ) = 0; }; @@ -809,8 +809,8 @@ public: std::vector RegisteredIds() { std::vector ids; - for(typename IdToProductMap::iterator it = associations_.begin(); - it != associations_.end(); ++it) + for (typename IdToProductMap::iterator it = associations_.begin(); + it != associations_.end(); ++it) { ids.push_back(it->first); } @@ -839,7 +839,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2 ); + return (i->second)( p1, p2 ); return this->OnUnknownType(id); } @@ -848,7 +848,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3 ); + return (i->second)( p1, p2, p3 ); return this->OnUnknownType(id); } @@ -857,7 +857,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4 ); + return (i->second)( p1, p2, p3, p4 ); return this->OnUnknownType(id); } @@ -866,7 +866,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5 ); + return (i->second)( p1, p2, p3, p4, p5 ); return this->OnUnknownType(id); } @@ -876,7 +876,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6 ); + return (i->second)( p1, p2, p3, p4, p5, p6 ); return this->OnUnknownType(id); } @@ -886,7 +886,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7 ); return this->OnUnknownType(id); } @@ -896,7 +896,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7, p8 ); return this->OnUnknownType(id); } @@ -906,16 +906,16 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7, p8, p9 ); return this->OnUnknownType(id); } AbstractProduct* CreateObject(const IdentifierType& id, Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, - Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9,Parm10 p10) + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10) { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10 ); return this->OnUnknownType(id); } @@ -926,7 +926,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11 ); return this->OnUnknownType(id); } @@ -937,7 +937,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12 ); return this->OnUnknownType(id); } @@ -948,7 +948,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13 ); return this->OnUnknownType(id); } @@ -959,7 +959,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14 ); return this->OnUnknownType(id); } @@ -970,7 +970,7 @@ public: { typename IdToProductMap::iterator i = associations_.find(id); if (i != associations_.end()) - return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15 ); + return (i->second)( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15 ); return this->OnUnknownType(id); } diff --git a/shared/loki/Function.h b/shared/loki/Function.h index f2badfe9..5f388d3c 100644 --- a/shared/loki/Function.h +++ b/shared/loki/Function.h @@ -54,7 +54,7 @@ struct Function : public Functor Function(const Function& func) : FBase() { - if( !func.empty()) + if ( !func.empty()) FBase::operator=(func); } @@ -62,14 +62,14 @@ Function(const Function& func) : FBase() template Function(Function func) : FBase() { - if(!func.empty()) + if (!func.empty()) FBase::operator=(func); } // clear by '= 0' Function(const int i) : FBase() { - if(i==0) + if (i == 0) FBase::clear(); else throw std::runtime_error("Loki::Function(const int i): i!=0"); @@ -79,7 +79,7 @@ template Function(Func func) : FBase(func) {} template -Function(const Host& host, const Func& func) : FBase(host,func) {} +Function(const Host& host, const Func& func) : FBase(host, func) {} }; @@ -89,38 +89,38 @@ Function(const Host& host, const Func& func) : FBase(host,func) {} //////////////////////////////////////////////////////////////////////////////// #define LOKI_FUNCTION_BODY \ - \ - Function() : FBase() {} \ - \ - Function(const Function& func) : FBase() \ - { \ - if( !func.empty()) \ - FBase::operator=(func); \ - } \ - \ - Function(const int i) : FBase() \ - { \ - if(i==0) \ - FBase::clear(); \ - else \ - throw std::runtime_error( \ - "Loki::Function(const int i): i!=0"); \ - } \ - \ - template \ - Function(Func func) : FBase(func) {} \ - \ - template \ - Function(const Host& host, const Func& func): FBase(host,func) {} + \ + Function() : FBase() {} \ + \ + Function(const Function& func) : FBase() \ + { \ + if( !func.empty()) \ + FBase::operator=(func); \ + } \ + \ + Function(const int i) : FBase() \ + { \ + if(i==0) \ + FBase::clear(); \ + else \ + throw std::runtime_error( \ + "Loki::Function(const int i): i!=0"); \ + } \ + \ + template \ + Function(Func func) : FBase(func) {} \ + \ + template \ + Function(const Host& host, const Func& func): FBase(host,func) {} #define LOKI_FUNCTION_R2_CTOR_BODY \ - \ - : FBase() \ - { \ - if(!func.empty()) \ - FBase::operator=(func); \ - } + \ + : FBase() \ + { \ + if(!func.empty()) \ + FBase::operator=(func); \ + } //////////////////////////////////////////////////////////////////////////////// @@ -143,225 +143,225 @@ struct Function<> // or define LOKI_ENABLE_FUNCTION }; -template +template struct Function : public Loki::Functor > { typedef Functor > FBase; - template + template Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06 > +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07 > +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07, class P08 > +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07, class Q08 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07, class P08, class P09 > +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07, class Q08, class Q09 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07, class P08, class P09, class P10 > +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07, class Q08, class Q09, class Q10 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07, class P08, class P09, class P10, + class P11 > +struct Function +: public Functor > { - typedef Functor >FBase; + typedef Functor >FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07, class Q08, class Q09, class Q10, + class Q11 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07, class P08, class P09, class P10, + class P11, class P12 > +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07, class Q08, class Q09, class Q10, + class Q11, class Q12 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07, class P08, class P09, class P10, + class P11, class P12, class P13 > +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07, class Q08, class Q09, class Q10, + class Q11, class Q12, class Q13 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07, class P08, class P09, class P10, + class P11, class P12, class P13, class P14 > +struct Function +: public Functor > { - typedef Functor > FBase; - template - Function(Function func) + typedef Functor > FBase; + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07, class Q08, class Q09, class Q10, + class Q11, class Q12, class Q13, class Q14 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY }; -template -struct Function -: public Functor > +template < class R, class P01, class P02, class P03, class P04, class P05, + class P06, class P07, class P08, class P09, class P10, + class P11, class P12, class P13, class P14, class P15 > +struct Function +: public Functor > { - typedef Functor > FBase; + typedef Functor > FBase; - template - Function(Function func) + template < class R2, class Q01, class Q02, class Q03, class Q04, class Q05, + class Q06, class Q07, class Q08, class Q09, class Q10, + class Q11, class Q12, class Q13, class Q14, class Q15 > + Function(Function func) LOKI_FUNCTION_R2_CTOR_BODY LOKI_FUNCTION_BODY diff --git a/shared/loki/Functor.h b/shared/loki/Functor.h index a03f87c8..664af077 100644 --- a/shared/loki/Functor.h +++ b/shared/loki/Functor.h @@ -122,8 +122,8 @@ struct FunctorImplBase // Specializations of FunctorImpl for up to 15 parameters follow //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL> +template < typename R, class TList, + template class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL > class FunctorImpl; //////////////////////////////////////////////////////////////////////////////// @@ -160,8 +160,8 @@ public: // Specialization for 2 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> +template < typename R, typename P1, typename P2, + template class ThreadingModel > class FunctorImpl, ThreadingModel> : public Private::FunctorImplBase { @@ -177,8 +177,8 @@ public: // Specialization for 3 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> +template < typename R, typename P1, typename P2, typename P3, + template class ThreadingModel > class FunctorImpl, ThreadingModel> : public Private::FunctorImplBase { @@ -195,8 +195,8 @@ public: // Specialization for 4 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> +template < typename R, typename P1, typename P2, typename P3, typename P4, + template class ThreadingModel > class FunctorImpl, ThreadingModel> : public Private::FunctorImplBase { @@ -214,9 +214,9 @@ public: // Specialization for 5 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> + template class ThreadingModel > class FunctorImpl, ThreadingModel> : public Private::FunctorImplBase { @@ -235,9 +235,9 @@ public: // Specialization for 6 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> + template class ThreadingModel > class FunctorImpl, ThreadingModel> : public Private::FunctorImplBase { @@ -257,9 +257,9 @@ public: // Specialization for 7 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> + template class ThreadingModel > class FunctorImpl, ThreadingModel> : public Private::FunctorImplBase { @@ -281,11 +281,11 @@ public: // Specialization for 8 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl, - ThreadingModel> + template class ThreadingModel > +class FunctorImpl < R, Seq, + ThreadingModel > : public Private::FunctorImplBase { public: @@ -307,11 +307,11 @@ public: // Specialization for 9 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl, - ThreadingModel> + template class ThreadingModel > +class FunctorImpl < R, Seq, + ThreadingModel > : public Private::FunctorImplBase { public: @@ -334,12 +334,12 @@ public: // Specialization for 10 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl, - ThreadingModel> + template class ThreadingModel > +class FunctorImpl < R, Seq, + ThreadingModel > : public Private::FunctorImplBase { public: @@ -363,13 +363,13 @@ public: // Specialization for 11 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl class ThreadingModel > +class FunctorImpl < R, Seq, - ThreadingModel> + ThreadingModel > : public Private::FunctorImplBase { public: @@ -394,13 +394,13 @@ public: // Specialization for 12 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl class ThreadingModel > +class FunctorImpl < R, Seq, - ThreadingModel> + ThreadingModel > : public Private::FunctorImplBase { public: @@ -426,13 +426,13 @@ public: // Specialization for 13 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl class ThreadingModel > +class FunctorImpl < R, Seq, - ThreadingModel> + ThreadingModel > : public Private::FunctorImplBase { public: @@ -459,14 +459,14 @@ public: // Specialization for 14 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl, - ThreadingModel> + template class ThreadingModel > +class FunctorImpl < R, + Seq < P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, + P14 > , + ThreadingModel > : public Private::FunctorImplBase { public: @@ -494,14 +494,14 @@ public: // Specialization for 15 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl, - ThreadingModel> + typename P15, template class ThreadingModel > +class FunctorImpl < R, + Seq < P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, + P14, P15 > , + ThreadingModel > : public Private::FunctorImplBase { public: @@ -548,8 +548,8 @@ public: // Specialization for 2 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> +template < typename R, typename P1, typename P2, + template class ThreadingModel > class FunctorImpl : public Private::FunctorImplBase { @@ -565,8 +565,8 @@ public: // Specialization for 3 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> +template < typename R, typename P1, typename P2, typename P3, + template class ThreadingModel > class FunctorImpl : public Private::FunctorImplBase { @@ -583,8 +583,8 @@ public: // Specialization for 4 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> +template < typename R, typename P1, typename P2, typename P3, typename P4, + template class ThreadingModel > class FunctorImpl : public Private::FunctorImplBase { @@ -602,9 +602,9 @@ public: // Specialization for 5 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> + template class ThreadingModel > class FunctorImpl : public Private::FunctorImplBase { @@ -623,9 +623,9 @@ public: // Specialization for 6 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> + template class ThreadingModel > class FunctorImpl : public Private::FunctorImplBase { @@ -645,9 +645,9 @@ public: // Specialization for 7 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> + template class ThreadingModel > class FunctorImpl : public Private::FunctorImplBase { @@ -669,11 +669,11 @@ public: // Specialization for 8 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl + template class ThreadingModel > +class FunctorImpl < R, LOKI_TYPELIST_8(P1, P2, P3, P4, P5, P6, P7, P8), + ThreadingModel > : public Private::FunctorImplBase { public: @@ -695,11 +695,11 @@ public: // Specialization for 9 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl + template class ThreadingModel > +class FunctorImpl < R, LOKI_TYPELIST_9(P1, P2, P3, P4, P5, P6, P7, P8, P9), + ThreadingModel > : public Private::FunctorImplBase { public: @@ -722,12 +722,12 @@ public: // Specialization for 10 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl + template class ThreadingModel > +class FunctorImpl < R, LOKI_TYPELIST_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10), + ThreadingModel > : public Private::FunctorImplBase { public: @@ -751,13 +751,13 @@ public: // Specialization for 11 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl class ThreadingModel > +class FunctorImpl < R, LOKI_TYPELIST_11(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11), - ThreadingModel> + ThreadingModel > : public Private::FunctorImplBase { public: @@ -782,13 +782,13 @@ public: // Specialization for 12 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl class ThreadingModel > +class FunctorImpl < R, LOKI_TYPELIST_12(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12), - ThreadingModel> + ThreadingModel > : public Private::FunctorImplBase { public: @@ -814,13 +814,13 @@ public: // Specialization for 13 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl class ThreadingModel > +class FunctorImpl < R, LOKI_TYPELIST_13(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13), - ThreadingModel> + ThreadingModel > : public Private::FunctorImplBase { public: @@ -847,14 +847,14 @@ public: // Specialization for 14 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl class ThreadingModel > +class FunctorImpl < R, LOKI_TYPELIST_14(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14), - ThreadingModel> + ThreadingModel > : public Private::FunctorImplBase { public: @@ -882,14 +882,14 @@ public: // Specialization for 15 parameters //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel> -class FunctorImpl class ThreadingModel > +class FunctorImpl < R, LOKI_TYPELIST_15(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15), - ThreadingModel> + ThreadingModel > : public Private::FunctorImplBase { public: @@ -957,13 +957,13 @@ public: { // there is no static information if Functor holds a member function // or a free function; this is the main difference to tr1::function - if(typeid(*this) != typeid(rhs)) + if (typeid(*this) != typeid(rhs)) return false; // cannot be equal const FunctorHandler& fh = static_cast(rhs); // if this line gives a compiler error, you are using a function object. // you need to implement bool MyFnObj::operator == (const MyFnObj&) const; - return f_==fh.f_; + return f_ == fh.f_; } #endif // operator() implementations for up to 15 arguments @@ -1045,8 +1045,8 @@ private: // Wraps pointers to member functions //////////////////////////////////////////////////////////////////////////////// -template +template < class ParentFunctor, typename PointerToObj, + typename PointerToMemFn > class MemFunHandler : public ParentFunctor::Impl { typedef typename ParentFunctor::Impl Base; @@ -1080,13 +1080,13 @@ public: bool operator==(const typename Base::FunctorImplBaseType& rhs) const { - if(typeid(*this) != typeid(rhs)) + if (typeid(*this) != typeid(rhs)) return false; // cannot be equal const MemFunHandler& mfh = static_cast(rhs); // if this line gives a compiler error, you are using a function object. // you need to implement bool MyFnObj::operator == (const MyFnObj&) const; - return pObj_==mfh.pObj_ && pMemFn_==mfh.pMemFn_; + return pObj_ == mfh.pObj_ && pMemFn_ == mfh.pMemFn_; } #endif @@ -1215,8 +1215,8 @@ public: /// objects which have no operator== implemented, keep in mind when you enable /// operator==. //////////////////////////////////////////////////////////////////////////////// -template class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL> +template < typename R = void, class TList = NullType, + template class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL > class Functor { public: @@ -1295,9 +1295,9 @@ public: bool operator==(const Functor& rhs) const { - if(spImpl_.get()==0 && rhs.spImpl_.get()==0) + if (spImpl_.get() == 0 && rhs.spImpl_.get() == 0) return true; - if(spImpl_.get()!=0 && rhs.spImpl_.get()!=0) + if (spImpl_.get() != 0 && rhs.spImpl_.get() != 0) return *spImpl_.get() == *rhs.spImpl_.get(); else return false; @@ -1305,7 +1305,7 @@ public: bool operator!=(const Functor& rhs) const { - return !(*this==rhs); + return !(*this == rhs); } #endif @@ -1445,7 +1445,7 @@ struct BinderFirstTraits< Functor > { typedef Functor OriginalFunctor; - typedef typename TL::Erase::Result> + typedef typename TL::Erase::Result> ::Result ParmList; @@ -1493,9 +1493,9 @@ class BinderFirst typedef typename OriginalFunctor::Parm1 BoundType; - typedef typename Private::BinderFirstBoundTypeStorage< + typedef typename Private::BinderFirstBoundTypeStorage < typename Private::BinderFirstTraits - ::OriginalParm1> + ::OriginalParm1 > ::RefOrValue BoundTypeStorage; @@ -1527,7 +1527,7 @@ public: bool operator==(const typename Base::FunctorImplBaseType& rhs) const { - if(typeid(*this) != typeid(rhs)) + if (typeid(*this) != typeid(rhs)) return false; // cannot be equal // if this line gives a compiler error, you are using a function object. // you need to implement bool MyFnObj::operator == (const MyFnObj&) const; @@ -1659,7 +1659,7 @@ public: bool operator==(const typename Base::Impl::FunctorImplBaseType& rhs) const { - if(typeid(*this) != typeid(rhs)) + if (typeid(*this) != typeid(rhs)) return false; // cannot be equal // if this line gives a compiler error, you are using a function object. // you need to implement bool MyFnObj::operator == (const MyFnObj&) const; diff --git a/shared/loki/HierarchyGenerators.h b/shared/loki/HierarchyGenerators.h index 83ec194c..126e0f3e 100644 --- a/shared/loki/HierarchyGenerators.h +++ b/shared/loki/HierarchyGenerators.h @@ -164,14 +164,14 @@ struct FieldHelper typedef const typename H::LeftBase ConstLeftBase; - typedef typename Select::Result LeftBase; + typedef typename Select < isConst, ConstLeftBase, + typename H::LeftBase >::Result LeftBase; - typedef typename Select::Result UnqualifiedResultType; + typedef typename Select < isTuple, ElementType, + UnitType >::Result UnqualifiedResultType; - typedef typename Select::Result ResultType; + typedef typename Select < isConst, const UnqualifiedResultType, + UnqualifiedResultType >::Result ResultType; static ResultType& Do(H& obj) { @@ -194,19 +194,19 @@ struct FieldHelper typedef const typename H::RightBase ConstRightBase; - typedef typename Select::Result RightBase; + typedef typename Select < isConst, ConstRightBase, + typename H::RightBase >::Result RightBase; - typedef typename Select::Result UnqualifiedResultType; + typedef typename Select < isTuple, ElementType, + UnitType >::Result UnqualifiedResultType; - typedef typename Select::Result ResultType; + typedef typename Select < isConst, const UnqualifiedResultType, + UnqualifiedResultType >::Result ResultType; static ResultType& Do(H& obj) { RightBase& rightBase = obj; - return FieldHelper::Do(rightBase); + return FieldHelper < RightBase, i - 1 >::Do(rightBase); } }; diff --git a/shared/loki/Key.h b/shared/loki/Key.h index c80d6f4e..a416d6a9 100644 --- a/shared/loki/Key.h +++ b/shared/loki/Key.h @@ -28,7 +28,7 @@ namespace Loki { -template< +template < class Factory, typename IdentifierType > @@ -44,7 +44,7 @@ bool operator<(const Key &k1, const Key &k2); /** * A Key class */ -template< +template < class Factory, typename IdentifierType > @@ -200,7 +200,7 @@ public: Key(const IdentifierType& id, Parm1& p1, Parm2& p2, Parm3& p3, Parm4& p4, Parm5& p5, - Parm6& p6, Parm7& p7, Parm8& p8, Parm9& p9,Parm10& p10) : count(10) + Parm6& p6, Parm7& p7, Parm8& p8, Parm9& p9, Parm10& p10) : count(10) { this->id = id; this->p1 = p1; @@ -331,209 +331,209 @@ public: template bool operator==(const Key &k1, const Key &k2) { - if( k1.count != k2.count ) + if ( k1.count != k2.count ) return false; - switch(k1.count) + switch (k1.count) { case -1: return true; case 0: - if( k1.id == k2.id ) + if ( k1.id == k2.id ) return true; else return false; case 1: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) ) return true; else return false; case 2: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) ) return true; else return false; case 3: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) ) return true; else return false; case 4: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) ) return true; else return false; case 5: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) ) return true; else return false; case 6: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) ) return true; else return false; case 7: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) ) return true; else return false; case 8: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) && - (k1.p8 == k2.p8) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) ) return true; else return false; case 9: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) && - (k1.p8 == k2.p8) && - (k1.p9 == k2.p9) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) ) return true; else return false; case 10: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) && - (k1.p8 == k2.p8) && - (k1.p9 == k2.p9) && - (k1.p10 == k2.p10) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) ) return true; else return false; case 11: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) && - (k1.p8 == k2.p8) && - (k1.p9 == k2.p9) && - (k1.p10 == k2.p10) && - (k1.p11 == k2.p11) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) ) return true; else return false; case 12: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) && - (k1.p8 == k2.p8) && - (k1.p9 == k2.p9) && - (k1.p10 == k2.p10) && - (k1.p11 == k2.p11) && - (k1.p12 == k2.p12) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) && + (k1.p12 == k2.p12) ) return true; else return false; case 13: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) && - (k1.p8 == k2.p8) && - (k1.p9 == k2.p9) && - (k1.p10 == k2.p10) && - (k1.p11 == k2.p11) && - (k1.p12 == k2.p12) && - (k1.p13 == k2.p13) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) && + (k1.p12 == k2.p12) && + (k1.p13 == k2.p13) ) return true; else return false; case 14: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) && - (k1.p8 == k2.p8) && - (k1.p9 == k2.p9) && - (k1.p10 == k2.p10) && - (k1.p11 == k2.p11) && - (k1.p12 == k2.p12) && - (k1.p13 == k2.p13) && - (k1.p14 == k2.p14) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) && + (k1.p12 == k2.p12) && + (k1.p13 == k2.p13) && + (k1.p14 == k2.p14) ) return true; else return false; case 15: - if( (k1.id == k2.id) && - (k1.p1 == k2.p1) && - (k1.p2 == k2.p2) && - (k1.p3 == k2.p3) && - (k1.p4 == k2.p4) && - (k1.p5 == k2.p5) && - (k1.p6 == k2.p6) && - (k1.p7 == k2.p7) && - (k1.p8 == k2.p8) && - (k1.p9 == k2.p9) && - (k1.p10 == k2.p10) && - (k1.p11 == k2.p11) && - (k1.p12 == k2.p12) && - (k1.p13 == k2.p13) && - (k1.p14 == k2.p14) && - (k1.p15 == k2.p15) ) + if ( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) && + (k1.p12 == k2.p12) && + (k1.p13 == k2.p13) && + (k1.p14 == k2.p14) && + (k1.p15 == k2.p15) ) return true; else return false; @@ -547,209 +547,209 @@ bool operator==(const Key &k1, const Key &k2) template bool operator<(const Key &k1, const Key &k2) { - if( k1.count < k2.count ) + if ( k1.count < k2.count ) return true; - switch(k1.count) + switch (k1.count) { case -1: return false; case 0: - if( k1.id < k2.id ) + if ( k1.id < k2.id ) return true; else return false; case 1: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) ) return true; else return false; case 2: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) ) return true; else return false; case 3: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) ) return true; else return false; case 4: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) ) return true; else return false; case 5: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) ) return true; else return false; case 6: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) ) return true; else return false; case 7: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) ) return true; else return false; case 8: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) || - (k1.p8 < k2.p8) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) ) return true; else return false; case 9: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) || - (k1.p8 < k2.p8) || - (k1.p9 < k2.p9) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) ) return true; else return false; case 10: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) || - (k1.p8 < k2.p8) || - (k1.p9 < k2.p9) || - (k1.p10 < k2.p10) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) ) return true; else return false; case 11: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) || - (k1.p8 < k2.p8) || - (k1.p9 < k2.p9) || - (k1.p10 < k2.p10) || - (k1.p11 < k2.p11) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) ) return true; else return false; case 12: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) || - (k1.p8 < k2.p8) || - (k1.p9 < k2.p9) || - (k1.p10 < k2.p10) || - (k1.p11 < k2.p11) || - (k1.p12 < k2.p12) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) || + (k1.p12 < k2.p12) ) return true; else return false; case 13: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) || - (k1.p8 < k2.p8) || - (k1.p9 < k2.p9) || - (k1.p10 < k2.p10) || - (k1.p11 < k2.p11) || - (k1.p12 < k2.p12) || - (k1.p13 < k2.p13) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) || + (k1.p12 < k2.p12) || + (k1.p13 < k2.p13) ) return true; else return false; case 14: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) || - (k1.p8 < k2.p8) || - (k1.p9 < k2.p9) || - (k1.p10 < k2.p10) || - (k1.p11 < k2.p11) || - (k1.p12 < k2.p12) || - (k1.p13 < k2.p13) || - (k1.p14 < k2.p14) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) || + (k1.p12 < k2.p12) || + (k1.p13 < k2.p13) || + (k1.p14 < k2.p14) ) return true; else return false; case 15: - if( (k1.id < k2.id) || - (k1.p1 < k2.p1) || - (k1.p2 < k2.p2) || - (k1.p3 < k2.p3) || - (k1.p4 < k2.p4) || - (k1.p5 < k2.p5) || - (k1.p6 < k2.p6) || - (k1.p7 < k2.p7) || - (k1.p8 < k2.p8) || - (k1.p9 < k2.p9) || - (k1.p10 < k2.p10) || - (k1.p11 < k2.p11) || - (k1.p12 < k2.p12) || - (k1.p13 < k2.p13) || - (k1.p14 < k2.p14) || - (k1.p15 < k2.p15) ) + if ( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) || + (k1.p12 < k2.p12) || + (k1.p13 < k2.p13) || + (k1.p14 < k2.p14) || + (k1.p15 < k2.p15) ) return true; else return false; diff --git a/shared/loki/MultiMethods.h b/shared/loki/MultiMethods.h index ece4fb17..ec5b7788 100644 --- a/shared/loki/MultiMethods.h +++ b/shared/loki/MultiMethods.h @@ -38,8 +38,8 @@ namespace Loki namespace Private { -template +template < class SomeLhs, class SomeRhs, + class Executor, typename ResultType > struct InvocationTraits { static ResultType @@ -85,12 +85,12 @@ class StaticDispatcher { if (Head* p2 = dynamic_cast(&rhs)) { - Int2Type<(symmetric && - int(TL::IndexOf::value) < - int(TL::IndexOf::value))> i2t; + Int2Type < (symmetric && + int(TL::IndexOf::value) < + int(TL::IndexOf::value)) > i2t; - typedef Private::InvocationTraits< - SomeLhs, Head, Executor, ResultType> CallTraits; + typedef Private::InvocationTraits < + SomeLhs, Head, Executor, ResultType > CallTraits; return CallTraits::DoDispatch(lhs, *p2, exec, i2t); } @@ -133,7 +133,7 @@ class BaseLhs, > class BasicDispatcher { - typedef std::pair KeyType; + typedef std::pair KeyType; typedef CallbackType MappedType; typedef AssocVector MapType; MapType callbackMap_; @@ -158,28 +158,28 @@ public: }; // Non-inline to reduce compile time overhead... -template -void BasicDispatcher +template < class BaseLhs, class BaseRhs, + typename ResultType, typename CallbackType > +void BasicDispatcher ::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun) { callbackMap_[KeyType(lhs, rhs)] = fun; } -template -bool BasicDispatcher +template < class BaseLhs, class BaseRhs, + typename ResultType, typename CallbackType > +bool BasicDispatcher ::DoRemove(TypeInfo lhs, TypeInfo rhs) { return callbackMap_.erase(KeyType(lhs, rhs)) == 1; } -template -ResultType BasicDispatcher +template < class BaseLhs, class BaseRhs, + typename ResultType, typename CallbackType > +ResultType BasicDispatcher ::Go(BaseLhs& lhs, BaseRhs& rhs) { - typename MapType::key_type k(typeid(lhs),typeid(rhs)); + typename MapType::key_type k(typeid(lhs), typeid(rhs)); typename MapType::iterator i = callbackMap_.find(k); if (i == callbackMap_.end()) { @@ -223,11 +223,11 @@ struct DynamicCaster namespace Private { -template + ResultType (*Callback)(SomeLhs&, SomeRhs&) > struct FnDispatcherHelper { static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs) @@ -247,15 +247,15 @@ struct FnDispatcherHelper // Features automated conversions //////////////////////////////////////////////////////////////////////////////// -template class CastingPolicy = DynamicCaster, template - class DispatcherBackend = BasicDispatcher> + class DispatcherBackend = BasicDispatcher > class FnDispatcher { - DispatcherBackend backEnd_; + DispatcherBackend < BaseLhs, BaseRhs, ResultType, + ResultType (*)(BaseLhs&, BaseRhs&) > backEnd_; public: template @@ -264,33 +264,33 @@ public: return backEnd_.template Add(pFun); } - template + template < class SomeLhs, class SomeRhs, + ResultType (*callback)(SomeLhs&, SomeRhs&) > void Add() { - typedef Private::FnDispatcherHelper< + typedef Private::FnDispatcherHelper < BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType, - CastingPolicy, - CastingPolicy, - callback> Local; + CastingPolicy, + CastingPolicy, + callback > Local; Add(&Local::Trampoline); } - template + bool symmetric > void Add(bool = true) // [gcc] dummy bool { - typedef Private::FnDispatcherHelper< + typedef Private::FnDispatcherHelper < BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType, - CastingPolicy, - CastingPolicy, - callback> Local; + CastingPolicy, + CastingPolicy, + callback > Local; Add(&Local::Trampoline); if (symmetric) @@ -318,19 +318,19 @@ public: namespace Private { -template + class Fun, bool SwapArgs > class FunctorDispatcherHelper { Fun fun_; - ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type) + ResultType Fire(BaseLhs& lhs, BaseRhs& rhs, Int2Type) { return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } - ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type) + ResultType Fire(BaseLhs& rhs, BaseRhs& lhs, Int2Type) { return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } @@ -339,7 +339,7 @@ public: ResultType operator()(BaseLhs& lhs, BaseRhs& rhs) { - return Fire(lhs,rhs,Int2Type()); + return Fire(lhs, rhs, Int2Type()); } }; } @@ -350,11 +350,11 @@ public: // Features automated casting //////////////////////////////////////////////////////////////////////////////// -template class CastingPolicy = DynamicCaster, template - class DispatcherBackend = BasicDispatcher> + class DispatcherBackend = BasicDispatcher > class FunctorDispatcher { typedef LOKI_TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList; @@ -366,31 +366,31 @@ public: template void Add(const Fun& fun) { - typedef Private::FunctorDispatcherHelper< + typedef Private::FunctorDispatcherHelper < BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType, CastingPolicy, CastingPolicy, - Fun, false> Adapter; + Fun, false > Adapter; backEnd_.template Add(FunctorType(Adapter(fun))); } template void Add(const Fun& fun) { - Add(fun); + Add(fun); if (symmetric) { // Note: symmetry only makes sense where BaseLhs==BaseRhs - typedef Private::FunctorDispatcherHelper< + typedef Private::FunctorDispatcherHelper < BaseLhs, BaseLhs, SomeLhs, SomeRhs, ResultType, CastingPolicy, CastingPolicy, - Fun, true> AdapterR; + Fun, true > AdapterR; backEnd_.template Add(FunctorType(AdapterR(fun))); } diff --git a/shared/loki/OrderedStatic.h b/shared/loki/OrderedStatic.h index 0f26b6e0..f0ff73c3 100644 --- a/shared/loki/OrderedStatic.h +++ b/shared/loki/OrderedStatic.h @@ -76,8 +76,8 @@ protected: void SetLongevity(T* ptr) { - val_=ptr; - Loki::SetLongevity(val_,longevity_); + val_ = ptr; + Loki::SetLongevity(val_, longevity_); } private: @@ -102,7 +102,7 @@ public: typedef void (OrderedStaticCreatorFunc::*Creator)(); void createObjects(); - void registerObject(unsigned int longevity,OrderedStaticCreatorFunc*,Creator); + void registerObject(unsigned int longevity, OrderedStaticCreatorFunc*, Creator); private: OrderedStaticManagerClass(const OrderedStaticManagerClass&); @@ -110,7 +110,7 @@ private: struct Data { - Data(unsigned int,OrderedStaticCreatorFunc*, Creator); + Data(unsigned int, OrderedStaticCreatorFunc*, Creator); unsigned int longevity; OrderedStaticCreatorFunc* object; Creator creator; @@ -158,7 +158,7 @@ public: OrderedStatic() : Private::OrderedStaticBase(L) { OrderedStaticManager::Instance().registerObject - (L,this,&Private::OrderedStaticCreatorFunc::createObject); + (L, this, &Private::OrderedStaticCreatorFunc::createObject); } void createObject() @@ -178,7 +178,7 @@ public: OrderedStatic(P1 p) : Private::OrderedStaticBase(L), para_(p) { OrderedStaticManager::Instance().registerObject - (L,this,&Private::OrderedStaticCreatorFunc::createObject); + (L, this, &Private::OrderedStaticCreatorFunc::createObject); } void createObject() @@ -203,7 +203,7 @@ public: OrderedStatic(Func p) : Private::OrderedStaticBase(L), para_(p) { OrderedStaticManager::Instance().registerObject - (L,this,&Private::OrderedStaticCreatorFunc::createObject); + (L, this, &Private::OrderedStaticCreatorFunc::createObject); } void createObject() diff --git a/shared/loki/Pimpl.h b/shared/loki/Pimpl.h index 788f76d8..8254e3e2 100644 --- a/shared/loki/Pimpl.h +++ b/shared/loki/Pimpl.h @@ -101,7 +101,7 @@ public: T& operator*() { - return ptr_.operator*(); + return ptr_.operator * (); } const T* operator->() const @@ -111,7 +111,7 @@ public: const T& operator*() const { - return ptr_.operator*(); + return ptr_.operator * (); } Pointer& wrapped() @@ -136,7 +136,7 @@ private: template > struct PimplOwner { - Pimpl LOKI_INHERITED_PIMPL_NAME; + Pimpl LOKI_INHERITED_PIMPL_NAME; }; diff --git a/shared/loki/Register.h b/shared/loki/Register.h index 32409f4b..2b549381 100644 --- a/shared/loki/Register.h +++ b/shared/loki/Register.h @@ -113,18 +113,18 @@ struct UnRegisterOnDeleteSet #define LOKI_CONCAT(a,b,c,d) LOKI_CONCATE(a,b,c,d) #define LOKI_CHECK_CLASS_IN_LIST( CLASS , LIST ) \ - \ + \ struct LOKI_CONCAT(check_,CLASS,_isInList_,LIST) \ { \ typedef int LOKI_CONCAT(ERROR_class_,CLASS,_isNotInList_,LIST); \ }; \ typedef Loki::Select::value == -1, \ - CLASS, \ - LOKI_CONCAT(check_,CLASS,_isInList_,LIST)> \ - ::Result LOKI_CONCAT(CLASS,isInList,LIST,result); \ + CLASS, \ + LOKI_CONCAT(check_,CLASS,_isInList_,LIST)> \ + ::Result LOKI_CONCAT(CLASS,isInList,LIST,result); \ typedef LOKI_CONCAT(CLASS,isInList,LIST,result):: \ - LOKI_CONCAT(ERROR_class_,CLASS,_isNotInList_,LIST) \ - LOKI_CONCAT(ERROR_class_,CLASS,_isNotInList__,LIST); + LOKI_CONCAT(ERROR_class_,CLASS,_isNotInList_,LIST) \ + LOKI_CONCAT(ERROR_class_,CLASS,_isNotInList__,LIST); } // namespace Loki diff --git a/shared/loki/SPCachedFactory.h b/shared/loki/SPCachedFactory.h index aab37127..e1b8ec8c 100644 --- a/shared/loki/SPCachedFactory.h +++ b/shared/loki/SPCachedFactory.h @@ -165,7 +165,7 @@ class AbstractProduct, class SmartPointer { private: - typedef SmartPtr< AbstractProduct,OwnershipPolicy, + typedef SmartPtr < AbstractProduct, OwnershipPolicy, ConversionPolicy, CheckingPolicy, FunctionStorage, ConstnessPolicy > CallBackSP; protected: @@ -195,7 +195,7 @@ private: CallBackSP& SP(*reinterpret_cast(pSP)); ReleaseObject(SP); } - virtual void ReleaseObject(ProductReturn& object)=0; + virtual void ReleaseObject(ProductReturn& object) = 0; const typename CallBackSP::FunctorType fun; }; diff --git a/shared/loki/SafeBits.h b/shared/loki/SafeBits.h index 4105f375..9e160c50 100644 --- a/shared/loki/SafeBits.h +++ b/shared/loki/SafeBits.h @@ -482,10 +482,10 @@ inline SafeBitField< unique_index, word_t > operator != ( bool, SafeBitField< un #ifdef LOKI_SAFE_BIT_FIELD #ifndef LOKI_BIT_FIELD_NONTEMPLATE_INIT #define LOKI_BIT_CONST( field_t, label, bit_index ) \ - static const field_t::const_t label = field_t::const_t::make_bit_const() + static const field_t::const_t label = field_t::const_t::make_bit_const() #else #define LOKI_BIT_CONST( field_t, label, bit_index ) \ - static const field_t::const_t label = field_t::const_t::make_bit_const( bit_index ) + static const field_t::const_t label = field_t::const_t::make_bit_const( bit_index ) #endif // LOKI_BIT_FIELD_NONTEMPLATE_INIT #else inline size_t make_bit_const( size_t i ) { return ( i > 0 ) ? ( size_t(1) << ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0; } diff --git a/shared/loki/SafeFormat.h b/shared/loki/SafeFormat.h index 2734e972..bd2837f9 100644 --- a/shared/loki/SafeFormat.h +++ b/shared/loki/SafeFormat.h @@ -73,7 +73,7 @@ template void write(std::pair& s, const Char* from, const Char* to) { assert(from <= to); - if(from + s.second < to) + if (from + s.second < to) throw std::overflow_error(""); // s.first: position one past the final copied element s.first = std::copy(from, to, s.first); @@ -106,9 +106,9 @@ struct PrintfState } #define LOKI_PRINTF_STATE_FORWARD(type) \ - PrintfState& operator()(type par) {\ - return (*this)(static_cast< LOKI_SAFEFORMAT_UNSIGNED_LONG >(par)); \ - } + PrintfState& operator()(type par) {\ + return (*this)(static_cast< LOKI_SAFEFORMAT_UNSIGNED_LONG >(par)); \ + } LOKI_PRINTF_STATE_FORWARD(bool) LOKI_PRINTF_STATE_FORWARD(char) @@ -171,21 +171,21 @@ struct PrintfState PrintfState& operator()(void* n) { if (result_ == -1) return *this; // don't even bother - PrintUsing_snprintf(n,"p"); + PrintUsing_snprintf(n, "p"); return *this; } PrintfState& operator()(double n) { if (result_ == -1) return *this; // don't even bother - PrintUsing_snprintf(n,"eEfgG"); + PrintUsing_snprintf(n, "eEfgG"); return *this; } PrintfState& operator()(long double n) { if (result_ == -1) return *this; // don't even bother - PrintUsing_snprintf(n,"eEfgG"); + PrintUsing_snprintf(n, "eEfgG"); return *this; } diff --git a/shared/loki/ScopeGuard.h b/shared/loki/ScopeGuard.h index 46e4d892..99ce569d 100644 --- a/shared/loki/ScopeGuard.h +++ b/shared/loki/ScopeGuard.h @@ -65,7 +65,7 @@ protected: { j.Execute(); } - catch(...) + catch (...) {} } @@ -440,15 +440,15 @@ inline ObjScopeGuardImpl0 MakeObjGuard(Obj& obj, MemFun memFun) } template -inline ObjScopeGuardImpl0 MakeGuard(Ret(Obj2::*memFun)(), Obj1& obj) +inline ObjScopeGuardImpl0 MakeGuard(Ret(Obj2::*memFun)(), Obj1& obj) { - return ObjScopeGuardImpl0::MakeObjGuard(obj,memFun); + return ObjScopeGuardImpl0::MakeObjGuard(obj, memFun); } template -inline ObjScopeGuardImpl0 MakeGuard(Ret(Obj2::*memFun)(), Obj1* obj) +inline ObjScopeGuardImpl0 MakeGuard(Ret(Obj2::*memFun)(), Obj1* obj) { - return ObjScopeGuardImpl0::MakeObjGuard(*obj,memFun); + return ObjScopeGuardImpl0::MakeObjGuard(*obj, memFun); } //////////////////////////////////////////////////////////////// @@ -503,15 +503,15 @@ inline ObjScopeGuardImpl1 MakeObjGuard(Obj& obj, MemFun memFun, } template -inline ObjScopeGuardImpl1 MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1& obj, P1b p1) +inline ObjScopeGuardImpl1 MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1& obj, P1b p1) { - return ObjScopeGuardImpl1::MakeObjGuard(obj,memFun,p1); + return ObjScopeGuardImpl1::MakeObjGuard(obj, memFun, p1); } template -inline ObjScopeGuardImpl1 MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1* obj, P1b p1) +inline ObjScopeGuardImpl1 MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1* obj, P1b p1) { - return ObjScopeGuardImpl1::MakeObjGuard(*obj,memFun,p1); + return ObjScopeGuardImpl1::MakeObjGuard(*obj, memFun, p1); } //////////////////////////////////////////////////////////////// @@ -567,15 +567,15 @@ inline ObjScopeGuardImpl2 MakeObjGuard(Obj& obj, MemFun mem } template -inline ObjScopeGuardImpl2 MakeGuard(Ret(Obj2::*memFun)(P1a,P2a), Obj1& obj, P1b p1, P2b p2) +inline ObjScopeGuardImpl2 MakeGuard(Ret(Obj2::*memFun)(P1a, P2a), Obj1& obj, P1b p1, P2b p2) { - return ObjScopeGuardImpl2::MakeObjGuard(obj,memFun,p1,p2); + return ObjScopeGuardImpl2::MakeObjGuard(obj, memFun, p1, p2); } template -inline ObjScopeGuardImpl2 MakeGuard(Ret(Obj2::*memFun)(P1a,P2a), Obj1* obj, P1b p1, P2b p2) +inline ObjScopeGuardImpl2 MakeGuard(Ret(Obj2::*memFun)(P1a, P2a), Obj1* obj, P1b p1, P2b p2) { - return ObjScopeGuardImpl2::MakeObjGuard(*obj,memFun,p1,p2); + return ObjScopeGuardImpl2::MakeObjGuard(*obj, memFun, p1, p2); } //////////////////////////////////////////////////////////////// @@ -662,5 +662,8 @@ MakeGuard( Ret( Obj2::*memFun )( P1a, P2a, P3a ), Obj1* obj, P1b p1, P2b p2, P3b #define LOKI_ON_BLOCK_EXIT ::Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = ::Loki::MakeGuard #define LOKI_ON_BLOCK_EXIT_OBJ ::Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = ::Loki::MakeObjGuard +//by ZenJu +#define LOKI_ON_BLOCK_EXIT2(X) ::Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = ::Loki::MakeGuard([&](){X;}); (void)LOKI_ANONYMOUS_VARIABLE(scopeGuard); + #endif // end file guardian diff --git a/shared/loki/Sequence.h b/shared/loki/Sequence.h index e8c8bd35..04a64174 100644 --- a/shared/loki/Sequence.h +++ b/shared/loki/Sequence.h @@ -22,16 +22,16 @@ namespace Loki template < -class T01=NullType,class T02=NullType,class T03=NullType,class T04=NullType,class T05=NullType, - class T06=NullType,class T07=NullType,class T08=NullType,class T09=NullType,class T10=NullType, - class T11=NullType,class T12=NullType,class T13=NullType,class T14=NullType,class T15=NullType, - class T16=NullType,class T17=NullType,class T18=NullType,class T19=NullType,class T20=NullType +class T01 = NullType, class T02 = NullType, class T03 = NullType, class T04 = NullType, class T05 = NullType, + class T06 = NullType, class T07 = NullType, class T08 = NullType, class T09 = NullType, class T10 = NullType, + class T11 = NullType, class T12 = NullType, class T13 = NullType, class T14 = NullType, class T15 = NullType, + class T16 = NullType, class T17 = NullType, class T18 = NullType, class T19 = NullType, class T20 = NullType > struct Seq { private: - typedef typename Seq< T02, T03, T04, T05, T06, T07, T08, T09, T10, - T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>::Type + typedef typename Seq < T02, T03, T04, T05, T06, T07, T08, T09, T10, + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 >::Type TailResult; public: typedef Typelist Type; diff --git a/shared/loki/Singleton.h b/shared/loki/Singleton.h index c5f1f567..1e479032 100644 --- a/shared/loki/Singleton.h +++ b/shared/loki/Singleton.h @@ -119,7 +119,7 @@ template class ConcreteLifetimeTracker : public LifetimeTracker { public: - ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d) + ConcreteLifetimeTracker(T* p, unsigned int longevity, Destroyer d) : LifetimeTracker(longevity) , pTracked_(p) , destroyer_(d) @@ -151,7 +151,7 @@ void SetLongevity(T* pDynObject, unsigned int longevity, using namespace Private; // manage lifetime of stack manually - if(pTrackerArray==0) + if (pTrackerArray == 0) pTrackerArray = new TrackerArray; // automatically delete the ConcreteLifetimeTracker object when a exception is thrown @@ -261,7 +261,7 @@ struct CreateUsing { //allocator.destroy(p); p->~T(); - allocator.deallocate(p,1); + allocator.deallocate(p, 1); } }; }; @@ -566,21 +566,21 @@ public: /// \ingroup LongevityLifetimeGroup /// \brief Longest possible SingletonWithLongevity lifetime: 0xFFFFFFFF template -struct DieLast : SingletonFixedLongevity<0xFFFFFFFF ,T> +struct DieLast : SingletonFixedLongevity<0xFFFFFFFF , T> {}; /// \struct DieDirectlyBeforeLast /// \ingroup LongevityLifetimeGroup /// \brief Lifetime is a one less than DieLast: 0xFFFFFFFF-1 template -struct DieDirectlyBeforeLast : SingletonFixedLongevity<0xFFFFFFFF-1 ,T> +struct DieDirectlyBeforeLast : SingletonFixedLongevity < 0xFFFFFFFF - 1 , T > {}; /// \struct DieFirst /// \ingroup LongevityLifetimeGroup /// \brief Shortest possible SingletonWithLongevity lifetime: 0 template -struct DieFirst : SingletonFixedLongevity<0,T> +struct DieFirst : SingletonFixedLongevity<0, T> {}; }//namespace LongevityLifetime @@ -616,7 +616,7 @@ class FollowIntoDeath static void Init() { static bool done = false; - if(!done) + if (!done) { followers_ = new Container; done = true; @@ -632,7 +632,7 @@ class FollowIntoDeath static void DestroyFollowers() { Init(); - for(iterator it = followers_->begin(); it != followers_->end(); ++it) + for (iterator it = followers_->begin(); it != followers_->end(); ++it) (*it)(); delete followers_; } @@ -660,7 +660,7 @@ public: // template instantiation, this adds a additional atexit entry // does not work with SetLonlevity, but there you can control // the lifetime with the GetLongevity function. - Lifetime >::ScheduleDestruction(0,Followers::DestroyFollowers); + Lifetime >::ScheduleDestruction(0, Followers::DestroyFollowers); } static void OnDeadReference() @@ -741,7 +741,7 @@ private: SingletonHolder(); // Data - typedef typename ThreadingModel::VolatileType PtrInstanceType; + typedef typename ThreadingModel::VolatileType PtrInstanceType; static PtrInstanceType pInstance_; static bool destroyed_; }; @@ -783,8 +783,8 @@ class T, template class ThreadingModel, class MutexPolicy > -inline T& SingletonHolder::Instance() +inline T& SingletonHolder < T, CreationPolicy, + LifetimePolicy, ThreadingModel, MutexPolicy >::Instance() { if (!pInstance_) { @@ -805,10 +805,10 @@ template class LifetimePolicy, template class ThreadingModel, class MutexPolicy > -void SingletonHolder::MakeInstance() +void SingletonHolder < T, CreationPolicy, + LifetimePolicy, ThreadingModel, MutexPolicy >::MakeInstance() { - typename ThreadingModel::Lock guard; + typename ThreadingModel::Lock guard; (void)guard; if (!pInstance_) @@ -875,14 +875,14 @@ public: /// Put this macro called with a SingletonHolder typedef into your cpp file. #define LOKI_SINGLETON_INSTANCE_DEFINITION(SHOLDER) \ -namespace Loki \ -{ \ + namespace Loki \ + { \ template<> \ SHOLDER::ObjectType& Singleton::Instance() \ { \ return SHOLDER::Instance(); \ } \ -} + } #endif // end file guardian diff --git a/shared/loki/SmallObj.cpp b/shared/loki/SmallObj.cpp index 0d82c1bb..1c42374f 100644 --- a/shared/loki/SmallObj.cpp +++ b/shared/loki/SmallObj.cpp @@ -1012,7 +1012,7 @@ void FixedAllocator::DoDeallocate(void* p) /// Calculates index into array where a FixedAllocator of numBytes is located. inline std::size_t GetOffset( std::size_t numBytes, std::size_t alignment ) { - const std::size_t alignExtra = alignment-1; + const std::size_t alignExtra = alignment - 1; return ( numBytes + alignExtra ) / alignment; } @@ -1070,7 +1070,7 @@ SmallObjAllocator::SmallObjAllocator( std::size_t pageSize, const std::size_t allocCount = GetOffset( maxObjectSize, objectAlignSize ); pool_ = new FixedAllocator[ allocCount ]; for ( std::size_t i = 0; i < allocCount; ++i ) - pool_[ i ].Initialize( ( i+1 ) * objectAlignSize, pageSize ); + pool_[ i ].Initialize( ( i + 1 ) * objectAlignSize, pageSize ); } // SmallObjAllocator::~SmallObjAllocator -------------------------------------- diff --git a/shared/loki/SmallObj.h b/shared/loki/SmallObj.h index 8725b911..10624cc2 100644 --- a/shared/loki/SmallObj.h +++ b/shared/loki/SmallObj.h @@ -224,14 +224,14 @@ class AllocatorSingleton : public SmallObjAllocator public: /// Defines type of allocator. - typedef AllocatorSingleton< ThreadingModel, chunkSize, + typedef AllocatorSingleton < ThreadingModel, chunkSize, maxSmallObjectSize, objectAlignSize, LifetimePolicy > MyAllocator; /// Defines type for thread-safety locking mechanism. typedef ThreadingModel< MyAllocator, MutexPolicy > MyThreadingModel; /// Defines singleton made from allocator. - typedef Loki::SingletonHolder< MyAllocator, Loki::CreateStatic, + typedef Loki::SingletonHolder < MyAllocator, Loki::CreateStatic, LifetimePolicy, ThreadingModel > MyAllocatorSingleton; /// Returns reference to the singleton. @@ -441,7 +441,7 @@ class SmallObjectBase public: /// Defines type of allocator singleton, must be public /// to handle singleton lifetime dependencies. - typedef AllocatorSingleton< ThreadingModel, chunkSize, + typedef AllocatorSingleton < ThreadingModel, chunkSize, maxSmallObjectSize, objectAlignSize, LifetimePolicy > ObjAllocatorSingleton; private: @@ -591,7 +591,7 @@ template class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEV template class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME, class MutexPolicy = LOKI_DEFAULT_MUTEX > -class SmallObject : public SmallObjectBase< ThreadingModel, chunkSize, +class SmallObject : public SmallObjectBase < ThreadingModel, chunkSize, maxSmallObjectSize, objectAlignSize, LifetimePolicy, MutexPolicy > { @@ -627,7 +627,7 @@ template class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEV template class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME, class MutexPolicy = LOKI_DEFAULT_MUTEX > -class SmallValueObject : public SmallObjectBase< ThreadingModel, chunkSize, +class SmallValueObject : public SmallObjectBase < ThreadingModel, chunkSize, maxSmallObjectSize, objectAlignSize, LifetimePolicy, MutexPolicy > { protected: diff --git a/shared/loki/SmartPtr.h b/shared/loki/SmartPtr.h index fb14258e..6f6f9996 100644 --- a/shared/loki/SmartPtr.h +++ b/shared/loki/SmartPtr.h @@ -440,7 +440,7 @@ public: : pCount_(static_cast( SmallObject<>::operator new(sizeof(uintptr_t)))) { - assert(pCount_!=0); + assert(pCount_ != 0); *pCount_ = 1; } @@ -500,7 +500,7 @@ private: /// fixed at a higher design level, and no change to this class could fix it. //////////////////////////////////////////////////////////////////////////////// -template