diff options
Diffstat (limited to 'src')
76 files changed, 2962 insertions, 2616 deletions
diff --git a/src/3rdParty/efsw/Atomic.hpp b/src/3rdParty/efsw/Atomic.hpp index 4008dfc..9015c60 100755..100644 --- a/src/3rdParty/efsw/Atomic.hpp +++ b/src/3rdParty/efsw/Atomic.hpp | |||
@@ -3,9 +3,7 @@ | |||
3 | 3 | ||
4 | #include <efsw/base.hpp> | 4 | #include <efsw/base.hpp> |
5 | 5 | ||
6 | #ifdef EFSW_USE_CXX11 | ||
7 | #include <atomic> | 6 | #include <atomic> |
8 | #endif | ||
9 | 7 | ||
10 | namespace efsw { | 8 | namespace efsw { |
11 | 9 | ||
@@ -14,36 +12,20 @@ template <typename T> class Atomic { | |||
14 | explicit Atomic( T set = false ) : set_( set ) {} | 12 | explicit Atomic( T set = false ) : set_( set ) {} |
15 | 13 | ||
16 | Atomic& operator=( T set ) { | 14 | Atomic& operator=( T set ) { |
17 | #ifdef EFSW_USE_CXX11 | ||
18 | set_.store( set, std::memory_order_release ); | 15 | set_.store( set, std::memory_order_release ); |
19 | #else | ||
20 | set_ = set; | ||
21 | #endif | ||
22 | return *this; | 16 | return *this; |
23 | } | 17 | } |
24 | 18 | ||
25 | explicit operator T() const { | 19 | explicit operator T() const { |
26 | #ifdef EFSW_USE_CXX11 | ||
27 | return set_.load( std::memory_order_acquire ); | 20 | return set_.load( std::memory_order_acquire ); |
28 | #else | ||
29 | return set_; | ||
30 | #endif | ||
31 | } | 21 | } |
32 | 22 | ||
33 | T load() const { | 23 | T load() const { |
34 | #ifdef EFSW_USE_CXX11 | ||
35 | return set_.load( std::memory_order_acquire ); | 24 | return set_.load( std::memory_order_acquire ); |
36 | #else | ||
37 | return set_; | ||
38 | #endif | ||
39 | } | 25 | } |
40 | 26 | ||
41 | private: | 27 | private: |
42 | #ifdef EFSW_USE_CXX11 | ||
43 | std::atomic<T> set_; | 28 | std::atomic<T> set_; |
44 | #else | ||
45 | volatile T set_; | ||
46 | #endif | ||
47 | }; | 29 | }; |
48 | 30 | ||
49 | } // namespace efsw | 31 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/Debug.cpp b/src/3rdParty/efsw/Debug.cpp index 18cfd31..18cfd31 100755..100644 --- a/src/3rdParty/efsw/Debug.cpp +++ b/src/3rdParty/efsw/Debug.cpp | |||
diff --git a/src/3rdParty/efsw/Debug.hpp b/src/3rdParty/efsw/Debug.hpp index 78d3557..fefaec4 100755..100644 --- a/src/3rdParty/efsw/Debug.hpp +++ b/src/3rdParty/efsw/Debug.hpp | |||
@@ -49,8 +49,10 @@ void efPRINTC( unsigned int cond, const char* format, ... ); | |||
49 | #define efDEBUGC( cond, format, args... ) \ | 49 | #define efDEBUGC( cond, format, args... ) \ |
50 | {} | 50 | {} |
51 | #else | 51 | #else |
52 | #define efDEBUG | 52 | #define efDEBUG( ... ) \ |
53 | #define efDEBUGC | 53 | {} |
54 | #define efDEBUGC( ... ) \ | ||
55 | {} | ||
54 | #endif | 56 | #endif |
55 | 57 | ||
56 | #endif | 58 | #endif |
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.cpp b/src/3rdParty/efsw/DirWatcherGeneric.cpp index 8b6bc8a..8b6bc8a 100755..100644 --- a/src/3rdParty/efsw/DirWatcherGeneric.cpp +++ b/src/3rdParty/efsw/DirWatcherGeneric.cpp | |||
diff --git a/src/3rdParty/efsw/DirWatcherGeneric.hpp b/src/3rdParty/efsw/DirWatcherGeneric.hpp index ca52de7..ca52de7 100755..100644 --- a/src/3rdParty/efsw/DirWatcherGeneric.hpp +++ b/src/3rdParty/efsw/DirWatcherGeneric.hpp | |||
diff --git a/src/3rdParty/efsw/DirectorySnapshot.cpp b/src/3rdParty/efsw/DirectorySnapshot.cpp index 6049e4a..f78475f 100755..100644 --- a/src/3rdParty/efsw/DirectorySnapshot.cpp +++ b/src/3rdParty/efsw/DirectorySnapshot.cpp | |||
@@ -44,7 +44,7 @@ void DirectorySnapshot::initFiles() { | |||
44 | Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); | 44 | Files = FileSystem::filesInfoFromPath( DirectoryInfo.Filepath ); |
45 | 45 | ||
46 | FileInfoMap::iterator it = Files.begin(); | 46 | FileInfoMap::iterator it = Files.begin(); |
47 | std::list<std::string> eraseFiles; | 47 | std::vector<std::string> eraseFiles; |
48 | 48 | ||
49 | /// Remove all non regular files and non directories | 49 | /// Remove all non regular files and non directories |
50 | for ( ; it != Files.end(); it++ ) { | 50 | for ( ; it != Files.end(); it++ ) { |
@@ -53,7 +53,7 @@ void DirectorySnapshot::initFiles() { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | for ( std::list<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); | 56 | for ( std::vector<std::string>::iterator eit = eraseFiles.begin(); eit != eraseFiles.end(); |
57 | eit++ ) { | 57 | eit++ ) { |
58 | Files.erase( *eit ); | 58 | Files.erase( *eit ); |
59 | } | 59 | } |
diff --git a/src/3rdParty/efsw/DirectorySnapshot.hpp b/src/3rdParty/efsw/DirectorySnapshot.hpp index 0e60542..0e60542 100755..100644 --- a/src/3rdParty/efsw/DirectorySnapshot.hpp +++ b/src/3rdParty/efsw/DirectorySnapshot.hpp | |||
diff --git a/src/3rdParty/efsw/DirectorySnapshotDiff.cpp b/src/3rdParty/efsw/DirectorySnapshotDiff.cpp index 37ee507..37ee507 100755..100644 --- a/src/3rdParty/efsw/DirectorySnapshotDiff.cpp +++ b/src/3rdParty/efsw/DirectorySnapshotDiff.cpp | |||
diff --git a/src/3rdParty/efsw/DirectorySnapshotDiff.hpp b/src/3rdParty/efsw/DirectorySnapshotDiff.hpp index 26a29ec..26a29ec 100755..100644 --- a/src/3rdParty/efsw/DirectorySnapshotDiff.hpp +++ b/src/3rdParty/efsw/DirectorySnapshotDiff.hpp | |||
diff --git a/src/3rdParty/efsw/FileInfo.cpp b/src/3rdParty/efsw/FileInfo.cpp index 072cd6d..707f617 100755..100644 --- a/src/3rdParty/efsw/FileInfo.cpp +++ b/src/3rdParty/efsw/FileInfo.cpp | |||
@@ -35,10 +35,6 @@ | |||
35 | #endif | 35 | #endif |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | ||
39 | #include <filesystem> | ||
40 | #endif | ||
41 | |||
42 | namespace efsw { | 38 | namespace efsw { |
43 | 39 | ||
44 | bool FileInfo::exists( const std::string& filePath ) { | 40 | bool FileInfo::exists( const std::string& filePath ) { |
@@ -186,12 +182,14 @@ bool FileInfo::isLink() const { | |||
186 | std::string FileInfo::linksTo() { | 182 | std::string FileInfo::linksTo() { |
187 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 | 183 | #if EFSW_PLATFORM != EFSW_PLATFORM_WIN32 |
188 | if ( isLink() ) { | 184 | if ( isLink() ) { |
189 | std::error_code ec; | 185 | char* ch = realpath( Filepath.c_str(), NULL ); |
190 | auto ch = std::filesystem::canonical( Filepath, ec ); | 186 | |
187 | if ( NULL != ch ) { | ||
188 | std::string tstr( ch ); | ||
191 | 189 | ||
192 | if ( !ec ) { | 190 | free( ch ); |
193 | 191 | ||
194 | return ch.string(); | 192 | return tstr; |
195 | } | 193 | } |
196 | } | 194 | } |
197 | #endif | 195 | #endif |
diff --git a/src/3rdParty/efsw/FileInfo.hpp b/src/3rdParty/efsw/FileInfo.hpp index f1bcf4b..1b55c35 100755..100644 --- a/src/3rdParty/efsw/FileInfo.hpp +++ b/src/3rdParty/efsw/FileInfo.hpp | |||
@@ -2,7 +2,7 @@ | |||
2 | #define EFSW_FILEINFO_HPP | 2 | #define EFSW_FILEINFO_HPP |
3 | 3 | ||
4 | #include <efsw/base.hpp> | 4 | #include <efsw/base.hpp> |
5 | #include <list> | 5 | #include <vector> |
6 | #include <map> | 6 | #include <map> |
7 | #include <string> | 7 | #include <string> |
8 | 8 | ||
@@ -18,11 +18,11 @@ class FileInfo { | |||
18 | 18 | ||
19 | FileInfo(); | 19 | FileInfo(); |
20 | 20 | ||
21 | explicit FileInfo( const std::string& filepath ); | 21 | FileInfo( const std::string& filepath ); |
22 | 22 | ||
23 | FileInfo( const std::string& filepath, bool linkInfo ); | 23 | FileInfo( const std::string& filepath, bool linkInfo ); |
24 | 24 | ||
25 | FileInfo( const FileInfo& ) = default; | 25 | FileInfo(const FileInfo&) = default; |
26 | 26 | ||
27 | bool operator==( const FileInfo& Other ) const; | 27 | bool operator==( const FileInfo& Other ) const; |
28 | 28 | ||
@@ -58,8 +58,8 @@ class FileInfo { | |||
58 | }; | 58 | }; |
59 | 59 | ||
60 | typedef std::map<std::string, FileInfo> FileInfoMap; | 60 | typedef std::map<std::string, FileInfo> FileInfoMap; |
61 | typedef std::list<FileInfo> FileInfoList; | 61 | typedef std::vector<FileInfo> FileInfoList; |
62 | typedef std::list<std::pair<std::string, FileInfo>> MovedList; | 62 | typedef std::vector<std::pair<std::string, FileInfo>> MovedList; |
63 | 63 | ||
64 | } // namespace efsw | 64 | } // namespace efsw |
65 | 65 | ||
diff --git a/src/3rdParty/efsw/FileSystem.cpp b/src/3rdParty/efsw/FileSystem.cpp index 867f120..1ed346c 100755..100644 --- a/src/3rdParty/efsw/FileSystem.cpp +++ b/src/3rdParty/efsw/FileSystem.cpp | |||
@@ -1,10 +1,19 @@ | |||
1 | #include <cstring> | ||
1 | #include <efsw/FileSystem.hpp> | 2 | #include <efsw/FileSystem.hpp> |
2 | #include <efsw/platform/platformimpl.hpp> | 3 | #include <efsw/platform/platformimpl.hpp> |
4 | #include <climits> | ||
3 | 5 | ||
4 | #if EFSW_OS == EFSW_OS_MACOSX | 6 | #if EFSW_OS == EFSW_OS_MACOSX |
5 | #include <CoreFoundation/CoreFoundation.h> | 7 | #include <CoreFoundation/CoreFoundation.h> |
6 | #endif | 8 | #endif |
7 | 9 | ||
10 | #if EFSW_OS == EFSW_OS_WIN | ||
11 | #ifndef WIN32_LEAN_AND_MEAN | ||
12 | #define WIN32_LEAN_AND_MEAN | ||
13 | #endif | ||
14 | #include <windows.h> | ||
15 | #endif | ||
16 | |||
8 | namespace efsw { | 17 | namespace efsw { |
9 | 18 | ||
10 | bool FileSystem::isDirectory( const std::string& path ) { | 19 | bool FileSystem::isDirectory( const std::string& path ) { |
@@ -26,13 +35,13 @@ bool FileSystem::slashAtEnd( std::string& dir ) { | |||
26 | } | 35 | } |
27 | 36 | ||
28 | void FileSystem::dirAddSlashAtEnd( std::string& dir ) { | 37 | void FileSystem::dirAddSlashAtEnd( std::string& dir ) { |
29 | if ( dir.size() > 1 && dir[dir.size() - 1] != getOSSlash() ) { | 38 | if ( dir.size() >= 1 && dir[dir.size() - 1] != getOSSlash() ) { |
30 | dir.push_back( getOSSlash() ); | 39 | dir.push_back( getOSSlash() ); |
31 | } | 40 | } |
32 | } | 41 | } |
33 | 42 | ||
34 | void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) { | 43 | void FileSystem::dirRemoveSlashAtEnd( std::string& dir ) { |
35 | if ( dir.size() > 1 && dir[dir.size() - 1] == getOSSlash() ) { | 44 | if ( dir.size() >= 1 && dir[dir.size() - 1] == getOSSlash() ) { |
36 | dir.erase( dir.size() - 1 ); | 45 | dir.erase( dir.size() - 1 ); |
37 | } | 46 | } |
38 | } | 47 | } |
@@ -91,13 +100,30 @@ std::string FileSystem::precomposeFileName( const std::string& name ) { | |||
91 | 100 | ||
92 | CFStringNormalize( cfMutable, kCFStringNormalizationFormC ); | 101 | CFStringNormalize( cfMutable, kCFStringNormalizationFormC ); |
93 | 102 | ||
94 | char c_str[255 + 1]; | 103 | const char* c_str = CFStringGetCStringPtr( cfMutable, kCFStringEncodingUTF8 ); |
95 | CFStringGetCString( cfMutable, c_str, sizeof( c_str ) - 1, kCFStringEncodingUTF8 ); | 104 | if ( c_str != NULL ) { |
96 | 105 | std::string result( c_str ); | |
97 | CFRelease( cfStringRef ); | 106 | CFRelease( cfStringRef ); |
98 | CFRelease( cfMutable ); | 107 | CFRelease( cfMutable ); |
108 | return result; | ||
109 | } | ||
110 | CFIndex length = CFStringGetLength( cfMutable ); | ||
111 | CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ); | ||
112 | if ( maxSize == kCFNotFound ) { | ||
113 | CFRelease( cfStringRef ); | ||
114 | CFRelease( cfMutable ); | ||
115 | return std::string(); | ||
116 | } | ||
99 | 117 | ||
100 | return std::string( c_str ); | 118 | std::string result( maxSize + 1, '\0' ); |
119 | if ( CFStringGetCString( cfMutable, &result[0], result.size(), kCFStringEncodingUTF8 ) ) { | ||
120 | result.resize( std::strlen( result.c_str() ) ); | ||
121 | CFRelease( cfStringRef ); | ||
122 | CFRelease( cfMutable ); | ||
123 | } else { | ||
124 | result.clear(); | ||
125 | } | ||
126 | return result; | ||
101 | #else | 127 | #else |
102 | return name; | 128 | return name; |
103 | #endif | 129 | #endif |
@@ -115,4 +141,21 @@ std::string FileSystem::getCurrentWorkingDirectory() { | |||
115 | return Platform::FileSystem::getCurrentWorkingDirectory(); | 141 | return Platform::FileSystem::getCurrentWorkingDirectory(); |
116 | } | 142 | } |
117 | 143 | ||
144 | std::string FileSystem::getRealPath( const std::string& path ) { | ||
145 | std::string realPath; | ||
146 | #if defined( EFSW_PLATFORM_POSIX ) | ||
147 | char dir[PATH_MAX]; | ||
148 | realpath( path.c_str(), &dir[0] ); | ||
149 | realPath = std::string( dir ); | ||
150 | #elif EFSW_OS == EFSW_OS_WIN | ||
151 | wchar_t dir[_MAX_PATH + 1]; | ||
152 | GetFullPathNameW( String::fromUtf8( path ).toWideString().c_str(), _MAX_PATH, &dir[0], | ||
153 | nullptr ); | ||
154 | realPath = String( dir ).toUtf8(); | ||
155 | #else | ||
156 | #warning FileSystem::getRealPath() not implemented on this platform. | ||
157 | #endif | ||
158 | return realPath; | ||
159 | } | ||
160 | |||
118 | } // namespace efsw | 161 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/FileSystem.hpp b/src/3rdParty/efsw/FileSystem.hpp index 6c24386..1d66ece 100755..100644 --- a/src/3rdParty/efsw/FileSystem.hpp +++ b/src/3rdParty/efsw/FileSystem.hpp | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | #include <efsw/FileInfo.hpp> | 4 | #include <efsw/FileInfo.hpp> |
5 | #include <efsw/base.hpp> | 5 | #include <efsw/base.hpp> |
6 | #include <map> | ||
7 | 6 | ||
8 | namespace efsw { | 7 | namespace efsw { |
9 | 8 | ||
@@ -34,6 +33,9 @@ class FileSystem { | |||
34 | static bool changeWorkingDirectory( const std::string& path ); | 33 | static bool changeWorkingDirectory( const std::string& path ); |
35 | 34 | ||
36 | static std::string getCurrentWorkingDirectory(); | 35 | static std::string getCurrentWorkingDirectory(); |
36 | |||
37 | static std::string getRealPath( const std::string& path ); | ||
38 | |||
37 | }; | 39 | }; |
38 | 40 | ||
39 | } // namespace efsw | 41 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/FileWatcher.cpp b/src/3rdParty/efsw/FileWatcher.cpp index 696a46f..f45b243 100755..100644 --- a/src/3rdParty/efsw/FileWatcher.cpp +++ b/src/3rdParty/efsw/FileWatcher.cpp | |||
@@ -1,119 +1,120 @@ | |||
1 | #include <efsw/FileSystem.hpp> | 1 | #include <efsw/FileSystem.hpp> |
2 | #include <efsw/FileWatcherGeneric.hpp> | 2 | #include <efsw/FileWatcherGeneric.hpp> |
3 | #include <efsw/FileWatcherImpl.hpp> | 3 | #include <efsw/FileWatcherImpl.hpp> |
4 | #include <efsw/efsw.hpp> | 4 | #include <efsw/efsw.hpp> |
5 | 5 | ||
6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
7 | #include <efsw/FileWatcherWin32.hpp> | 7 | #include <efsw/FileWatcherWin32.hpp> |
8 | #define FILEWATCHER_IMPL FileWatcherWin32 | 8 | #define FILEWATCHER_IMPL FileWatcherWin32 |
9 | #define BACKEND_NAME "Win32" | 9 | #define BACKEND_NAME "Win32" |
10 | #elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY | 10 | #elif EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY |
11 | #include <efsw/FileWatcherInotify.hpp> | 11 | #include <efsw/FileWatcherInotify.hpp> |
12 | #define FILEWATCHER_IMPL FileWatcherInotify | 12 | #define FILEWATCHER_IMPL FileWatcherInotify |
13 | #define BACKEND_NAME "Inotify" | 13 | #define BACKEND_NAME "Inotify" |
14 | #elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE | 14 | #elif EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE |
15 | #include <efsw/FileWatcherKqueue.hpp> | 15 | #include <efsw/FileWatcherKqueue.hpp> |
16 | #define FILEWATCHER_IMPL FileWatcherKqueue | 16 | #define FILEWATCHER_IMPL FileWatcherKqueue |
17 | #define BACKEND_NAME "Kqueue" | 17 | #define BACKEND_NAME "Kqueue" |
18 | #elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | 18 | #elif EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS |
19 | #include <efsw/FileWatcherFSEvents.hpp> | 19 | #include <efsw/FileWatcherFSEvents.hpp> |
20 | #define FILEWATCHER_IMPL FileWatcherFSEvents | 20 | #define FILEWATCHER_IMPL FileWatcherFSEvents |
21 | #define BACKEND_NAME "FSEvents" | 21 | #define BACKEND_NAME "FSEvents" |
22 | #else | 22 | #else |
23 | #define FILEWATCHER_IMPL FileWatcherGeneric | 23 | #define FILEWATCHER_IMPL FileWatcherGeneric |
24 | #define BACKEND_NAME "Generic" | 24 | #define BACKEND_NAME "Generic" |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | #include <efsw/Debug.hpp> | 27 | #include <efsw/Debug.hpp> |
28 | 28 | ||
29 | namespace efsw { | 29 | namespace efsw { |
30 | 30 | ||
31 | FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { | 31 | FileWatcher::FileWatcher() : mFollowSymlinks( false ), mOutOfScopeLinks( false ) { |
32 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); | 32 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); |
33 | 33 | ||
34 | mImpl = new FILEWATCHER_IMPL( this ); | 34 | mImpl = new FILEWATCHER_IMPL( this ); |
35 | 35 | ||
36 | if ( !mImpl->initOK() ) { | 36 | if ( !mImpl->initOK() ) { |
37 | efSAFE_DELETE( mImpl ); | 37 | efSAFE_DELETE( mImpl ); |
38 | 38 | ||
39 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); | 39 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); |
40 | 40 | ||
41 | mImpl = new FileWatcherGeneric( this ); | 41 | mImpl = new FileWatcherGeneric( this ); |
42 | } | 42 | } |
43 | } | 43 | } |
44 | 44 | ||
45 | FileWatcher::FileWatcher( bool useGenericFileWatcher ) : | 45 | FileWatcher::FileWatcher( bool useGenericFileWatcher ) : |
46 | mFollowSymlinks( false ), mOutOfScopeLinks( false ) { | 46 | mFollowSymlinks( false ), mOutOfScopeLinks( false ) { |
47 | if ( useGenericFileWatcher ) { | 47 | if ( useGenericFileWatcher ) { |
48 | efDEBUG( "Using backend: Generic\n" ); | 48 | efDEBUG( "Using backend: Generic\n" ); |
49 | 49 | ||
50 | mImpl = new FileWatcherGeneric( this ); | 50 | mImpl = new FileWatcherGeneric( this ); |
51 | } else { | 51 | } else { |
52 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); | 52 | efDEBUG( "Using backend: %s\n", BACKEND_NAME ); |
53 | 53 | ||
54 | mImpl = new FILEWATCHER_IMPL( this ); | 54 | mImpl = new FILEWATCHER_IMPL( this ); |
55 | 55 | ||
56 | if ( !mImpl->initOK() ) { | 56 | if ( !mImpl->initOK() ) { |
57 | efSAFE_DELETE( mImpl ); | 57 | efSAFE_DELETE( mImpl ); |
58 | 58 | ||
59 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); | 59 | efDEBUG( "Falled back to backend: %s\n", BACKEND_NAME ); |
60 | 60 | ||
61 | mImpl = new FileWatcherGeneric( this ); | 61 | mImpl = new FileWatcherGeneric( this ); |
62 | } | 62 | } |
63 | } | 63 | } |
64 | } | 64 | } |
65 | 65 | ||
66 | FileWatcher::~FileWatcher() { | 66 | FileWatcher::~FileWatcher() { |
67 | efSAFE_DELETE( mImpl ); | 67 | efSAFE_DELETE( mImpl ); |
68 | } | 68 | } |
69 | 69 | ||
70 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { | 70 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher ) { |
71 | if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { | 71 | return addWatch( directory, watcher, false, {} ); |
72 | return mImpl->addWatch( directory, watcher, false ); | 72 | } |
73 | } else { | 73 | |
74 | return Errors::Log::createLastError( Errors::FileRemote, directory ); | 74 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, |
75 | } | 75 | bool recursive ) { |
76 | } | 76 | return addWatch( directory, watcher, recursive, {} ); |
77 | 77 | } | |
78 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, | 78 | |
79 | bool recursive ) { | 79 | WatchID FileWatcher::addWatch( const std::string& directory, FileWatchListener* watcher, |
80 | if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { | 80 | bool recursive, const std::vector<WatcherOption>& options ) { |
81 | return mImpl->addWatch( directory, watcher, recursive ); | 81 | if ( mImpl->mIsGeneric || !FileSystem::isRemoteFS( directory ) ) { |
82 | } else { | 82 | return mImpl->addWatch( directory, watcher, recursive, options ); |
83 | return Errors::Log::createLastError( Errors::FileRemote, directory ); | 83 | } else { |
84 | } | 84 | return Errors::Log::createLastError( Errors::FileRemote, directory ); |
85 | } | 85 | } |
86 | 86 | } | |
87 | void FileWatcher::removeWatch( const std::string& directory ) { | 87 | |
88 | mImpl->removeWatch( directory ); | 88 | void FileWatcher::removeWatch( const std::string& directory ) { |
89 | } | 89 | mImpl->removeWatch( directory ); |
90 | 90 | } | |
91 | void FileWatcher::removeWatch( WatchID watchid ) { | 91 | |
92 | mImpl->removeWatch( watchid ); | 92 | void FileWatcher::removeWatch( WatchID watchid ) { |
93 | } | 93 | mImpl->removeWatch( watchid ); |
94 | 94 | } | |
95 | void FileWatcher::watch() { | 95 | |
96 | mImpl->watch(); | 96 | void FileWatcher::watch() { |
97 | } | 97 | mImpl->watch(); |
98 | 98 | } | |
99 | std::list<std::string> FileWatcher::directories() { | 99 | |
100 | return mImpl->directories(); | 100 | std::vector<std::string> FileWatcher::directories() { |
101 | } | 101 | return mImpl->directories(); |
102 | 102 | } | |
103 | void FileWatcher::followSymlinks( bool follow ) { | 103 | |
104 | mFollowSymlinks = follow; | 104 | void FileWatcher::followSymlinks( bool follow ) { |
105 | } | 105 | mFollowSymlinks = follow; |
106 | 106 | } | |
107 | const bool& FileWatcher::followSymlinks() const { | 107 | |
108 | return mFollowSymlinks; | 108 | const bool& FileWatcher::followSymlinks() const { |
109 | } | 109 | return mFollowSymlinks; |
110 | 110 | } | |
111 | void FileWatcher::allowOutOfScopeLinks( bool allow ) { | 111 | |
112 | mOutOfScopeLinks = allow; | 112 | void FileWatcher::allowOutOfScopeLinks( bool allow ) { |
113 | } | 113 | mOutOfScopeLinks = allow; |
114 | 114 | } | |
115 | const bool& FileWatcher::allowOutOfScopeLinks() const { | 115 | |
116 | return mOutOfScopeLinks; | 116 | const bool& FileWatcher::allowOutOfScopeLinks() const { |
117 | } | 117 | return mOutOfScopeLinks; |
118 | 118 | } | |
119 | } // namespace efsw | 119 | |
120 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileWatcherCWrapper.cpp b/src/3rdParty/efsw/FileWatcherCWrapper.cpp index 5c49a66..8712d6e 100755..100644 --- a/src/3rdParty/efsw/FileWatcherCWrapper.cpp +++ b/src/3rdParty/efsw/FileWatcherCWrapper.cpp | |||
@@ -28,12 +28,12 @@ class Watcher_CAPI : public efsw::FileWatchListener { | |||
28 | */ | 28 | */ |
29 | static std::vector<Watcher_CAPI*> g_callbacks; | 29 | static std::vector<Watcher_CAPI*> g_callbacks; |
30 | 30 | ||
31 | Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn ) { | 31 | Watcher_CAPI* find_callback( efsw_watcher watcher, efsw_pfn_fileaction_callback fn, void* param ) { |
32 | for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); | 32 | for ( std::vector<Watcher_CAPI*>::iterator i = g_callbacks.begin(); i != g_callbacks.end(); |
33 | ++i ) { | 33 | ++i ) { |
34 | Watcher_CAPI* callback = *i; | 34 | Watcher_CAPI* callback = *i; |
35 | 35 | ||
36 | if ( callback->mFn == fn && callback->mWatcher == watcher ) | 36 | if ( callback->mFn == fn && callback->mWatcher == watcher && callback->mParam == param ) |
37 | return *i; | 37 | return *i; |
38 | } | 38 | } |
39 | 39 | ||
@@ -71,17 +71,35 @@ const char* efsw_getlasterror() { | |||
71 | return log_str.c_str(); | 71 | return log_str.c_str(); |
72 | } | 72 | } |
73 | 73 | ||
74 | EFSW_API void efsw_clearlasterror() { | ||
75 | efsw::Errors::Log::clearLastError(); | ||
76 | } | ||
77 | |||
74 | efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory, | 78 | efsw_watchid efsw_addwatch( efsw_watcher watcher, const char* directory, |
75 | efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) { | 79 | efsw_pfn_fileaction_callback callback_fn, int recursive, void* param ) { |
76 | Watcher_CAPI* callback = find_callback( watcher, callback_fn ); | 80 | return efsw_addwatch_withoptions( watcher, directory, callback_fn, recursive, 0, 0, param ); |
81 | } | ||
82 | |||
83 | efsw_watchid efsw_addwatch_withoptions(efsw_watcher watcher, const char* directory, | ||
84 | efsw_pfn_fileaction_callback callback_fn, int recursive, | ||
85 | efsw_watcher_option *options, int options_number, | ||
86 | void* param) { | ||
87 | Watcher_CAPI* callback = find_callback( watcher, callback_fn, param ); | ||
77 | 88 | ||
78 | if ( callback == NULL ) { | 89 | if ( callback == NULL ) { |
79 | callback = new Watcher_CAPI( watcher, callback_fn, param ); | 90 | callback = new Watcher_CAPI( watcher, callback_fn, param ); |
80 | g_callbacks.push_back( callback ); | 91 | g_callbacks.push_back( callback ); |
81 | } | 92 | } |
82 | 93 | ||
94 | std::vector<efsw::WatcherOption> watcher_options{}; | ||
95 | for ( int i = 0; i < options_number; i++ ) { | ||
96 | efsw_watcher_option* option = &options[i]; | ||
97 | watcher_options.emplace_back( efsw::WatcherOption{ | ||
98 | static_cast<efsw::Option>(option->option), option->value } ); | ||
99 | } | ||
100 | |||
83 | return ( (efsw::FileWatcher*)watcher ) | 101 | return ( (efsw::FileWatcher*)watcher ) |
84 | ->addWatch( std::string( directory ), callback, TOBOOL( recursive ) ); | 102 | ->addWatch( std::string( directory ), callback, TOBOOL( recursive ), watcher_options ); |
85 | } | 103 | } |
86 | 104 | ||
87 | void efsw_removewatch( efsw_watcher watcher, const char* directory ) { | 105 | void efsw_removewatch( efsw_watcher watcher, const char* directory ) { |
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.cpp b/src/3rdParty/efsw/FileWatcherFSEvents.cpp index bcfdbe6..70ec2b1 100755..100644 --- a/src/3rdParty/efsw/FileWatcherFSEvents.cpp +++ b/src/3rdParty/efsw/FileWatcherFSEvents.cpp | |||
@@ -41,6 +41,32 @@ bool FileWatcherFSEvents::isGranular() { | |||
41 | return getOSXReleaseNumber() >= 11; | 41 | return getOSXReleaseNumber() >= 11; |
42 | } | 42 | } |
43 | 43 | ||
44 | static std::string convertCFStringToStdString( CFStringRef cfString ) { | ||
45 | // Try to get the C string pointer directly | ||
46 | const char* cStr = CFStringGetCStringPtr( cfString, kCFStringEncodingUTF8 ); | ||
47 | |||
48 | if ( cStr ) { | ||
49 | // If the pointer is valid, directly return a std::string from it | ||
50 | return std::string( cStr ); | ||
51 | } else { | ||
52 | // If not, manually convert it | ||
53 | CFIndex length = CFStringGetLength( cfString ); | ||
54 | CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8 ) + | ||
55 | 1; // +1 for null terminator | ||
56 | |||
57 | char* buffer = new char[maxSize]; | ||
58 | |||
59 | if ( CFStringGetCString( cfString, buffer, maxSize, kCFStringEncodingUTF8 ) ) { | ||
60 | std::string result( buffer ); | ||
61 | delete[] buffer; | ||
62 | return result; | ||
63 | } else { | ||
64 | delete[] buffer; | ||
65 | return ""; | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
44 | void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, void* userData, | 70 | void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, void* userData, |
45 | size_t numEvents, void* eventPaths, | 71 | size_t numEvents, void* eventPaths, |
46 | const FSEventStreamEventFlags eventFlags[], | 72 | const FSEventStreamEventFlags eventFlags[], |
@@ -51,8 +77,24 @@ void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, | |||
51 | events.reserve( numEvents ); | 77 | events.reserve( numEvents ); |
52 | 78 | ||
53 | for ( size_t i = 0; i < numEvents; i++ ) { | 79 | for ( size_t i = 0; i < numEvents; i++ ) { |
54 | events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), (long)eventFlags[i], | 80 | if ( isGranular() ) { |
55 | (Uint64)eventIds[i] ) ); | 81 | CFDictionaryRef pathInfoDict = |
82 | static_cast<CFDictionaryRef>( CFArrayGetValueAtIndex( (CFArrayRef)eventPaths, i ) ); | ||
83 | CFStringRef path = static_cast<CFStringRef>( | ||
84 | CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedDataPathKey ) ); | ||
85 | CFNumberRef cfInode = static_cast<CFNumberRef>( | ||
86 | CFDictionaryGetValue( pathInfoDict, kFSEventStreamEventExtendedFileIDKey ) ); | ||
87 | |||
88 | if ( cfInode ) { | ||
89 | unsigned long inode = 0; | ||
90 | CFNumberGetValue( cfInode, kCFNumberLongType, &inode ); | ||
91 | events.push_back( FSEvent( convertCFStringToStdString( path ), (long)eventFlags[i], | ||
92 | (Uint64)eventIds[i], inode ) ); | ||
93 | } | ||
94 | } else { | ||
95 | events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), | ||
96 | (long)eventFlags[i], (Uint64)eventIds[i] ) ); | ||
97 | } | ||
56 | } | 98 | } |
57 | 99 | ||
58 | watcher->handleActions( events ); | 100 | watcher->handleActions( events ); |
@@ -63,7 +105,7 @@ void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef /*streamRef*/, | |||
63 | } | 105 | } |
64 | 106 | ||
65 | FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : | 107 | FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : |
66 | FileWatcherImpl( parent ), mRunLoopRef( NULL ), mLastWatchID( 0 ), mThread( NULL ) { | 108 | FileWatcherImpl( parent ), mLastWatchID( 0 ) { |
67 | mInitOK = true; | 109 | mInitOK = true; |
68 | 110 | ||
69 | watch(); | 111 | watch(); |
@@ -72,10 +114,7 @@ FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) : | |||
72 | FileWatcherFSEvents::~FileWatcherFSEvents() { | 114 | FileWatcherFSEvents::~FileWatcherFSEvents() { |
73 | mInitOK = false; | 115 | mInitOK = false; |
74 | 116 | ||
75 | if ( mRunLoopRef.load() ) | 117 | mWatchCond.notify_all(); |
76 | CFRunLoopStop( mRunLoopRef.load() ); | ||
77 | |||
78 | efSAFE_DELETE( mThread ); | ||
79 | 118 | ||
80 | WatchMap::iterator iter = mWatches.begin(); | 119 | WatchMap::iterator iter = mWatches.begin(); |
81 | 120 | ||
@@ -84,18 +123,11 @@ FileWatcherFSEvents::~FileWatcherFSEvents() { | |||
84 | 123 | ||
85 | efSAFE_DELETE( watch ); | 124 | efSAFE_DELETE( watch ); |
86 | } | 125 | } |
87 | |||
88 | mWatches.clear(); | ||
89 | } | 126 | } |
90 | 127 | ||
91 | WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, | 128 | WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher, |
92 | bool recursive ) { | 129 | bool recursive, const std::vector<WatcherOption>& options ) { |
93 | /// Wait to the RunLoopRef to be ready | 130 | std::string dir( FileSystem::getRealPath( directory ) ); |
94 | while ( NULL == mRunLoopRef.load() ) { | ||
95 | System::sleep( 1 ); | ||
96 | } | ||
97 | |||
98 | std::string dir( directory ); | ||
99 | 131 | ||
100 | FileInfo fi( dir ); | 132 | FileInfo fi( dir ); |
101 | 133 | ||
@@ -135,12 +167,18 @@ WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchLi | |||
135 | pWatch->Directory = dir; | 167 | pWatch->Directory = dir; |
136 | pWatch->Recursive = recursive; | 168 | pWatch->Recursive = recursive; |
137 | pWatch->FWatcher = this; | 169 | pWatch->FWatcher = this; |
170 | pWatch->ModifiedFlags = | ||
171 | getOptionValue( options, Option::MacModifiedFilter, efswFSEventsModified ); | ||
172 | pWatch->SanitizeEvents = getOptionValue( options, Option::MacSanitizeEvents, 0 ) != 0; | ||
138 | 173 | ||
139 | pWatch->init(); | 174 | pWatch->init(); |
140 | 175 | ||
141 | Lock lock( mWatchesLock ); | 176 | { |
142 | mWatches.insert( std::make_pair( mLastWatchID, pWatch ) ); | 177 | Lock lock( mWatchesLock ); |
178 | mWatches.insert( std::make_pair( mLastWatchID, pWatch ) ); | ||
179 | } | ||
143 | 180 | ||
181 | mWatchCond.notify_all(); | ||
144 | return pWatch->ID; | 182 | return pWatch->ID; |
145 | } | 183 | } |
146 | 184 | ||
@@ -174,50 +212,20 @@ void FileWatcherFSEvents::removeWatch( WatchID watchid ) { | |||
174 | efSAFE_DELETE( watch ); | 212 | efSAFE_DELETE( watch ); |
175 | } | 213 | } |
176 | 214 | ||
177 | void FileWatcherFSEvents::watch() { | 215 | void FileWatcherFSEvents::watch() {} |
178 | if ( NULL == mThread ) { | ||
179 | mThread = new Thread( &FileWatcherFSEvents::run, this ); | ||
180 | mThread->launch(); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | void FileWatcherFSEvents::run() { | ||
185 | mRunLoopRef = CFRunLoopGetCurrent(); | ||
186 | |||
187 | while ( mInitOK ) { | ||
188 | mNeedInitMutex.lock(); | ||
189 | |||
190 | if ( !mNeedInit.empty() ) { | ||
191 | for ( std::vector<WatcherFSEvents*>::iterator it = mNeedInit.begin(); | ||
192 | it != mNeedInit.end(); ++it ) { | ||
193 | ( *it )->initAsync(); | ||
194 | } | ||
195 | |||
196 | mNeedInit.clear(); | ||
197 | } | ||
198 | |||
199 | mNeedInitMutex.unlock(); | ||
200 | |||
201 | if ( mWatches.empty() ) { | ||
202 | System::sleep( 100 ); | ||
203 | } else { | ||
204 | CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut ); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | mRunLoopRef = NULL; | ||
209 | } | ||
210 | 216 | ||
211 | void FileWatcherFSEvents::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, | 217 | void FileWatcherFSEvents::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, |
212 | unsigned long /*action*/, std::string /*oldFilename*/ ) { | 218 | unsigned long /*action*/, std::string /*oldFilename*/ ) { |
213 | /// Not used | 219 | /// Not used |
214 | } | 220 | } |
215 | 221 | ||
216 | std::list<std::string> FileWatcherFSEvents::directories() { | 222 | std::vector<std::string> FileWatcherFSEvents::directories() { |
217 | std::list<std::string> dirs; | 223 | std::vector<std::string> dirs; |
218 | 224 | ||
219 | Lock lock( mWatchesLock ); | 225 | Lock lock( mWatchesLock ); |
220 | 226 | ||
227 | dirs.reserve( mWatches.size() ); | ||
228 | |||
221 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 229 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { |
222 | dirs.push_back( std::string( it->second->Directory ) ); | 230 | dirs.push_back( std::string( it->second->Directory ) ); |
223 | } | 231 | } |
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.hpp b/src/3rdParty/efsw/FileWatcherFSEvents.hpp index 5279847..daa538c 100755..100644 --- a/src/3rdParty/efsw/FileWatcherFSEvents.hpp +++ b/src/3rdParty/efsw/FileWatcherFSEvents.hpp | |||
@@ -7,33 +7,15 @@ | |||
7 | 7 | ||
8 | #include <CoreFoundation/CoreFoundation.h> | 8 | #include <CoreFoundation/CoreFoundation.h> |
9 | #include <CoreServices/CoreServices.h> | 9 | #include <CoreServices/CoreServices.h> |
10 | #include <dispatch/dispatch.h> | ||
10 | #include <efsw/WatcherFSEvents.hpp> | 11 | #include <efsw/WatcherFSEvents.hpp> |
11 | #include <list> | ||
12 | #include <map> | 12 | #include <map> |
13 | #include <vector> | 13 | #include <vector> |
14 | #include <condition_variable> | ||
15 | #include <mutex> | ||
14 | 16 | ||
15 | namespace efsw { | 17 | namespace efsw { |
16 | 18 | ||
17 | /* OSX < 10.7 has no file events */ | ||
18 | /* So i declare the events constants */ | ||
19 | enum FSEventEvents { | ||
20 | efswFSEventStreamCreateFlagFileEvents = 0x00000010, | ||
21 | efswFSEventStreamEventFlagItemCreated = 0x00000100, | ||
22 | efswFSEventStreamEventFlagItemRemoved = 0x00000200, | ||
23 | efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, | ||
24 | efswFSEventStreamEventFlagItemRenamed = 0x00000800, | ||
25 | efswFSEventStreamEventFlagItemModified = 0x00001000, | ||
26 | efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, | ||
27 | efswFSEventStreamEventFlagItemChangeOwner = 0x00004000, | ||
28 | efswFSEventStreamEventFlagItemXattrMod = 0x00008000, | ||
29 | efswFSEventStreamEventFlagItemIsFile = 0x00010000, | ||
30 | efswFSEventStreamEventFlagItemIsDir = 0x00020000, | ||
31 | efswFSEventStreamEventFlagItemIsSymlink = 0x00040000, | ||
32 | efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod | | ||
33 | efswFSEventStreamEventFlagItemModified | | ||
34 | efswFSEventStreamEventFlagItemInodeMetaMod | ||
35 | }; | ||
36 | |||
37 | /// Implementation for Win32 based on ReadDirectoryChangesW. | 19 | /// Implementation for Win32 based on ReadDirectoryChangesW. |
38 | /// @class FileWatcherFSEvents | 20 | /// @class FileWatcherFSEvents |
39 | class FileWatcherFSEvents : public FileWatcherImpl { | 21 | class FileWatcherFSEvents : public FileWatcherImpl { |
@@ -52,48 +34,43 @@ class FileWatcherFSEvents : public FileWatcherImpl { | |||
52 | 34 | ||
53 | /// Add a directory watch | 35 | /// Add a directory watch |
54 | /// On error returns WatchID with Error type. | 36 | /// On error returns WatchID with Error type. |
55 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 37 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
38 | const std::vector<WatcherOption> &options ) override; | ||
56 | 39 | ||
57 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 40 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
58 | void removeWatch( const std::string& directory ); | 41 | void removeWatch( const std::string& directory ) override; |
59 | 42 | ||
60 | /// Remove a directory watch. This is a map lookup O(logn). | 43 | /// Remove a directory watch. This is a map lookup O(logn). |
61 | void removeWatch( WatchID watchid ); | 44 | void removeWatch( WatchID watchid ) override; |
62 | 45 | ||
63 | /// Updates the watcher. Must be called often. | 46 | /// Updates the watcher. Must be called often. |
64 | void watch(); | 47 | void watch() override; |
65 | 48 | ||
66 | /// Handles the action | 49 | /// Handles the action |
67 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 50 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
68 | std::string oldFilename = "" ); | 51 | std::string oldFilename = "" ) override; |
69 | 52 | ||
70 | /// @return Returns a list of the directories that are being watched | 53 | /// @return Returns a list of the directories that are being watched |
71 | std::list<std::string> directories(); | 54 | std::vector<std::string> directories() override; |
72 | 55 | ||
73 | protected: | 56 | protected: |
74 | static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents, | 57 | static void FSEventCallback( ConstFSEventStreamRef streamRef, void* userData, size_t numEvents, |
75 | void* eventPaths, const FSEventStreamEventFlags eventFlags[], | 58 | void* eventPaths, const FSEventStreamEventFlags eventFlags[], |
76 | const FSEventStreamEventId eventIds[] ); | 59 | const FSEventStreamEventId eventIds[] ); |
77 | 60 | ||
78 | Atomic<CFRunLoopRef> mRunLoopRef; | ||
79 | |||
80 | /// Vector of WatcherWin32 pointers | 61 | /// Vector of WatcherWin32 pointers |
81 | WatchMap mWatches; | 62 | WatchMap mWatches; |
82 | 63 | ||
83 | /// The last watchid | 64 | /// The last watchid |
84 | WatchID mLastWatchID; | 65 | WatchID mLastWatchID; |
85 | 66 | ||
86 | Thread* mThread; | ||
87 | |||
88 | Mutex mWatchesLock; | 67 | Mutex mWatchesLock; |
89 | 68 | ||
90 | bool pathInWatches( const std::string& path ); | 69 | bool pathInWatches( const std::string& path ) override; |
91 | 70 | ||
92 | std::vector<WatcherFSEvents*> mNeedInit; | 71 | std::mutex mWatchesMutex; |
93 | Mutex mNeedInitMutex; | 72 | std::condition_variable mWatchCond; |
94 | 73 | ||
95 | private: | ||
96 | void run(); | ||
97 | }; | 74 | }; |
98 | 75 | ||
99 | } // namespace efsw | 76 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.cpp b/src/3rdParty/efsw/FileWatcherGeneric.cpp index 074cff1..3f3c52e 100755..100644 --- a/src/3rdParty/efsw/FileWatcherGeneric.cpp +++ b/src/3rdParty/efsw/FileWatcherGeneric.cpp | |||
@@ -25,7 +25,7 @@ FileWatcherGeneric::~FileWatcherGeneric() { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, | 27 | WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, |
28 | bool recursive ) { | 28 | bool recursive, const std::vector<WatcherOption>& options ) { |
29 | std::string dir( directory ); | 29 | std::string dir( directory ); |
30 | 30 | ||
31 | FileSystem::dirAddSlashAtEnd( dir ); | 31 | FileSystem::dirAddSlashAtEnd( dir ); |
@@ -127,11 +127,13 @@ void FileWatcherGeneric::handleAction( Watcher*, const std::string&, unsigned lo | |||
127 | /// Not used | 127 | /// Not used |
128 | } | 128 | } |
129 | 129 | ||
130 | std::list<std::string> FileWatcherGeneric::directories() { | 130 | std::vector<std::string> FileWatcherGeneric::directories() { |
131 | std::list<std::string> dirs; | 131 | std::vector<std::string> dirs; |
132 | 132 | ||
133 | Lock lock( mWatchesLock ); | 133 | Lock lock( mWatchesLock ); |
134 | 134 | ||
135 | dirs.reserve( mWatches.size() ); | ||
136 | |||
135 | WatchList::iterator it = mWatches.begin(); | 137 | WatchList::iterator it = mWatches.begin(); |
136 | 138 | ||
137 | for ( ; it != mWatches.end(); ++it ) { | 139 | for ( ; it != mWatches.end(); ++it ) { |
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.hpp b/src/3rdParty/efsw/FileWatcherGeneric.hpp index 4cb0b67..47f7e04 100755..100644 --- a/src/3rdParty/efsw/FileWatcherGeneric.hpp +++ b/src/3rdParty/efsw/FileWatcherGeneric.hpp | |||
@@ -4,7 +4,7 @@ | |||
4 | #include <efsw/DirWatcherGeneric.hpp> | 4 | #include <efsw/DirWatcherGeneric.hpp> |
5 | #include <efsw/FileWatcherImpl.hpp> | 5 | #include <efsw/FileWatcherImpl.hpp> |
6 | #include <efsw/WatcherGeneric.hpp> | 6 | #include <efsw/WatcherGeneric.hpp> |
7 | #include <list> | 7 | #include <vector> |
8 | 8 | ||
9 | namespace efsw { | 9 | namespace efsw { |
10 | 10 | ||
@@ -12,7 +12,7 @@ namespace efsw { | |||
12 | /// @class FileWatcherGeneric | 12 | /// @class FileWatcherGeneric |
13 | class FileWatcherGeneric : public FileWatcherImpl { | 13 | class FileWatcherGeneric : public FileWatcherImpl { |
14 | public: | 14 | public: |
15 | typedef std::list<WatcherGeneric*> WatchList; | 15 | typedef std::vector<WatcherGeneric*> WatchList; |
16 | 16 | ||
17 | FileWatcherGeneric( FileWatcher* parent ); | 17 | FileWatcherGeneric( FileWatcher* parent ); |
18 | 18 | ||
@@ -20,23 +20,24 @@ class FileWatcherGeneric : public FileWatcherImpl { | |||
20 | 20 | ||
21 | /// Add a directory watch | 21 | /// Add a directory watch |
22 | /// On error returns WatchID with Error type. | 22 | /// On error returns WatchID with Error type. |
23 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 23 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
24 | const std::vector<WatcherOption> &options ) override; | ||
24 | 25 | ||
25 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 26 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
26 | void removeWatch( const std::string& directory ); | 27 | void removeWatch( const std::string& directory ) override; |
27 | 28 | ||
28 | /// Remove a directory watch. This is a map lookup O(logn). | 29 | /// Remove a directory watch. This is a map lookup O(logn). |
29 | void removeWatch( WatchID watchid ); | 30 | void removeWatch( WatchID watchid ) override; |
30 | 31 | ||
31 | /// Updates the watcher. Must be called often. | 32 | /// Updates the watcher. Must be called often. |
32 | void watch(); | 33 | void watch() override; |
33 | 34 | ||
34 | /// Handles the action | 35 | /// Handles the action |
35 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 36 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
36 | std::string oldFilename = "" ); | 37 | std::string oldFilename = "" ) override; |
37 | 38 | ||
38 | /// @return Returns a list of the directories that are being watched | 39 | /// @return Returns a list of the directories that are being watched |
39 | std::list<std::string> directories(); | 40 | std::vector<std::string> directories() override; |
40 | 41 | ||
41 | protected: | 42 | protected: |
42 | Thread* mThread; | 43 | Thread* mThread; |
@@ -49,7 +50,7 @@ class FileWatcherGeneric : public FileWatcherImpl { | |||
49 | 50 | ||
50 | Mutex mWatchesLock; | 51 | Mutex mWatchesLock; |
51 | 52 | ||
52 | bool pathInWatches( const std::string& path ); | 53 | bool pathInWatches( const std::string& path ) override; |
53 | 54 | ||
54 | private: | 55 | private: |
55 | void run(); | 56 | void run(); |
diff --git a/src/3rdParty/efsw/FileWatcherImpl.cpp b/src/3rdParty/efsw/FileWatcherImpl.cpp index f6b86a5..bf69a45 100755..100644 --- a/src/3rdParty/efsw/FileWatcherImpl.cpp +++ b/src/3rdParty/efsw/FileWatcherImpl.cpp | |||
@@ -1,23 +1,34 @@ | |||
1 | #include <efsw/FileWatcherImpl.hpp> | 1 | #include <efsw/FileWatcherImpl.hpp> |
2 | #include <efsw/String.hpp> | 2 | #include <efsw/String.hpp> |
3 | #include <efsw/System.hpp> | 3 | #include <efsw/System.hpp> |
4 | 4 | ||
5 | namespace efsw { | 5 | namespace efsw { |
6 | 6 | ||
7 | FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : | 7 | FileWatcherImpl::FileWatcherImpl( FileWatcher* parent ) : |
8 | mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { | 8 | mFileWatcher( parent ), mInitOK( false ), mIsGeneric( false ) { |
9 | System::maxFD(); | 9 | System::maxFD(); |
10 | } | 10 | } |
11 | 11 | ||
12 | FileWatcherImpl::~FileWatcherImpl() {} | 12 | FileWatcherImpl::~FileWatcherImpl() {} |
13 | 13 | ||
14 | bool FileWatcherImpl::initOK() { | 14 | bool FileWatcherImpl::initOK() { |
15 | return static_cast<bool>( mInitOK ); | 15 | return static_cast<bool>( mInitOK ); |
16 | } | 16 | } |
17 | 17 | ||
18 | bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { | 18 | bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) { |
19 | return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || | 19 | return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || |
20 | -1 != String::strStartsWith( curPath, link ); | 20 | -1 != String::strStartsWith( curPath, link ); |
21 | } | 21 | } |
22 | 22 | ||
23 | } // namespace efsw | 23 | int FileWatcherImpl::getOptionValue( const std::vector<WatcherOption>& options, Option option, |
24 | int defaultValue ) { | ||
25 | for ( size_t i = 0; i < options.size(); i++ ) { | ||
26 | if ( options[i].mOption == option ) { | ||
27 | return options[i].mValue; | ||
28 | } | ||
29 | } | ||
30 | |||
31 | return defaultValue; | ||
32 | } | ||
33 | |||
34 | } // namespace efsw | ||
diff --git a/src/3rdParty/efsw/FileWatcherImpl.hpp b/src/3rdParty/efsw/FileWatcherImpl.hpp index ea1beb8..a6ec472 100755..100644 --- a/src/3rdParty/efsw/FileWatcherImpl.hpp +++ b/src/3rdParty/efsw/FileWatcherImpl.hpp | |||
@@ -1,57 +1,64 @@ | |||
1 | #ifndef EFSW_FILEWATCHERIMPL_HPP | 1 | #ifndef EFSW_FILEWATCHERIMPL_HPP |
2 | #define EFSW_FILEWATCHERIMPL_HPP | 2 | #define EFSW_FILEWATCHERIMPL_HPP |
3 | 3 | ||
4 | #include <efsw/Atomic.hpp> | 4 | #include <efsw/Atomic.hpp> |
5 | #include <efsw/Mutex.hpp> | 5 | #include <efsw/Mutex.hpp> |
6 | #include <efsw/Thread.hpp> | 6 | #include <efsw/Thread.hpp> |
7 | #include <efsw/Watcher.hpp> | 7 | #include <efsw/Watcher.hpp> |
8 | #include <efsw/base.hpp> | 8 | #include <efsw/base.hpp> |
9 | #include <efsw/efsw.hpp> | 9 | #include <efsw/efsw.hpp> |
10 | 10 | ||
11 | namespace efsw { | 11 | namespace efsw { |
12 | 12 | ||
13 | class FileWatcherImpl { | 13 | class FileWatcherImpl { |
14 | public: | 14 | public: |
15 | FileWatcherImpl( FileWatcher* parent ); | 15 | FileWatcherImpl( FileWatcher* parent ); |
16 | 16 | ||
17 | virtual ~FileWatcherImpl(); | 17 | virtual ~FileWatcherImpl(); |
18 | 18 | ||
19 | /// Add a directory watch | 19 | /// Add a directory watch |
20 | /// On error returns WatchID with Error type. | 20 | /// On error returns WatchID with Error type. |
21 | virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, | 21 | virtual WatchID addWatch( const std::string& directory, FileWatchListener* watcher, |
22 | bool recursive ) = 0; | 22 | bool recursive, const std::vector<WatcherOption>& options = {} ) = 0; |
23 | 23 | ||
24 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 24 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
25 | virtual void removeWatch( const std::string& directory ) = 0; | 25 | virtual void removeWatch( const std::string& directory ) = 0; |
26 | 26 | ||
27 | /// Remove a directory watch. This is a map lookup O(logn). | 27 | /// Remove a directory watch. This is a map lookup O(logn). |
28 | virtual void removeWatch( WatchID watchid ) = 0; | 28 | virtual void removeWatch( WatchID watchid ) = 0; |
29 | 29 | ||
30 | /// Updates the watcher. Must be called often. | 30 | /// Updates the watcher. Must be called often. |
31 | virtual void watch() = 0; | 31 | virtual void watch() = 0; |
32 | 32 | ||
33 | /// Handles the action | 33 | /// Handles the action |
34 | virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 34 | virtual void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
35 | std::string oldFilename = "" ) = 0; | 35 | std::string oldFilename = "" ) = 0; |
36 | 36 | ||
37 | /// @return Returns a list of the directories that are being watched | 37 | /// @return Returns a list of the directories that are being watched |
38 | virtual std::list<std::string> directories() = 0; | 38 | virtual std::vector<std::string> directories() = 0; |
39 | 39 | ||
40 | /// @return true if the backend init successfully | 40 | /// @return true if the backend init successfully |
41 | virtual bool initOK(); | 41 | virtual bool initOK(); |
42 | 42 | ||
43 | /// @return If the link is allowed according to the current path and the state of out scope | 43 | /// @return If the link is allowed according to the current path and the state of out scope |
44 | /// links | 44 | /// links |
45 | virtual bool linkAllowed( const std::string& curPath, const std::string& link ); | 45 | virtual bool linkAllowed( const std::string& curPath, const std::string& link ); |
46 | 46 | ||
47 | /// Search if a directory already exists in the watches | 47 | /// Search if a directory already exists in the watches |
48 | virtual bool pathInWatches( const std::string& path ) = 0; | 48 | virtual bool pathInWatches( const std::string& path ) = 0; |
49 | 49 | ||
50 | FileWatcher* mFileWatcher; | 50 | protected: |
51 | Atomic<bool> mInitOK; | 51 | friend class FileWatcher; |
52 | bool mIsGeneric; | 52 | friend class DirWatcherGeneric; |
53 | }; | 53 | |
54 | 54 | FileWatcher* mFileWatcher; | |
55 | } // namespace efsw | 55 | Atomic<bool> mInitOK; |
56 | 56 | bool mIsGeneric; | |
57 | #endif | 57 | |
58 | int getOptionValue( const std::vector<WatcherOption>& options, Option option, | ||
59 | int defaultValue ); | ||
60 | }; | ||
61 | |||
62 | } // namespace efsw | ||
63 | |||
64 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherInotify.cpp b/src/3rdParty/efsw/FileWatcherInotify.cpp index e0da76b..1ec3d48 100755..100644 --- a/src/3rdParty/efsw/FileWatcherInotify.cpp +++ b/src/3rdParty/efsw/FileWatcherInotify.cpp | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <algorithm> | ||
1 | #include <efsw/FileWatcherInotify.hpp> | 2 | #include <efsw/FileWatcherInotify.hpp> |
2 | 3 | ||
3 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY | 4 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY |
@@ -26,7 +27,7 @@ | |||
26 | namespace efsw { | 27 | namespace efsw { |
27 | 28 | ||
28 | FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : | 29 | FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : |
29 | FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ) { | 30 | FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ), mIsTakingAction( false ) { |
30 | mFD = inotify_init(); | 31 | mFD = inotify_init(); |
31 | 32 | ||
32 | if ( mFD < 0 ) { | 33 | if ( mFD < 0 ) { |
@@ -38,13 +39,20 @@ FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : | |||
38 | 39 | ||
39 | FileWatcherInotify::~FileWatcherInotify() { | 40 | FileWatcherInotify::~FileWatcherInotify() { |
40 | mInitOK = false; | 41 | mInitOK = false; |
41 | 42 | // There is deadlock when release FileWatcherInotify instance since its handAction | |
43 | // function is still running and hangs in requiring lock without init lock captured. | ||
44 | while ( mIsTakingAction ) { | ||
45 | // It'd use condition-wait instead of sleep. Actually efsw has no such | ||
46 | // implementation so we just skip and sleep while for that to avoid deadlock. | ||
47 | usleep( 1000 ); | ||
48 | }; | ||
42 | Lock initLock( mInitLock ); | 49 | Lock initLock( mInitLock ); |
43 | 50 | ||
44 | efSAFE_DELETE( mThread ); | 51 | efSAFE_DELETE( mThread ); |
45 | 52 | ||
46 | Lock l( mWatchesLock ); | 53 | Lock l( mWatchesLock ); |
47 | Lock l2( mRealWatchesLock ); | 54 | Lock l2( mRealWatchesLock ); |
55 | |||
48 | WatchMap::iterator iter = mWatches.begin(); | 56 | WatchMap::iterator iter = mWatches.begin(); |
49 | WatchMap::iterator end = mWatches.end(); | 57 | WatchMap::iterator end = mWatches.end(); |
50 | 58 | ||
@@ -61,15 +69,17 @@ FileWatcherInotify::~FileWatcherInotify() { | |||
61 | } | 69 | } |
62 | 70 | ||
63 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, | 71 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, |
64 | bool recursive ) { | 72 | bool recursive, const std::vector<WatcherOption>& options ) { |
65 | if ( !mInitOK ) | 73 | if ( !mInitOK ) |
66 | return Errors::Log::createLastError( Errors::Unspecified, directory ); | 74 | return Errors::Log::createLastError( Errors::Unspecified, directory ); |
67 | Lock initLock( mInitLock ); | 75 | Lock initLock( mInitLock ); |
68 | return addWatch( directory, watcher, recursive, NULL ); | 76 | bool syntheticEvents = getOptionValue( options, Options::LinuxProduceSyntheticEvents, 0 ) != 0; |
77 | return addWatch( directory, watcher, recursive, syntheticEvents, NULL ); | ||
69 | } | 78 | } |
70 | 79 | ||
71 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, | 80 | WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, |
72 | bool recursive, WatcherInotify* parent ) { | 81 | bool recursive, bool syntheticEvents, |
82 | WatcherInotify* parent, bool fromInternalEvent ) { | ||
73 | std::string dir( directory ); | 83 | std::string dir( directory ); |
74 | 84 | ||
75 | FileSystem::dirAddSlashAtEnd( dir ); | 85 | FileSystem::dirAddSlashAtEnd( dir ); |
@@ -133,6 +143,7 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis | |||
133 | { | 143 | { |
134 | Lock lock( mWatchesLock ); | 144 | Lock lock( mWatchesLock ); |
135 | mWatches.insert( std::make_pair( wd, pWatch ) ); | 145 | mWatches.insert( std::make_pair( wd, pWatch ) ); |
146 | mWatchesRef[pWatch->Directory] = wd; | ||
136 | } | 147 | } |
137 | 148 | ||
138 | if ( NULL == pWatch->Parent ) { | 149 | if ( NULL == pWatch->Parent ) { |
@@ -151,7 +162,17 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis | |||
151 | const FileInfo& cfi = it->second; | 162 | const FileInfo& cfi = it->second; |
152 | 163 | ||
153 | if ( cfi.isDirectory() && cfi.isReadable() ) { | 164 | if ( cfi.isDirectory() && cfi.isReadable() ) { |
154 | addWatch( cfi.Filepath, watcher, recursive, pWatch ); | 165 | addWatch( cfi.Filepath, watcher, recursive, syntheticEvents, pWatch ); |
166 | } | ||
167 | } | ||
168 | |||
169 | if ( fromInternalEvent && parent != NULL && syntheticEvents ) { | ||
170 | for ( const auto& file : files ) { | ||
171 | if ( file.second.isRegularFile() ) { | ||
172 | pWatch->Listener->handleFileAction( | ||
173 | pWatch->ID, pWatch->Directory, | ||
174 | FileSystem::fileNameFromPath( file.second.Filepath ), Actions::Add ); | ||
175 | } | ||
155 | } | 176 | } |
156 | } | 177 | } |
157 | } | 178 | } |
@@ -161,6 +182,8 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis | |||
161 | 182 | ||
162 | void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { | 183 | void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { |
163 | WatchMap::iterator iter = mWatches.find( watchid ); | 184 | WatchMap::iterator iter = mWatches.find( watchid ); |
185 | if ( iter == mWatches.end() ) | ||
186 | return; | ||
164 | 187 | ||
165 | WatcherInotify* watch = iter->second; | 188 | WatcherInotify* watch = iter->second; |
166 | 189 | ||
@@ -173,22 +196,21 @@ void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { | |||
173 | } | 196 | } |
174 | } | 197 | } |
175 | 198 | ||
176 | if ( watch->Recursive ) { | 199 | if ( watch->Recursive && NULL == watch->Parent ) { |
177 | WatchMap::iterator it = mWatches.begin(); | 200 | WatchMap::iterator it = mWatches.begin(); |
178 | std::list<WatchID> eraseWatches; | 201 | std::vector<WatchID> eraseWatches; |
179 | 202 | ||
180 | for ( ; it != mWatches.end(); ++it ) { | 203 | for ( ; it != mWatches.end(); ++it ) |
181 | if ( it->second != watch && it->second->inParentTree( watch ) ) { | 204 | if ( it->second != watch && it->second->inParentTree( watch ) ) |
182 | eraseWatches.push_back( it->second->InotifyID ); | 205 | eraseWatches.push_back( it->second->InotifyID ); |
183 | } | ||
184 | } | ||
185 | 206 | ||
186 | for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); | 207 | for ( std::vector<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); |
187 | ++eit ) { | 208 | ++eit ) { |
188 | removeWatch( *eit ); | 209 | removeWatch( *eit ); |
189 | } | 210 | } |
190 | } | 211 | } |
191 | 212 | ||
213 | mWatchesRef.erase( watch->Directory ); | ||
192 | mWatches.erase( iter ); | 214 | mWatches.erase( iter ); |
193 | 215 | ||
194 | if ( NULL == watch->Parent ) { | 216 | if ( NULL == watch->Parent ) { |
@@ -217,52 +239,11 @@ void FileWatcherInotify::removeWatch( const std::string& directory ) { | |||
217 | Lock lock( mWatchesLock ); | 239 | Lock lock( mWatchesLock ); |
218 | Lock l( mRealWatchesLock ); | 240 | Lock l( mRealWatchesLock ); |
219 | 241 | ||
220 | WatchMap::iterator iter = mWatches.begin(); | 242 | std::unordered_map<std::string, WatchID>::iterator ref = mWatchesRef.find( directory ); |
221 | 243 | if ( ref == mWatchesRef.end() ) | |
222 | for ( ; iter != mWatches.end(); ++iter ) { | 244 | return; |
223 | if ( directory == iter->second->Directory ) { | ||
224 | WatcherInotify* watch = iter->second; | ||
225 | |||
226 | if ( watch->Recursive ) { | ||
227 | WatchMap::iterator it = mWatches.begin(); | ||
228 | std::list<WatchID> eraseWatches; | ||
229 | |||
230 | for ( ; it != mWatches.end(); ++it ) { | ||
231 | if ( it->second->inParentTree( watch ) ) { | ||
232 | eraseWatches.push_back( it->second->InotifyID ); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); | ||
237 | eit != eraseWatches.end(); ++eit ) { | ||
238 | removeWatchLocked( *eit ); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | mWatches.erase( iter ); | ||
243 | |||
244 | if ( NULL == watch->Parent ) { | ||
245 | WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID ); | ||
246 | |||
247 | if ( eraseit != mRealWatches.end() ) { | ||
248 | mRealWatches.erase( eraseit ); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | int err = inotify_rm_watch( mFD, watch->InotifyID ); | ||
253 | |||
254 | if ( err < 0 ) { | ||
255 | efDEBUG( "Error removing watch %d: %s\n", watch->InotifyID, strerror( errno ) ); | ||
256 | } else { | ||
257 | efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(), | ||
258 | watch->InotifyID ); | ||
259 | } | ||
260 | |||
261 | efSAFE_DELETE( watch ); | ||
262 | 245 | ||
263 | break; | 246 | removeWatchLocked( ref->second ); |
264 | } | ||
265 | } | ||
266 | } | 247 | } |
267 | 248 | ||
268 | void FileWatcherInotify::removeWatch( WatchID watchid ) { | 249 | void FileWatcherInotify::removeWatch( WatchID watchid ) { |
@@ -270,13 +251,6 @@ void FileWatcherInotify::removeWatch( WatchID watchid ) { | |||
270 | return; | 251 | return; |
271 | Lock initLock( mInitLock ); | 252 | Lock initLock( mInitLock ); |
272 | Lock lock( mWatchesLock ); | 253 | Lock lock( mWatchesLock ); |
273 | |||
274 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
275 | |||
276 | if ( iter == mWatches.end() ) { | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | removeWatchLocked( watchid ); | 254 | removeWatchLocked( watchid ); |
281 | } | 255 | } |
282 | 256 | ||
@@ -295,10 +269,8 @@ Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) { | |||
295 | 269 | ||
296 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 270 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { |
297 | Watcher* watcher = it->second; | 271 | Watcher* watcher = it->second; |
298 | 272 | if ( watcher->Directory == watcherPath ) | |
299 | if ( watcher->Directory == watcherPath ) { | ||
300 | return watcher; | 273 | return watcher; |
301 | } | ||
302 | } | 274 | } |
303 | 275 | ||
304 | return NULL; | 276 | return NULL; |
@@ -422,7 +394,7 @@ void FileWatcherInotify::run() { | |||
422 | const std::string& oldFileName = ( *it ).second; | 394 | const std::string& oldFileName = ( *it ).second; |
423 | 395 | ||
424 | /// Check if the file move was a folder already being watched | 396 | /// Check if the file move was a folder already being watched |
425 | std::list<Watcher*> eraseWatches; | 397 | std::vector<Watcher*> eraseWatches; |
426 | 398 | ||
427 | { | 399 | { |
428 | Lock lock( mWatchesLock ); | 400 | Lock lock( mWatchesLock ); |
@@ -439,12 +411,15 @@ void FileWatcherInotify::run() { | |||
439 | } | 411 | } |
440 | 412 | ||
441 | /// Remove invalid watches | 413 | /// Remove invalid watches |
442 | eraseWatches.sort(); | 414 | std::stable_sort( eraseWatches.begin(), eraseWatches.end(), |
415 | []( const Watcher* left, const Watcher* right ) { | ||
416 | return left->Directory < right->Directory; | ||
417 | } ); | ||
443 | 418 | ||
444 | if ( eraseWatches.empty() ) { | 419 | if ( eraseWatches.empty() ) { |
445 | handleAction( watch, oldFileName, IN_DELETE ); | 420 | handleAction( watch, oldFileName, IN_DELETE ); |
446 | } else { | 421 | } else { |
447 | for ( std::list<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); | 422 | for ( std::vector<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); |
448 | eit != eraseWatches.rend(); ++eit ) { | 423 | eit != eraseWatches.rend(); ++eit ) { |
449 | Watcher* rmWatch = *eit; | 424 | Watcher* rmWatch = *eit; |
450 | 425 | ||
@@ -485,8 +460,9 @@ void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath ) | |||
485 | } | 460 | } |
486 | 461 | ||
487 | if ( !found ) { | 462 | if ( !found ) { |
488 | addWatch( fpath, watch->Listener, watch->Recursive, | 463 | WatcherInotify* iWatch = static_cast<WatcherInotify*>( watch ); |
489 | static_cast<WatcherInotify*>( watch ) ); | 464 | addWatch( fpath, watch->Listener, watch->Recursive, iWatch->syntheticEvents, |
465 | static_cast<WatcherInotify*>( watch ), true ); | ||
490 | } | 466 | } |
491 | } | 467 | } |
492 | } | 468 | } |
@@ -496,7 +472,7 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena | |||
496 | if ( !watch || !watch->Listener || !mInitOK ) { | 472 | if ( !watch || !watch->Listener || !mInitOK ) { |
497 | return; | 473 | return; |
498 | } | 474 | } |
499 | 475 | mIsTakingAction = true; | |
500 | Lock initLock( mInitLock ); | 476 | Lock initLock( mInitLock ); |
501 | 477 | ||
502 | std::string fpath( watch->Directory + filename ); | 478 | std::string fpath( watch->Directory + filename ); |
@@ -563,18 +539,20 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena | |||
563 | } | 539 | } |
564 | } | 540 | } |
565 | } | 541 | } |
542 | mIsTakingAction = false; | ||
566 | } | 543 | } |
567 | 544 | ||
568 | std::list<std::string> FileWatcherInotify::directories() { | 545 | std::vector<std::string> FileWatcherInotify::directories() { |
569 | std::list<std::string> dirs; | 546 | std::vector<std::string> dirs; |
570 | 547 | ||
571 | Lock l( mRealWatchesLock ); | 548 | Lock l( mRealWatchesLock ); |
572 | 549 | ||
550 | dirs.reserve( mRealWatches.size() ); | ||
551 | |||
573 | WatchMap::iterator it = mRealWatches.begin(); | 552 | WatchMap::iterator it = mRealWatches.begin(); |
574 | 553 | ||
575 | for ( ; it != mRealWatches.end(); ++it ) { | 554 | for ( ; it != mRealWatches.end(); ++it ) |
576 | dirs.push_back( it->second->Directory ); | 555 | dirs.push_back( it->second->Directory ); |
577 | } | ||
578 | 556 | ||
579 | return dirs; | 557 | return dirs; |
580 | } | 558 | } |
@@ -585,11 +563,9 @@ bool FileWatcherInotify::pathInWatches( const std::string& path ) { | |||
585 | /// Search in the real watches, since it must allow adding a watch already watched as a subdir | 563 | /// Search in the real watches, since it must allow adding a watch already watched as a subdir |
586 | WatchMap::iterator it = mRealWatches.begin(); | 564 | WatchMap::iterator it = mRealWatches.begin(); |
587 | 565 | ||
588 | for ( ; it != mRealWatches.end(); ++it ) { | 566 | for ( ; it != mRealWatches.end(); ++it ) |
589 | if ( it->second->Directory == path ) { | 567 | if ( it->second->Directory == path ) |
590 | return true; | 568 | return true; |
591 | } | ||
592 | } | ||
593 | 569 | ||
594 | return false; | 570 | return false; |
595 | } | 571 | } |
diff --git a/src/3rdParty/efsw/FileWatcherInotify.hpp b/src/3rdParty/efsw/FileWatcherInotify.hpp index dc922ac..26d2c0b 100755..100644 --- a/src/3rdParty/efsw/FileWatcherInotify.hpp +++ b/src/3rdParty/efsw/FileWatcherInotify.hpp | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #include <efsw/WatcherInotify.hpp> | 8 | #include <efsw/WatcherInotify.hpp> |
9 | #include <map> | 9 | #include <map> |
10 | #include <unordered_map> | ||
10 | #include <vector> | 11 | #include <vector> |
11 | 12 | ||
12 | namespace efsw { | 13 | namespace efsw { |
@@ -24,23 +25,24 @@ class FileWatcherInotify : public FileWatcherImpl { | |||
24 | 25 | ||
25 | /// Add a directory watch | 26 | /// Add a directory watch |
26 | /// On error returns WatchID with Error type. | 27 | /// On error returns WatchID with Error type. |
27 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 28 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
29 | const std::vector<WatcherOption>& options ) override; | ||
28 | 30 | ||
29 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 31 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
30 | void removeWatch( const std::string& directory ); | 32 | void removeWatch( const std::string& directory ) override; |
31 | 33 | ||
32 | /// Remove a directory watch. This is a map lookup O(logn). | 34 | /// Remove a directory watch. This is a map lookup O(logn). |
33 | void removeWatch( WatchID watchid ); | 35 | void removeWatch( WatchID watchid ) override; |
34 | 36 | ||
35 | /// Updates the watcher. Must be called often. | 37 | /// Updates the watcher. Must be called often. |
36 | void watch(); | 38 | void watch() override; |
37 | 39 | ||
38 | /// Handles the action | 40 | /// Handles the action |
39 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 41 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
40 | std::string oldFilename = "" ); | 42 | std::string oldFilename = "" ) override; |
41 | 43 | ||
42 | /// @return Returns a list of the directories that are being watched | 44 | /// @return Returns a list of the directories that are being watched |
43 | std::list<std::string> directories(); | 45 | std::vector<std::string> directories() override; |
44 | 46 | ||
45 | protected: | 47 | protected: |
46 | /// Map of WatchID to WatchStruct pointers | 48 | /// Map of WatchID to WatchStruct pointers |
@@ -49,6 +51,8 @@ class FileWatcherInotify : public FileWatcherImpl { | |||
49 | /// User added watches | 51 | /// User added watches |
50 | WatchMap mRealWatches; | 52 | WatchMap mRealWatches; |
51 | 53 | ||
54 | std::unordered_map<std::string, WatchID> mWatchesRef; | ||
55 | |||
52 | /// inotify file descriptor | 56 | /// inotify file descriptor |
53 | int mFD; | 57 | int mFD; |
54 | 58 | ||
@@ -57,12 +61,14 @@ class FileWatcherInotify : public FileWatcherImpl { | |||
57 | Mutex mWatchesLock; | 61 | Mutex mWatchesLock; |
58 | Mutex mRealWatchesLock; | 62 | Mutex mRealWatchesLock; |
59 | Mutex mInitLock; | 63 | Mutex mInitLock; |
64 | bool mIsTakingAction; | ||
60 | std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches; | 65 | std::vector<std::pair<WatcherInotify*, std::string>> mMovedOutsideWatches; |
61 | 66 | ||
62 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, | 67 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
63 | WatcherInotify* parent = NULL ); | 68 | bool syntheticEvents, WatcherInotify* parent = NULL, |
69 | bool fromInternalEvent = false ); | ||
64 | 70 | ||
65 | bool pathInWatches( const std::string& path ); | 71 | bool pathInWatches( const std::string& path ) override; |
66 | 72 | ||
67 | private: | 73 | private: |
68 | void run(); | 74 | void run(); |
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.cpp b/src/3rdParty/efsw/FileWatcherKqueue.cpp index 38ffad9..ad03036 100755..100644 --- a/src/3rdParty/efsw/FileWatcherKqueue.cpp +++ b/src/3rdParty/efsw/FileWatcherKqueue.cpp | |||
@@ -45,7 +45,7 @@ FileWatcherKqueue::~FileWatcherKqueue() { | |||
45 | } | 45 | } |
46 | 46 | ||
47 | WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, | 47 | WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, |
48 | bool recursive ) { | 48 | bool recursive, const std::vector<WatcherOption>& /*options*/ ) { |
49 | static bool s_ug = false; | 49 | static bool s_ug = false; |
50 | 50 | ||
51 | std::string dir( directory ); | 51 | std::string dir( directory ); |
@@ -184,11 +184,13 @@ void FileWatcherKqueue::run() { | |||
184 | void FileWatcherKqueue::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, | 184 | void FileWatcherKqueue::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, |
185 | unsigned long /*action*/, std::string /*oldFilename*/ ) {} | 185 | unsigned long /*action*/, std::string /*oldFilename*/ ) {} |
186 | 186 | ||
187 | std::list<std::string> FileWatcherKqueue::directories() { | 187 | std::vector<std::string> FileWatcherKqueue::directories() { |
188 | std::list<std::string> dirs; | 188 | std::vector<std::string> dirs; |
189 | 189 | ||
190 | Lock lock( mWatchesLock ); | 190 | Lock lock( mWatchesLock ); |
191 | 191 | ||
192 | dirs.reserve( mWatches.size() ); | ||
193 | |||
192 | WatchMap::iterator it = mWatches.begin(); | 194 | WatchMap::iterator it = mWatches.begin(); |
193 | 195 | ||
194 | for ( ; it != mWatches.end(); ++it ) { | 196 | for ( ; it != mWatches.end(); ++it ) { |
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.hpp b/src/3rdParty/efsw/FileWatcherKqueue.hpp index 1bf3755..ff5327b 100755..100644 --- a/src/3rdParty/efsw/FileWatcherKqueue.hpp +++ b/src/3rdParty/efsw/FileWatcherKqueue.hpp | |||
@@ -21,23 +21,24 @@ class FileWatcherKqueue : public FileWatcherImpl { | |||
21 | 21 | ||
22 | /// Add a directory watch | 22 | /// Add a directory watch |
23 | /// On error returns WatchID with Error type. | 23 | /// On error returns WatchID with Error type. |
24 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 24 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
25 | const std::vector<WatcherOption> &options ) override; | ||
25 | 26 | ||
26 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 27 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
27 | void removeWatch( const std::string& directory ); | 28 | void removeWatch( const std::string& directory ) override; |
28 | 29 | ||
29 | /// Remove a directory watch. This is a map lookup O(logn). | 30 | /// Remove a directory watch. This is a map lookup O(logn). |
30 | void removeWatch( WatchID watchid ); | 31 | void removeWatch( WatchID watchid ) override; |
31 | 32 | ||
32 | /// Updates the watcher. Must be called often. | 33 | /// Updates the watcher. Must be called often. |
33 | void watch(); | 34 | void watch() override; |
34 | 35 | ||
35 | /// Handles the action | 36 | /// Handles the action |
36 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 37 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
37 | std::string oldFilename = "" ); | 38 | std::string oldFilename = "" ) override; |
38 | 39 | ||
39 | /// @return Returns a list of the directories that are being watched | 40 | /// @return Returns a list of the directories that are being watched |
40 | std::list<std::string> directories(); | 41 | std::vector<std::string> directories() override; |
41 | 42 | ||
42 | protected: | 43 | protected: |
43 | /// Map of WatchID to WatchStruct pointers | 44 | /// Map of WatchID to WatchStruct pointers |
@@ -53,7 +54,7 @@ class FileWatcherKqueue : public FileWatcherImpl { | |||
53 | 54 | ||
54 | Mutex mWatchesLock; | 55 | Mutex mWatchesLock; |
55 | 56 | ||
56 | std::list<WatchID> mRemoveList; | 57 | std::vector<WatchID> mRemoveList; |
57 | 58 | ||
58 | long mFileDescriptorCount; | 59 | long mFileDescriptorCount; |
59 | 60 | ||
@@ -61,7 +62,7 @@ class FileWatcherKqueue : public FileWatcherImpl { | |||
61 | 62 | ||
62 | bool isAddingWatcher() const; | 63 | bool isAddingWatcher() const; |
63 | 64 | ||
64 | bool pathInWatches( const std::string& path ); | 65 | bool pathInWatches( const std::string& path ) override; |
65 | 66 | ||
66 | void addFD(); | 67 | void addFD(); |
67 | 68 | ||
diff --git a/src/3rdParty/efsw/FileWatcherWin32.cpp b/src/3rdParty/efsw/FileWatcherWin32.cpp index 963dc98..19b71d7 100755..100644 --- a/src/3rdParty/efsw/FileWatcherWin32.cpp +++ b/src/3rdParty/efsw/FileWatcherWin32.cpp | |||
@@ -1,257 +1,267 @@ | |||
1 | #include <efsw/FileSystem.hpp> | 1 | #include <efsw/FileSystem.hpp> |
2 | #include <efsw/FileWatcherWin32.hpp> | 2 | #include <efsw/FileWatcherWin32.hpp> |
3 | #include <efsw/Lock.hpp> | 3 | #include <efsw/Lock.hpp> |
4 | #include <efsw/String.hpp> | 4 | #include <efsw/String.hpp> |
5 | #include <efsw/System.hpp> | 5 | #include <efsw/System.hpp> |
6 | 6 | ||
7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
8 | 8 | ||
9 | namespace efsw { | 9 | namespace efsw { |
10 | 10 | ||
11 | FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : | 11 | FileWatcherWin32::FileWatcherWin32( FileWatcher* parent ) : |
12 | FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { | 12 | FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ) { |
13 | mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); | 13 | mIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ); |
14 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) | 14 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) |
15 | mInitOK = true; | 15 | mInitOK = true; |
16 | } | 16 | } |
17 | 17 | ||
18 | FileWatcherWin32::~FileWatcherWin32() { | 18 | FileWatcherWin32::~FileWatcherWin32() { |
19 | mInitOK = false; | 19 | mInitOK = false; |
20 | 20 | ||
21 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { | 21 | if ( mIOCP && mIOCP != INVALID_HANDLE_VALUE ) { |
22 | PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL ); | 22 | PostQueuedCompletionStatus( mIOCP, 0, reinterpret_cast<ULONG_PTR>( this ), NULL ); |
23 | } | 23 | } |
24 | 24 | ||
25 | efSAFE_DELETE( mThread ); | 25 | efSAFE_DELETE( mThread ); |
26 | 26 | ||
27 | removeAllWatches(); | 27 | removeAllWatches(); |
28 | 28 | ||
29 | CloseHandle( mIOCP ); | 29 | if ( mIOCP ) |
30 | } | 30 | CloseHandle( mIOCP ); |
31 | 31 | } | |
32 | WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, | 32 | |
33 | bool recursive ) { | 33 | WatchID FileWatcherWin32::addWatch( const std::string& directory, FileWatchListener* watcher, |
34 | std::string dir( directory ); | 34 | bool recursive, const std::vector<WatcherOption> &options ) { |
35 | 35 | std::string dir( directory ); | |
36 | FileInfo fi( dir ); | 36 | |
37 | 37 | FileInfo fi( dir ); | |
38 | if ( !fi.isDirectory() ) { | 38 | |
39 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | 39 | if ( !fi.isDirectory() ) { |
40 | } else if ( !fi.isReadable() ) { | 40 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); |
41 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | 41 | } else if ( !fi.isReadable() ) { |
42 | } | 42 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); |
43 | 43 | } | |
44 | FileSystem::dirAddSlashAtEnd( dir ); | 44 | |
45 | 45 | FileSystem::dirAddSlashAtEnd( dir ); | |
46 | Lock lock( mWatchesLock ); | 46 | |
47 | 47 | Lock lock( mWatchesLock ); | |
48 | if ( pathInWatches( dir ) ) { | 48 | |
49 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); | 49 | if ( pathInWatches( dir ) ) { |
50 | } | 50 | return Errors::Log::createLastError( Errors::FileRepeated, dir ); |
51 | 51 | } | |
52 | WatchID watchid = ++mLastWatchID; | 52 | |
53 | 53 | WatchID watchid = ++mLastWatchID; | |
54 | WatcherStructWin32* watch = CreateWatch( | 54 | |
55 | String::fromUtf8( dir ).toWideString().c_str(), recursive, | 55 | DWORD bufferSize = static_cast<DWORD>( getOptionValue(options, Option::WinBufferSize, 63 * 1024) ); |
56 | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME | | 56 | DWORD notifyFilter = static_cast<DWORD>( getOptionValue(options, Option::WinNotifyFilter, |
57 | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE, | 57 | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE | |
58 | mIOCP ); | 58 | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | |
59 | 59 | FILE_NOTIFY_CHANGE_SIZE) ); | |
60 | if ( NULL == watch ) { | 60 | |
61 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | 61 | WatcherStructWin32* watch = CreateWatch( String::fromUtf8( dir ).toWideString().c_str(), |
62 | } | 62 | recursive, bufferSize, notifyFilter, mIOCP ); |
63 | 63 | ||
64 | // Add the handle to the handles vector | 64 | if ( NULL == watch ) { |
65 | watch->Watch->ID = watchid; | 65 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); |
66 | watch->Watch->Watch = this; | 66 | } |
67 | watch->Watch->Listener = watcher; | 67 | |
68 | watch->Watch->DirName = new char[dir.length() + 1]; | 68 | // Add the handle to the handles vector |
69 | strcpy( watch->Watch->DirName, dir.c_str() ); | 69 | watch->Watch->ID = watchid; |
70 | 70 | watch->Watch->Watch = this; | |
71 | mWatches.insert( watch ); | 71 | watch->Watch->Listener = watcher; |
72 | 72 | watch->Watch->DirName = new char[dir.length() + 1]; | |
73 | return watchid; | 73 | strcpy( watch->Watch->DirName, dir.c_str() ); |
74 | } | 74 | |
75 | 75 | mWatches.insert( watch ); | |
76 | void FileWatcherWin32::removeWatch( const std::string& directory ) { | 76 | |
77 | Lock lock( mWatchesLock ); | 77 | return watchid; |
78 | 78 | } | |
79 | Watches::iterator iter = mWatches.begin(); | 79 | |
80 | 80 | void FileWatcherWin32::removeWatch( const std::string& directory ) { | |
81 | for ( ; iter != mWatches.end(); ++iter ) { | 81 | Lock lock( mWatchesLock ); |
82 | if ( directory == ( *iter )->Watch->DirName ) { | 82 | |
83 | removeWatch( *iter ); | 83 | Watches::iterator iter = mWatches.begin(); |
84 | break; | 84 | |
85 | } | 85 | for ( ; iter != mWatches.end(); ++iter ) { |
86 | } | 86 | if ( directory == ( *iter )->Watch->DirName ) { |
87 | } | 87 | removeWatch( *iter ); |
88 | 88 | break; | |
89 | void FileWatcherWin32::removeWatch( WatchID watchid ) { | 89 | } |
90 | Lock lock( mWatchesLock ); | 90 | } |
91 | 91 | } | |
92 | Watches::iterator iter = mWatches.begin(); | 92 | |
93 | 93 | void FileWatcherWin32::removeWatch( WatchID watchid ) { | |
94 | for ( ; iter != mWatches.end(); ++iter ) { | 94 | Lock lock( mWatchesLock ); |
95 | // Find the watch ID | 95 | |
96 | if ( ( *iter )->Watch->ID == watchid ) { | 96 | Watches::iterator iter = mWatches.begin(); |
97 | removeWatch( *iter ); | 97 | |
98 | return; | 98 | for ( ; iter != mWatches.end(); ++iter ) { |
99 | } | 99 | // Find the watch ID |
100 | } | 100 | if ( ( *iter )->Watch->ID == watchid ) { |
101 | } | 101 | removeWatch( *iter ); |
102 | 102 | return; | |
103 | void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { | 103 | } |
104 | Lock lock( mWatchesLock ); | 104 | } |
105 | 105 | } | |
106 | DestroyWatch( watch ); | 106 | |
107 | mWatches.erase( watch ); | 107 | void FileWatcherWin32::removeWatch( WatcherStructWin32* watch ) { |
108 | } | 108 | Lock lock( mWatchesLock ); |
109 | 109 | ||
110 | void FileWatcherWin32::watch() { | 110 | DestroyWatch( watch ); |
111 | if ( NULL == mThread ) { | 111 | mWatches.erase( watch ); |
112 | mThread = new Thread( &FileWatcherWin32::run, this ); | 112 | } |
113 | mThread->launch(); | 113 | |
114 | } | 114 | void FileWatcherWin32::watch() { |
115 | } | 115 | if ( NULL == mThread ) { |
116 | 116 | mThread = new Thread( &FileWatcherWin32::run, this ); | |
117 | void FileWatcherWin32::removeAllWatches() { | 117 | mThread->launch(); |
118 | Lock lock( mWatchesLock ); | 118 | } |
119 | 119 | } | |
120 | Watches::iterator iter = mWatches.begin(); | 120 | |
121 | 121 | void FileWatcherWin32::removeAllWatches() { | |
122 | for ( ; iter != mWatches.end(); ++iter ) { | 122 | Lock lock( mWatchesLock ); |
123 | DestroyWatch( ( *iter ) ); | 123 | |
124 | } | 124 | Watches::iterator iter = mWatches.begin(); |
125 | 125 | ||
126 | mWatches.clear(); | 126 | for ( ; iter != mWatches.end(); ++iter ) { |
127 | } | 127 | DestroyWatch( ( *iter ) ); |
128 | 128 | } | |
129 | void FileWatcherWin32::run() { | 129 | |
130 | do { | 130 | mWatches.clear(); |
131 | if ( mInitOK && !mWatches.empty() ) { | 131 | } |
132 | DWORD numOfBytes = 0; | 132 | |
133 | OVERLAPPED* ov = NULL; | 133 | void FileWatcherWin32::run() { |
134 | ULONG_PTR compKey = 0; | 134 | do { |
135 | BOOL res = FALSE; | 135 | if ( mInitOK && !mWatches.empty() ) { |
136 | 136 | DWORD numOfBytes = 0; | |
137 | while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov, | 137 | OVERLAPPED* ov = NULL; |
138 | INFINITE ) ) != FALSE ) { | 138 | ULONG_PTR compKey = 0; |
139 | if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) { | 139 | BOOL res = FALSE; |
140 | break; | 140 | |
141 | } else { | 141 | while ( ( res = GetQueuedCompletionStatus( mIOCP, &numOfBytes, &compKey, &ov, |
142 | Lock lock( mWatchesLock ); | 142 | INFINITE ) ) != FALSE ) { |
143 | WatchCallback( numOfBytes, ov ); | 143 | if ( compKey != 0 && compKey == reinterpret_cast<ULONG_PTR>( this ) ) { |
144 | } | 144 | break; |
145 | } | 145 | } else { |
146 | } else { | 146 | Lock lock( mWatchesLock ); |
147 | System::sleep( 10 ); | 147 | if (mWatches.find( (WatcherStructWin32*)ov ) != mWatches.end()) |
148 | } | 148 | WatchCallback( numOfBytes, ov ); |
149 | } while ( mInitOK ); | 149 | } |
150 | 150 | } | |
151 | removeAllWatches(); | 151 | } else { |
152 | } | 152 | System::sleep( 10 ); |
153 | 153 | } | |
154 | void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, | 154 | } while ( mInitOK ); |
155 | unsigned long action, std::string /*oldFilename*/ ) { | 155 | |
156 | Action fwAction; | 156 | removeAllWatches(); |
157 | 157 | } | |
158 | switch ( action ) { | 158 | |
159 | case FILE_ACTION_RENAMED_OLD_NAME: | 159 | void FileWatcherWin32::handleAction( Watcher* watch, const std::string& filename, |
160 | watch->OldFileName = filename; | 160 | unsigned long action, std::string /*oldFilename*/ ) { |
161 | return; | 161 | Action fwAction; |
162 | case FILE_ACTION_ADDED: | 162 | |
163 | fwAction = Actions::Add; | 163 | switch ( action ) { |
164 | break; | 164 | case FILE_ACTION_RENAMED_OLD_NAME: |
165 | case FILE_ACTION_RENAMED_NEW_NAME: { | 165 | watch->OldFileName = filename; |
166 | fwAction = Actions::Moved; | 166 | return; |
167 | 167 | case FILE_ACTION_ADDED: | |
168 | std::string fpath( watch->Directory + filename ); | 168 | fwAction = Actions::Add; |
169 | 169 | break; | |
170 | // Update the directory path | 170 | case FILE_ACTION_RENAMED_NEW_NAME: { |
171 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | 171 | fwAction = Actions::Moved; |
172 | // Update the new directory path | 172 | |
173 | std::string opath( watch->Directory + watch->OldFileName ); | 173 | std::string fpath( watch->Directory + filename ); |
174 | FileSystem::dirAddSlashAtEnd( opath ); | 174 | |
175 | FileSystem::dirAddSlashAtEnd( fpath ); | 175 | // Update the directory path |
176 | 176 | if ( watch->Recursive && FileSystem::isDirectory( fpath ) ) { | |
177 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 177 | // Update the new directory path |
178 | if ( ( *it )->Watch->Directory == opath ) { | 178 | std::string opath( watch->Directory + watch->OldFileName ); |
179 | ( *it )->Watch->Directory = fpath; | 179 | FileSystem::dirAddSlashAtEnd( opath ); |
180 | 180 | FileSystem::dirAddSlashAtEnd( fpath ); | |
181 | break; | 181 | |
182 | } | 182 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { |
183 | } | 183 | if ( ( *it )->Watch->Directory == opath ) { |
184 | } | 184 | ( *it )->Watch->Directory = fpath; |
185 | 185 | ||
186 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); | 186 | break; |
187 | std::string realFilename = filename; | 187 | } |
188 | std::size_t sepPos = filename.find_last_of( "/\\" ); | 188 | } |
189 | std::string oldFolderPath = | 189 | } |
190 | static_cast<WatcherWin32*>( watch )->DirName + | 190 | |
191 | watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); | 191 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); |
192 | 192 | std::string realFilename = filename; | |
193 | if ( sepPos != std::string::npos ) { | 193 | std::size_t sepPos = filename.find_last_of( "/\\" ); |
194 | folderPath += filename.substr( 0, sepPos ); | 194 | std::string oldFolderPath = |
195 | realFilename = filename.substr( sepPos + 1 ); | 195 | static_cast<WatcherWin32*>( watch )->DirName + |
196 | } | 196 | watch->OldFileName.substr( 0, watch->OldFileName.find_last_of( "/\\" ) ); |
197 | 197 | ||
198 | if ( folderPath == oldFolderPath ) { | 198 | if ( sepPos != std::string::npos ) { |
199 | watch->Listener->handleFileAction( | 199 | folderPath += |
200 | watch->ID, folderPath, realFilename, fwAction, | 200 | filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); |
201 | FileSystem::fileNameFromPath( watch->OldFileName ) ); | 201 | realFilename = filename.substr( sepPos + 1 ); |
202 | } else { | 202 | } |
203 | watch->Listener->handleFileAction( watch->ID, | 203 | |
204 | static_cast<WatcherWin32*>( watch )->DirName, | 204 | if ( folderPath == oldFolderPath ) { |
205 | filename, fwAction, watch->OldFileName ); | 205 | watch->Listener->handleFileAction( |
206 | } | 206 | watch->ID, folderPath, realFilename, fwAction, |
207 | return; | 207 | FileSystem::fileNameFromPath( watch->OldFileName ) ); |
208 | } | 208 | } else { |
209 | case FILE_ACTION_REMOVED: | 209 | watch->Listener->handleFileAction( watch->ID, |
210 | fwAction = Actions::Delete; | 210 | static_cast<WatcherWin32*>( watch )->DirName, |
211 | break; | 211 | filename, fwAction, watch->OldFileName ); |
212 | case FILE_ACTION_MODIFIED: | 212 | } |
213 | fwAction = Actions::Modified; | 213 | return; |
214 | break; | 214 | } |
215 | default: | 215 | case FILE_ACTION_REMOVED: |
216 | return; | 216 | fwAction = Actions::Delete; |
217 | }; | 217 | break; |
218 | 218 | case FILE_ACTION_MODIFIED: | |
219 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); | 219 | fwAction = Actions::Modified; |
220 | std::string realFilename = filename; | 220 | break; |
221 | std::size_t sepPos = filename.find_last_of( "/\\" ); | 221 | default: |
222 | 222 | return; | |
223 | if ( sepPos != std::string::npos ) { | 223 | }; |
224 | folderPath += filename.substr( 0, sepPos ); | 224 | |
225 | realFilename = filename.substr( sepPos + 1 ); | 225 | std::string folderPath( static_cast<WatcherWin32*>( watch )->DirName ); |
226 | } | 226 | std::string realFilename = filename; |
227 | 227 | std::size_t sepPos = filename.find_last_of( "/\\" ); | |
228 | watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); | 228 | |
229 | } | 229 | if ( sepPos != std::string::npos ) { |
230 | 230 | folderPath += filename.substr( 0, sepPos + 1 < filename.size() ? sepPos + 1 : sepPos ); | |
231 | std::list<std::string> FileWatcherWin32::directories() { | 231 | realFilename = filename.substr( sepPos + 1 ); |
232 | std::list<std::string> dirs; | 232 | } |
233 | 233 | ||
234 | Lock lock( mWatchesLock ); | 234 | FileSystem::dirAddSlashAtEnd( folderPath ); |
235 | 235 | ||
236 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 236 | watch->Listener->handleFileAction( watch->ID, folderPath, realFilename, fwAction ); |
237 | dirs.push_back( std::string( ( *it )->Watch->DirName ) ); | 237 | } |
238 | } | 238 | |
239 | 239 | std::vector<std::string> FileWatcherWin32::directories() { | |
240 | return dirs; | 240 | std::vector<std::string> dirs; |
241 | } | 241 | |
242 | 242 | Lock lock( mWatchesLock ); | |
243 | bool FileWatcherWin32::pathInWatches( const std::string& path ) { | 243 | |
244 | Lock lock( mWatchesLock ); | 244 | dirs.reserve( mWatches.size() ); |
245 | 245 | ||
246 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | 246 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { |
247 | if ( ( *it )->Watch->DirName == path ) { | 247 | dirs.push_back( std::string( ( *it )->Watch->DirName ) ); |
248 | return true; | 248 | } |
249 | } | 249 | |
250 | } | 250 | return dirs; |
251 | 251 | } | |
252 | return false; | 252 | |
253 | } | 253 | bool FileWatcherWin32::pathInWatches( const std::string& path ) { |
254 | 254 | Lock lock( mWatchesLock ); | |
255 | } // namespace efsw | 255 | |
256 | 256 | for ( Watches::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | |
257 | #endif | 257 | if ( ( *it )->Watch->DirName == path ) { |
258 | return true; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | return false; | ||
263 | } | ||
264 | |||
265 | } // namespace efsw | ||
266 | |||
267 | #endif | ||
diff --git a/src/3rdParty/efsw/FileWatcherWin32.hpp b/src/3rdParty/efsw/FileWatcherWin32.hpp index 94439cf..3016aac 100755..100644 --- a/src/3rdParty/efsw/FileWatcherWin32.hpp +++ b/src/3rdParty/efsw/FileWatcherWin32.hpp | |||
@@ -1,70 +1,71 @@ | |||
1 | #ifndef EFSW_FILEWATCHERWIN32_HPP | 1 | #ifndef EFSW_FILEWATCHERWIN32_HPP |
2 | #define EFSW_FILEWATCHERWIN32_HPP | 2 | #define EFSW_FILEWATCHERWIN32_HPP |
3 | 3 | ||
4 | #include <efsw/base.hpp> | 4 | #include <efsw/base.hpp> |
5 | 5 | ||
6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
7 | 7 | ||
8 | #include <efsw/WatcherWin32.hpp> | 8 | #include <efsw/WatcherWin32.hpp> |
9 | #include <map> | 9 | #include <map> |
10 | #include <set> | 10 | #include <unordered_set> |
11 | #include <vector> | 11 | #include <vector> |
12 | 12 | ||
13 | namespace efsw { | 13 | namespace efsw { |
14 | 14 | ||
15 | /// Implementation for Win32 based on ReadDirectoryChangesW. | 15 | /// Implementation for Win32 based on ReadDirectoryChangesW. |
16 | /// @class FileWatcherWin32 | 16 | /// @class FileWatcherWin32 |
17 | class FileWatcherWin32 : public FileWatcherImpl { | 17 | class FileWatcherWin32 : public FileWatcherImpl { |
18 | public: | 18 | public: |
19 | /// type for a map from WatchID to WatcherWin32 pointer | 19 | /// type for a map from WatchID to WatcherWin32 pointer |
20 | typedef std::set<WatcherStructWin32*> Watches; | 20 | typedef std::unordered_set<WatcherStructWin32*> Watches; |
21 | 21 | ||
22 | FileWatcherWin32( FileWatcher* parent ); | 22 | FileWatcherWin32( FileWatcher* parent ); |
23 | 23 | ||
24 | virtual ~FileWatcherWin32(); | 24 | virtual ~FileWatcherWin32(); |
25 | 25 | ||
26 | /// Add a directory watch | 26 | /// Add a directory watch |
27 | /// On error returns WatchID with Error type. | 27 | /// On error returns WatchID with Error type. |
28 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 28 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
29 | 29 | const std::vector<WatcherOption> &options ) override; | |
30 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). | 30 | |
31 | void removeWatch( const std::string& directory ); | 31 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). |
32 | 32 | void removeWatch( const std::string& directory ) override; | |
33 | /// Remove a directory watch. This is a map lookup O(logn). | 33 | |
34 | void removeWatch( WatchID watchid ); | 34 | /// Remove a directory watch. This is a map lookup O(logn). |
35 | 35 | void removeWatch( WatchID watchid ) override; | |
36 | /// Updates the watcher. Must be called often. | 36 | |
37 | void watch(); | 37 | /// Updates the watcher. Must be called often. |
38 | 38 | void watch() override; | |
39 | /// Handles the action | 39 | |
40 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, | 40 | /// Handles the action |
41 | std::string oldFilename = "" ); | 41 | void handleAction( Watcher* watch, const std::string& filename, unsigned long action, |
42 | 42 | std::string oldFilename = "" ) override; | |
43 | /// @return Returns a list of the directories that are being watched | 43 | |
44 | std::list<std::string> directories(); | 44 | /// @return Returns a list of the directories that are being watched |
45 | 45 | std::vector<std::string> directories() override; | |
46 | protected: | 46 | |
47 | HANDLE mIOCP; | 47 | protected: |
48 | Watches mWatches; | 48 | HANDLE mIOCP; |
49 | 49 | Watches mWatches; | |
50 | /// The last watchid | 50 | |
51 | WatchID mLastWatchID; | 51 | /// The last watchid |
52 | Thread* mThread; | 52 | WatchID mLastWatchID; |
53 | Mutex mWatchesLock; | 53 | Thread* mThread; |
54 | 54 | Mutex mWatchesLock; | |
55 | bool pathInWatches( const std::string& path ); | 55 | |
56 | 56 | bool pathInWatches( const std::string& path ) override; | |
57 | /// Remove all directory watches. | 57 | |
58 | void removeAllWatches(); | 58 | /// Remove all directory watches. |
59 | 59 | void removeAllWatches(); | |
60 | void removeWatch( WatcherStructWin32* watch ); | 60 | |
61 | 61 | void removeWatch( WatcherStructWin32* watch ); | |
62 | private: | 62 | |
63 | void run(); | 63 | private: |
64 | }; | 64 | void run(); |
65 | 65 | }; | |
66 | } // namespace efsw | 66 | |
67 | 67 | } // namespace efsw | |
68 | #endif | 68 | |
69 | 69 | #endif | |
70 | #endif | 70 | |
71 | #endif | ||
diff --git a/src/3rdParty/efsw/LICENSE b/src/3rdParty/efsw/LICENSE index 37f354a..37f354a 100755..100644 --- a/src/3rdParty/efsw/LICENSE +++ b/src/3rdParty/efsw/LICENSE | |||
diff --git a/src/3rdParty/efsw/Lock.hpp b/src/3rdParty/efsw/Lock.hpp index e8c522a..e8c522a 100755..100644 --- a/src/3rdParty/efsw/Lock.hpp +++ b/src/3rdParty/efsw/Lock.hpp | |||
diff --git a/src/3rdParty/efsw/Log.cpp b/src/3rdParty/efsw/Log.cpp index ddf7a62..6f32df7 100755..100644 --- a/src/3rdParty/efsw/Log.cpp +++ b/src/3rdParty/efsw/Log.cpp | |||
@@ -1,20 +1,31 @@ | |||
1 | #include <efsw/efsw.hpp> | 1 | #include <efsw/efsw.hpp> |
2 | #include <efsw/Debug.hpp> | ||
2 | 3 | ||
3 | namespace efsw { namespace Errors { | 4 | namespace efsw { namespace Errors { |
4 | 5 | ||
5 | static std::string LastError; | 6 | static std::string LastError = ""; |
7 | static Error LastErrorCode = NoError; | ||
6 | 8 | ||
7 | std::string Log::getLastErrorLog() { | 9 | std::string Log::getLastErrorLog() { |
8 | return LastError; | 10 | return LastError; |
9 | } | 11 | } |
10 | 12 | ||
13 | Error Log::getLastErrorCode() { | ||
14 | return LastErrorCode; | ||
15 | } | ||
16 | |||
17 | void Log::clearLastError() { | ||
18 | LastErrorCode = NoError; | ||
19 | LastError = ""; | ||
20 | } | ||
21 | |||
11 | Error Log::createLastError( Error err, std::string log ) { | 22 | Error Log::createLastError( Error err, std::string log ) { |
12 | switch ( err ) { | 23 | switch ( err ) { |
13 | case FileNotFound: | 24 | case FileNotFound: |
14 | LastError = "File not found ( " + log + " )"; | 25 | LastError = "File not found ( " + log + " )"; |
15 | break; | 26 | break; |
16 | case FileRepeated: | 27 | case FileRepeated: |
17 | LastError = "File reapeated in watches ( " + log + " )"; | 28 | LastError = "File repeated in watches ( " + log + " )"; |
18 | break; | 29 | break; |
19 | case FileOutOfScope: | 30 | case FileOutOfScope: |
20 | LastError = "Symlink file out of scope ( " + log + " )"; | 31 | LastError = "Symlink file out of scope ( " + log + " )"; |
@@ -23,11 +34,15 @@ Error Log::createLastError( Error err, std::string log ) { | |||
23 | LastError = | 34 | LastError = |
24 | "File is located in a remote file system, use a generic watcher. ( " + log + " )"; | 35 | "File is located in a remote file system, use a generic watcher. ( " + log + " )"; |
25 | break; | 36 | break; |
37 | case WatcherFailed: | ||
38 | LastError = "File system watcher failed ( " + log + " )"; | ||
39 | break; | ||
26 | case Unspecified: | 40 | case Unspecified: |
27 | default: | 41 | default: |
28 | LastError = log; | 42 | LastError = log; |
29 | } | 43 | } |
30 | 44 | ||
45 | efDEBUG( "%s\n", LastError.c_str() ); | ||
31 | return err; | 46 | return err; |
32 | } | 47 | } |
33 | 48 | ||
diff --git a/src/3rdParty/efsw/Mutex.cpp b/src/3rdParty/efsw/Mutex.cpp index c961db1..c961db1 100755..100644 --- a/src/3rdParty/efsw/Mutex.cpp +++ b/src/3rdParty/efsw/Mutex.cpp | |||
diff --git a/src/3rdParty/efsw/Mutex.hpp b/src/3rdParty/efsw/Mutex.hpp index d98ad17..d98ad17 100755..100644 --- a/src/3rdParty/efsw/Mutex.hpp +++ b/src/3rdParty/efsw/Mutex.hpp | |||
diff --git a/src/3rdParty/efsw/String.cpp b/src/3rdParty/efsw/String.cpp index e3ba68f..e3ba68f 100755..100644 --- a/src/3rdParty/efsw/String.cpp +++ b/src/3rdParty/efsw/String.cpp | |||
diff --git a/src/3rdParty/efsw/String.hpp b/src/3rdParty/efsw/String.hpp index 65bce33..b42b945 100755..100644 --- a/src/3rdParty/efsw/String.hpp +++ b/src/3rdParty/efsw/String.hpp | |||
@@ -11,7 +11,6 @@ | |||
11 | #include <cstdlib> | 11 | #include <cstdlib> |
12 | #include <cstring> | 12 | #include <cstring> |
13 | #include <efsw/base.hpp> | 13 | #include <efsw/base.hpp> |
14 | #include <fstream> | ||
15 | #include <iostream> | 14 | #include <iostream> |
16 | #include <locale> | 15 | #include <locale> |
17 | #include <sstream> | 16 | #include <sstream> |
@@ -24,7 +23,7 @@ namespace efsw { | |||
24 | * **/ | 23 | * **/ |
25 | class String { | 24 | class String { |
26 | public: | 25 | public: |
27 | typedef Uint32 StringBaseType; | 26 | typedef char32_t StringBaseType; |
28 | typedef std::basic_string<StringBaseType> StringType; | 27 | typedef std::basic_string<StringBaseType> StringType; |
29 | typedef StringType::iterator Iterator; //! Iterator type | 28 | typedef StringType::iterator Iterator; //! Iterator type |
30 | typedef StringType::const_iterator ConstIterator; //! Constant iterator type | 29 | typedef StringType::const_iterator ConstIterator; //! Constant iterator type |
diff --git a/src/3rdParty/efsw/System.cpp b/src/3rdParty/efsw/System.cpp index ba68bf4..ba68bf4 100755..100644 --- a/src/3rdParty/efsw/System.cpp +++ b/src/3rdParty/efsw/System.cpp | |||
diff --git a/src/3rdParty/efsw/System.hpp b/src/3rdParty/efsw/System.hpp index 498e121..498e121 100755..100644 --- a/src/3rdParty/efsw/System.hpp +++ b/src/3rdParty/efsw/System.hpp | |||
diff --git a/src/3rdParty/efsw/Thread.cpp b/src/3rdParty/efsw/Thread.cpp index e3f0fa0..cfa88b4 100755..100644 --- a/src/3rdParty/efsw/Thread.cpp +++ b/src/3rdParty/efsw/Thread.cpp | |||
@@ -34,7 +34,8 @@ void Thread::terminate() { | |||
34 | } | 34 | } |
35 | 35 | ||
36 | void Thread::run() { | 36 | void Thread::run() { |
37 | mEntryPoint->run(); | 37 | if ( mEntryPoint ) |
38 | mEntryPoint->run(); | ||
38 | } | 39 | } |
39 | 40 | ||
40 | } // namespace efsw | 41 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/Thread.hpp b/src/3rdParty/efsw/Thread.hpp index b60373c..b60373c 100755..100644 --- a/src/3rdParty/efsw/Thread.hpp +++ b/src/3rdParty/efsw/Thread.hpp | |||
diff --git a/src/3rdParty/efsw/Utf.hpp b/src/3rdParty/efsw/Utf.hpp index 6e9ea71..1b042cd 100755..100644 --- a/src/3rdParty/efsw/Utf.hpp +++ b/src/3rdParty/efsw/Utf.hpp | |||
@@ -1,721 +1,721 @@ | |||
1 | /** NOTE: | 1 | /** NOTE: |
2 | * This code is based on the Utf implementation from SFML2. License zlib/png ( | 2 | * This code is based on the Utf implementation from SFML2. License zlib/png ( |
3 | *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not | 3 | *http://www.sfml-dev.org/license.php ) The class was modified to fit efsw own needs. This is not |
4 | *the original implementation from SFML2. | 4 | *the original implementation from SFML2. |
5 | * */ | 5 | * */ |
6 | 6 | ||
7 | #ifndef EFSW_UTF_HPP | 7 | #ifndef EFSW_UTF_HPP |
8 | #define EFSW_UTF_HPP | 8 | #define EFSW_UTF_HPP |
9 | 9 | ||
10 | //////////////////////////////////////////////////////////// | 10 | //////////////////////////////////////////////////////////// |
11 | // Headers | 11 | // Headers |
12 | //////////////////////////////////////////////////////////// | 12 | //////////////////////////////////////////////////////////// |
13 | #include <cstdlib> | 13 | #include <cstdlib> |
14 | #include <efsw/base.hpp> | 14 | #include <efsw/base.hpp> |
15 | #include <locale> | 15 | #include <locale> |
16 | #include <string> | 16 | #include <string> |
17 | 17 | ||
18 | namespace efsw { | 18 | namespace efsw { |
19 | 19 | ||
20 | template <unsigned int N> class Utf; | 20 | template <unsigned int N> class Utf; |
21 | 21 | ||
22 | //////////////////////////////////////////////////////////// | 22 | //////////////////////////////////////////////////////////// |
23 | /// \brief Specialization of the Utf template for UTF-8 | 23 | /// \brief Specialization of the Utf template for UTF-8 |
24 | /// | 24 | /// |
25 | //////////////////////////////////////////////////////////// | 25 | //////////////////////////////////////////////////////////// |
26 | template <> class Utf<8> { | 26 | template <> class Utf<8> { |
27 | public: | 27 | public: |
28 | //////////////////////////////////////////////////////////// | 28 | //////////////////////////////////////////////////////////// |
29 | /// \brief Decode a single UTF-8 character | 29 | /// \brief Decode a single UTF-8 character |
30 | /// | 30 | /// |
31 | /// Decoding a character means finding its unique 32-bits | 31 | /// Decoding a character means finding its unique 32-bits |
32 | /// code (called the codepoint) in the Unicode standard. | 32 | /// code (called the codepoint) in the Unicode standard. |
33 | /// | 33 | /// |
34 | /// \param begin Iterator pointing to the beginning of the input sequence | 34 | /// \param begin Iterator pointing to the beginning of the input sequence |
35 | /// \param end Iterator pointing to the end of the input sequence | 35 | /// \param end Iterator pointing to the end of the input sequence |
36 | /// \param output Codepoint of the decoded UTF-8 character | 36 | /// \param output Codepoint of the decoded UTF-8 character |
37 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | 37 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid |
38 | /// | 38 | /// |
39 | /// \return Iterator pointing to one past the last read element of the input sequence | 39 | /// \return Iterator pointing to one past the last read element of the input sequence |
40 | /// | 40 | /// |
41 | //////////////////////////////////////////////////////////// | 41 | //////////////////////////////////////////////////////////// |
42 | template <typename In> | 42 | template <typename In> |
43 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | 43 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); |
44 | 44 | ||
45 | //////////////////////////////////////////////////////////// | 45 | //////////////////////////////////////////////////////////// |
46 | /// \brief Encode a single UTF-8 character | 46 | /// \brief Encode a single UTF-8 character |
47 | /// | 47 | /// |
48 | /// Encoding a character means converting a unique 32-bits | 48 | /// Encoding a character means converting a unique 32-bits |
49 | /// code (called the codepoint) in the target encoding, UTF-8. | 49 | /// code (called the codepoint) in the target encoding, UTF-8. |
50 | /// | 50 | /// |
51 | /// \param input Codepoint to encode as UTF-8 | 51 | /// \param input Codepoint to encode as UTF-8 |
52 | /// \param output Iterator pointing to the beginning of the output sequence | 52 | /// \param output Iterator pointing to the beginning of the output sequence |
53 | /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) | 53 | /// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them) |
54 | /// | 54 | /// |
55 | /// \return Iterator to the end of the output sequence which has been written | 55 | /// \return Iterator to the end of the output sequence which has been written |
56 | /// | 56 | /// |
57 | //////////////////////////////////////////////////////////// | 57 | //////////////////////////////////////////////////////////// |
58 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); | 58 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint8 replacement = 0 ); |
59 | 59 | ||
60 | //////////////////////////////////////////////////////////// | 60 | //////////////////////////////////////////////////////////// |
61 | /// \brief Advance to the next UTF-8 character | 61 | /// \brief Advance to the next UTF-8 character |
62 | /// | 62 | /// |
63 | /// This function is necessary for multi-elements encodings, as | 63 | /// This function is necessary for multi-elements encodings, as |
64 | /// a single character may use more than 1 storage element. | 64 | /// a single character may use more than 1 storage element. |
65 | /// | 65 | /// |
66 | /// \param begin Iterator pointing to the beginning of the input sequence | 66 | /// \param begin Iterator pointing to the beginning of the input sequence |
67 | /// \param end Iterator pointing to the end of the input sequence | 67 | /// \param end Iterator pointing to the end of the input sequence |
68 | /// | 68 | /// |
69 | /// \return Iterator pointing to one past the last read element of the input sequence | 69 | /// \return Iterator pointing to one past the last read element of the input sequence |
70 | /// | 70 | /// |
71 | //////////////////////////////////////////////////////////// | 71 | //////////////////////////////////////////////////////////// |
72 | template <typename In> static In Next( In begin, In end ); | 72 | template <typename In> static In Next( In begin, In end ); |
73 | 73 | ||
74 | //////////////////////////////////////////////////////////// | 74 | //////////////////////////////////////////////////////////// |
75 | /// \brief Count the number of characters of a UTF-8 sequence | 75 | /// \brief Count the number of characters of a UTF-8 sequence |
76 | /// | 76 | /// |
77 | /// This function is necessary for multi-elements encodings, as | 77 | /// This function is necessary for multi-elements encodings, as |
78 | /// a single character may use more than 1 storage element, thus the | 78 | /// a single character may use more than 1 storage element, thus the |
79 | /// total size can be different from (begin - end). | 79 | /// total size can be different from (begin - end). |
80 | /// | 80 | /// |
81 | /// \param begin Iterator pointing to the beginning of the input sequence | 81 | /// \param begin Iterator pointing to the beginning of the input sequence |
82 | /// \param end Iterator pointing to the end of the input sequence | 82 | /// \param end Iterator pointing to the end of the input sequence |
83 | /// | 83 | /// |
84 | /// \return Iterator pointing to one past the last read element of the input sequence | 84 | /// \return Iterator pointing to one past the last read element of the input sequence |
85 | /// | 85 | /// |
86 | //////////////////////////////////////////////////////////// | 86 | //////////////////////////////////////////////////////////// |
87 | template <typename In> static std::size_t Count( In begin, In end ); | 87 | template <typename In> static std::size_t Count( In begin, In end ); |
88 | 88 | ||
89 | //////////////////////////////////////////////////////////// | 89 | //////////////////////////////////////////////////////////// |
90 | /// \brief Convert an ANSI characters range to UTF-8 | 90 | /// \brief Convert an ANSI characters range to UTF-8 |
91 | /// | 91 | /// |
92 | /// The current global locale will be used by default, unless you | 92 | /// The current global locale will be used by default, unless you |
93 | /// pass a custom one in the \a locale parameter. | 93 | /// pass a custom one in the \a locale parameter. |
94 | /// | 94 | /// |
95 | /// \param begin Iterator pointing to the beginning of the input sequence | 95 | /// \param begin Iterator pointing to the beginning of the input sequence |
96 | /// \param end Iterator pointing to the end of the input sequence | 96 | /// \param end Iterator pointing to the end of the input sequence |
97 | /// \param output Iterator pointing to the beginning of the output sequence | 97 | /// \param output Iterator pointing to the beginning of the output sequence |
98 | /// \param locale Locale to use for conversion | 98 | /// \param locale Locale to use for conversion |
99 | /// | 99 | /// |
100 | /// \return Iterator to the end of the output sequence which has been written | 100 | /// \return Iterator to the end of the output sequence which has been written |
101 | /// | 101 | /// |
102 | //////////////////////////////////////////////////////////// | 102 | //////////////////////////////////////////////////////////// |
103 | template <typename In, typename Out> | 103 | template <typename In, typename Out> |
104 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | 104 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); |
105 | 105 | ||
106 | //////////////////////////////////////////////////////////// | 106 | //////////////////////////////////////////////////////////// |
107 | /// \brief Convert a wide characters range to UTF-8 | 107 | /// \brief Convert a wide characters range to UTF-8 |
108 | /// | 108 | /// |
109 | /// \param begin Iterator pointing to the beginning of the input sequence | 109 | /// \param begin Iterator pointing to the beginning of the input sequence |
110 | /// \param end Iterator pointing to the end of the input sequence | 110 | /// \param end Iterator pointing to the end of the input sequence |
111 | /// \param output Iterator pointing to the beginning of the output sequence | 111 | /// \param output Iterator pointing to the beginning of the output sequence |
112 | /// | 112 | /// |
113 | /// \return Iterator to the end of the output sequence which has been written | 113 | /// \return Iterator to the end of the output sequence which has been written |
114 | /// | 114 | /// |
115 | //////////////////////////////////////////////////////////// | 115 | //////////////////////////////////////////////////////////// |
116 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | 116 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); |
117 | 117 | ||
118 | //////////////////////////////////////////////////////////// | 118 | //////////////////////////////////////////////////////////// |
119 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 | 119 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8 |
120 | /// | 120 | /// |
121 | /// \param begin Iterator pointing to the beginning of the input sequence | 121 | /// \param begin Iterator pointing to the beginning of the input sequence |
122 | /// \param end Iterator pointing to the end of the input sequence | 122 | /// \param end Iterator pointing to the end of the input sequence |
123 | /// \param output Iterator pointing to the beginning of the output sequence | 123 | /// \param output Iterator pointing to the beginning of the output sequence |
124 | /// \param locale Locale to use for conversion | 124 | /// \param locale Locale to use for conversion |
125 | /// | 125 | /// |
126 | /// \return Iterator to the end of the output sequence which has been written | 126 | /// \return Iterator to the end of the output sequence which has been written |
127 | /// | 127 | /// |
128 | //////////////////////////////////////////////////////////// | 128 | //////////////////////////////////////////////////////////// |
129 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | 129 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); |
130 | 130 | ||
131 | //////////////////////////////////////////////////////////// | 131 | //////////////////////////////////////////////////////////// |
132 | /// \brief Convert an UTF-8 characters range to ANSI characters | 132 | /// \brief Convert an UTF-8 characters range to ANSI characters |
133 | /// | 133 | /// |
134 | /// The current global locale will be used by default, unless you | 134 | /// The current global locale will be used by default, unless you |
135 | /// pass a custom one in the \a locale parameter. | 135 | /// pass a custom one in the \a locale parameter. |
136 | /// | 136 | /// |
137 | /// \param begin Iterator pointing to the beginning of the input sequence | 137 | /// \param begin Iterator pointing to the beginning of the input sequence |
138 | /// \param end Iterator pointing to the end of the input sequence | 138 | /// \param end Iterator pointing to the end of the input sequence |
139 | /// \param output Iterator pointing to the beginning of the output sequence | 139 | /// \param output Iterator pointing to the beginning of the output sequence |
140 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | 140 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) |
141 | /// \param locale Locale to use for conversion | 141 | /// \param locale Locale to use for conversion |
142 | /// | 142 | /// |
143 | /// \return Iterator to the end of the output sequence which has been written | 143 | /// \return Iterator to the end of the output sequence which has been written |
144 | /// | 144 | /// |
145 | //////////////////////////////////////////////////////////// | 145 | //////////////////////////////////////////////////////////// |
146 | template <typename In, typename Out> | 146 | template <typename In, typename Out> |
147 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | 147 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, |
148 | const std::locale& locale = std::locale() ); | 148 | const std::locale& locale = std::locale() ); |
149 | 149 | ||
150 | #ifndef EFSW_NO_WIDECHAR | 150 | #ifndef EFSW_NO_WIDECHAR |
151 | //////////////////////////////////////////////////////////// | 151 | //////////////////////////////////////////////////////////// |
152 | /// \brief Convert an UTF-8 characters range to wide characters | 152 | /// \brief Convert an UTF-8 characters range to wide characters |
153 | /// | 153 | /// |
154 | /// \param begin Iterator pointing to the beginning of the input sequence | 154 | /// \param begin Iterator pointing to the beginning of the input sequence |
155 | /// \param end Iterator pointing to the end of the input sequence | 155 | /// \param end Iterator pointing to the end of the input sequence |
156 | /// \param output Iterator pointing to the beginning of the output sequence | 156 | /// \param output Iterator pointing to the beginning of the output sequence |
157 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 157 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
158 | /// | 158 | /// |
159 | /// \return Iterator to the end of the output sequence which has been written | 159 | /// \return Iterator to the end of the output sequence which has been written |
160 | /// | 160 | /// |
161 | //////////////////////////////////////////////////////////// | 161 | //////////////////////////////////////////////////////////// |
162 | template <typename In, typename Out> | 162 | template <typename In, typename Out> |
163 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | 163 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); |
164 | #endif | 164 | #endif |
165 | 165 | ||
166 | //////////////////////////////////////////////////////////// | 166 | //////////////////////////////////////////////////////////// |
167 | /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters | 167 | /// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters |
168 | /// | 168 | /// |
169 | /// \param begin Iterator pointing to the beginning of the input sequence | 169 | /// \param begin Iterator pointing to the beginning of the input sequence |
170 | /// \param end Iterator pointing to the end of the input sequence | 170 | /// \param end Iterator pointing to the end of the input sequence |
171 | /// \param output Iterator pointing to the beginning of the output sequence | 171 | /// \param output Iterator pointing to the beginning of the output sequence |
172 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 172 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
173 | /// | 173 | /// |
174 | /// \return Iterator to the end of the output sequence which has been written | 174 | /// \return Iterator to the end of the output sequence which has been written |
175 | /// | 175 | /// |
176 | //////////////////////////////////////////////////////////// | 176 | //////////////////////////////////////////////////////////// |
177 | template <typename In, typename Out> | 177 | template <typename In, typename Out> |
178 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | 178 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); |
179 | 179 | ||
180 | //////////////////////////////////////////////////////////// | 180 | //////////////////////////////////////////////////////////// |
181 | /// \brief Convert a UTF-8 characters range to UTF-8 | 181 | /// \brief Convert a UTF-8 characters range to UTF-8 |
182 | /// | 182 | /// |
183 | /// This functions does nothing more than a direct copy; | 183 | /// This functions does nothing more than a direct copy; |
184 | /// it is defined only to provide the same interface as other | 184 | /// it is defined only to provide the same interface as other |
185 | /// specializations of the efsw::Utf<> template, and allow | 185 | /// specializations of the efsw::Utf<> template, and allow |
186 | /// generic code to be written on top of it. | 186 | /// generic code to be written on top of it. |
187 | /// | 187 | /// |
188 | /// \param begin Iterator pointing to the beginning of the input sequence | 188 | /// \param begin Iterator pointing to the beginning of the input sequence |
189 | /// \param end Iterator pointing to the end of the input sequence | 189 | /// \param end Iterator pointing to the end of the input sequence |
190 | /// \param output Iterator pointing to the beginning of the output sequence | 190 | /// \param output Iterator pointing to the beginning of the output sequence |
191 | /// | 191 | /// |
192 | /// \return Iterator to the end of the output sequence which has been written | 192 | /// \return Iterator to the end of the output sequence which has been written |
193 | /// | 193 | /// |
194 | //////////////////////////////////////////////////////////// | 194 | //////////////////////////////////////////////////////////// |
195 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | 195 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); |
196 | 196 | ||
197 | //////////////////////////////////////////////////////////// | 197 | //////////////////////////////////////////////////////////// |
198 | /// \brief Convert a UTF-8 characters range to UTF-16 | 198 | /// \brief Convert a UTF-8 characters range to UTF-16 |
199 | /// | 199 | /// |
200 | /// \param begin Iterator pointing to the beginning of the input sequence | 200 | /// \param begin Iterator pointing to the beginning of the input sequence |
201 | /// \param end Iterator pointing to the end of the input sequence | 201 | /// \param end Iterator pointing to the end of the input sequence |
202 | /// \param output Iterator pointing to the beginning of the output sequence | 202 | /// \param output Iterator pointing to the beginning of the output sequence |
203 | /// | 203 | /// |
204 | /// \return Iterator to the end of the output sequence which has been written | 204 | /// \return Iterator to the end of the output sequence which has been written |
205 | /// | 205 | /// |
206 | //////////////////////////////////////////////////////////// | 206 | //////////////////////////////////////////////////////////// |
207 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | 207 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); |
208 | 208 | ||
209 | //////////////////////////////////////////////////////////// | 209 | //////////////////////////////////////////////////////////// |
210 | /// \brief Convert a UTF-8 characters range to UTF-32 | 210 | /// \brief Convert a UTF-8 characters range to UTF-32 |
211 | /// | 211 | /// |
212 | /// \param begin Iterator pointing to the beginning of the input sequence | 212 | /// \param begin Iterator pointing to the beginning of the input sequence |
213 | /// \param end Iterator pointing to the end of the input sequence | 213 | /// \param end Iterator pointing to the end of the input sequence |
214 | /// \param output Iterator pointing to the beginning of the output sequence | 214 | /// \param output Iterator pointing to the beginning of the output sequence |
215 | /// | 215 | /// |
216 | /// \return Iterator to the end of the output sequence which has been written | 216 | /// \return Iterator to the end of the output sequence which has been written |
217 | /// | 217 | /// |
218 | //////////////////////////////////////////////////////////// | 218 | //////////////////////////////////////////////////////////// |
219 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | 219 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); |
220 | }; | 220 | }; |
221 | 221 | ||
222 | //////////////////////////////////////////////////////////// | 222 | //////////////////////////////////////////////////////////// |
223 | /// \brief Specialization of the Utf template for UTF-16 | 223 | /// \brief Specialization of the Utf template for UTF-16 |
224 | /// | 224 | /// |
225 | //////////////////////////////////////////////////////////// | 225 | //////////////////////////////////////////////////////////// |
226 | template <> class Utf<16> { | 226 | template <> class Utf<16> { |
227 | public: | 227 | public: |
228 | //////////////////////////////////////////////////////////// | 228 | //////////////////////////////////////////////////////////// |
229 | /// \brief Decode a single UTF-16 character | 229 | /// \brief Decode a single UTF-16 character |
230 | /// | 230 | /// |
231 | /// Decoding a character means finding its unique 32-bits | 231 | /// Decoding a character means finding its unique 32-bits |
232 | /// code (called the codepoint) in the Unicode standard. | 232 | /// code (called the codepoint) in the Unicode standard. |
233 | /// | 233 | /// |
234 | /// \param begin Iterator pointing to the beginning of the input sequence | 234 | /// \param begin Iterator pointing to the beginning of the input sequence |
235 | /// \param end Iterator pointing to the end of the input sequence | 235 | /// \param end Iterator pointing to the end of the input sequence |
236 | /// \param output Codepoint of the decoded UTF-16 character | 236 | /// \param output Codepoint of the decoded UTF-16 character |
237 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | 237 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid |
238 | /// | 238 | /// |
239 | /// \return Iterator pointing to one past the last read element of the input sequence | 239 | /// \return Iterator pointing to one past the last read element of the input sequence |
240 | /// | 240 | /// |
241 | //////////////////////////////////////////////////////////// | 241 | //////////////////////////////////////////////////////////// |
242 | template <typename In> | 242 | template <typename In> |
243 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | 243 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); |
244 | 244 | ||
245 | //////////////////////////////////////////////////////////// | 245 | //////////////////////////////////////////////////////////// |
246 | /// \brief Encode a single UTF-16 character | 246 | /// \brief Encode a single UTF-16 character |
247 | /// | 247 | /// |
248 | /// Encoding a character means converting a unique 32-bits | 248 | /// Encoding a character means converting a unique 32-bits |
249 | /// code (called the codepoint) in the target encoding, UTF-16. | 249 | /// code (called the codepoint) in the target encoding, UTF-16. |
250 | /// | 250 | /// |
251 | /// \param input Codepoint to encode as UTF-16 | 251 | /// \param input Codepoint to encode as UTF-16 |
252 | /// \param output Iterator pointing to the beginning of the output sequence | 252 | /// \param output Iterator pointing to the beginning of the output sequence |
253 | /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) | 253 | /// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them) |
254 | /// | 254 | /// |
255 | /// \return Iterator to the end of the output sequence which has been written | 255 | /// \return Iterator to the end of the output sequence which has been written |
256 | /// | 256 | /// |
257 | //////////////////////////////////////////////////////////// | 257 | //////////////////////////////////////////////////////////// |
258 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); | 258 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint16 replacement = 0 ); |
259 | 259 | ||
260 | //////////////////////////////////////////////////////////// | 260 | //////////////////////////////////////////////////////////// |
261 | /// \brief Advance to the next UTF-16 character | 261 | /// \brief Advance to the next UTF-16 character |
262 | /// | 262 | /// |
263 | /// This function is necessary for multi-elements encodings, as | 263 | /// This function is necessary for multi-elements encodings, as |
264 | /// a single character may use more than 1 storage element. | 264 | /// a single character may use more than 1 storage element. |
265 | /// | 265 | /// |
266 | /// \param begin Iterator pointing to the beginning of the input sequence | 266 | /// \param begin Iterator pointing to the beginning of the input sequence |
267 | /// \param end Iterator pointing to the end of the input sequence | 267 | /// \param end Iterator pointing to the end of the input sequence |
268 | /// | 268 | /// |
269 | /// \return Iterator pointing to one past the last read element of the input sequence | 269 | /// \return Iterator pointing to one past the last read element of the input sequence |
270 | /// | 270 | /// |
271 | //////////////////////////////////////////////////////////// | 271 | //////////////////////////////////////////////////////////// |
272 | template <typename In> static In Next( In begin, In end ); | 272 | template <typename In> static In Next( In begin, In end ); |
273 | 273 | ||
274 | //////////////////////////////////////////////////////////// | 274 | //////////////////////////////////////////////////////////// |
275 | /// \brief Count the number of characters of a UTF-16 sequence | 275 | /// \brief Count the number of characters of a UTF-16 sequence |
276 | /// | 276 | /// |
277 | /// This function is necessary for multi-elements encodings, as | 277 | /// This function is necessary for multi-elements encodings, as |
278 | /// a single character may use more than 1 storage element, thus the | 278 | /// a single character may use more than 1 storage element, thus the |
279 | /// total size can be different from (begin - end). | 279 | /// total size can be different from (begin - end). |
280 | /// | 280 | /// |
281 | /// \param begin Iterator pointing to the beginning of the input sequence | 281 | /// \param begin Iterator pointing to the beginning of the input sequence |
282 | /// \param end Iterator pointing to the end of the input sequence | 282 | /// \param end Iterator pointing to the end of the input sequence |
283 | /// | 283 | /// |
284 | /// \return Iterator pointing to one past the last read element of the input sequence | 284 | /// \return Iterator pointing to one past the last read element of the input sequence |
285 | /// | 285 | /// |
286 | //////////////////////////////////////////////////////////// | 286 | //////////////////////////////////////////////////////////// |
287 | template <typename In> static std::size_t Count( In begin, In end ); | 287 | template <typename In> static std::size_t Count( In begin, In end ); |
288 | 288 | ||
289 | //////////////////////////////////////////////////////////// | 289 | //////////////////////////////////////////////////////////// |
290 | /// \brief Convert an ANSI characters range to UTF-16 | 290 | /// \brief Convert an ANSI characters range to UTF-16 |
291 | /// | 291 | /// |
292 | /// The current global locale will be used by default, unless you | 292 | /// The current global locale will be used by default, unless you |
293 | /// pass a custom one in the \a locale parameter. | 293 | /// pass a custom one in the \a locale parameter. |
294 | /// | 294 | /// |
295 | /// \param begin Iterator pointing to the beginning of the input sequence | 295 | /// \param begin Iterator pointing to the beginning of the input sequence |
296 | /// \param end Iterator pointing to the end of the input sequence | 296 | /// \param end Iterator pointing to the end of the input sequence |
297 | /// \param output Iterator pointing to the beginning of the output sequence | 297 | /// \param output Iterator pointing to the beginning of the output sequence |
298 | /// \param locale Locale to use for conversion | 298 | /// \param locale Locale to use for conversion |
299 | /// | 299 | /// |
300 | /// \return Iterator to the end of the output sequence which has been written | 300 | /// \return Iterator to the end of the output sequence which has been written |
301 | /// | 301 | /// |
302 | //////////////////////////////////////////////////////////// | 302 | //////////////////////////////////////////////////////////// |
303 | template <typename In, typename Out> | 303 | template <typename In, typename Out> |
304 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | 304 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); |
305 | 305 | ||
306 | //////////////////////////////////////////////////////////// | 306 | //////////////////////////////////////////////////////////// |
307 | /// \brief Convert a wide characters range to UTF-16 | 307 | /// \brief Convert a wide characters range to UTF-16 |
308 | /// | 308 | /// |
309 | /// \param begin Iterator pointing to the beginning of the input sequence | 309 | /// \param begin Iterator pointing to the beginning of the input sequence |
310 | /// \param end Iterator pointing to the end of the input sequence | 310 | /// \param end Iterator pointing to the end of the input sequence |
311 | /// \param output Iterator pointing to the beginning of the output sequence | 311 | /// \param output Iterator pointing to the beginning of the output sequence |
312 | /// | 312 | /// |
313 | /// \return Iterator to the end of the output sequence which has been written | 313 | /// \return Iterator to the end of the output sequence which has been written |
314 | /// | 314 | /// |
315 | //////////////////////////////////////////////////////////// | 315 | //////////////////////////////////////////////////////////// |
316 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | 316 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); |
317 | 317 | ||
318 | //////////////////////////////////////////////////////////// | 318 | //////////////////////////////////////////////////////////// |
319 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 | 319 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16 |
320 | /// | 320 | /// |
321 | /// \param begin Iterator pointing to the beginning of the input sequence | 321 | /// \param begin Iterator pointing to the beginning of the input sequence |
322 | /// \param end Iterator pointing to the end of the input sequence | 322 | /// \param end Iterator pointing to the end of the input sequence |
323 | /// \param output Iterator pointing to the beginning of the output sequence | 323 | /// \param output Iterator pointing to the beginning of the output sequence |
324 | /// \param locale Locale to use for conversion | 324 | /// \param locale Locale to use for conversion |
325 | /// | 325 | /// |
326 | /// \return Iterator to the end of the output sequence which has been written | 326 | /// \return Iterator to the end of the output sequence which has been written |
327 | /// | 327 | /// |
328 | //////////////////////////////////////////////////////////// | 328 | //////////////////////////////////////////////////////////// |
329 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | 329 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); |
330 | 330 | ||
331 | //////////////////////////////////////////////////////////// | 331 | //////////////////////////////////////////////////////////// |
332 | /// \brief Convert an UTF-16 characters range to ANSI characters | 332 | /// \brief Convert an UTF-16 characters range to ANSI characters |
333 | /// | 333 | /// |
334 | /// The current global locale will be used by default, unless you | 334 | /// The current global locale will be used by default, unless you |
335 | /// pass a custom one in the \a locale parameter. | 335 | /// pass a custom one in the \a locale parameter. |
336 | /// | 336 | /// |
337 | /// \param begin Iterator pointing to the beginning of the input sequence | 337 | /// \param begin Iterator pointing to the beginning of the input sequence |
338 | /// \param end Iterator pointing to the end of the input sequence | 338 | /// \param end Iterator pointing to the end of the input sequence |
339 | /// \param output Iterator pointing to the beginning of the output sequence | 339 | /// \param output Iterator pointing to the beginning of the output sequence |
340 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | 340 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) |
341 | /// \param locale Locale to use for conversion | 341 | /// \param locale Locale to use for conversion |
342 | /// | 342 | /// |
343 | /// \return Iterator to the end of the output sequence which has been written | 343 | /// \return Iterator to the end of the output sequence which has been written |
344 | /// | 344 | /// |
345 | //////////////////////////////////////////////////////////// | 345 | //////////////////////////////////////////////////////////// |
346 | template <typename In, typename Out> | 346 | template <typename In, typename Out> |
347 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | 347 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, |
348 | const std::locale& locale = std::locale() ); | 348 | const std::locale& locale = std::locale() ); |
349 | 349 | ||
350 | #ifndef EFSW_NO_WIDECHAR | 350 | #ifndef EFSW_NO_WIDECHAR |
351 | //////////////////////////////////////////////////////////// | 351 | //////////////////////////////////////////////////////////// |
352 | /// \brief Convert an UTF-16 characters range to wide characters | 352 | /// \brief Convert an UTF-16 characters range to wide characters |
353 | /// | 353 | /// |
354 | /// \param begin Iterator pointing to the beginning of the input sequence | 354 | /// \param begin Iterator pointing to the beginning of the input sequence |
355 | /// \param end Iterator pointing to the end of the input sequence | 355 | /// \param end Iterator pointing to the end of the input sequence |
356 | /// \param output Iterator pointing to the beginning of the output sequence | 356 | /// \param output Iterator pointing to the beginning of the output sequence |
357 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 357 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
358 | /// | 358 | /// |
359 | /// \return Iterator to the end of the output sequence which has been written | 359 | /// \return Iterator to the end of the output sequence which has been written |
360 | /// | 360 | /// |
361 | //////////////////////////////////////////////////////////// | 361 | //////////////////////////////////////////////////////////// |
362 | template <typename In, typename Out> | 362 | template <typename In, typename Out> |
363 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | 363 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); |
364 | #endif | 364 | #endif |
365 | 365 | ||
366 | //////////////////////////////////////////////////////////// | 366 | //////////////////////////////////////////////////////////// |
367 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters | 367 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters |
368 | /// | 368 | /// |
369 | /// \param begin Iterator pointing to the beginning of the input sequence | 369 | /// \param begin Iterator pointing to the beginning of the input sequence |
370 | /// \param end Iterator pointing to the end of the input sequence | 370 | /// \param end Iterator pointing to the end of the input sequence |
371 | /// \param output Iterator pointing to the beginning of the output sequence | 371 | /// \param output Iterator pointing to the beginning of the output sequence |
372 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 372 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
373 | /// | 373 | /// |
374 | /// \return Iterator to the end of the output sequence which has been written | 374 | /// \return Iterator to the end of the output sequence which has been written |
375 | /// | 375 | /// |
376 | //////////////////////////////////////////////////////////// | 376 | //////////////////////////////////////////////////////////// |
377 | template <typename In, typename Out> | 377 | template <typename In, typename Out> |
378 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | 378 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); |
379 | 379 | ||
380 | //////////////////////////////////////////////////////////// | 380 | //////////////////////////////////////////////////////////// |
381 | /// \brief Convert a UTF-16 characters range to UTF-8 | 381 | /// \brief Convert a UTF-16 characters range to UTF-8 |
382 | /// | 382 | /// |
383 | /// \param begin Iterator pointing to the beginning of the input sequence | 383 | /// \param begin Iterator pointing to the beginning of the input sequence |
384 | /// \param end Iterator pointing to the end of the input sequence | 384 | /// \param end Iterator pointing to the end of the input sequence |
385 | /// \param output Iterator pointing to the beginning of the output sequence | 385 | /// \param output Iterator pointing to the beginning of the output sequence |
386 | /// | 386 | /// |
387 | /// \return Iterator to the end of the output sequence which has been written | 387 | /// \return Iterator to the end of the output sequence which has been written |
388 | /// | 388 | /// |
389 | //////////////////////////////////////////////////////////// | 389 | //////////////////////////////////////////////////////////// |
390 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | 390 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); |
391 | 391 | ||
392 | //////////////////////////////////////////////////////////// | 392 | //////////////////////////////////////////////////////////// |
393 | /// \brief Convert a UTF-16 characters range to UTF-16 | 393 | /// \brief Convert a UTF-16 characters range to UTF-16 |
394 | /// | 394 | /// |
395 | /// This functions does nothing more than a direct copy; | 395 | /// This functions does nothing more than a direct copy; |
396 | /// it is defined only to provide the same interface as other | 396 | /// it is defined only to provide the same interface as other |
397 | /// specializations of the efsw::Utf<> template, and allow | 397 | /// specializations of the efsw::Utf<> template, and allow |
398 | /// generic code to be written on top of it. | 398 | /// generic code to be written on top of it. |
399 | /// | 399 | /// |
400 | /// \param begin Iterator pointing to the beginning of the input sequence | 400 | /// \param begin Iterator pointing to the beginning of the input sequence |
401 | /// \param end Iterator pointing to the end of the input sequence | 401 | /// \param end Iterator pointing to the end of the input sequence |
402 | /// \param output Iterator pointing to the beginning of the output sequence | 402 | /// \param output Iterator pointing to the beginning of the output sequence |
403 | /// | 403 | /// |
404 | /// \return Iterator to the end of the output sequence which has been written | 404 | /// \return Iterator to the end of the output sequence which has been written |
405 | /// | 405 | /// |
406 | //////////////////////////////////////////////////////////// | 406 | //////////////////////////////////////////////////////////// |
407 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | 407 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); |
408 | 408 | ||
409 | //////////////////////////////////////////////////////////// | 409 | //////////////////////////////////////////////////////////// |
410 | /// \brief Convert a UTF-16 characters range to UTF-32 | 410 | /// \brief Convert a UTF-16 characters range to UTF-32 |
411 | /// | 411 | /// |
412 | /// \param begin Iterator pointing to the beginning of the input sequence | 412 | /// \param begin Iterator pointing to the beginning of the input sequence |
413 | /// \param end Iterator pointing to the end of the input sequence | 413 | /// \param end Iterator pointing to the end of the input sequence |
414 | /// \param output Iterator pointing to the beginning of the output sequence | 414 | /// \param output Iterator pointing to the beginning of the output sequence |
415 | /// | 415 | /// |
416 | /// \return Iterator to the end of the output sequence which has been written | 416 | /// \return Iterator to the end of the output sequence which has been written |
417 | /// | 417 | /// |
418 | //////////////////////////////////////////////////////////// | 418 | //////////////////////////////////////////////////////////// |
419 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | 419 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); |
420 | }; | 420 | }; |
421 | 421 | ||
422 | //////////////////////////////////////////////////////////// | 422 | //////////////////////////////////////////////////////////// |
423 | /// \brief Specialization of the Utf template for UTF-32 | 423 | /// \brief Specialization of the Utf template for UTF-32 |
424 | /// | 424 | /// |
425 | //////////////////////////////////////////////////////////// | 425 | //////////////////////////////////////////////////////////// |
426 | template <> class Utf<32> { | 426 | template <> class Utf<32> { |
427 | public: | 427 | public: |
428 | //////////////////////////////////////////////////////////// | 428 | //////////////////////////////////////////////////////////// |
429 | /// \brief Decode a single UTF-32 character | 429 | /// \brief Decode a single UTF-32 character |
430 | /// | 430 | /// |
431 | /// Decoding a character means finding its unique 32-bits | 431 | /// Decoding a character means finding its unique 32-bits |
432 | /// code (called the codepoint) in the Unicode standard. | 432 | /// code (called the codepoint) in the Unicode standard. |
433 | /// For UTF-32, the character value is the same as the codepoint. | 433 | /// For UTF-32, the character value is the same as the codepoint. |
434 | /// | 434 | /// |
435 | /// \param begin Iterator pointing to the beginning of the input sequence | 435 | /// \param begin Iterator pointing to the beginning of the input sequence |
436 | /// \param end Iterator pointing to the end of the input sequence | 436 | /// \param end Iterator pointing to the end of the input sequence |
437 | /// \param output Codepoint of the decoded UTF-32 character | 437 | /// \param output Codepoint of the decoded UTF-32 character |
438 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid | 438 | /// \param replacement Replacement character to use in case the UTF-8 sequence is invalid |
439 | /// | 439 | /// |
440 | /// \return Iterator pointing to one past the last read element of the input sequence | 440 | /// \return Iterator pointing to one past the last read element of the input sequence |
441 | /// | 441 | /// |
442 | //////////////////////////////////////////////////////////// | 442 | //////////////////////////////////////////////////////////// |
443 | template <typename In> | 443 | template <typename In> |
444 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); | 444 | static In Decode( In begin, In end, Uint32& output, Uint32 replacement = 0 ); |
445 | 445 | ||
446 | //////////////////////////////////////////////////////////// | 446 | //////////////////////////////////////////////////////////// |
447 | /// \brief Encode a single UTF-32 character | 447 | /// \brief Encode a single UTF-32 character |
448 | /// | 448 | /// |
449 | /// Encoding a character means converting a unique 32-bits | 449 | /// Encoding a character means converting a unique 32-bits |
450 | /// code (called the codepoint) in the target encoding, UTF-32. | 450 | /// code (called the codepoint) in the target encoding, UTF-32. |
451 | /// For UTF-32, the codepoint is the same as the character value. | 451 | /// For UTF-32, the codepoint is the same as the character value. |
452 | /// | 452 | /// |
453 | /// \param input Codepoint to encode as UTF-32 | 453 | /// \param input Codepoint to encode as UTF-32 |
454 | /// \param output Iterator pointing to the beginning of the output sequence | 454 | /// \param output Iterator pointing to the beginning of the output sequence |
455 | /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) | 455 | /// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them) |
456 | /// | 456 | /// |
457 | /// \return Iterator to the end of the output sequence which has been written | 457 | /// \return Iterator to the end of the output sequence which has been written |
458 | /// | 458 | /// |
459 | //////////////////////////////////////////////////////////// | 459 | //////////////////////////////////////////////////////////// |
460 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); | 460 | template <typename Out> static Out Encode( Uint32 input, Out output, Uint32 replacement = 0 ); |
461 | 461 | ||
462 | //////////////////////////////////////////////////////////// | 462 | //////////////////////////////////////////////////////////// |
463 | /// \brief Advance to the next UTF-32 character | 463 | /// \brief Advance to the next UTF-32 character |
464 | /// | 464 | /// |
465 | /// This function is trivial for UTF-32, which can store | 465 | /// This function is trivial for UTF-32, which can store |
466 | /// every character in a single storage element. | 466 | /// every character in a single storage element. |
467 | /// | 467 | /// |
468 | /// \param begin Iterator pointing to the beginning of the input sequence | 468 | /// \param begin Iterator pointing to the beginning of the input sequence |
469 | /// \param end Iterator pointing to the end of the input sequence | 469 | /// \param end Iterator pointing to the end of the input sequence |
470 | /// | 470 | /// |
471 | /// \return Iterator pointing to one past the last read element of the input sequence | 471 | /// \return Iterator pointing to one past the last read element of the input sequence |
472 | /// | 472 | /// |
473 | //////////////////////////////////////////////////////////// | 473 | //////////////////////////////////////////////////////////// |
474 | template <typename In> static In Next( In begin, In end ); | 474 | template <typename In> static In Next( In begin, In end ); |
475 | 475 | ||
476 | //////////////////////////////////////////////////////////// | 476 | //////////////////////////////////////////////////////////// |
477 | /// \brief Count the number of characters of a UTF-32 sequence | 477 | /// \brief Count the number of characters of a UTF-32 sequence |
478 | /// | 478 | /// |
479 | /// This function is trivial for UTF-32, which can store | 479 | /// This function is trivial for UTF-32, which can store |
480 | /// every character in a single storage element. | 480 | /// every character in a single storage element. |
481 | /// | 481 | /// |
482 | /// \param begin Iterator pointing to the beginning of the input sequence | 482 | /// \param begin Iterator pointing to the beginning of the input sequence |
483 | /// \param end Iterator pointing to the end of the input sequence | 483 | /// \param end Iterator pointing to the end of the input sequence |
484 | /// | 484 | /// |
485 | /// \return Iterator pointing to one past the last read element of the input sequence | 485 | /// \return Iterator pointing to one past the last read element of the input sequence |
486 | /// | 486 | /// |
487 | //////////////////////////////////////////////////////////// | 487 | //////////////////////////////////////////////////////////// |
488 | template <typename In> static std::size_t Count( In begin, In end ); | 488 | template <typename In> static std::size_t Count( In begin, In end ); |
489 | 489 | ||
490 | //////////////////////////////////////////////////////////// | 490 | //////////////////////////////////////////////////////////// |
491 | /// \brief Convert an ANSI characters range to UTF-32 | 491 | /// \brief Convert an ANSI characters range to UTF-32 |
492 | /// | 492 | /// |
493 | /// The current global locale will be used by default, unless you | 493 | /// The current global locale will be used by default, unless you |
494 | /// pass a custom one in the \a locale parameter. | 494 | /// pass a custom one in the \a locale parameter. |
495 | /// | 495 | /// |
496 | /// \param begin Iterator pointing to the beginning of the input sequence | 496 | /// \param begin Iterator pointing to the beginning of the input sequence |
497 | /// \param end Iterator pointing to the end of the input sequence | 497 | /// \param end Iterator pointing to the end of the input sequence |
498 | /// \param output Iterator pointing to the beginning of the output sequence | 498 | /// \param output Iterator pointing to the beginning of the output sequence |
499 | /// \param locale Locale to use for conversion | 499 | /// \param locale Locale to use for conversion |
500 | /// | 500 | /// |
501 | /// \return Iterator to the end of the output sequence which has been written | 501 | /// \return Iterator to the end of the output sequence which has been written |
502 | /// | 502 | /// |
503 | //////////////////////////////////////////////////////////// | 503 | //////////////////////////////////////////////////////////// |
504 | template <typename In, typename Out> | 504 | template <typename In, typename Out> |
505 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); | 505 | static Out FromAnsi( In begin, In end, Out output, const std::locale& locale = std::locale() ); |
506 | 506 | ||
507 | //////////////////////////////////////////////////////////// | 507 | //////////////////////////////////////////////////////////// |
508 | /// \brief Convert a wide characters range to UTF-32 | 508 | /// \brief Convert a wide characters range to UTF-32 |
509 | /// | 509 | /// |
510 | /// \param begin Iterator pointing to the beginning of the input sequence | 510 | /// \param begin Iterator pointing to the beginning of the input sequence |
511 | /// \param end Iterator pointing to the end of the input sequence | 511 | /// \param end Iterator pointing to the end of the input sequence |
512 | /// \param output Iterator pointing to the beginning of the output sequence | 512 | /// \param output Iterator pointing to the beginning of the output sequence |
513 | /// | 513 | /// |
514 | /// \return Iterator to the end of the output sequence which has been written | 514 | /// \return Iterator to the end of the output sequence which has been written |
515 | /// | 515 | /// |
516 | //////////////////////////////////////////////////////////// | 516 | //////////////////////////////////////////////////////////// |
517 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); | 517 | template <typename In, typename Out> static Out FromWide( In begin, In end, Out output ); |
518 | 518 | ||
519 | //////////////////////////////////////////////////////////// | 519 | //////////////////////////////////////////////////////////// |
520 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 | 520 | /// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32 |
521 | /// | 521 | /// |
522 | /// \param begin Iterator pointing to the beginning of the input sequence | 522 | /// \param begin Iterator pointing to the beginning of the input sequence |
523 | /// \param end Iterator pointing to the end of the input sequence | 523 | /// \param end Iterator pointing to the end of the input sequence |
524 | /// \param output Iterator pointing to the beginning of the output sequence | 524 | /// \param output Iterator pointing to the beginning of the output sequence |
525 | /// \param locale Locale to use for conversion | 525 | /// \param locale Locale to use for conversion |
526 | /// | 526 | /// |
527 | /// \return Iterator to the end of the output sequence which has been written | 527 | /// \return Iterator to the end of the output sequence which has been written |
528 | /// | 528 | /// |
529 | //////////////////////////////////////////////////////////// | 529 | //////////////////////////////////////////////////////////// |
530 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); | 530 | template <typename In, typename Out> static Out FromLatin1( In begin, In end, Out output ); |
531 | 531 | ||
532 | //////////////////////////////////////////////////////////// | 532 | //////////////////////////////////////////////////////////// |
533 | /// \brief Convert an UTF-32 characters range to ANSI characters | 533 | /// \brief Convert an UTF-32 characters range to ANSI characters |
534 | /// | 534 | /// |
535 | /// The current global locale will be used by default, unless you | 535 | /// The current global locale will be used by default, unless you |
536 | /// pass a custom one in the \a locale parameter. | 536 | /// pass a custom one in the \a locale parameter. |
537 | /// | 537 | /// |
538 | /// \param begin Iterator pointing to the beginning of the input sequence | 538 | /// \param begin Iterator pointing to the beginning of the input sequence |
539 | /// \param end Iterator pointing to the end of the input sequence | 539 | /// \param end Iterator pointing to the end of the input sequence |
540 | /// \param output Iterator pointing to the beginning of the output sequence | 540 | /// \param output Iterator pointing to the beginning of the output sequence |
541 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) | 541 | /// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them) |
542 | /// \param locale Locale to use for conversion | 542 | /// \param locale Locale to use for conversion |
543 | /// | 543 | /// |
544 | /// \return Iterator to the end of the output sequence which has been written | 544 | /// \return Iterator to the end of the output sequence which has been written |
545 | /// | 545 | /// |
546 | //////////////////////////////////////////////////////////// | 546 | //////////////////////////////////////////////////////////// |
547 | template <typename In, typename Out> | 547 | template <typename In, typename Out> |
548 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, | 548 | static Out ToAnsi( In begin, In end, Out output, char replacement = 0, |
549 | const std::locale& locale = std::locale() ); | 549 | const std::locale& locale = std::locale() ); |
550 | 550 | ||
551 | #ifndef EFSW_NO_WIDECHAR | 551 | #ifndef EFSW_NO_WIDECHAR |
552 | //////////////////////////////////////////////////////////// | 552 | //////////////////////////////////////////////////////////// |
553 | /// \brief Convert an UTF-32 characters range to wide characters | 553 | /// \brief Convert an UTF-32 characters range to wide characters |
554 | /// | 554 | /// |
555 | /// \param begin Iterator pointing to the beginning of the input sequence | 555 | /// \param begin Iterator pointing to the beginning of the input sequence |
556 | /// \param end Iterator pointing to the end of the input sequence | 556 | /// \param end Iterator pointing to the end of the input sequence |
557 | /// \param output Iterator pointing to the beginning of the output sequence | 557 | /// \param output Iterator pointing to the beginning of the output sequence |
558 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 558 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
559 | /// | 559 | /// |
560 | /// \return Iterator to the end of the output sequence which has been written | 560 | /// \return Iterator to the end of the output sequence which has been written |
561 | /// | 561 | /// |
562 | //////////////////////////////////////////////////////////// | 562 | //////////////////////////////////////////////////////////// |
563 | template <typename In, typename Out> | 563 | template <typename In, typename Out> |
564 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); | 564 | static Out ToWide( In begin, In end, Out output, wchar_t replacement = 0 ); |
565 | #endif | 565 | #endif |
566 | 566 | ||
567 | //////////////////////////////////////////////////////////// | 567 | //////////////////////////////////////////////////////////// |
568 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters | 568 | /// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters |
569 | /// | 569 | /// |
570 | /// \param begin Iterator pointing to the beginning of the input sequence | 570 | /// \param begin Iterator pointing to the beginning of the input sequence |
571 | /// \param end Iterator pointing to the end of the input sequence | 571 | /// \param end Iterator pointing to the end of the input sequence |
572 | /// \param output Iterator pointing to the beginning of the output sequence | 572 | /// \param output Iterator pointing to the beginning of the output sequence |
573 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) | 573 | /// \param replacement Replacement for characters not convertible to wide (use 0 to skip them) |
574 | /// | 574 | /// |
575 | /// \return Iterator to the end of the output sequence which has been written | 575 | /// \return Iterator to the end of the output sequence which has been written |
576 | /// | 576 | /// |
577 | //////////////////////////////////////////////////////////// | 577 | //////////////////////////////////////////////////////////// |
578 | template <typename In, typename Out> | 578 | template <typename In, typename Out> |
579 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); | 579 | static Out ToLatin1( In begin, In end, Out output, char replacement = 0 ); |
580 | 580 | ||
581 | //////////////////////////////////////////////////////////// | 581 | //////////////////////////////////////////////////////////// |
582 | /// \brief Convert a UTF-32 characters range to UTF-8 | 582 | /// \brief Convert a UTF-32 characters range to UTF-8 |
583 | /// | 583 | /// |
584 | /// \param begin Iterator pointing to the beginning of the input sequence | 584 | /// \param begin Iterator pointing to the beginning of the input sequence |
585 | /// \param end Iterator pointing to the end of the input sequence | 585 | /// \param end Iterator pointing to the end of the input sequence |
586 | /// \param output Iterator pointing to the beginning of the output sequence | 586 | /// \param output Iterator pointing to the beginning of the output sequence |
587 | /// | 587 | /// |
588 | /// \return Iterator to the end of the output sequence which has been written | 588 | /// \return Iterator to the end of the output sequence which has been written |
589 | /// | 589 | /// |
590 | //////////////////////////////////////////////////////////// | 590 | //////////////////////////////////////////////////////////// |
591 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); | 591 | template <typename In, typename Out> static Out toUtf8( In begin, In end, Out output ); |
592 | 592 | ||
593 | //////////////////////////////////////////////////////////// | 593 | //////////////////////////////////////////////////////////// |
594 | /// \brief Convert a UTF-32 characters range to UTF-16 | 594 | /// \brief Convert a UTF-32 characters range to UTF-16 |
595 | /// | 595 | /// |
596 | /// \param begin Iterator pointing to the beginning of the input sequence | 596 | /// \param begin Iterator pointing to the beginning of the input sequence |
597 | /// \param end Iterator pointing to the end of the input sequence | 597 | /// \param end Iterator pointing to the end of the input sequence |
598 | /// \param output Iterator pointing to the beginning of the output sequence | 598 | /// \param output Iterator pointing to the beginning of the output sequence |
599 | /// | 599 | /// |
600 | /// \return Iterator to the end of the output sequence which has been written | 600 | /// \return Iterator to the end of the output sequence which has been written |
601 | /// | 601 | /// |
602 | //////////////////////////////////////////////////////////// | 602 | //////////////////////////////////////////////////////////// |
603 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); | 603 | template <typename In, typename Out> static Out ToUtf16( In begin, In end, Out output ); |
604 | 604 | ||
605 | //////////////////////////////////////////////////////////// | 605 | //////////////////////////////////////////////////////////// |
606 | /// \brief Convert a UTF-32 characters range to UTF-32 | 606 | /// \brief Convert a UTF-32 characters range to UTF-32 |
607 | /// | 607 | /// |
608 | /// This functions does nothing more than a direct copy; | 608 | /// This functions does nothing more than a direct copy; |
609 | /// it is defined only to provide the same interface as other | 609 | /// it is defined only to provide the same interface as other |
610 | /// specializations of the efsw::Utf<> template, and allow | 610 | /// specializations of the efsw::Utf<> template, and allow |
611 | /// generic code to be written on top of it. | 611 | /// generic code to be written on top of it. |
612 | /// | 612 | /// |
613 | /// \param begin Iterator pointing to the beginning of the input sequence | 613 | /// \param begin Iterator pointing to the beginning of the input sequence |
614 | /// \param end Iterator pointing to the end of the input sequence | 614 | /// \param end Iterator pointing to the end of the input sequence |
615 | /// \param output Iterator pointing to the beginning of the output sequence | 615 | /// \param output Iterator pointing to the beginning of the output sequence |
616 | /// | 616 | /// |
617 | /// \return Iterator to the end of the output sequence which has been written | 617 | /// \return Iterator to the end of the output sequence which has been written |
618 | /// | 618 | /// |
619 | //////////////////////////////////////////////////////////// | 619 | //////////////////////////////////////////////////////////// |
620 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); | 620 | template <typename In, typename Out> static Out ToUtf32( In begin, In end, Out output ); |
621 | 621 | ||
622 | //////////////////////////////////////////////////////////// | 622 | //////////////////////////////////////////////////////////// |
623 | /// \brief Decode a single ANSI character to UTF-32 | 623 | /// \brief Decode a single ANSI character to UTF-32 |
624 | /// | 624 | /// |
625 | /// This function does not exist in other specializations | 625 | /// This function does not exist in other specializations |
626 | /// of efsw::Utf<>, it is defined for convenience (it is used by | 626 | /// of efsw::Utf<>, it is defined for convenience (it is used by |
627 | /// several other conversion functions). | 627 | /// several other conversion functions). |
628 | /// | 628 | /// |
629 | /// \param input Input ANSI character | 629 | /// \param input Input ANSI character |
630 | /// \param locale Locale to use for conversion | 630 | /// \param locale Locale to use for conversion |
631 | /// | 631 | /// |
632 | /// \return Converted character | 632 | /// \return Converted character |
633 | /// | 633 | /// |
634 | //////////////////////////////////////////////////////////// | 634 | //////////////////////////////////////////////////////////// |
635 | template <typename In> | 635 | template <typename In> |
636 | static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); | 636 | static Uint32 DecodeAnsi( In input, const std::locale& locale = std::locale() ); |
637 | 637 | ||
638 | //////////////////////////////////////////////////////////// | 638 | //////////////////////////////////////////////////////////// |
639 | /// \brief Decode a single wide character to UTF-32 | 639 | /// \brief Decode a single wide character to UTF-32 |
640 | /// | 640 | /// |
641 | /// This function does not exist in other specializations | 641 | /// This function does not exist in other specializations |
642 | /// of efsw::Utf<>, it is defined for convenience (it is used by | 642 | /// of efsw::Utf<>, it is defined for convenience (it is used by |
643 | /// several other conversion functions). | 643 | /// several other conversion functions). |
644 | /// | 644 | /// |
645 | /// \param input Input wide character | 645 | /// \param input Input wide character |
646 | /// | 646 | /// |
647 | /// \return Converted character | 647 | /// \return Converted character |
648 | /// | 648 | /// |
649 | //////////////////////////////////////////////////////////// | 649 | //////////////////////////////////////////////////////////// |
650 | template <typename In> static Uint32 DecodeWide( In input ); | 650 | template <typename In> static Uint32 DecodeWide( In input ); |
651 | 651 | ||
652 | //////////////////////////////////////////////////////////// | 652 | //////////////////////////////////////////////////////////// |
653 | /// \brief Encode a single UTF-32 character to ANSI | 653 | /// \brief Encode a single UTF-32 character to ANSI |
654 | /// | 654 | /// |
655 | /// This function does not exist in other specializations | 655 | /// This function does not exist in other specializations |
656 | /// of efsw::Utf<>, it is defined for convenience (it is used by | 656 | /// of efsw::Utf<>, it is defined for convenience (it is used by |
657 | /// several other conversion functions). | 657 | /// several other conversion functions). |
658 | /// | 658 | /// |
659 | /// \param codepoint Iterator pointing to the beginning of the input sequence | 659 | /// \param codepoint Iterator pointing to the beginning of the input sequence |
660 | /// \param output Iterator pointing to the beginning of the output sequence | 660 | /// \param output Iterator pointing to the beginning of the output sequence |
661 | /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to | 661 | /// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to |
662 | /// skip it) \param locale Locale to use for conversion | 662 | /// skip it) \param locale Locale to use for conversion |
663 | /// | 663 | /// |
664 | /// \return Iterator to the end of the output sequence which has been written | 664 | /// \return Iterator to the end of the output sequence which has been written |
665 | /// | 665 | /// |
666 | //////////////////////////////////////////////////////////// | 666 | //////////////////////////////////////////////////////////// |
667 | template <typename Out> | 667 | template <typename Out> |
668 | static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, | 668 | static Out EncodeAnsi( Uint32 codepoint, Out output, char replacement = 0, |
669 | const std::locale& locale = std::locale() ); | 669 | const std::locale& locale = std::locale() ); |
670 | 670 | ||
671 | #ifndef EFSW_NO_WIDECHAR | 671 | #ifndef EFSW_NO_WIDECHAR |
672 | //////////////////////////////////////////////////////////// | 672 | //////////////////////////////////////////////////////////// |
673 | /// \brief Encode a single UTF-32 character to wide | 673 | /// \brief Encode a single UTF-32 character to wide |
674 | /// | 674 | /// |
675 | /// This function does not exist in other specializations | 675 | /// This function does not exist in other specializations |
676 | /// of efsw::Utf<>, it is defined for convenience (it is used by | 676 | /// of efsw::Utf<>, it is defined for convenience (it is used by |
677 | /// several other conversion functions). | 677 | /// several other conversion functions). |
678 | /// | 678 | /// |
679 | /// \param codepoint Iterator pointing to the beginning of the input sequence | 679 | /// \param codepoint Iterator pointing to the beginning of the input sequence |
680 | /// \param output Iterator pointing to the beginning of the output sequence | 680 | /// \param output Iterator pointing to the beginning of the output sequence |
681 | /// \param replacement Replacement if the input character is not convertible to wide (use 0 to | 681 | /// \param replacement Replacement if the input character is not convertible to wide (use 0 to |
682 | /// skip it) | 682 | /// skip it) |
683 | /// | 683 | /// |
684 | /// \return Iterator to the end of the output sequence which has been written | 684 | /// \return Iterator to the end of the output sequence which has been written |
685 | /// | 685 | /// |
686 | //////////////////////////////////////////////////////////// | 686 | //////////////////////////////////////////////////////////// |
687 | template <typename Out> | 687 | template <typename Out> |
688 | static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); | 688 | static Out EncodeWide( Uint32 codepoint, Out output, wchar_t replacement = 0 ); |
689 | #endif | 689 | #endif |
690 | }; | 690 | }; |
691 | 691 | ||
692 | #include "Utf.inl" | 692 | #include "Utf.inl" |
693 | 693 | ||
694 | // Make typedefs to get rid of the template syntax | 694 | // Make typedefs to get rid of the template syntax |
695 | typedef Utf<8> Utf8; | 695 | typedef Utf<8> Utf8; |
696 | typedef Utf<16> Utf16; | 696 | typedef Utf<16> Utf16; |
697 | typedef Utf<32> Utf32; | 697 | typedef Utf<32> Utf32; |
698 | 698 | ||
699 | } // namespace efsw | 699 | } // namespace efsw |
700 | #endif | 700 | #endif |
701 | 701 | ||
702 | //////////////////////////////////////////////////////////// | 702 | //////////////////////////////////////////////////////////// |
703 | /// \class efsw::Utf | 703 | /// \class efsw::Utf |
704 | /// \ingroup system | 704 | /// \ingroup system |
705 | /// | 705 | /// |
706 | /// Utility class providing generic functions for UTF conversions. | 706 | /// Utility class providing generic functions for UTF conversions. |
707 | /// | 707 | /// |
708 | /// efsw::Utf is a low-level, generic interface for counting, iterating, | 708 | /// efsw::Utf is a low-level, generic interface for counting, iterating, |
709 | /// encoding and decoding Unicode characters and strings. It is able | 709 | /// encoding and decoding Unicode characters and strings. It is able |
710 | /// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. | 710 | /// to handle ANSI, wide, UTF-8, UTF-16 and UTF-32 encodings. |
711 | /// | 711 | /// |
712 | /// efsw::Utf<X> functions are all static, these classes are not meant to | 712 | /// efsw::Utf<X> functions are all static, these classes are not meant to |
713 | /// be instanciated. All the functions are template, so that you | 713 | /// be instanciated. All the functions are template, so that you |
714 | /// can use any character / string type for a given encoding. | 714 | /// can use any character / string type for a given encoding. |
715 | /// | 715 | /// |
716 | /// It has 3 specializations: | 716 | /// It has 3 specializations: |
717 | /// \li efsw::Utf<8> (typedef'd to efsw::Utf8) | 717 | /// \li efsw::Utf<8> (typedef'd to efsw::Utf8) |
718 | /// \li efsw::Utf<16> (typedef'd to efsw::Utf16) | 718 | /// \li efsw::Utf<16> (typedef'd to efsw::Utf16) |
719 | /// \li efsw::Utf<32> (typedef'd to efsw::Utf32) | 719 | /// \li efsw::Utf<32> (typedef'd to efsw::Utf32) |
720 | /// | 720 | /// |
721 | //////////////////////////////////////////////////////////// | 721 | //////////////////////////////////////////////////////////// |
diff --git a/src/3rdParty/efsw/Utf.inl b/src/3rdParty/efsw/Utf.inl index 5b6c2e0..5c9d7a3 100755..100644 --- a/src/3rdParty/efsw/Utf.inl +++ b/src/3rdParty/efsw/Utf.inl | |||
@@ -1,576 +1,576 @@ | |||
1 | // References : | 1 | // References : |
2 | // http://www.unicode.org/ | 2 | // http://www.unicode.org/ |
3 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c | 3 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c |
4 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h | 4 | // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h |
5 | // http://people.w3.org/rishida/scripts/uniview/conversion | 5 | // http://people.w3.org/rishida/scripts/uniview/conversion |
6 | //////////////////////////////////////////////////////////// | 6 | //////////////////////////////////////////////////////////// |
7 | 7 | ||
8 | template <typename In> In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { | 8 | template <typename In> In Utf<8>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { |
9 | // Some useful precomputed data | 9 | // Some useful precomputed data |
10 | static const int trailing[256] = { | 10 | static const int trailing[256] = { |
11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 11 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
13 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 13 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
14 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 14 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
15 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 15 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
18 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, | 18 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, |
19 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; | 19 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; |
20 | static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080, | 20 | static const Uint32 offsets[6] = { 0x00000000, 0x00003080, 0x000E2080, |
21 | 0x03C82080, 0xFA082080, 0x82082080 }; | 21 | 0x03C82080, 0xFA082080, 0x82082080 }; |
22 | 22 | ||
23 | // Decode the character | 23 | // Decode the character |
24 | int trailingBytes = trailing[static_cast<Uint8>( *begin )]; | 24 | int trailingBytes = trailing[static_cast<Uint8>( *begin )]; |
25 | if ( begin + trailingBytes < end ) { | 25 | if ( begin + trailingBytes < end ) { |
26 | output = 0; | 26 | output = 0; |
27 | switch ( trailingBytes ) { | 27 | switch ( trailingBytes ) { |
28 | case 5: | 28 | case 5: |
29 | output += static_cast<Uint8>( *begin++ ); | 29 | output += static_cast<Uint8>( *begin++ ); |
30 | output <<= 6; | 30 | output <<= 6; |
31 | case 4: | 31 | case 4: |
32 | output += static_cast<Uint8>( *begin++ ); | 32 | output += static_cast<Uint8>( *begin++ ); |
33 | output <<= 6; | 33 | output <<= 6; |
34 | case 3: | 34 | case 3: |
35 | output += static_cast<Uint8>( *begin++ ); | 35 | output += static_cast<Uint8>( *begin++ ); |
36 | output <<= 6; | 36 | output <<= 6; |
37 | case 2: | 37 | case 2: |
38 | output += static_cast<Uint8>( *begin++ ); | 38 | output += static_cast<Uint8>( *begin++ ); |
39 | output <<= 6; | 39 | output <<= 6; |
40 | case 1: | 40 | case 1: |
41 | output += static_cast<Uint8>( *begin++ ); | 41 | output += static_cast<Uint8>( *begin++ ); |
42 | output <<= 6; | 42 | output <<= 6; |
43 | case 0: | 43 | case 0: |
44 | output += static_cast<Uint8>( *begin++ ); | 44 | output += static_cast<Uint8>( *begin++ ); |
45 | } | 45 | } |
46 | output -= offsets[trailingBytes]; | 46 | output -= offsets[trailingBytes]; |
47 | } else { | 47 | } else { |
48 | // Incomplete character | 48 | // Incomplete character |
49 | begin = end; | 49 | begin = end; |
50 | output = replacement; | 50 | output = replacement; |
51 | } | 51 | } |
52 | 52 | ||
53 | return begin; | 53 | return begin; |
54 | } | 54 | } |
55 | 55 | ||
56 | template <typename Out> Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { | 56 | template <typename Out> Out Utf<8>::Encode( Uint32 input, Out output, Uint8 replacement ) { |
57 | // Some useful precomputed data | 57 | // Some useful precomputed data |
58 | static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | 58 | static const Uint8 firstBytes[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; |
59 | 59 | ||
60 | // Encode the character | 60 | // Encode the character |
61 | if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { | 61 | if ( ( input > 0x0010FFFF ) || ( ( input >= 0xD800 ) && ( input <= 0xDBFF ) ) ) { |
62 | // Invalid character | 62 | // Invalid character |
63 | if ( replacement ) | 63 | if ( replacement ) |
64 | *output++ = replacement; | 64 | *output++ = replacement; |
65 | } else { | 65 | } else { |
66 | // Valid character | 66 | // Valid character |
67 | 67 | ||
68 | // Get the number of bytes to write | 68 | // Get the number of bytes to write |
69 | int bytesToWrite = 1; | 69 | int bytesToWrite = 1; |
70 | if ( input < 0x80 ) | 70 | if ( input < 0x80 ) |
71 | bytesToWrite = 1; | 71 | bytesToWrite = 1; |
72 | else if ( input < 0x800 ) | 72 | else if ( input < 0x800 ) |
73 | bytesToWrite = 2; | 73 | bytesToWrite = 2; |
74 | else if ( input < 0x10000 ) | 74 | else if ( input < 0x10000 ) |
75 | bytesToWrite = 3; | 75 | bytesToWrite = 3; |
76 | else if ( input <= 0x0010FFFF ) | 76 | else if ( input <= 0x0010FFFF ) |
77 | bytesToWrite = 4; | 77 | bytesToWrite = 4; |
78 | 78 | ||
79 | // Extract the bytes to write | 79 | // Extract the bytes to write |
80 | Uint8 bytes[4]; | 80 | Uint8 bytes[4]; |
81 | switch ( bytesToWrite ) { | 81 | switch ( bytesToWrite ) { |
82 | case 4: | 82 | case 4: |
83 | bytes[3] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | 83 | bytes[3] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); |
84 | input >>= 6; | 84 | input >>= 6; |
85 | case 3: | 85 | case 3: |
86 | bytes[2] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | 86 | bytes[2] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); |
87 | input >>= 6; | 87 | input >>= 6; |
88 | case 2: | 88 | case 2: |
89 | bytes[1] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); | 89 | bytes[1] = static_cast<Uint8>( ( input | 0x80 ) & 0xBF ); |
90 | input >>= 6; | 90 | input >>= 6; |
91 | case 1: | 91 | case 1: |
92 | bytes[0] = static_cast<Uint8>( input | firstBytes[bytesToWrite] ); | 92 | bytes[0] = static_cast<Uint8>( input | firstBytes[bytesToWrite] ); |
93 | } | 93 | } |
94 | 94 | ||
95 | // Add them to the output | 95 | // Add them to the output |
96 | const Uint8* currentByte = bytes; | 96 | const Uint8* currentByte = bytes; |
97 | switch ( bytesToWrite ) { | 97 | switch ( bytesToWrite ) { |
98 | case 4: | 98 | case 4: |
99 | *output++ = *currentByte++; | 99 | *output++ = *currentByte++; |
100 | case 3: | 100 | case 3: |
101 | *output++ = *currentByte++; | 101 | *output++ = *currentByte++; |
102 | case 2: | 102 | case 2: |
103 | *output++ = *currentByte++; | 103 | *output++ = *currentByte++; |
104 | case 1: | 104 | case 1: |
105 | *output++ = *currentByte++; | 105 | *output++ = *currentByte++; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | return output; | 109 | return output; |
110 | } | 110 | } |
111 | 111 | ||
112 | template <typename In> In Utf<8>::Next( In begin, In end ) { | 112 | template <typename In> In Utf<8>::Next( In begin, In end ) { |
113 | Uint32 codepoint; | 113 | Uint32 codepoint; |
114 | return Decode( begin, end, codepoint ); | 114 | return Decode( begin, end, codepoint ); |
115 | } | 115 | } |
116 | 116 | ||
117 | template <typename In> std::size_t Utf<8>::Count( In begin, In end ) { | 117 | template <typename In> std::size_t Utf<8>::Count( In begin, In end ) { |
118 | std::size_t length = 0; | 118 | std::size_t length = 0; |
119 | while ( begin < end ) { | 119 | while ( begin < end ) { |
120 | begin = Next( begin, end ); | 120 | begin = Next( begin, end ); |
121 | ++length; | 121 | ++length; |
122 | } | 122 | } |
123 | 123 | ||
124 | return length; | 124 | return length; |
125 | } | 125 | } |
126 | 126 | ||
127 | template <typename In, typename Out> | 127 | template <typename In, typename Out> |
128 | Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | 128 | Out Utf<8>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { |
129 | while ( begin < end ) { | 129 | while ( begin < end ) { |
130 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); | 130 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); |
131 | output = Encode( codepoint, output ); | 131 | output = Encode( codepoint, output ); |
132 | } | 132 | } |
133 | 133 | ||
134 | return output; | 134 | return output; |
135 | } | 135 | } |
136 | 136 | ||
137 | template <typename In, typename Out> Out Utf<8>::FromWide( In begin, In end, Out output ) { | 137 | template <typename In, typename Out> Out Utf<8>::FromWide( In begin, In end, Out output ) { |
138 | while ( begin < end ) { | 138 | while ( begin < end ) { |
139 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); | 139 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); |
140 | output = Encode( codepoint, output ); | 140 | output = Encode( codepoint, output ); |
141 | } | 141 | } |
142 | 142 | ||
143 | return output; | 143 | return output; |
144 | } | 144 | } |
145 | 145 | ||
146 | template <typename In, typename Out> Out Utf<8>::FromLatin1( In begin, In end, Out output ) { | 146 | template <typename In, typename Out> Out Utf<8>::FromLatin1( In begin, In end, Out output ) { |
147 | // Latin-1 is directly compatible with Unicode encodings, | 147 | // Latin-1 is directly compatible with Unicode encodings, |
148 | // and can thus be treated as (a sub-range of) UTF-32 | 148 | // and can thus be treated as (a sub-range of) UTF-32 |
149 | while ( begin < end ) | 149 | while ( begin < end ) |
150 | output = Encode( *begin++, output ); | 150 | output = Encode( *begin++, output ); |
151 | 151 | ||
152 | return output; | 152 | return output; |
153 | } | 153 | } |
154 | 154 | ||
155 | template <typename In, typename Out> | 155 | template <typename In, typename Out> |
156 | Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | 156 | Out Utf<8>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { |
157 | while ( begin < end ) { | 157 | while ( begin < end ) { |
158 | Uint32 codepoint; | 158 | Uint32 codepoint; |
159 | begin = Decode( begin, end, codepoint ); | 159 | begin = Decode( begin, end, codepoint ); |
160 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); | 160 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); |
161 | } | 161 | } |
162 | 162 | ||
163 | return output; | 163 | return output; |
164 | } | 164 | } |
165 | 165 | ||
166 | #ifndef EFSW_NO_WIDECHAR | 166 | #ifndef EFSW_NO_WIDECHAR |
167 | template <typename In, typename Out> | 167 | template <typename In, typename Out> |
168 | Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | 168 | Out Utf<8>::ToWide( In begin, In end, Out output, wchar_t replacement ) { |
169 | while ( begin < end ) { | 169 | while ( begin < end ) { |
170 | Uint32 codepoint; | 170 | Uint32 codepoint; |
171 | begin = Decode( begin, end, codepoint ); | 171 | begin = Decode( begin, end, codepoint ); |
172 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); | 172 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); |
173 | } | 173 | } |
174 | 174 | ||
175 | return output; | 175 | return output; |
176 | } | 176 | } |
177 | #endif | 177 | #endif |
178 | 178 | ||
179 | template <typename In, typename Out> | 179 | template <typename In, typename Out> |
180 | Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { | 180 | Out Utf<8>::ToLatin1( In begin, In end, Out output, char replacement ) { |
181 | // Latin-1 is directly compatible with Unicode encodings, | 181 | // Latin-1 is directly compatible with Unicode encodings, |
182 | // and can thus be treated as (a sub-range of) UTF-32 | 182 | // and can thus be treated as (a sub-range of) UTF-32 |
183 | while ( begin < end ) { | 183 | while ( begin < end ) { |
184 | Uint32 codepoint; | 184 | Uint32 codepoint; |
185 | begin = Decode( begin, end, codepoint ); | 185 | begin = Decode( begin, end, codepoint ); |
186 | *output++ = codepoint < 256 ? static_cast<char>( codepoint ) : replacement; | 186 | *output++ = codepoint < 256 ? static_cast<char>( codepoint ) : replacement; |
187 | } | 187 | } |
188 | 188 | ||
189 | return output; | 189 | return output; |
190 | } | 190 | } |
191 | 191 | ||
192 | template <typename In, typename Out> Out Utf<8>::toUtf8( In begin, In end, Out output ) { | 192 | template <typename In, typename Out> Out Utf<8>::toUtf8( In begin, In end, Out output ) { |
193 | while ( begin < end ) | 193 | while ( begin < end ) |
194 | *output++ = *begin++; | 194 | *output++ = *begin++; |
195 | 195 | ||
196 | return output; | 196 | return output; |
197 | } | 197 | } |
198 | 198 | ||
199 | template <typename In, typename Out> Out Utf<8>::ToUtf16( In begin, In end, Out output ) { | 199 | template <typename In, typename Out> Out Utf<8>::ToUtf16( In begin, In end, Out output ) { |
200 | while ( begin < end ) { | 200 | while ( begin < end ) { |
201 | Uint32 codepoint; | 201 | Uint32 codepoint; |
202 | begin = Decode( begin, end, codepoint ); | 202 | begin = Decode( begin, end, codepoint ); |
203 | output = Utf<16>::Encode( codepoint, output ); | 203 | output = Utf<16>::Encode( codepoint, output ); |
204 | } | 204 | } |
205 | 205 | ||
206 | return output; | 206 | return output; |
207 | } | 207 | } |
208 | 208 | ||
209 | template <typename In, typename Out> Out Utf<8>::ToUtf32( In begin, In end, Out output ) { | 209 | template <typename In, typename Out> Out Utf<8>::ToUtf32( In begin, In end, Out output ) { |
210 | while ( begin < end ) { | 210 | while ( begin < end ) { |
211 | Uint32 codepoint; | 211 | Uint32 codepoint; |
212 | begin = Decode( begin, end, codepoint ); | 212 | begin = Decode( begin, end, codepoint ); |
213 | *output++ = codepoint; | 213 | *output++ = codepoint; |
214 | } | 214 | } |
215 | 215 | ||
216 | return output; | 216 | return output; |
217 | } | 217 | } |
218 | 218 | ||
219 | template <typename In> In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { | 219 | template <typename In> In Utf<16>::Decode( In begin, In end, Uint32& output, Uint32 replacement ) { |
220 | Uint16 first = *begin++; | 220 | Uint16 first = *begin++; |
221 | 221 | ||
222 | // If it's a surrogate pair, first convert to a single UTF-32 character | 222 | // If it's a surrogate pair, first convert to a single UTF-32 character |
223 | if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { | 223 | if ( ( first >= 0xD800 ) && ( first <= 0xDBFF ) ) { |
224 | if ( begin < end ) { | 224 | if ( begin < end ) { |
225 | Uint32 second = *begin++; | 225 | Uint32 second = *begin++; |
226 | if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { | 226 | if ( ( second >= 0xDC00 ) && ( second <= 0xDFFF ) ) { |
227 | // The second element is valid: convert the two elements to a UTF-32 character | 227 | // The second element is valid: convert the two elements to a UTF-32 character |
228 | output = static_cast<Uint32>( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) + | 228 | output = static_cast<Uint32>( ( ( first - 0xD800 ) << 10 ) + ( second - 0xDC00 ) + |
229 | 0x0010000 ); | 229 | 0x0010000 ); |
230 | } else { | 230 | } else { |
231 | // Invalid character | 231 | // Invalid character |
232 | output = replacement; | 232 | output = replacement; |
233 | } | 233 | } |
234 | } else { | 234 | } else { |
235 | // Invalid character | 235 | // Invalid character |
236 | begin = end; | 236 | begin = end; |
237 | output = replacement; | 237 | output = replacement; |
238 | } | 238 | } |
239 | } else { | 239 | } else { |
240 | // We can make a direct copy | 240 | // We can make a direct copy |
241 | output = first; | 241 | output = first; |
242 | } | 242 | } |
243 | 243 | ||
244 | return begin; | 244 | return begin; |
245 | } | 245 | } |
246 | 246 | ||
247 | template <typename Out> Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { | 247 | template <typename Out> Out Utf<16>::Encode( Uint32 input, Out output, Uint16 replacement ) { |
248 | if ( input < 0xFFFF ) { | 248 | if ( input < 0xFFFF ) { |
249 | // The character can be copied directly, we just need to check if it's in the valid range | 249 | // The character can be copied directly, we just need to check if it's in the valid range |
250 | if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) { | 250 | if ( ( input >= 0xD800 ) && ( input <= 0xDFFF ) ) { |
251 | // Invalid character (this range is reserved) | 251 | // Invalid character (this range is reserved) |
252 | if ( replacement ) | 252 | if ( replacement ) |
253 | *output++ = replacement; | 253 | *output++ = replacement; |
254 | } else { | 254 | } else { |
255 | // Valid character directly convertible to a single UTF-16 character | 255 | // Valid character directly convertible to a single UTF-16 character |
256 | *output++ = static_cast<Uint16>( input ); | 256 | *output++ = static_cast<Uint16>( input ); |
257 | } | 257 | } |
258 | } else if ( input > 0x0010FFFF ) { | 258 | } else if ( input > 0x0010FFFF ) { |
259 | // Invalid character (greater than the maximum unicode value) | 259 | // Invalid character (greater than the maximum unicode value) |
260 | if ( replacement ) | 260 | if ( replacement ) |
261 | *output++ = replacement; | 261 | *output++ = replacement; |
262 | } else { | 262 | } else { |
263 | // The input character will be converted to two UTF-16 elements | 263 | // The input character will be converted to two UTF-16 elements |
264 | input -= 0x0010000; | 264 | input -= 0x0010000; |
265 | *output++ = static_cast<Uint16>( ( input >> 10 ) + 0xD800 ); | 265 | *output++ = static_cast<Uint16>( ( input >> 10 ) + 0xD800 ); |
266 | *output++ = static_cast<Uint16>( ( input & 0x3FFUL ) + 0xDC00 ); | 266 | *output++ = static_cast<Uint16>( ( input & 0x3FFUL ) + 0xDC00 ); |
267 | } | 267 | } |
268 | 268 | ||
269 | return output; | 269 | return output; |
270 | } | 270 | } |
271 | 271 | ||
272 | template <typename In> In Utf<16>::Next( In begin, In end ) { | 272 | template <typename In> In Utf<16>::Next( In begin, In end ) { |
273 | Uint32 codepoint; | 273 | Uint32 codepoint; |
274 | return Decode( begin, end, codepoint ); | 274 | return Decode( begin, end, codepoint ); |
275 | } | 275 | } |
276 | 276 | ||
277 | template <typename In> std::size_t Utf<16>::Count( In begin, In end ) { | 277 | template <typename In> std::size_t Utf<16>::Count( In begin, In end ) { |
278 | std::size_t length = 0; | 278 | std::size_t length = 0; |
279 | while ( begin < end ) { | 279 | while ( begin < end ) { |
280 | begin = Next( begin, end ); | 280 | begin = Next( begin, end ); |
281 | ++length; | 281 | ++length; |
282 | } | 282 | } |
283 | 283 | ||
284 | return length; | 284 | return length; |
285 | } | 285 | } |
286 | 286 | ||
287 | template <typename In, typename Out> | 287 | template <typename In, typename Out> |
288 | Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | 288 | Out Utf<16>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { |
289 | while ( begin < end ) { | 289 | while ( begin < end ) { |
290 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); | 290 | Uint32 codepoint = Utf<32>::DecodeAnsi( *begin++, locale ); |
291 | output = Encode( codepoint, output ); | 291 | output = Encode( codepoint, output ); |
292 | } | 292 | } |
293 | 293 | ||
294 | return output; | 294 | return output; |
295 | } | 295 | } |
296 | 296 | ||
297 | template <typename In, typename Out> Out Utf<16>::FromWide( In begin, In end, Out output ) { | 297 | template <typename In, typename Out> Out Utf<16>::FromWide( In begin, In end, Out output ) { |
298 | while ( begin < end ) { | 298 | while ( begin < end ) { |
299 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); | 299 | Uint32 codepoint = Utf<32>::DecodeWide( *begin++ ); |
300 | output = Encode( codepoint, output ); | 300 | output = Encode( codepoint, output ); |
301 | } | 301 | } |
302 | 302 | ||
303 | return output; | 303 | return output; |
304 | } | 304 | } |
305 | 305 | ||
306 | template <typename In, typename Out> Out Utf<16>::FromLatin1( In begin, In end, Out output ) { | 306 | template <typename In, typename Out> Out Utf<16>::FromLatin1( In begin, In end, Out output ) { |
307 | // Latin-1 is directly compatible with Unicode encodings, | 307 | // Latin-1 is directly compatible with Unicode encodings, |
308 | // and can thus be treated as (a sub-range of) UTF-32 | 308 | // and can thus be treated as (a sub-range of) UTF-32 |
309 | while ( begin < end ) | 309 | while ( begin < end ) |
310 | *output++ = *begin++; | 310 | *output++ = *begin++; |
311 | 311 | ||
312 | return output; | 312 | return output; |
313 | } | 313 | } |
314 | 314 | ||
315 | template <typename In, typename Out> | 315 | template <typename In, typename Out> |
316 | Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | 316 | Out Utf<16>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { |
317 | while ( begin < end ) { | 317 | while ( begin < end ) { |
318 | Uint32 codepoint; | 318 | Uint32 codepoint; |
319 | begin = Decode( begin, end, codepoint ); | 319 | begin = Decode( begin, end, codepoint ); |
320 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); | 320 | output = Utf<32>::EncodeAnsi( codepoint, output, replacement, locale ); |
321 | } | 321 | } |
322 | 322 | ||
323 | return output; | 323 | return output; |
324 | } | 324 | } |
325 | 325 | ||
326 | #ifndef EFSW_NO_WIDECHAR | 326 | #ifndef EFSW_NO_WIDECHAR |
327 | template <typename In, typename Out> | 327 | template <typename In, typename Out> |
328 | Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | 328 | Out Utf<16>::ToWide( In begin, In end, Out output, wchar_t replacement ) { |
329 | while ( begin < end ) { | 329 | while ( begin < end ) { |
330 | Uint32 codepoint; | 330 | Uint32 codepoint; |
331 | begin = Decode( begin, end, codepoint ); | 331 | begin = Decode( begin, end, codepoint ); |
332 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); | 332 | output = Utf<32>::EncodeWide( codepoint, output, replacement ); |
333 | } | 333 | } |
334 | 334 | ||
335 | return output; | 335 | return output; |
336 | } | 336 | } |
337 | #endif | 337 | #endif |
338 | 338 | ||
339 | template <typename In, typename Out> | 339 | template <typename In, typename Out> |
340 | Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { | 340 | Out Utf<16>::ToLatin1( In begin, In end, Out output, char replacement ) { |
341 | // Latin-1 is directly compatible with Unicode encodings, | 341 | // Latin-1 is directly compatible with Unicode encodings, |
342 | // and can thus be treated as (a sub-range of) UTF-32 | 342 | // and can thus be treated as (a sub-range of) UTF-32 |
343 | while ( begin < end ) { | 343 | while ( begin < end ) { |
344 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; | 344 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; |
345 | begin++; | 345 | begin++; |
346 | } | 346 | } |
347 | 347 | ||
348 | return output; | 348 | return output; |
349 | } | 349 | } |
350 | 350 | ||
351 | template <typename In, typename Out> Out Utf<16>::toUtf8( In begin, In end, Out output ) { | 351 | template <typename In, typename Out> Out Utf<16>::toUtf8( In begin, In end, Out output ) { |
352 | while ( begin < end ) { | 352 | while ( begin < end ) { |
353 | Uint32 codepoint; | 353 | Uint32 codepoint; |
354 | begin = Decode( begin, end, codepoint ); | 354 | begin = Decode( begin, end, codepoint ); |
355 | output = Utf<8>::Encode( codepoint, output ); | 355 | output = Utf<8>::Encode( codepoint, output ); |
356 | } | 356 | } |
357 | 357 | ||
358 | return output; | 358 | return output; |
359 | } | 359 | } |
360 | 360 | ||
361 | template <typename In, typename Out> Out Utf<16>::ToUtf16( In begin, In end, Out output ) { | 361 | template <typename In, typename Out> Out Utf<16>::ToUtf16( In begin, In end, Out output ) { |
362 | while ( begin < end ) | 362 | while ( begin < end ) |
363 | *output++ = *begin++; | 363 | *output++ = *begin++; |
364 | 364 | ||
365 | return output; | 365 | return output; |
366 | } | 366 | } |
367 | 367 | ||
368 | template <typename In, typename Out> Out Utf<16>::ToUtf32( In begin, In end, Out output ) { | 368 | template <typename In, typename Out> Out Utf<16>::ToUtf32( In begin, In end, Out output ) { |
369 | while ( begin < end ) { | 369 | while ( begin < end ) { |
370 | Uint32 codepoint; | 370 | Uint32 codepoint; |
371 | begin = Decode( begin, end, codepoint ); | 371 | begin = Decode( begin, end, codepoint ); |
372 | *output++ = codepoint; | 372 | *output++ = codepoint; |
373 | } | 373 | } |
374 | 374 | ||
375 | return output; | 375 | return output; |
376 | } | 376 | } |
377 | 377 | ||
378 | template <typename In> In Utf<32>::Decode( In begin, In /*end*/, Uint32& output, Uint32 ) { | 378 | template <typename In> In Utf<32>::Decode( In begin, In /*end*/, Uint32& output, Uint32 ) { |
379 | output = *begin++; | 379 | output = *begin++; |
380 | return begin; | 380 | return begin; |
381 | } | 381 | } |
382 | 382 | ||
383 | template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 /*replacement*/ ) { | 383 | template <typename Out> Out Utf<32>::Encode( Uint32 input, Out output, Uint32 /*replacement*/ ) { |
384 | *output++ = input; | 384 | *output++ = input; |
385 | return output; | 385 | return output; |
386 | } | 386 | } |
387 | 387 | ||
388 | template <typename In> In Utf<32>::Next( In begin, In /*end*/ ) { | 388 | template <typename In> In Utf<32>::Next( In begin, In /*end*/ ) { |
389 | return ++begin; | 389 | return ++begin; |
390 | } | 390 | } |
391 | 391 | ||
392 | template <typename In> std::size_t Utf<32>::Count( In begin, In end ) { | 392 | template <typename In> std::size_t Utf<32>::Count( In begin, In end ) { |
393 | return begin - end; | 393 | return begin - end; |
394 | } | 394 | } |
395 | 395 | ||
396 | template <typename In, typename Out> | 396 | template <typename In, typename Out> |
397 | Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { | 397 | Out Utf<32>::FromAnsi( In begin, In end, Out output, const std::locale& locale ) { |
398 | while ( begin < end ) | 398 | while ( begin < end ) |
399 | *output++ = DecodeAnsi( *begin++, locale ); | 399 | *output++ = DecodeAnsi( *begin++, locale ); |
400 | 400 | ||
401 | return output; | 401 | return output; |
402 | } | 402 | } |
403 | 403 | ||
404 | template <typename In, typename Out> Out Utf<32>::FromWide( In begin, In end, Out output ) { | 404 | template <typename In, typename Out> Out Utf<32>::FromWide( In begin, In end, Out output ) { |
405 | while ( begin < end ) | 405 | while ( begin < end ) |
406 | *output++ = DecodeWide( *begin++ ); | 406 | *output++ = DecodeWide( *begin++ ); |
407 | 407 | ||
408 | return output; | 408 | return output; |
409 | } | 409 | } |
410 | 410 | ||
411 | template <typename In, typename Out> Out Utf<32>::FromLatin1( In begin, In end, Out output ) { | 411 | template <typename In, typename Out> Out Utf<32>::FromLatin1( In begin, In end, Out output ) { |
412 | // Latin-1 is directly compatible with Unicode encodings, | 412 | // Latin-1 is directly compatible with Unicode encodings, |
413 | // and can thus be treated as (a sub-range of) UTF-32 | 413 | // and can thus be treated as (a sub-range of) UTF-32 |
414 | while ( begin < end ) | 414 | while ( begin < end ) |
415 | *output++ = *begin++; | 415 | *output++ = *begin++; |
416 | 416 | ||
417 | return output; | 417 | return output; |
418 | } | 418 | } |
419 | 419 | ||
420 | template <typename In, typename Out> | 420 | template <typename In, typename Out> |
421 | Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { | 421 | Out Utf<32>::ToAnsi( In begin, In end, Out output, char replacement, const std::locale& locale ) { |
422 | while ( begin < end ) | 422 | while ( begin < end ) |
423 | output = EncodeAnsi( *begin++, output, replacement, locale ); | 423 | output = EncodeAnsi( *begin++, output, replacement, locale ); |
424 | 424 | ||
425 | return output; | 425 | return output; |
426 | } | 426 | } |
427 | 427 | ||
428 | #ifndef EFSW_NO_WIDECHAR | 428 | #ifndef EFSW_NO_WIDECHAR |
429 | template <typename In, typename Out> | 429 | template <typename In, typename Out> |
430 | Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { | 430 | Out Utf<32>::ToWide( In begin, In end, Out output, wchar_t replacement ) { |
431 | while ( begin < end ) | 431 | while ( begin < end ) |
432 | output = EncodeWide( *begin++, output, replacement ); | 432 | output = EncodeWide( *begin++, output, replacement ); |
433 | 433 | ||
434 | return output; | 434 | return output; |
435 | } | 435 | } |
436 | #endif | 436 | #endif |
437 | 437 | ||
438 | template <typename In, typename Out> | 438 | template <typename In, typename Out> |
439 | Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { | 439 | Out Utf<32>::ToLatin1( In begin, In end, Out output, char replacement ) { |
440 | // Latin-1 is directly compatible with Unicode encodings, | 440 | // Latin-1 is directly compatible with Unicode encodings, |
441 | // and can thus be treated as (a sub-range of) UTF-32 | 441 | // and can thus be treated as (a sub-range of) UTF-32 |
442 | while ( begin < end ) { | 442 | while ( begin < end ) { |
443 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; | 443 | *output++ = *begin < 256 ? static_cast<char>( *begin ) : replacement; |
444 | begin++; | 444 | begin++; |
445 | } | 445 | } |
446 | 446 | ||
447 | return output; | 447 | return output; |
448 | } | 448 | } |
449 | 449 | ||
450 | template <typename In, typename Out> Out Utf<32>::toUtf8( In begin, In end, Out output ) { | 450 | template <typename In, typename Out> Out Utf<32>::toUtf8( In begin, In end, Out output ) { |
451 | while ( begin < end ) | 451 | while ( begin < end ) |
452 | output = Utf<8>::Encode( *begin++, output ); | 452 | output = Utf<8>::Encode( *begin++, output ); |
453 | 453 | ||
454 | return output; | 454 | return output; |
455 | } | 455 | } |
456 | 456 | ||
457 | template <typename In, typename Out> Out Utf<32>::ToUtf16( In begin, In end, Out output ) { | 457 | template <typename In, typename Out> Out Utf<32>::ToUtf16( In begin, In end, Out output ) { |
458 | while ( begin < end ) | 458 | while ( begin < end ) |
459 | output = Utf<16>::Encode( *begin++, output ); | 459 | output = Utf<16>::Encode( *begin++, output ); |
460 | 460 | ||
461 | return output; | 461 | return output; |
462 | } | 462 | } |
463 | 463 | ||
464 | template <typename In, typename Out> Out Utf<32>::ToUtf32( In begin, In end, Out output ) { | 464 | template <typename In, typename Out> Out Utf<32>::ToUtf32( In begin, In end, Out output ) { |
465 | while ( begin < end ) | 465 | while ( begin < end ) |
466 | *output++ = *begin++; | 466 | *output++ = *begin++; |
467 | 467 | ||
468 | return output; | 468 | return output; |
469 | } | 469 | } |
470 | 470 | ||
471 | template <typename In> Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { | 471 | template <typename In> Uint32 Utf<32>::DecodeAnsi( In input, const std::locale& locale ) { |
472 | // On Windows, gcc's standard library (glibc++) has almost | 472 | // On Windows, gcc's standard library (glibc++) has almost |
473 | // no support for Unicode stuff. As a consequence, in this | 473 | // no support for Unicode stuff. As a consequence, in this |
474 | // context we can only use the default locale and ignore | 474 | // context we can only use the default locale and ignore |
475 | // the one passed as parameter. | 475 | // the one passed as parameter. |
476 | 476 | ||
477 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ | 477 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ |
478 | ( defined( __GLIBCPP__ ) || \ | 478 | ( defined( __GLIBCPP__ ) || \ |
479 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ | 479 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ |
480 | !( defined( __SGI_STL_PORT ) || \ | 480 | !( defined( __SGI_STL_PORT ) || \ |
481 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ | 481 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ |
482 | 482 | ||
483 | wchar_t character = 0; | 483 | wchar_t character = 0; |
484 | mbtowc( &character, &input, 1 ); | 484 | mbtowc( &character, &input, 1 ); |
485 | return static_cast<Uint32>( character ); | 485 | return static_cast<Uint32>( character ); |
486 | 486 | ||
487 | #else | 487 | #else |
488 | // Get the facet of the locale which deals with character conversion | 488 | // Get the facet of the locale which deals with character conversion |
489 | #ifndef EFSW_NO_WIDECHAR | 489 | #ifndef EFSW_NO_WIDECHAR |
490 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); | 490 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); |
491 | #else | 491 | #else |
492 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); | 492 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); |
493 | #endif | 493 | #endif |
494 | 494 | ||
495 | // Use the facet to convert each character of the input string | 495 | // Use the facet to convert each character of the input string |
496 | return static_cast<Uint32>( facet.widen( input ) ); | 496 | return static_cast<Uint32>( facet.widen( input ) ); |
497 | 497 | ||
498 | #endif | 498 | #endif |
499 | } | 499 | } |
500 | 500 | ||
501 | template <typename In> Uint32 Utf<32>::DecodeWide( In input ) { | 501 | template <typename In> Uint32 Utf<32>::DecodeWide( In input ) { |
502 | // The encoding of wide characters is not well defined and is left to the system; | 502 | // The encoding of wide characters is not well defined and is left to the system; |
503 | // however we can safely assume that it is UCS-2 on Windows and | 503 | // however we can safely assume that it is UCS-2 on Windows and |
504 | // UCS-4 on Unix systems. | 504 | // UCS-4 on Unix systems. |
505 | // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, | 505 | // In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4, |
506 | // and UCS-4 *is* UTF-32). | 506 | // and UCS-4 *is* UTF-32). |
507 | 507 | ||
508 | return input; | 508 | return input; |
509 | } | 509 | } |
510 | 510 | ||
511 | template <typename Out> | 511 | template <typename Out> |
512 | Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, | 512 | Out Utf<32>::EncodeAnsi( Uint32 codepoint, Out output, char replacement, |
513 | const std::locale& locale ) { | 513 | const std::locale& locale ) { |
514 | // On Windows, gcc's standard library (glibc++) has almost | 514 | // On Windows, gcc's standard library (glibc++) has almost |
515 | // no support for Unicode stuff. As a consequence, in this | 515 | // no support for Unicode stuff. As a consequence, in this |
516 | // context we can only use the default locale and ignore | 516 | // context we can only use the default locale and ignore |
517 | // the one passed as parameter. | 517 | // the one passed as parameter. |
518 | 518 | ||
519 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ | 519 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN && /* if Windows ... */ \ |
520 | ( defined( __GLIBCPP__ ) || \ | 520 | ( defined( __GLIBCPP__ ) || \ |
521 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ | 521 | defined( __GLIBCXX__ ) ) && /* ... and standard library is glibc++ ... */ \ |
522 | !( defined( __SGI_STL_PORT ) || \ | 522 | !( defined( __SGI_STL_PORT ) || \ |
523 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ | 523 | defined( _STLPORT_VERSION ) ) /* ... and STLPort is not used on top of it */ |
524 | 524 | ||
525 | char character = 0; | 525 | char character = 0; |
526 | if ( wctomb( &character, static_cast<wchar_t>( codepoint ) ) >= 0 ) | 526 | if ( wctomb( &character, static_cast<wchar_t>( codepoint ) ) >= 0 ) |
527 | *output++ = character; | 527 | *output++ = character; |
528 | else if ( replacement ) | 528 | else if ( replacement ) |
529 | *output++ = replacement; | 529 | *output++ = replacement; |
530 | 530 | ||
531 | return output; | 531 | return output; |
532 | 532 | ||
533 | #else | 533 | #else |
534 | // Get the facet of the locale which deals with character conversion | 534 | // Get the facet of the locale which deals with character conversion |
535 | #ifndef EFSW_NO_WIDECHAR | 535 | #ifndef EFSW_NO_WIDECHAR |
536 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); | 536 | const std::ctype<wchar_t>& facet = std::use_facet<std::ctype<wchar_t>>( locale ); |
537 | #else | 537 | #else |
538 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); | 538 | const std::ctype<char>& facet = std::use_facet<std::ctype<char>>( locale ); |
539 | #endif | 539 | #endif |
540 | 540 | ||
541 | // Use the facet to convert each character of the input string | 541 | // Use the facet to convert each character of the input string |
542 | *output++ = facet.narrow( static_cast<wchar_t>( codepoint ), replacement ); | 542 | *output++ = facet.narrow( static_cast<wchar_t>( codepoint ), replacement ); |
543 | 543 | ||
544 | return output; | 544 | return output; |
545 | 545 | ||
546 | #endif | 546 | #endif |
547 | } | 547 | } |
548 | 548 | ||
549 | #ifndef EFSW_NO_WIDECHAR | 549 | #ifndef EFSW_NO_WIDECHAR |
550 | template <typename Out> | 550 | template <typename Out> |
551 | Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { | 551 | Out Utf<32>::EncodeWide( Uint32 codepoint, Out output, wchar_t replacement ) { |
552 | // The encoding of wide characters is not well defined and is left to the system; | 552 | // The encoding of wide characters is not well defined and is left to the system; |
553 | // however we can safely assume that it is UCS-2 on Windows and | 553 | // however we can safely assume that it is UCS-2 on Windows and |
554 | // UCS-4 on Unix systems. | 554 | // UCS-4 on Unix systems. |
555 | // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). | 555 | // For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4). |
556 | // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). | 556 | // For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32). |
557 | 557 | ||
558 | switch ( sizeof( wchar_t ) ) { | 558 | switch ( sizeof( wchar_t ) ) { |
559 | case 4: { | 559 | case 4: { |
560 | *output++ = static_cast<wchar_t>( codepoint ); | 560 | *output++ = static_cast<wchar_t>( codepoint ); |
561 | break; | 561 | break; |
562 | } | 562 | } |
563 | 563 | ||
564 | default: { | 564 | default: { |
565 | if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { | 565 | if ( ( codepoint <= 0xFFFF ) && ( ( codepoint < 0xD800 ) || ( codepoint > 0xDFFF ) ) ) { |
566 | *output++ = static_cast<wchar_t>( codepoint ); | 566 | *output++ = static_cast<wchar_t>( codepoint ); |
567 | } else if ( replacement ) { | 567 | } else if ( replacement ) { |
568 | *output++ = replacement; | 568 | *output++ = replacement; |
569 | } | 569 | } |
570 | break; | 570 | break; |
571 | } | 571 | } |
572 | } | 572 | } |
573 | 573 | ||
574 | return output; | 574 | return output; |
575 | } | 575 | } |
576 | #endif | 576 | #endif |
diff --git a/src/3rdParty/efsw/Watcher.cpp b/src/3rdParty/efsw/Watcher.cpp index 913ae3c..913ae3c 100755..100644 --- a/src/3rdParty/efsw/Watcher.cpp +++ b/src/3rdParty/efsw/Watcher.cpp | |||
diff --git a/src/3rdParty/efsw/Watcher.hpp b/src/3rdParty/efsw/Watcher.hpp index 84f0980..84f0980 100755..100644 --- a/src/3rdParty/efsw/Watcher.hpp +++ b/src/3rdParty/efsw/Watcher.hpp | |||
diff --git a/src/3rdParty/efsw/WatcherFSEvents.cpp b/src/3rdParty/efsw/WatcherFSEvents.cpp index b562d3c..f963374 100755..100644 --- a/src/3rdParty/efsw/WatcherFSEvents.cpp +++ b/src/3rdParty/efsw/WatcherFSEvents.cpp | |||
@@ -8,22 +8,11 @@ | |||
8 | namespace efsw { | 8 | namespace efsw { |
9 | 9 | ||
10 | WatcherFSEvents::WatcherFSEvents() : | 10 | WatcherFSEvents::WatcherFSEvents() : |
11 | Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ), initializedAsync( false ) {} | 11 | Watcher(), FWatcher( NULL ), FSStream( NULL ), WatcherGen( NULL ) {} |
12 | |||
13 | WatcherFSEvents::WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, | ||
14 | bool recursive, WatcherFSEvents* /*parent*/ ) : | ||
15 | Watcher( id, directory, listener, recursive ), | ||
16 | FWatcher( NULL ), | ||
17 | FSStream( NULL ), | ||
18 | WatcherGen( NULL ), | ||
19 | initializedAsync( false ) {} | ||
20 | 12 | ||
21 | WatcherFSEvents::~WatcherFSEvents() { | 13 | WatcherFSEvents::~WatcherFSEvents() { |
22 | if ( NULL != FSStream ) { | 14 | if ( NULL != FSStream ) { |
23 | if ( initializedAsync ) { | 15 | FSEventStreamStop( FSStream ); |
24 | FSEventStreamStop( FSStream ); | ||
25 | } | ||
26 | |||
27 | FSEventStreamInvalidate( FSStream ); | 16 | FSEventStreamInvalidate( FSStream ); |
28 | FSEventStreamRelease( FSStream ); | 17 | FSEventStreamRelease( FSStream ); |
29 | } | 18 | } |
@@ -39,7 +28,9 @@ void WatcherFSEvents::init() { | |||
39 | Uint32 streamFlags = kFSEventStreamCreateFlagNone; | 28 | Uint32 streamFlags = kFSEventStreamCreateFlagNone; |
40 | 29 | ||
41 | if ( FileWatcherFSEvents::isGranular() ) { | 30 | if ( FileWatcherFSEvents::isGranular() ) { |
42 | streamFlags = efswFSEventStreamCreateFlagFileEvents; | 31 | streamFlags = efswFSEventStreamCreateFlagFileEvents | efswFSEventStreamCreateFlagNoDefer | |
32 | efswFSEventStreamCreateFlagUseExtendedData | | ||
33 | efswFSEventStreamCreateFlagUseCFTypes; | ||
43 | } else { | 34 | } else { |
44 | WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive ); | 35 | WatcherGen = new WatcherGeneric( ID, Directory, Listener, FWatcher.load(), Recursive ); |
45 | } | 36 | } |
@@ -52,49 +43,49 @@ void WatcherFSEvents::init() { | |||
52 | ctx.release = NULL; | 43 | ctx.release = NULL; |
53 | ctx.copyDescription = NULL; | 44 | ctx.copyDescription = NULL; |
54 | 45 | ||
46 | dispatch_queue_t queue = dispatch_queue_create( NULL, NULL ); | ||
47 | |||
55 | FSStream = | 48 | FSStream = |
56 | FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, | 49 | FSEventStreamCreate( kCFAllocatorDefault, &FileWatcherFSEvents::FSEventCallback, &ctx, |
57 | CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0.25, streamFlags ); | 50 | CFDirectoryArray, kFSEventStreamEventIdSinceNow, 0., streamFlags ); |
58 | FWatcher.load()->mNeedInitMutex.lock(); | ||
59 | FWatcher.load()->mNeedInit.push_back( this ); | ||
60 | FWatcher.load()->mNeedInitMutex.unlock(); | ||
61 | 51 | ||
62 | CFRelease( CFDirectoryArray ); | 52 | FSEventStreamSetDispatchQueue( FSStream, queue ); |
63 | CFRelease( CFDirectory ); | ||
64 | } | ||
65 | 53 | ||
66 | void WatcherFSEvents::initAsync() { | ||
67 | FSEventStreamScheduleWithRunLoop( FSStream, FWatcher.load()->mRunLoopRef.load(), | ||
68 | kCFRunLoopDefaultMode ); | ||
69 | FSEventStreamStart( FSStream ); | 54 | FSEventStreamStart( FSStream ); |
70 | initializedAsync = true; | 55 | |
56 | CFRelease( CFDirectoryArray ); | ||
57 | CFRelease( CFDirectory ); | ||
71 | } | 58 | } |
72 | 59 | ||
73 | void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, | 60 | void WatcherFSEvents::sendFileAction( WatchID watchid, const std::string& dir, |
74 | const std::string& filename, Action action, | 61 | const std::string& filename, Action action, |
75 | std::string oldFilename ) { | 62 | std::string oldFilename ) { |
76 | Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), | 63 | Listener->handleFileAction( watchid, FileSystem::precomposeFileName( dir ), |
77 | FileSystem::precomposeFileName( filename ), action, oldFilename ); | 64 | FileSystem::precomposeFileName( filename ), action, |
65 | FileSystem::precomposeFileName( oldFilename ) ); | ||
78 | } | 66 | } |
79 | 67 | ||
80 | void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, | 68 | void WatcherFSEvents::handleAddModDel( const Uint32& flags, const std::string& path, |
81 | std::string& dirPath, std::string& filePath ) { | 69 | std::string& dirPath, std::string& filePath, Uint64 inode ) { |
82 | if ( flags & efswFSEventStreamEventFlagItemCreated ) { | 70 | if ( ( flags & efswFSEventStreamEventFlagItemCreated ) && FileInfo::exists( path ) && |
83 | if ( FileInfo::exists( path ) ) { | 71 | ( !SanitizeEvents || FilesAdded.find( inode ) != FilesAdded.end() ) ) { |
84 | sendFileAction( ID, dirPath, filePath, Actions::Add ); | 72 | sendFileAction( ID, dirPath, filePath, Actions::Add ); |
85 | } | 73 | |
74 | if ( SanitizeEvents ) | ||
75 | FilesAdded.insert( inode ); | ||
86 | } | 76 | } |
87 | 77 | ||
88 | if ( flags & efswFSEventsModified ) { | 78 | if ( flags & ModifiedFlags ) { |
89 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); | 79 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); |
90 | } | 80 | } |
91 | 81 | ||
92 | if ( flags & efswFSEventStreamEventFlagItemRemoved ) { | 82 | if ( ( flags & efswFSEventStreamEventFlagItemRemoved ) && !FileInfo::exists( path ) ) { |
93 | // Since i don't know the order, at least i try to keep the data consistent with the real | 83 | // Since i don't know the order, at least i try to keep the data consistent with the real |
94 | // state | 84 | // state |
95 | if ( !FileInfo::exists( path ) ) { | 85 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); |
96 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | 86 | |
97 | } | 87 | if ( SanitizeEvents ) |
88 | FilesAdded.erase( inode ); | ||
98 | } | 89 | } |
99 | } | 90 | } |
100 | 91 | ||
@@ -136,19 +127,20 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | |||
136 | // been added modified and erased, but i can't know if first was erased and then added | 127 | // been added modified and erased, but i can't know if first was erased and then added |
137 | // and modified, or added, then modified and then erased. I don't know what they were | 128 | // and modified, or added, then modified and then erased. I don't know what they were |
138 | // thinking by doing this... | 129 | // thinking by doing this... |
139 | efDEBUG( "Event in: %s - flags: %ld\n", event.Path.c_str(), event.Flags ); | 130 | efDEBUG( "Event in: %s - flags: 0x%x\n", event.Path.c_str(), event.Flags ); |
140 | 131 | ||
141 | if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) { | 132 | if ( event.Flags & efswFSEventStreamEventFlagItemRenamed ) { |
142 | if ( ( i + 1 < esize ) && | 133 | if ( ( i + 1 < esize ) && |
143 | ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) && | 134 | ( events[i + 1].Flags & efswFSEventStreamEventFlagItemRenamed ) && |
144 | ( events[i + 1].Id == event.Id + 1 ) ) { | 135 | ( events[i + 1].inode == event.inode ) ) { |
145 | FSEvent& nEvent = events[i + 1]; | 136 | FSEvent& nEvent = events[i + 1]; |
146 | std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); | 137 | std::string newDir( FileSystem::pathRemoveFileName( nEvent.Path ) ); |
147 | std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); | 138 | std::string newFilepath( FileSystem::fileNameFromPath( nEvent.Path ) ); |
148 | 139 | ||
149 | if ( event.Path != nEvent.Path ) { | 140 | if ( event.Path != nEvent.Path ) { |
150 | if ( dirPath == newDir ) { | 141 | if ( dirPath == newDir ) { |
151 | if ( !FileInfo::exists( event.Path ) ) { | 142 | if ( !FileInfo::exists( event.Path ) || |
143 | 0 == strcasecmp( event.Path.c_str(), nEvent.Path.c_str() ) ) { | ||
152 | sendFileAction( ID, dirPath, newFilepath, Actions::Moved, | 144 | sendFileAction( ID, dirPath, newFilepath, Actions::Moved, |
153 | filePath ); | 145 | filePath ); |
154 | } else { | 146 | } else { |
@@ -159,12 +151,12 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | |||
159 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | 151 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); |
160 | sendFileAction( ID, newDir, newFilepath, Actions::Add ); | 152 | sendFileAction( ID, newDir, newFilepath, Actions::Add ); |
161 | 153 | ||
162 | if ( nEvent.Flags & efswFSEventsModified ) { | 154 | if ( nEvent.Flags & ModifiedFlags ) { |
163 | sendFileAction( ID, newDir, newFilepath, Actions::Modified ); | 155 | sendFileAction( ID, newDir, newFilepath, Actions::Modified ); |
164 | } | 156 | } |
165 | } | 157 | } |
166 | } else { | 158 | } else { |
167 | handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath ); | 159 | handleAddModDel( nEvent.Flags, nEvent.Path, dirPath, filePath, event.inode ); |
168 | } | 160 | } |
169 | 161 | ||
170 | if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | | 162 | if ( nEvent.Flags & ( efswFSEventStreamEventFlagItemCreated | |
@@ -180,14 +172,14 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | |||
180 | } else if ( FileInfo::exists( event.Path ) ) { | 172 | } else if ( FileInfo::exists( event.Path ) ) { |
181 | sendFileAction( ID, dirPath, filePath, Actions::Add ); | 173 | sendFileAction( ID, dirPath, filePath, Actions::Add ); |
182 | 174 | ||
183 | if ( event.Flags & efswFSEventsModified ) { | 175 | if ( event.Flags & ModifiedFlags ) { |
184 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); | 176 | sendFileAction( ID, dirPath, filePath, Actions::Modified ); |
185 | } | 177 | } |
186 | } else { | 178 | } else { |
187 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); | 179 | sendFileAction( ID, dirPath, filePath, Actions::Delete ); |
188 | } | 180 | } |
189 | } else { | 181 | } else { |
190 | handleAddModDel( event.Flags, event.Path, dirPath, filePath ); | 182 | handleAddModDel( event.Flags, event.Path, dirPath, filePath, event.inode ); |
191 | } | 183 | } |
192 | } else { | 184 | } else { |
193 | efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); | 185 | efDEBUG( "Directory: %s changed\n", event.Path.c_str() ); |
@@ -197,7 +189,7 @@ void WatcherFSEvents::handleActions( std::vector<FSEvent>& events ) { | |||
197 | } | 189 | } |
198 | 190 | ||
199 | void WatcherFSEvents::process() { | 191 | void WatcherFSEvents::process() { |
200 | std::set<std::string>::iterator it = DirsChanged.begin(); | 192 | std::unordered_set<std::string>::iterator it = DirsChanged.begin(); |
201 | 193 | ||
202 | for ( ; it != DirsChanged.end(); it++ ) { | 194 | for ( ; it != DirsChanged.end(); it++ ) { |
203 | if ( !FileWatcherFSEvents::isGranular() ) { | 195 | if ( !FileWatcherFSEvents::isGranular() ) { |
diff --git a/src/3rdParty/efsw/WatcherFSEvents.hpp b/src/3rdParty/efsw/WatcherFSEvents.hpp index 4dbb231..f05b094 100755..100644 --- a/src/3rdParty/efsw/WatcherFSEvents.hpp +++ b/src/3rdParty/efsw/WatcherFSEvents.hpp | |||
@@ -9,51 +9,72 @@ | |||
9 | #include <CoreServices/CoreServices.h> | 9 | #include <CoreServices/CoreServices.h> |
10 | #include <efsw/FileInfo.hpp> | 10 | #include <efsw/FileInfo.hpp> |
11 | #include <efsw/WatcherGeneric.hpp> | 11 | #include <efsw/WatcherGeneric.hpp> |
12 | #include <set> | 12 | #include <unordered_set> |
13 | #include <vector> | 13 | #include <vector> |
14 | 14 | ||
15 | namespace efsw { | 15 | namespace efsw { |
16 | 16 | ||
17 | /* OSX < 10.7 has no file events */ | ||
18 | /* So i declare the events constants */ | ||
19 | enum FSEventEvents { | ||
20 | efswFSEventStreamCreateFlagUseCFTypes = 0x00000001, | ||
21 | efswFSEventStreamCreateFlagNoDefer = 0x00000002, | ||
22 | efswFSEventStreamCreateFlagFileEvents = 0x00000010, | ||
23 | efswFSEventStreamCreateFlagUseExtendedData = 0x00000040, | ||
24 | efswFSEventStreamEventFlagItemCreated = 0x00000100, | ||
25 | efswFSEventStreamEventFlagItemRemoved = 0x00000200, | ||
26 | efswFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, | ||
27 | efswFSEventStreamEventFlagItemRenamed = 0x00000800, | ||
28 | efswFSEventStreamEventFlagItemModified = 0x00001000, | ||
29 | efswFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, | ||
30 | efswFSEventStreamEventFlagItemChangeOwner = 0x00004000, | ||
31 | efswFSEventStreamEventFlagItemXattrMod = 0x00008000, | ||
32 | efswFSEventStreamEventFlagItemIsFile = 0x00010000, | ||
33 | efswFSEventStreamEventFlagItemIsDir = 0x00020000, | ||
34 | efswFSEventStreamEventFlagItemIsSymlink = 0x00040000, | ||
35 | efswFSEventsModified = efswFSEventStreamEventFlagItemFinderInfoMod | | ||
36 | efswFSEventStreamEventFlagItemModified | | ||
37 | efswFSEventStreamEventFlagItemInodeMetaMod | ||
38 | }; | ||
39 | |||
17 | class FileWatcherFSEvents; | 40 | class FileWatcherFSEvents; |
18 | 41 | ||
19 | class FSEvent { | 42 | class FSEvent { |
20 | public: | 43 | public: |
21 | FSEvent( std::string path, long flags, Uint64 id ) : Path( path ), Flags( flags ), Id( id ) {} | 44 | FSEvent( std::string path, long flags, Uint64 id, Uint64 inode = 0 ) : |
45 | Path( path ), Flags( flags ), Id( id ), inode( inode ) {} | ||
22 | 46 | ||
23 | std::string Path; | 47 | std::string Path; |
24 | long Flags; | 48 | long Flags{ 0 }; |
25 | Uint64 Id; | 49 | Uint64 Id{ 0 }; |
50 | Uint64 inode{ 0 }; | ||
26 | }; | 51 | }; |
27 | 52 | ||
28 | class WatcherFSEvents : public Watcher { | 53 | class WatcherFSEvents : public Watcher { |
29 | public: | 54 | public: |
30 | WatcherFSEvents(); | 55 | WatcherFSEvents(); |
31 | 56 | ||
32 | WatcherFSEvents( WatchID id, std::string directory, FileWatchListener* listener, bool recursive, | ||
33 | WatcherFSEvents* parent = NULL ); | ||
34 | |||
35 | ~WatcherFSEvents(); | 57 | ~WatcherFSEvents(); |
36 | 58 | ||
37 | void init(); | 59 | void init(); |
38 | 60 | ||
39 | void initAsync(); | ||
40 | |||
41 | void handleActions( std::vector<FSEvent>& events ); | 61 | void handleActions( std::vector<FSEvent>& events ); |
42 | 62 | ||
43 | void process(); | 63 | void process(); |
44 | 64 | ||
45 | Atomic<FileWatcherFSEvents*> FWatcher; | 65 | Atomic<FileWatcherFSEvents*> FWatcher; |
46 | FSEventStreamRef FSStream; | 66 | FSEventStreamRef FSStream; |
67 | Uint64 ModifiedFlags{ efswFSEventsModified }; | ||
68 | bool SanitizeEvents{ false }; | ||
47 | 69 | ||
48 | protected: | 70 | protected: |
49 | void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, | 71 | void handleAddModDel( const Uint32& flags, const std::string& path, std::string& dirPath, |
50 | std::string& filePath ); | 72 | std::string& filePath, Uint64 inode ); |
51 | 73 | ||
52 | WatcherGeneric* WatcherGen; | 74 | WatcherGeneric* WatcherGen; |
53 | 75 | ||
54 | Atomic<bool> initializedAsync; | 76 | std::unordered_set<std::string> DirsChanged; |
55 | 77 | std::unordered_set<Uint64> FilesAdded; | |
56 | std::set<std::string> DirsChanged; | ||
57 | 78 | ||
58 | void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, | 79 | void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, |
59 | Action action, std::string oldFilename = "" ); | 80 | Action action, std::string oldFilename = "" ); |
diff --git a/src/3rdParty/efsw/WatcherGeneric.cpp b/src/3rdParty/efsw/WatcherGeneric.cpp index a6bb106..a6bb106 100755..100644 --- a/src/3rdParty/efsw/WatcherGeneric.cpp +++ b/src/3rdParty/efsw/WatcherGeneric.cpp | |||
diff --git a/src/3rdParty/efsw/WatcherGeneric.hpp b/src/3rdParty/efsw/WatcherGeneric.hpp index 9cf8365..d11ec20 100755..100644 --- a/src/3rdParty/efsw/WatcherGeneric.hpp +++ b/src/3rdParty/efsw/WatcherGeneric.hpp | |||
@@ -17,7 +17,7 @@ class WatcherGeneric : public Watcher { | |||
17 | 17 | ||
18 | ~WatcherGeneric(); | 18 | ~WatcherGeneric(); |
19 | 19 | ||
20 | void watch(); | 20 | void watch() override; |
21 | 21 | ||
22 | void watchDir( std::string dir ); | 22 | void watchDir( std::string dir ); |
23 | 23 | ||
diff --git a/src/3rdParty/efsw/WatcherInotify.cpp b/src/3rdParty/efsw/WatcherInotify.cpp index 7259bb1..812ddae 100755..100644 --- a/src/3rdParty/efsw/WatcherInotify.cpp +++ b/src/3rdParty/efsw/WatcherInotify.cpp | |||
@@ -4,10 +4,6 @@ namespace efsw { | |||
4 | 4 | ||
5 | WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {} | 5 | WatcherInotify::WatcherInotify() : Watcher(), Parent( NULL ) {} |
6 | 6 | ||
7 | WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener* listener, | ||
8 | bool recursive, WatcherInotify* parent ) : | ||
9 | Watcher( id, directory, listener, recursive ), Parent( parent ), DirInfo( directory ) {} | ||
10 | |||
11 | bool WatcherInotify::inParentTree( WatcherInotify* parent ) { | 7 | bool WatcherInotify::inParentTree( WatcherInotify* parent ) { |
12 | WatcherInotify* tNext = Parent; | 8 | WatcherInotify* tNext = Parent; |
13 | 9 | ||
diff --git a/src/3rdParty/efsw/WatcherInotify.hpp b/src/3rdParty/efsw/WatcherInotify.hpp index bf2ff5e..ec55ed0 100755..100644 --- a/src/3rdParty/efsw/WatcherInotify.hpp +++ b/src/3rdParty/efsw/WatcherInotify.hpp | |||
@@ -10,15 +10,13 @@ class WatcherInotify : public Watcher { | |||
10 | public: | 10 | public: |
11 | WatcherInotify(); | 11 | WatcherInotify(); |
12 | 12 | ||
13 | WatcherInotify( WatchID id, std::string directory, FileWatchListener* listener, bool recursive, | ||
14 | WatcherInotify* parent = NULL ); | ||
15 | |||
16 | bool inParentTree( WatcherInotify* parent ); | 13 | bool inParentTree( WatcherInotify* parent ); |
17 | 14 | ||
18 | WatcherInotify* Parent; | 15 | WatcherInotify* Parent; |
19 | WatchID InotifyID; | 16 | WatchID InotifyID; |
20 | 17 | ||
21 | FileInfo DirInfo; | 18 | FileInfo DirInfo; |
19 | bool syntheticEvents{ false }; | ||
22 | }; | 20 | }; |
23 | 21 | ||
24 | } // namespace efsw | 22 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/WatcherKqueue.cpp b/src/3rdParty/efsw/WatcherKqueue.cpp index 441948a..424b989 100755..100644 --- a/src/3rdParty/efsw/WatcherKqueue.cpp +++ b/src/3rdParty/efsw/WatcherKqueue.cpp | |||
@@ -139,7 +139,7 @@ void WatcherKqueue::addAll() { | |||
139 | void WatcherKqueue::removeAll() { | 139 | void WatcherKqueue::removeAll() { |
140 | efDEBUG( "removeAll(): Removing all child watchers\n" ); | 140 | efDEBUG( "removeAll(): Removing all child watchers\n" ); |
141 | 141 | ||
142 | std::list<WatchID> erase; | 142 | std::vector<WatchID> erase; |
143 | 143 | ||
144 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) { | 144 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); it++ ) { |
145 | efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); | 145 | efDEBUG( "removeAll(): Removed child watcher %s\n", it->second->Directory.c_str() ); |
@@ -147,7 +147,7 @@ void WatcherKqueue::removeAll() { | |||
147 | erase.push_back( it->second->ID ); | 147 | erase.push_back( it->second->ID ); |
148 | } | 148 | } |
149 | 149 | ||
150 | for ( std::list<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) { | 150 | for ( std::vector<WatchID>::iterator eit = erase.begin(); eit != erase.end(); eit++ ) { |
151 | removeWatch( *eit ); | 151 | removeWatch( *eit ); |
152 | } | 152 | } |
153 | } | 153 | } |
@@ -354,7 +354,8 @@ void WatcherKqueue::watch() { | |||
354 | bool needScan = false; | 354 | bool needScan = false; |
355 | 355 | ||
356 | // Then we get the the events of the current folder | 356 | // Then we get the the events of the current folder |
357 | while ( ( nev = kevent( mKqueue, &mChangeList[0], mChangeListCount + 1, &event, 1, | 357 | while ( !mChangeList.empty() && |
358 | ( nev = kevent( mKqueue, mChangeList.data(), mChangeListCount + 1, &event, 1, | ||
358 | &mWatcher->mTimeOut ) ) != 0 ) { | 359 | &mWatcher->mTimeOut ) ) != 0 ) { |
359 | // An error ocurred? | 360 | // An error ocurred? |
360 | if ( nev == -1 ) { | 361 | if ( nev == -1 ) { |
@@ -436,7 +437,6 @@ void WatcherKqueue::moveDirectory( std::string oldPath, std::string newPath, boo | |||
436 | 437 | ||
437 | WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, | 438 | WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, |
438 | bool recursive, WatcherKqueue* parent ) { | 439 | bool recursive, WatcherKqueue* parent ) { |
439 | static long s_fc = 0; | ||
440 | static bool s_ug = false; | 440 | static bool s_ug = false; |
441 | 441 | ||
442 | std::string dir( directory ); | 442 | std::string dir( directory ); |
@@ -478,8 +478,6 @@ WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener | |||
478 | 478 | ||
479 | watch->addAll(); | 479 | watch->addAll(); |
480 | 480 | ||
481 | s_fc++; | ||
482 | |||
483 | // if failed to open the directory... erase the watcher | 481 | // if failed to open the directory... erase the watcher |
484 | if ( !watch->initOK() ) { | 482 | if ( !watch->initOK() ) { |
485 | int le = watch->lastErrno(); | 483 | int le = watch->lastErrno(); |
@@ -502,9 +500,8 @@ WatchID WatcherKqueue::addWatch( const std::string& directory, FileWatchListener | |||
502 | } | 500 | } |
503 | } else { | 501 | } else { |
504 | if ( !s_ug ) { | 502 | if ( !s_ug ) { |
505 | efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld. Folders " | 503 | efDEBUG( "Started using WatcherGeneric, reached file descriptors limit: %ld.\n", |
506 | "added: %ld\n", | 504 | mWatcher->mFileDescriptorCount ); |
507 | mWatcher->mFileDescriptorCount, s_fc ); | ||
508 | s_ug = true; | 505 | s_ug = true; |
509 | } | 506 | } |
510 | 507 | ||
diff --git a/src/3rdParty/efsw/WatcherKqueue.hpp b/src/3rdParty/efsw/WatcherKqueue.hpp index 87d898c..75c0f62 100755..100644 --- a/src/3rdParty/efsw/WatcherKqueue.hpp +++ b/src/3rdParty/efsw/WatcherKqueue.hpp | |||
@@ -49,7 +49,7 @@ class WatcherKqueue : public Watcher { | |||
49 | 49 | ||
50 | WatchID watchingDirectory( std::string dir ); | 50 | WatchID watchingDirectory( std::string dir ); |
51 | 51 | ||
52 | void watch(); | 52 | void watch() override; |
53 | 53 | ||
54 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, | 54 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
55 | WatcherKqueue* parent ); | 55 | WatcherKqueue* parent ); |
diff --git a/src/3rdParty/efsw/WatcherWin32.cpp b/src/3rdParty/efsw/WatcherWin32.cpp index 3e8bcc7..712419e 100755..100644 --- a/src/3rdParty/efsw/WatcherWin32.cpp +++ b/src/3rdParty/efsw/WatcherWin32.cpp | |||
@@ -1,34 +1,114 @@ | |||
1 | #include <efsw/Debug.hpp> | ||
1 | #include <efsw/String.hpp> | 2 | #include <efsw/String.hpp> |
2 | #include <efsw/WatcherWin32.hpp> | 3 | #include <efsw/WatcherWin32.hpp> |
3 | 4 | ||
4 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 5 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
5 | 6 | ||
7 | #include <algorithm> | ||
8 | |||
6 | namespace efsw { | 9 | namespace efsw { |
7 | 10 | ||
8 | /// Unpacks events and passes them to a user defined callback. | 11 | struct EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX { |
9 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { | 12 | DWORD NextEntryOffset; |
10 | if ( dwNumberOfBytesTransfered == 0 || NULL == lpOverlapped ) { | 13 | DWORD Action; |
11 | return; | 14 | LARGE_INTEGER CreationTime; |
15 | LARGE_INTEGER LastModificationTime; | ||
16 | LARGE_INTEGER LastChangeTime; | ||
17 | LARGE_INTEGER LastAccessTime; | ||
18 | LARGE_INTEGER AllocatedLength; | ||
19 | LARGE_INTEGER FileSize; | ||
20 | DWORD FileAttributes; | ||
21 | DWORD ReparsePointTag; | ||
22 | LARGE_INTEGER FileId; | ||
23 | LARGE_INTEGER ParentFileId; | ||
24 | DWORD FileNameLength; | ||
25 | WCHAR FileName[1]; | ||
26 | }; | ||
27 | |||
28 | typedef EFSW_FILE_NOTIFY_EXTENDED_INFORMATION_EX* EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX; | ||
29 | |||
30 | typedef BOOL( WINAPI* EFSW_LPREADDIRECTORYCHANGESEXW )( HANDLE hDirectory, LPVOID lpBuffer, | ||
31 | DWORD nBufferLength, BOOL bWatchSubtree, | ||
32 | DWORD dwNotifyFilter, LPDWORD lpBytesReturned, | ||
33 | LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, | ||
34 | DWORD ReadDirectoryNotifyInformationClass ); | ||
35 | |||
36 | static EFSW_LPREADDIRECTORYCHANGESEXW pReadDirectoryChangesExW = NULL; | ||
37 | |||
38 | #define EFSW_ReadDirectoryNotifyExtendedInformation 2 | ||
39 | |||
40 | static void initReadDirectoryChangesEx() { | ||
41 | static bool hasInit = false; | ||
42 | if ( !hasInit ) { | ||
43 | hasInit = true; | ||
44 | |||
45 | HMODULE hModule = GetModuleHandleW( L"Kernel32.dll" ); | ||
46 | if ( !hModule ) | ||
47 | return; | ||
48 | |||
49 | pReadDirectoryChangesExW = | ||
50 | (EFSW_LPREADDIRECTORYCHANGESEXW)GetProcAddress( hModule, "ReadDirectoryChangesExW" ); | ||
12 | } | 51 | } |
52 | } | ||
13 | 53 | ||
14 | char szFile[MAX_PATH]; | 54 | void WatchCallbackOld( WatcherWin32* pWatch ) { |
15 | PFILE_NOTIFY_INFORMATION pNotify; | 55 | PFILE_NOTIFY_INFORMATION pNotify; |
16 | WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped; | ||
17 | WatcherWin32* pWatch = tWatch->Watch; | ||
18 | size_t offset = 0; | 56 | size_t offset = 0; |
19 | |||
20 | do { | 57 | do { |
21 | bool skip = false; | 58 | bool skip = false; |
22 | 59 | ||
23 | pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset]; | 60 | pNotify = (PFILE_NOTIFY_INFORMATION)&pWatch->Buffer[offset]; |
24 | offset += pNotify->NextEntryOffset; | 61 | offset += pNotify->NextEntryOffset; |
62 | int count = | ||
63 | WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | ||
64 | pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL ); | ||
65 | if ( count == 0 ) | ||
66 | continue; | ||
67 | |||
68 | std::string nfile( count, '\0' ); | ||
69 | |||
70 | count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | ||
71 | pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count, | ||
72 | NULL, NULL ); | ||
73 | |||
74 | if ( FILE_ACTION_MODIFIED == pNotify->Action ) { | ||
75 | FileInfo fifile( std::string( pWatch->DirName ) + nfile ); | ||
76 | |||
77 | if ( pWatch->LastModifiedEvent.file.ModificationTime == fifile.ModificationTime && | ||
78 | pWatch->LastModifiedEvent.file.Size == fifile.Size && | ||
79 | pWatch->LastModifiedEvent.fileName == nfile ) { | ||
80 | skip = true; | ||
81 | } | ||
82 | |||
83 | pWatch->LastModifiedEvent.fileName = nfile; | ||
84 | pWatch->LastModifiedEvent.file = fifile; | ||
85 | } | ||
86 | |||
87 | if ( !skip ) { | ||
88 | pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); | ||
89 | } | ||
90 | } while ( pNotify->NextEntryOffset != 0 ); | ||
91 | } | ||
92 | |||
93 | void WatchCallbackEx( WatcherWin32* pWatch ) { | ||
94 | EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX pNotify; | ||
95 | size_t offset = 0; | ||
96 | do { | ||
97 | bool skip = false; | ||
98 | |||
99 | pNotify = (EFSW_PFILE_NOTIFY_EXTENDED_INFORMATION_EX)&pWatch->Buffer[offset]; | ||
100 | offset += pNotify->NextEntryOffset; | ||
101 | int count = | ||
102 | WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | ||
103 | pNotify->FileNameLength / sizeof( WCHAR ), NULL, 0, NULL, NULL ); | ||
104 | if ( count == 0 ) | ||
105 | continue; | ||
25 | 106 | ||
26 | int count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, | 107 | std::string nfile( count, '\0' ); |
27 | pNotify->FileNameLength / sizeof( WCHAR ), szFile, | ||
28 | MAX_PATH - 1, NULL, NULL ); | ||
29 | szFile[count] = TEXT( '\0' ); | ||
30 | 108 | ||
31 | std::string nfile( szFile ); | 109 | count = WideCharToMultiByte( CP_UTF8, 0, pNotify->FileName, |
110 | pNotify->FileNameLength / sizeof( WCHAR ), &nfile[0], count, | ||
111 | NULL, NULL ); | ||
32 | 112 | ||
33 | if ( FILE_ACTION_MODIFIED == pNotify->Action ) { | 113 | if ( FILE_ACTION_MODIFIED == pNotify->Action ) { |
34 | FileInfo fifile( std::string( pWatch->DirName ) + nfile ); | 114 | FileInfo fifile( std::string( pWatch->DirName ) + nfile ); |
@@ -41,12 +121,59 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve | |||
41 | 121 | ||
42 | pWatch->LastModifiedEvent.fileName = nfile; | 122 | pWatch->LastModifiedEvent.fileName = nfile; |
43 | pWatch->LastModifiedEvent.file = fifile; | 123 | pWatch->LastModifiedEvent.file = fifile; |
124 | } else if ( FILE_ACTION_RENAMED_OLD_NAME == pNotify->Action ) { | ||
125 | pWatch->OldFiles.emplace_back( nfile, pNotify->FileId ); | ||
126 | skip = true; | ||
127 | } else if ( FILE_ACTION_RENAMED_NEW_NAME == pNotify->Action ) { | ||
128 | std::string oldFile; | ||
129 | LARGE_INTEGER oldFileId{}; | ||
130 | |||
131 | for ( auto it = pWatch->OldFiles.begin(); it != pWatch->OldFiles.end(); ++it ) { | ||
132 | if ( it->second.QuadPart == pNotify->FileId.QuadPart ) { | ||
133 | oldFile = it->first; | ||
134 | oldFileId = it->second; | ||
135 | it = pWatch->OldFiles.erase( it ); | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | if ( oldFile.empty() ) { | ||
141 | pWatch->Watch->handleAction( pWatch, nfile, FILE_ACTION_ADDED ); | ||
142 | skip = true; | ||
143 | } else { | ||
144 | pWatch->Watch->handleAction( pWatch, oldFile, FILE_ACTION_RENAMED_OLD_NAME ); | ||
145 | } | ||
44 | } | 146 | } |
45 | 147 | ||
46 | if ( !skip ) { | 148 | if ( !skip ) { |
47 | pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); | 149 | pWatch->Watch->handleAction( pWatch, nfile, pNotify->Action ); |
48 | } | 150 | } |
49 | } while ( pNotify->NextEntryOffset != 0 ); | 151 | } while ( pNotify->NextEntryOffset != 0 ); |
152 | } | ||
153 | |||
154 | /// Unpacks events and passes them to a user defined callback. | ||
155 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { | ||
156 | if ( NULL == lpOverlapped ) { | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | WatcherStructWin32* tWatch = (WatcherStructWin32*)lpOverlapped; | ||
161 | WatcherWin32* pWatch = tWatch->Watch; | ||
162 | |||
163 | if ( dwNumberOfBytesTransfered == 0 ) { | ||
164 | if ( nullptr != pWatch && !pWatch->StopNow ) { | ||
165 | RefreshWatch( tWatch ); | ||
166 | } else { | ||
167 | return; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | // Fork watch depending on the Windows API supported | ||
172 | if ( pWatch->Extended ) { | ||
173 | WatchCallbackEx( pWatch ); | ||
174 | } else { | ||
175 | WatchCallbackOld( pWatch ); | ||
176 | } | ||
50 | 177 | ||
51 | if ( !pWatch->StopNow ) { | 178 | if ( !pWatch->StopNow ) { |
52 | RefreshWatch( tWatch ); | 179 | RefreshWatch( tWatch ); |
@@ -54,11 +181,40 @@ void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOve | |||
54 | } | 181 | } |
55 | 182 | ||
56 | /// Refreshes the directory monitoring. | 183 | /// Refreshes the directory monitoring. |
57 | bool RefreshWatch( WatcherStructWin32* pWatch ) { | 184 | RefreshResult RefreshWatch( WatcherStructWin32* pWatch ) { |
58 | return ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer, | 185 | initReadDirectoryChangesEx(); |
59 | sizeof( pWatch->Watch->Buffer ), pWatch->Watch->Recursive, | 186 | |
60 | pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, | 187 | bool bRet = false; |
61 | NULL ) != 0; | 188 | RefreshResult ret = RefreshResult::Failed; |
189 | pWatch->Watch->Extended = false; | ||
190 | |||
191 | if ( pReadDirectoryChangesExW ) { | ||
192 | bRet = pReadDirectoryChangesExW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(), | ||
193 | (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive, | ||
194 | pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, | ||
195 | NULL, EFSW_ReadDirectoryNotifyExtendedInformation ) != 0; | ||
196 | if ( bRet ) { | ||
197 | ret = RefreshResult::SucessEx; | ||
198 | pWatch->Watch->Extended = true; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if ( !bRet ) { | ||
203 | bRet = ReadDirectoryChangesW( pWatch->Watch->DirHandle, pWatch->Watch->Buffer.data(), | ||
204 | (DWORD)pWatch->Watch->Buffer.size(), pWatch->Watch->Recursive, | ||
205 | pWatch->Watch->NotifyFilter, NULL, &pWatch->Overlapped, | ||
206 | NULL ) != 0; | ||
207 | |||
208 | if ( bRet ) | ||
209 | ret = RefreshResult::Success; | ||
210 | } | ||
211 | |||
212 | if ( !bRet ) { | ||
213 | std::string error = std::to_string( GetLastError() ); | ||
214 | Errors::Log::createLastError( Errors::WatcherFailed, error ); | ||
215 | } | ||
216 | |||
217 | return ret; | ||
62 | } | 218 | } |
63 | 219 | ||
64 | /// Stops monitoring a directory. | 220 | /// Stops monitoring a directory. |
@@ -70,19 +226,17 @@ void DestroyWatch( WatcherStructWin32* pWatch ) { | |||
70 | CloseHandle( pWatch->Watch->DirHandle ); | 226 | CloseHandle( pWatch->Watch->DirHandle ); |
71 | efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); | 227 | efSAFE_DELETE_ARRAY( pWatch->Watch->DirName ); |
72 | efSAFE_DELETE( pWatch->Watch ); | 228 | efSAFE_DELETE( pWatch->Watch ); |
229 | efSAFE_DELETE( pWatch ); | ||
73 | } | 230 | } |
74 | } | 231 | } |
75 | 232 | ||
76 | /// Starts monitoring a directory. | 233 | /// Starts monitoring a directory. |
77 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, | 234 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, |
78 | HANDLE iocp ) { | 235 | DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ) { |
79 | WatcherStructWin32* tWatch; | 236 | WatcherStructWin32* tWatch = new WatcherStructWin32(); |
80 | size_t ptrsize = sizeof( *tWatch ); | 237 | WatcherWin32* pWatch = new WatcherWin32(bufferSize); |
81 | tWatch = static_cast<WatcherStructWin32*>( | 238 | if (tWatch) |
82 | HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, ptrsize ) ); | 239 | tWatch->Watch = pWatch; |
83 | |||
84 | WatcherWin32* pWatch = new WatcherWin32(); | ||
85 | tWatch->Watch = pWatch; | ||
86 | 240 | ||
87 | pWatch->DirHandle = CreateFileW( | 241 | pWatch->DirHandle = CreateFileW( |
88 | szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, | 242 | szDirectory, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, |
@@ -90,17 +244,17 @@ WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD Noti | |||
90 | 244 | ||
91 | if ( pWatch->DirHandle != INVALID_HANDLE_VALUE && | 245 | if ( pWatch->DirHandle != INVALID_HANDLE_VALUE && |
92 | CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { | 246 | CreateIoCompletionPort( pWatch->DirHandle, iocp, 0, 1 ) ) { |
93 | pWatch->NotifyFilter = NotifyFilter; | 247 | pWatch->NotifyFilter = notifyFilter; |
94 | pWatch->Recursive = recursive; | 248 | pWatch->Recursive = recursive; |
95 | 249 | ||
96 | if ( RefreshWatch( tWatch ) ) { | 250 | if ( RefreshResult::Failed != RefreshWatch( tWatch ) ) { |
97 | return tWatch; | 251 | return tWatch; |
98 | } | 252 | } |
99 | } | 253 | } |
100 | 254 | ||
101 | CloseHandle( pWatch->DirHandle ); | 255 | CloseHandle( pWatch->DirHandle ); |
102 | efSAFE_DELETE( pWatch->Watch ); | 256 | efSAFE_DELETE( pWatch->Watch ); |
103 | HeapFree( GetProcessHeap(), 0, tWatch ); | 257 | efSAFE_DELETE( tWatch ); |
104 | return NULL; | 258 | return NULL; |
105 | } | 259 | } |
106 | 260 | ||
diff --git a/src/3rdParty/efsw/WatcherWin32.hpp b/src/3rdParty/efsw/WatcherWin32.hpp index 71e13be..ea1e8e4 100755..100644 --- a/src/3rdParty/efsw/WatcherWin32.hpp +++ b/src/3rdParty/efsw/WatcherWin32.hpp | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <efsw/FileInfo.hpp> | 4 | #include <efsw/FileInfo.hpp> |
5 | #include <efsw/FileWatcherImpl.hpp> | 5 | #include <efsw/FileWatcherImpl.hpp> |
6 | #include <vector> | ||
6 | 7 | ||
7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 | 8 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 |
8 | 9 | ||
@@ -21,6 +22,8 @@ namespace efsw { | |||
21 | 22 | ||
22 | class WatcherWin32; | 23 | class WatcherWin32; |
23 | 24 | ||
25 | enum RefreshResult { Failed, Success, SucessEx }; | ||
26 | |||
24 | /// Internal watch data | 27 | /// Internal watch data |
25 | struct WatcherStructWin32 { | 28 | struct WatcherStructWin32 { |
26 | OVERLAPPED Overlapped; | 29 | OVERLAPPED Overlapped; |
@@ -32,39 +35,41 @@ struct sLastModifiedEvent { | |||
32 | std::string fileName; | 35 | std::string fileName; |
33 | }; | 36 | }; |
34 | 37 | ||
35 | bool RefreshWatch( WatcherStructWin32* pWatch ); | 38 | RefreshResult RefreshWatch( WatcherStructWin32* pWatch ); |
36 | 39 | ||
37 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ); | 40 | void CALLBACK WatchCallback( DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ); |
38 | 41 | ||
39 | void DestroyWatch( WatcherStructWin32* pWatch ); | 42 | void DestroyWatch( WatcherStructWin32* pWatch ); |
40 | 43 | ||
41 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter, | 44 | WatcherStructWin32* CreateWatch( LPCWSTR szDirectory, bool recursive, |
42 | HANDLE iocp ); | 45 | DWORD bufferSize, DWORD notifyFilter, HANDLE iocp ); |
43 | 46 | ||
44 | class WatcherWin32 : public Watcher { | 47 | class WatcherWin32 : public Watcher { |
45 | public: | 48 | public: |
46 | WatcherWin32() : | 49 | WatcherWin32(DWORD dwBufferSize) : |
47 | Struct( NULL ), | 50 | Struct( NULL ), |
48 | DirHandle( NULL ), | 51 | DirHandle( NULL ), |
52 | Buffer(), | ||
49 | lParam( 0 ), | 53 | lParam( 0 ), |
50 | NotifyFilter( 0 ), | 54 | NotifyFilter( 0 ), |
51 | StopNow( false ), | 55 | StopNow( false ), |
56 | Extended( false ), | ||
52 | Watch( NULL ), | 57 | Watch( NULL ), |
53 | DirName( NULL ) {} | 58 | DirName( NULL ) { |
59 | Buffer.resize(dwBufferSize); | ||
60 | } | ||
54 | 61 | ||
55 | WatcherStructWin32* Struct; | 62 | WatcherStructWin32* Struct; |
56 | HANDLE DirHandle; | 63 | HANDLE DirHandle; |
57 | BYTE Buffer | 64 | std::vector<BYTE> Buffer; |
58 | [63 * | ||
59 | 1024]; // do NOT make this bigger than 64K because it will fail if the folder being watched | ||
60 | // is on the network! (see | ||
61 | // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) | ||
62 | LPARAM lParam; | 65 | LPARAM lParam; |
63 | DWORD NotifyFilter; | 66 | DWORD NotifyFilter; |
64 | bool StopNow; | 67 | bool StopNow; |
68 | bool Extended; | ||
65 | FileWatcherImpl* Watch; | 69 | FileWatcherImpl* Watch; |
66 | char* DirName; | 70 | char* DirName; |
67 | sLastModifiedEvent LastModifiedEvent; | 71 | sLastModifiedEvent LastModifiedEvent; |
72 | std::vector<std::pair<std::string, LARGE_INTEGER>> OldFiles; | ||
68 | }; | 73 | }; |
69 | 74 | ||
70 | } // namespace efsw | 75 | } // namespace efsw |
diff --git a/src/3rdParty/efsw/base.hpp b/src/3rdParty/efsw/base.hpp index 43abc4f..43abc4f 100755..100644 --- a/src/3rdParty/efsw/base.hpp +++ b/src/3rdParty/efsw/base.hpp | |||
diff --git a/src/3rdParty/efsw/efsw.h b/src/3rdParty/efsw/efsw.h index 28e63e2..30cf595 100755..100644 --- a/src/3rdParty/efsw/efsw.h +++ b/src/3rdParty/efsw/efsw.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | @author Sepul Sepehr Taghdisian | 2 | @author Sepul Sepehr Taghdisian |
3 | 3 | ||
4 | Copyright (c) 2013 Martin Lucas Golini | 4 | Copyright (c) 2024 MartÃn Lucas Golini |
5 | 5 | ||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | of this software and associated documentation files (the "Software"), to deal | 7 | of this software and associated documentation files (the "Software"), to deal |
@@ -32,31 +32,31 @@ | |||
32 | extern "C" { | 32 | extern "C" { |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | #if defined(_WIN32) | 35 | #if defined( _WIN32 ) |
36 | #ifdef EFSW_DYNAMIC | 36 | #ifdef EFSW_DYNAMIC |
37 | // Windows platforms | 37 | // Windows platforms |
38 | #ifdef EFSW_EXPORTS | 38 | #ifdef EFSW_EXPORTS |
39 | // From DLL side, we must export | 39 | // From DLL side, we must export |
40 | #define EFSW_API __declspec(dllexport) | 40 | #define EFSW_API __declspec( dllexport ) |
41 | #else | ||
42 | // From client application side, we must import | ||
43 | #define EFSW_API __declspec(dllimport) | ||
44 | #endif | ||
45 | #else | ||
46 | // No specific directive needed for static build | ||
47 | #ifndef EFSW_API | ||
48 | #define EFSW_API | ||
49 | #endif | ||
50 | #endif | ||
51 | #else | 41 | #else |
52 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) | 42 | // From client application side, we must import |
53 | #define EFSW_API __attribute__ ((visibility("default"))) | 43 | #define EFSW_API __declspec( dllimport ) |
54 | #endif | 44 | #endif |
55 | 45 | #else | |
56 | // Other platforms don't need to define anything | 46 | // No specific directive needed for static build |
57 | #ifndef EFSW_API | 47 | #ifndef EFSW_API |
58 | #define EFSW_API | 48 | #define EFSW_API |
59 | #endif | 49 | #endif |
50 | #endif | ||
51 | #else | ||
52 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) | ||
53 | #define EFSW_API __attribute__( ( visibility( "default" ) ) ) | ||
54 | #endif | ||
55 | |||
56 | // Other platforms don't need to define anything | ||
57 | #ifndef EFSW_API | ||
58 | #define EFSW_API | ||
59 | #endif | ||
60 | #endif | 60 | #endif |
61 | 61 | ||
62 | /// Type for a watch id | 62 | /// Type for a watch id |
@@ -65,84 +65,127 @@ typedef long efsw_watchid; | |||
65 | /// Type for watcher | 65 | /// Type for watcher |
66 | typedef void* efsw_watcher; | 66 | typedef void* efsw_watcher; |
67 | 67 | ||
68 | enum efsw_action | 68 | enum efsw_action { |
69 | { | 69 | EFSW_ADD = 1, /// Sent when a file is created or renamed |
70 | EFSW_ADD = 1, /// Sent when a file is created or renamed | 70 | EFSW_DELETE = 2, /// Sent when a file is deleted or renamed |
71 | EFSW_DELETE = 2, /// Sent when a file is deleted or renamed | 71 | EFSW_MODIFIED = 3, /// Sent when a file is modified |
72 | EFSW_MODIFIED = 3, /// Sent when a file is modified | 72 | EFSW_MOVED = 4 /// Sent when a file is moved |
73 | EFSW_MOVED = 4 /// Sent when a file is moved | 73 | }; |
74 | |||
75 | enum efsw_error { | ||
76 | EFSW_NOTFOUND = -1, | ||
77 | EFSW_REPEATED = -2, | ||
78 | EFSW_OUTOFSCOPE = -3, | ||
79 | EFSW_NOTREADABLE = -4, | ||
80 | EFSW_REMOTE = -5, | ||
81 | EFSW_WATCHER_FAILED = -6, | ||
82 | EFSW_UNSPECIFIED = -7 | ||
74 | }; | 83 | }; |
75 | 84 | ||
76 | enum efsw_error | 85 | enum efsw_option { |
77 | { | 86 | /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and |
78 | EFSW_NOTFOUND = -1, | 87 | /// file system events may be dropped. For that, using a different (bigger) buffer size |
79 | EFSW_REPEATED = -2, | 88 | /// can be defined here, but note that this does not work for network drives, |
80 | EFSW_OUTOFSCOPE = -3, | 89 | /// because a buffer larger than 64K will fail the folder being watched, see |
81 | EFSW_NOTREADABLE = -4, | 90 | /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) |
82 | EFSW_REMOTE = -5, | 91 | EFSW_OPT_WIN_BUFFER_SIZE = 1, |
83 | EFSW_UNSPECIFIED = -6 | 92 | /// For Windows, per default all events are captured but we might only be interested |
93 | /// in a subset; the value of the option should be set to a bitwise or'ed set of | ||
94 | /// FILE_NOTIFY_CHANGE_* flags. | ||
95 | EFSW_OPT_WIN_NOTIFY_FILTER = 2, | ||
96 | /// For macOS (FSEvents backend), per default all modified event types are capture but we might | ||
97 | // only be interested in a subset; the value of the option should be set to a set of bitwise | ||
98 | // from: | ||
99 | // kFSEventStreamEventFlagItemFinderInfoMod | ||
100 | // kFSEventStreamEventFlagItemModified | ||
101 | // kFSEventStreamEventFlagItemInodeMetaMod | ||
102 | // Default configuration will set the 3 flags | ||
103 | EFSW_OPT_MAC_MODIFIED_FILTER = 3, | ||
104 | /// macOS sometimes informs incorrect or old file states that may confuse the consumer | ||
105 | /// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing | ||
106 | /// the number of events reported. This will have an small performance and memory impact as a | ||
107 | /// consequence. | ||
108 | EFSW_OPT_MAC_SANITIZE_EVENTS = 4, | ||
109 | /// Linux does not support natively recursive watchers. This means that when using recursive | ||
110 | /// watches efsw registers new watchers for each directory. If new file are created between | ||
111 | /// the time efsw takes to register the new directory those events might be missed. To avoid | ||
112 | /// missing new file notifications efsw will trigger synthetic new file events for existing | ||
113 | /// files in the new directroy watched. This might have the unintended consequence of sending | ||
114 | /// duplicated created events due to the system also emitting this event. | ||
115 | LINUX_PRODUCE_SYNTHETIC_EVENTS = 5, | ||
84 | }; | 116 | }; |
85 | 117 | ||
86 | /// Basic interface for listening for file events. | 118 | /// Basic interface for listening for file events. |
87 | typedef void (*efsw_pfn_fileaction_callback) ( | 119 | typedef void ( *efsw_pfn_fileaction_callback )( efsw_watcher watcher, efsw_watchid watchid, |
88 | efsw_watcher watcher, | 120 | const char* dir, const char* filename, |
89 | efsw_watchid watchid, | 121 | enum efsw_action action, const char* old_filename, |
90 | const char* dir, | 122 | void* param ); |
91 | const char* filename, | 123 | |
92 | enum efsw_action action, | 124 | typedef struct { |
93 | const char* old_filename, | 125 | enum efsw_option option; |
94 | void* param | 126 | int value; |
95 | ); | 127 | } efsw_watcher_option; |
96 | 128 | ||
97 | /** | 129 | /** |
98 | * Creates a new file-watcher | 130 | * Creates a new file-watcher |
99 | * @param generic_mode Force the use of the Generic file watcher | 131 | * @param generic_mode Force the use of the Generic file watcher |
100 | */ | 132 | */ |
101 | efsw_watcher EFSW_API efsw_create(int generic_mode); | 133 | efsw_watcher EFSW_API efsw_create( int generic_mode ); |
102 | 134 | ||
103 | /// Release the file-watcher and unwatch any directories | 135 | /// Release the file-watcher and unwatch any directories |
104 | void EFSW_API efsw_release(efsw_watcher watcher); | 136 | void EFSW_API efsw_release( efsw_watcher watcher ); |
105 | 137 | ||
106 | /// Retreive last error occured by file-watcher | 138 | /// Retrieve last error occured by file-watcher |
107 | EFSW_API const char* efsw_getlasterror(); | 139 | EFSW_API const char* efsw_getlasterror(); |
108 | 140 | ||
109 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. | 141 | /// Reset file-watcher last error |
110 | /// For backwards compatibility. | 142 | EFSW_API void efsw_clearlasterror(); |
143 | |||
144 | /// Add a directory watch | ||
111 | /// On error returns WatchID with Error type. | 145 | /// On error returns WatchID with Error type. |
112 | efsw_watchid EFSW_API efsw_addwatch(efsw_watcher watcher, const char* directory, | 146 | efsw_watchid EFSW_API efsw_addwatch( efsw_watcher watcher, const char* directory, |
113 | efsw_pfn_fileaction_callback callback_fn, int recursive, void* param); | 147 | efsw_pfn_fileaction_callback callback_fn, int recursive, |
148 | void* param ); | ||
149 | |||
150 | /// Add a directory watch, specifying options | ||
151 | /// @param options Pointer to an array of watcher options | ||
152 | /// @param nr_options Number of options referenced by \p options | ||
153 | efsw_watchid EFSW_API efsw_addwatch_withoptions( efsw_watcher watcher, const char* directory, | ||
154 | efsw_pfn_fileaction_callback callback_fn, | ||
155 | int recursive, efsw_watcher_option* options, | ||
156 | int options_number, void* param ); | ||
114 | 157 | ||
115 | /// Remove a directory watch. This is a brute force search O(nlogn). | 158 | /// Remove a directory watch. This is a brute force search O(nlogn). |
116 | void EFSW_API efsw_removewatch(efsw_watcher watcher, const char* directory); | 159 | void EFSW_API efsw_removewatch( efsw_watcher watcher, const char* directory ); |
117 | 160 | ||
118 | /// Remove a directory watch. This is a map lookup O(logn). | 161 | /// Remove a directory watch. This is a map lookup O(logn). |
119 | void EFSW_API efsw_removewatch_byid(efsw_watcher watcher, efsw_watchid watchid); | 162 | void EFSW_API efsw_removewatch_byid( efsw_watcher watcher, efsw_watchid watchid ); |
120 | 163 | ||
121 | /// Starts watching ( in other thread ) | 164 | /// Starts watching ( in other thread ) |
122 | void EFSW_API efsw_watch(efsw_watcher watcher); | 165 | void EFSW_API efsw_watch( efsw_watcher watcher ); |
123 | 166 | ||
124 | /** | 167 | /** |
125 | * Allow recursive watchers to follow symbolic links to other directories | 168 | * Allow recursive watchers to follow symbolic links to other directories |
126 | * followSymlinks is disabled by default | 169 | * followSymlinks is disabled by default |
127 | */ | 170 | */ |
128 | void EFSW_API efsw_follow_symlinks(efsw_watcher watcher, int enable); | 171 | void EFSW_API efsw_follow_symlinks( efsw_watcher watcher, int enable ); |
129 | 172 | ||
130 | /** @return If can follow symbolic links to directorioes */ | 173 | /** @return If can follow symbolic links to directorioes */ |
131 | int EFSW_API efsw_follow_symlinks_isenabled(efsw_watcher watcher); | 174 | int EFSW_API efsw_follow_symlinks_isenabled( efsw_watcher watcher ); |
132 | 175 | ||
133 | /** | 176 | /** |
134 | * When enable this it will allow symlinks to watch recursively out of the pointed directory. | 177 | * When enable this it will allow symlinks to watch recursively out of the pointed directory. |
135 | * follorSymlinks must be enabled to this work. | 178 | * follorSymlinks must be enabled to this work. |
136 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is not allowed, | 179 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is not |
137 | * it's only allowed to symlink anything from /home/ and deeper. This is to avoid great levels of recursion. | 180 | * allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid great |
138 | * Enabling this could lead in infinite recursion, and crash the watcher ( it will try not to avoid this ). | 181 | * levels of recursion. Enabling this could lead in infinite recursion, and crash the watcher ( it |
139 | * Buy enabling out of scope links, it will allow this behavior. | 182 | * will try not to avoid this ). Buy enabling out of scope links, it will allow this behavior. |
140 | * allowOutOfScopeLinks are disabled by default. | 183 | * allowOutOfScopeLinks are disabled by default. |
141 | */ | 184 | */ |
142 | void EFSW_API efsw_allow_outofscopelinks(efsw_watcher watcher, int allow); | 185 | void EFSW_API efsw_allow_outofscopelinks( efsw_watcher watcher, int allow ); |
143 | 186 | ||
144 | /// @return Returns if out of scope links are allowed | 187 | /// @return Returns if out of scope links are allowed |
145 | int EFSW_API efsw_outofscopelinks_isallowed(efsw_watcher watcher); | 188 | int EFSW_API efsw_outofscopelinks_isallowed( efsw_watcher watcher ); |
146 | 189 | ||
147 | #ifdef __cplusplus | 190 | #ifdef __cplusplus |
148 | } | 191 | } |
diff --git a/src/3rdParty/efsw/efsw.hpp b/src/3rdParty/efsw/efsw.hpp index 12af116..11a5dec 100755..100644 --- a/src/3rdParty/efsw/efsw.hpp +++ b/src/3rdParty/efsw/efsw.hpp | |||
@@ -1,195 +1,261 @@ | |||
1 | /** | 1 | /** |
2 | @author MartÃn Lucas Golini | 2 | @author MartÃn Lucas Golini |
3 | 3 | ||
4 | Copyright (c) 2013 MartÃn Lucas Golini | 4 | Copyright (c) 2024 MartÃn Lucas Golini |
5 | 5 | ||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | of this software and associated documentation files (the "Software"), to deal | 7 | of this software and associated documentation files (the "Software"), to deal |
8 | in the Software without restriction, including without limitation the rights | 8 | in the Software without restriction, including without limitation the rights |
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | copies of the Software, and to permit persons to whom the Software is | 10 | copies of the Software, and to permit persons to whom the Software is |
11 | furnished to do so, subject to the following conditions: | 11 | furnished to do so, subject to the following conditions: |
12 | 12 | ||
13 | The above copyright notice and this permission notice shall be included in | 13 | The above copyright notice and this permission notice shall be included in |
14 | all copies or substantial portions of the Software. | 14 | all copies or substantial portions of the Software. |
15 | 15 | ||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | THE SOFTWARE. | 22 | THE SOFTWARE. |
23 | 23 | ||
24 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) | 24 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) |
25 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. | 25 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #ifndef ESFW_HPP | 28 | #ifndef ESFW_HPP |
29 | #define ESFW_HPP | 29 | #define ESFW_HPP |
30 | 30 | ||
31 | #include <list> | 31 | #include <string> |
32 | #include <string> | 32 | #include <vector> |
33 | 33 | ||
34 | #if defined( _WIN32 ) | 34 | #if defined( _WIN32 ) |
35 | #ifdef EFSW_DYNAMIC | 35 | #ifdef EFSW_DYNAMIC |
36 | // Windows platforms | 36 | // Windows platforms |
37 | #ifdef EFSW_EXPORTS | 37 | #ifdef EFSW_EXPORTS |
38 | // From DLL side, we must export | 38 | // From DLL side, we must export |
39 | #define EFSW_API __declspec( dllexport ) | 39 | #define EFSW_API __declspec( dllexport ) |
40 | #else | 40 | #else |
41 | // From client application side, we must import | 41 | // From client application side, we must import |
42 | #define EFSW_API __declspec( dllimport ) | 42 | #define EFSW_API __declspec( dllimport ) |
43 | #endif | 43 | #endif |
44 | #else | 44 | #else |
45 | // No specific directive needed for static build | 45 | // No specific directive needed for static build |
46 | #ifndef EFSW_API | 46 | #ifndef EFSW_API |
47 | #define EFSW_API | 47 | #define EFSW_API |
48 | #endif | 48 | #endif |
49 | #endif | 49 | #endif |
50 | #else | 50 | #else |
51 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) | 51 | #if ( __GNUC__ >= 4 ) && defined( EFSW_EXPORTS ) |
52 | #ifndef EFSW_API | 52 | #ifndef EFSW_API |
53 | #define EFSW_API __attribute__( ( visibility( "default" ) ) ) | 53 | #define EFSW_API __attribute__( ( visibility( "default" ) ) ) |
54 | #endif | 54 | #endif |
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | // Other platforms don't need to define anything | 57 | // Other platforms don't need to define anything |
58 | #ifndef EFSW_API | 58 | #ifndef EFSW_API |
59 | #define EFSW_API | 59 | #define EFSW_API |
60 | #endif | 60 | #endif |
61 | #endif | 61 | #endif |
62 | 62 | ||
63 | namespace efsw { | 63 | namespace efsw { |
64 | 64 | ||
65 | /// Type for a watch id | 65 | /// Type for a watch id |
66 | typedef long WatchID; | 66 | typedef long WatchID; |
67 | 67 | ||
68 | // forward declarations | 68 | // forward declarations |
69 | class FileWatcherImpl; | 69 | class FileWatcherImpl; |
70 | class FileWatchListener; | 70 | class FileWatchListener; |
71 | 71 | class WatcherOption; | |
72 | /// Actions to listen for. Rename will send two events, one for | 72 | |
73 | /// the deletion of the old file, and one for the creation of the | 73 | /// Actions to listen for. Rename will send two events, one for |
74 | /// new file. | 74 | /// the deletion of the old file, and one for the creation of the |
75 | namespace Actions { | 75 | /// new file. |
76 | enum Action { | 76 | namespace Actions { |
77 | /// Sent when a file is created or renamed | 77 | enum Action { |
78 | Add = 1, | 78 | /// Sent when a file is created or renamed |
79 | /// Sent when a file is deleted or renamed | 79 | Add = 1, |
80 | Delete = 2, | 80 | /// Sent when a file is deleted or renamed |
81 | /// Sent when a file is modified | 81 | Delete = 2, |
82 | Modified = 3, | 82 | /// Sent when a file is modified |
83 | /// Sent when a file is moved | 83 | Modified = 3, |
84 | Moved = 4 | 84 | /// Sent when a file is moved |
85 | }; | 85 | Moved = 4 |
86 | } | 86 | }; |
87 | typedef Actions::Action Action; | 87 | } |
88 | 88 | typedef Actions::Action Action; | |
89 | /// Errors log namespace | 89 | |
90 | namespace Errors { | 90 | /// Errors log namespace |
91 | 91 | namespace Errors { | |
92 | enum Error { | 92 | |
93 | FileNotFound = -1, | 93 | enum Error { |
94 | FileRepeated = -2, | 94 | NoError = 0, |
95 | FileOutOfScope = -3, | 95 | FileNotFound = -1, |
96 | FileNotReadable = -4, | 96 | FileRepeated = -2, |
97 | FileRemote = -5, /** Directory in remote file system ( create a generic FileWatcher instance to | 97 | FileOutOfScope = -3, |
98 | watch this directory ). */ | 98 | FileNotReadable = -4, |
99 | Unspecified = -6 | 99 | /// Directory in remote file system |
100 | }; | 100 | /// ( create a generic FileWatcher instance to watch this directory ). |
101 | 101 | FileRemote = -5, | |
102 | class EFSW_API Log { | 102 | /// File system watcher failed to watch for changes. |
103 | public: | 103 | WatcherFailed = -6, |
104 | /// @return The last error logged | 104 | Unspecified = -7 |
105 | static std::string getLastErrorLog(); | 105 | }; |
106 | 106 | ||
107 | /// Creates an error of the type specified | 107 | class EFSW_API Log { |
108 | static Error createLastError( Error err, std::string log ); | 108 | public: |
109 | }; | 109 | /// @return The last error logged |
110 | 110 | static std::string getLastErrorLog(); | |
111 | } // namespace Errors | 111 | |
112 | typedef Errors::Error Error; | 112 | /// @return The code of the last error logged |
113 | 113 | static Error getLastErrorCode(); | |
114 | /// Listens to files and directories and dispatches events | 114 | |
115 | /// to notify the listener of files and directories changes. | 115 | /// Reset last error |
116 | /// @class FileWatcher | 116 | static void clearLastError(); |
117 | class EFSW_API FileWatcher { | 117 | |
118 | public: | 118 | /// Creates an error of the type specified |
119 | /// Default constructor, will use the default platform file watcher | 119 | static Error createLastError( Error err, std::string log ); |
120 | FileWatcher(); | 120 | }; |
121 | 121 | ||
122 | /// Constructor that lets you force the use of the Generic File Watcher | 122 | } // namespace Errors |
123 | explicit FileWatcher( bool useGenericFileWatcher ); | 123 | typedef Errors::Error Error; |
124 | 124 | ||
125 | virtual ~FileWatcher(); | 125 | /// Optional file watcher settings. |
126 | 126 | namespace Options { | |
127 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. | 127 | enum Option { |
128 | /// For backwards compatibility. | 128 | /// For Windows, the default buffer size of 63*1024 bytes sometimes is not enough and |
129 | /// On error returns WatchID with Error type. | 129 | /// file system events may be dropped. For that, using a different (bigger) buffer size |
130 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher ); | 130 | /// can be defined here, but note that this does not work for network drives, |
131 | 131 | /// because a buffer larger than 64K will fail the folder being watched, see | |
132 | /// Add a directory watch | 132 | /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) |
133 | /// On error returns WatchID with Error type. | 133 | WinBufferSize = 1, |
134 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); | 134 | /// For Windows, per default all events are captured but we might only be interested |
135 | 135 | /// in a subset; the value of the option should be set to a bitwise or'ed set of | |
136 | /// Remove a directory watch. This is a brute force search O(nlogn). | 136 | /// FILE_NOTIFY_CHANGE_* flags. |
137 | void removeWatch( const std::string& directory ); | 137 | WinNotifyFilter = 2, |
138 | 138 | /// For macOS (FSEvents backend), per default all modified event types are capture but we might | |
139 | /// Remove a directory watch. This is a map lookup O(logn). | 139 | /// only be interested in a subset; the value of the option should be set to a set of bitwise |
140 | void removeWatch( WatchID watchid ); | 140 | /// from: |
141 | 141 | /// kFSEventStreamEventFlagItemFinderInfoMod | |
142 | /// Starts watching ( in other thread ) | 142 | /// kFSEventStreamEventFlagItemModified |
143 | void watch(); | 143 | /// kFSEventStreamEventFlagItemInodeMetaMod |
144 | 144 | /// Default configuration will set the 3 flags | |
145 | /// @return Returns a list of the directories that are being watched | 145 | MacModifiedFilter = 3, |
146 | std::list<std::string> directories(); | 146 | /// macOS sometimes informs incorrect or old file states that may confuse the consumer |
147 | 147 | /// The events sanitizer will try to sanitize incorrectly reported events in favor of reducing | |
148 | /** Allow recursive watchers to follow symbolic links to other directories | 148 | /// the number of events reported. This will have an small performance and memory impact as a |
149 | * followSymlinks is disabled by default | 149 | /// consequence. |
150 | */ | 150 | MacSanitizeEvents = 4, |
151 | void followSymlinks( bool follow ); | 151 | /// Linux does not support natively recursive watchers. This means that when using recursive |
152 | 152 | /// watches efsw registers new watchers for each directory. If new file are created between | |
153 | /** @return If can follow symbolic links to directorioes */ | 153 | /// the time efsw takes to register the new directory those events might be missed. To avoid |
154 | const bool& followSymlinks() const; | 154 | /// missing new file notifications efsw will trigger synthetic created file events for existing |
155 | 155 | /// files in the new directroy watched. This might have the unintended consequence of sending | |
156 | /** When enable this it will allow symlinks to watch recursively out of the pointed directory. | 156 | /// duplicated created events due to the system also emitting this event. |
157 | * follorSymlinks must be enabled to this work. | 157 | LinuxProduceSyntheticEvents = 5, |
158 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is | 158 | }; |
159 | * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid | 159 | } |
160 | * great levels of recursion. Enabling this could lead in infinite recursion, and crash the | 160 | typedef Options::Option Option; |
161 | * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow | 161 | |
162 | * this behavior. allowOutOfScopeLinks are disabled by default. | 162 | /// Listens to files and directories and dispatches events |
163 | */ | 163 | /// to notify the listener of files and directories changes. |
164 | void allowOutOfScopeLinks( bool allow ); | 164 | /// @class FileWatcher |
165 | 165 | class EFSW_API FileWatcher { | |
166 | /// @return Returns if out of scope links are allowed | 166 | public: |
167 | const bool& allowOutOfScopeLinks() const; | 167 | /// Default constructor, will use the default platform file watcher |
168 | 168 | FileWatcher(); | |
169 | private: | 169 | |
170 | /// The implementation | 170 | /// Constructor that lets you force the use of the Generic File Watcher |
171 | FileWatcherImpl* mImpl; | 171 | explicit FileWatcher( bool useGenericFileWatcher ); |
172 | bool mFollowSymlinks; | 172 | |
173 | bool mOutOfScopeLinks; | 173 | virtual ~FileWatcher(); |
174 | }; | 174 | |
175 | 175 | /// Add a directory watch. Same as the other addWatch, but doesn't have recursive option. | |
176 | /// Basic interface for listening for file events. | 176 | /// For backwards compatibility. |
177 | /// @class FileWatchListener | 177 | /// On error returns WatchID with Error type. |
178 | class FileWatchListener { | 178 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher ); |
179 | public: | 179 | |
180 | virtual ~FileWatchListener() {} | 180 | /// Add a directory watch |
181 | 181 | /// On error returns WatchID with Error type. | |
182 | /// Handles the action file action | 182 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ); |
183 | /// @param watchid The watch id for the directory | 183 | |
184 | /// @param dir The directory | 184 | /// Add a directory watch, allowing customization with options |
185 | /// @param filename The filename that was accessed (not full path) | 185 | /// @param directory The folder to be watched |
186 | /// @param action Action that was performed | 186 | /// @param watcher The listener to receive events |
187 | /// @param oldFilename The name of the file or directory moved | 187 | /// @param recursive Set this to true to include subdirectories |
188 | virtual void handleFileAction( WatchID watchid, const std::string& dir, | 188 | /// @param options Allows customization of a watcher |
189 | const std::string& filename, Action action, | 189 | /// @return Returns the watch id for the directory or, on error, a WatchID with Error type. |
190 | std::string oldFilename = "" ) = 0; | 190 | WatchID addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive, |
191 | }; | 191 | const std::vector<WatcherOption>& options ); |
192 | 192 | ||
193 | } // namespace efsw | 193 | /// Remove a directory watch. This is a brute force search O(nlogn). |
194 | 194 | void removeWatch( const std::string& directory ); | |
195 | #endif | 195 | |
196 | /// Remove a directory watch. This is a map lookup O(logn). | ||
197 | void removeWatch( WatchID watchid ); | ||
198 | |||
199 | /// Starts watching ( in other thread ) | ||
200 | void watch(); | ||
201 | |||
202 | /// @return Returns a list of the directories that are being watched | ||
203 | std::vector<std::string> directories(); | ||
204 | |||
205 | /** Allow recursive watchers to follow symbolic links to other directories | ||
206 | * followSymlinks is disabled by default | ||
207 | */ | ||
208 | void followSymlinks( bool follow ); | ||
209 | |||
210 | /** @return If can follow symbolic links to directorioes */ | ||
211 | const bool& followSymlinks() const; | ||
212 | |||
213 | /** When enable this it will allow symlinks to watch recursively out of the pointed directory. | ||
214 | * follorSymlinks must be enabled to this work. | ||
215 | * For example, added symlink to /home/folder, and the symlink points to /, this by default is | ||
216 | * not allowed, it's only allowed to symlink anything from /home/ and deeper. This is to avoid | ||
217 | * great levels of recursion. Enabling this could lead in infinite recursion, and crash the | ||
218 | * watcher ( it will try not to avoid this ). Buy enabling out of scope links, it will allow | ||
219 | * this behavior. allowOutOfScopeLinks are disabled by default. | ||
220 | */ | ||
221 | void allowOutOfScopeLinks( bool allow ); | ||
222 | |||
223 | /// @return Returns if out of scope links are allowed | ||
224 | const bool& allowOutOfScopeLinks() const; | ||
225 | |||
226 | private: | ||
227 | /// The implementation | ||
228 | FileWatcherImpl* mImpl; | ||
229 | bool mFollowSymlinks; | ||
230 | bool mOutOfScopeLinks; | ||
231 | }; | ||
232 | |||
233 | /// Basic interface for listening for file events. | ||
234 | /// @class FileWatchListener | ||
235 | class FileWatchListener { | ||
236 | public: | ||
237 | virtual ~FileWatchListener() {} | ||
238 | |||
239 | /// Handles the action file action | ||
240 | /// @param watchid The watch id for the directory | ||
241 | /// @param dir The directory | ||
242 | /// @param filename The filename that was accessed (not full path) | ||
243 | /// @param action Action that was performed | ||
244 | /// @param oldFilename The name of the file or directory moved | ||
245 | virtual void handleFileAction( WatchID watchid, const std::string& dir, | ||
246 | const std::string& filename, Action action, | ||
247 | std::string oldFilename = "" ) = 0; | ||
248 | }; | ||
249 | |||
250 | /// Optional, typically platform specific parameter for customization of a watcher. | ||
251 | /// @class WatcherOption | ||
252 | class WatcherOption { | ||
253 | public: | ||
254 | WatcherOption( Option option, int value ) : mOption( option ), mValue( value ){}; | ||
255 | Option mOption; | ||
256 | int mValue; | ||
257 | }; | ||
258 | |||
259 | } // namespace efsw | ||
260 | |||
261 | #endif | ||
diff --git a/src/3rdParty/efsw/inotify-nosys.h b/src/3rdParty/efsw/inotify-nosys.h index be1e627..be1e627 100755..100644 --- a/src/3rdParty/efsw/inotify-nosys.h +++ b/src/3rdParty/efsw/inotify-nosys.h | |||
diff --git a/src/3rdParty/efsw/platform/platformimpl.hpp b/src/3rdParty/efsw/platform/platformimpl.hpp index 5442580..5442580 100755..100644 --- a/src/3rdParty/efsw/platform/platformimpl.hpp +++ b/src/3rdParty/efsw/platform/platformimpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp b/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp index 92eeb47..92eeb47 100755..100644 --- a/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp +++ b/src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp b/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp index 0bfba76..0bfba76 100755..100644 --- a/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp +++ b/src/3rdParty/efsw/platform/posix/FileSystemImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/MutexImpl.cpp b/src/3rdParty/efsw/platform/posix/MutexImpl.cpp index 2233798..2233798 100755..100644 --- a/src/3rdParty/efsw/platform/posix/MutexImpl.cpp +++ b/src/3rdParty/efsw/platform/posix/MutexImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/MutexImpl.hpp b/src/3rdParty/efsw/platform/posix/MutexImpl.hpp index a33d827..a33d827 100755..100644 --- a/src/3rdParty/efsw/platform/posix/MutexImpl.hpp +++ b/src/3rdParty/efsw/platform/posix/MutexImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/SystemImpl.cpp b/src/3rdParty/efsw/platform/posix/SystemImpl.cpp index 37d4120..37d4120 100755..100644 --- a/src/3rdParty/efsw/platform/posix/SystemImpl.cpp +++ b/src/3rdParty/efsw/platform/posix/SystemImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/SystemImpl.hpp b/src/3rdParty/efsw/platform/posix/SystemImpl.hpp index 9322b06..9322b06 100755..100644 --- a/src/3rdParty/efsw/platform/posix/SystemImpl.hpp +++ b/src/3rdParty/efsw/platform/posix/SystemImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp b/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp index e0ae84f..772fbc9 100755..100644 --- a/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp +++ b/src/3rdParty/efsw/platform/posix/ThreadImpl.cpp | |||
@@ -5,11 +5,10 @@ | |||
5 | 5 | ||
6 | #include <cassert> | 6 | #include <cassert> |
7 | #include <efsw/Debug.hpp> | 7 | #include <efsw/Debug.hpp> |
8 | #include <iostream> | ||
9 | 8 | ||
10 | namespace efsw { namespace Platform { | 9 | namespace efsw { namespace Platform { |
11 | 10 | ||
12 | ThreadImpl::ThreadImpl( Thread* owner ) : mIsActive( false ) { | 11 | ThreadImpl::ThreadImpl( efsw::Thread* owner ) : mIsActive( false ) { |
13 | mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; | 12 | mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; |
14 | 13 | ||
15 | if ( !mIsActive ) { | 14 | if ( !mIsActive ) { |
@@ -17,14 +16,16 @@ ThreadImpl::ThreadImpl( Thread* owner ) : mIsActive( false ) { | |||
17 | } | 16 | } |
18 | } | 17 | } |
19 | 18 | ||
19 | ThreadImpl::~ThreadImpl() { | ||
20 | terminate(); | ||
21 | } | ||
22 | |||
20 | void ThreadImpl::wait() { | 23 | void ThreadImpl::wait() { |
21 | // Wait for the thread to finish, no timeout | 24 | // Wait for the thread to finish, no timeout |
22 | if ( mIsActive ) { | 25 | if ( mIsActive ) { |
23 | assert( pthread_equal( pthread_self(), mThread ) == 0 ); | 26 | assert( pthread_equal( pthread_self(), mThread ) == 0 ); |
24 | 27 | ||
25 | pthread_join( mThread, NULL ); | 28 | mIsActive = pthread_join( mThread, NULL ) != 0; |
26 | |||
27 | mIsActive = false; // Reset the thread state | ||
28 | } | 29 | } |
29 | } | 30 | } |
30 | 31 | ||
@@ -41,14 +42,14 @@ void ThreadImpl::terminate() { | |||
41 | } | 42 | } |
42 | 43 | ||
43 | void* ThreadImpl::entryPoint( void* userData ) { | 44 | void* ThreadImpl::entryPoint( void* userData ) { |
44 | // The Thread instance is stored in the user data | ||
45 | Thread* owner = static_cast<Thread*>( userData ); | ||
46 | |||
47 | // Tell the thread to handle cancel requests immediatly | 45 | // Tell the thread to handle cancel requests immediatly |
48 | #ifdef PTHREAD_CANCEL_ASYNCHRONOUS | 46 | #ifdef PTHREAD_CANCEL_ASYNCHRONOUS |
49 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); | 47 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); |
50 | #endif | 48 | #endif |
51 | 49 | ||
50 | // The Thread instance is stored in the user data | ||
51 | Thread* owner = static_cast<Thread*>( userData ); | ||
52 | |||
52 | // Forward to the owner | 53 | // Forward to the owner |
53 | owner->run(); | 54 | owner->run(); |
54 | 55 | ||
diff --git a/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp b/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp index ffc6da0..2e02f9a 100755..100644 --- a/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp +++ b/src/3rdParty/efsw/platform/posix/ThreadImpl.hpp | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | #if defined( EFSW_PLATFORM_POSIX ) | 6 | #if defined( EFSW_PLATFORM_POSIX ) |
7 | 7 | ||
8 | #include <efsw/Atomic.hpp> | ||
8 | #include <pthread.h> | 9 | #include <pthread.h> |
9 | 10 | ||
10 | namespace efsw { | 11 | namespace efsw { |
@@ -15,7 +16,9 @@ namespace Platform { | |||
15 | 16 | ||
16 | class ThreadImpl { | 17 | class ThreadImpl { |
17 | public: | 18 | public: |
18 | ThreadImpl( Thread* owner ); | 19 | explicit ThreadImpl( efsw::Thread* owner ); |
20 | |||
21 | ~ThreadImpl(); | ||
19 | 22 | ||
20 | void wait(); | 23 | void wait(); |
21 | 24 | ||
@@ -25,7 +28,7 @@ class ThreadImpl { | |||
25 | static void* entryPoint( void* userData ); | 28 | static void* entryPoint( void* userData ); |
26 | 29 | ||
27 | pthread_t mThread; | 30 | pthread_t mThread; |
28 | bool mIsActive; | 31 | Atomic<bool> mIsActive; |
29 | }; | 32 | }; |
30 | 33 | ||
31 | } // namespace Platform | 34 | } // namespace Platform |
diff --git a/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp b/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp index 2b87513..2b87513 100755..100644 --- a/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp +++ b/src/3rdParty/efsw/platform/win/FileSystemImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp b/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp index e952efc..e952efc 100755..100644 --- a/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp +++ b/src/3rdParty/efsw/platform/win/FileSystemImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/win/MutexImpl.cpp b/src/3rdParty/efsw/platform/win/MutexImpl.cpp index 62b7f83..62b7f83 100755..100644 --- a/src/3rdParty/efsw/platform/win/MutexImpl.cpp +++ b/src/3rdParty/efsw/platform/win/MutexImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/win/MutexImpl.hpp b/src/3rdParty/efsw/platform/win/MutexImpl.hpp index 7b06492..7b06492 100755..100644 --- a/src/3rdParty/efsw/platform/win/MutexImpl.hpp +++ b/src/3rdParty/efsw/platform/win/MutexImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/win/SystemImpl.cpp b/src/3rdParty/efsw/platform/win/SystemImpl.cpp index d1f2b21..d1f2b21 100755..100644 --- a/src/3rdParty/efsw/platform/win/SystemImpl.cpp +++ b/src/3rdParty/efsw/platform/win/SystemImpl.cpp | |||
diff --git a/src/3rdParty/efsw/platform/win/SystemImpl.hpp b/src/3rdParty/efsw/platform/win/SystemImpl.hpp index 99b4867..99b4867 100755..100644 --- a/src/3rdParty/efsw/platform/win/SystemImpl.hpp +++ b/src/3rdParty/efsw/platform/win/SystemImpl.hpp | |||
diff --git a/src/3rdParty/efsw/platform/win/ThreadImpl.cpp b/src/3rdParty/efsw/platform/win/ThreadImpl.cpp index d0fde8b..463934c 100755..100644 --- a/src/3rdParty/efsw/platform/win/ThreadImpl.cpp +++ b/src/3rdParty/efsw/platform/win/ThreadImpl.cpp | |||
@@ -8,7 +8,7 @@ | |||
8 | 8 | ||
9 | namespace efsw { namespace Platform { | 9 | namespace efsw { namespace Platform { |
10 | 10 | ||
11 | ThreadImpl::ThreadImpl( Thread* owner ) { | 11 | ThreadImpl::ThreadImpl( efsw::Thread* owner ) { |
12 | mThread = reinterpret_cast<HANDLE>( | 12 | mThread = reinterpret_cast<HANDLE>( |
13 | _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); | 13 | _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); |
14 | 14 | ||
diff --git a/src/3rdParty/efsw/platform/win/ThreadImpl.hpp b/src/3rdParty/efsw/platform/win/ThreadImpl.hpp index 1afb593..455f24c 100755..100644 --- a/src/3rdParty/efsw/platform/win/ThreadImpl.hpp +++ b/src/3rdParty/efsw/platform/win/ThreadImpl.hpp | |||
@@ -19,7 +19,7 @@ namespace Platform { | |||
19 | 19 | ||
20 | class ThreadImpl { | 20 | class ThreadImpl { |
21 | public: | 21 | public: |
22 | ThreadImpl( Thread* owner ); | 22 | explicit ThreadImpl( efsw::Thread* owner ); |
23 | 23 | ||
24 | ~ThreadImpl(); | 24 | ~ThreadImpl(); |
25 | 25 | ||
diff --git a/src/3rdParty/efsw/sophist.h b/src/3rdParty/efsw/sophist.h index 3a64504..82e5c36 100755..100644 --- a/src/3rdParty/efsw/sophist.h +++ b/src/3rdParty/efsw/sophist.h | |||
@@ -1,147 +1,147 @@ | |||
1 | /* sophist.h - 0.3 - public domain - Sean Barrett 2010 | 1 | /* sophist.h - 0.3 - public domain - Sean Barrett 2010 |
2 | ** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net | 2 | ** Knowledge drawn from Brian Hook's posh.h and http://predef.sourceforge.net |
3 | ** Sophist provides portable types; you typedef/#define them to your own names | 3 | ** Sophist provides portable types; you typedef/#define them to your own names |
4 | ** | 4 | ** |
5 | ** defines: | 5 | ** defines: |
6 | ** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian | 6 | ** - SOPHIST_endian - either SOPHIST_little_endian or SOPHIST_big_endian |
7 | ** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined | 7 | ** - SOPHIST_has_64 - either 0 or 1; if 0, int64 types aren't defined |
8 | ** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit | 8 | ** - SOPHIST_pointer64 - either 0 or 1; if 1, pointer is 64-bit |
9 | ** | 9 | ** |
10 | ** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer | 10 | ** - SOPHIST_intptr, SOPHIST_uintptr - integer same size as pointer |
11 | ** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 | 11 | ** - SOPHIST_int8, SOPHIST_uint8, SOPHIST_int16, SOPHIST_uint16 |
12 | ** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 | 12 | ** - SOPHIST_int32, SOPHIST_uint32, SOPHIST_int64, SOPHIST_uint64 |
13 | ** - SOPHIST_int64_constant(number) - macros for creating 64-bit | 13 | ** - SOPHIST_int64_constant(number) - macros for creating 64-bit |
14 | ** - SOPHIST_uint64_constant(number) integer constants | 14 | ** - SOPHIST_uint64_constant(number) integer constants |
15 | ** - SOPHIST_printf_format64 - string for printf format for int64 | 15 | ** - SOPHIST_printf_format64 - string for printf format for int64 |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifndef __INCLUDE_SOPHIST_H__ | 18 | #ifndef __INCLUDE_SOPHIST_H__ |
19 | #define __INCLUDE_SOPHIST_H__ | 19 | #define __INCLUDE_SOPHIST_H__ |
20 | 20 | ||
21 | #define SOPHIST_compiletime_assert(name,val) \ | 21 | #define SOPHIST_compiletime_assert(name,val) \ |
22 | typedef int SOPHIST__assert##name[(val) ? 1 : -1] | 22 | typedef int SOPHIST__assert##name[(val) ? 1 : -1] |
23 | 23 | ||
24 | /* define a couple synthetic rules to make code more readable */ | 24 | /* define a couple synthetic rules to make code more readable */ |
25 | #if (defined(__sparc__) || defined(__sparc)) && \ | 25 | #if (defined(__sparc__) || defined(__sparc)) && \ |
26 | (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) | 26 | (defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)) |
27 | #define SOPHIST_sparc64 | 27 | #define SOPHIST_sparc64 |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | #if (defined(linux) || defined(__linux__)) && \ | 30 | #if (defined(linux) || defined(__linux__)) && \ |
31 | (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) | 31 | (defined(__alpha)||defined(__alpha__)||defined(__x86_64__)||defined(_M_X64)) |
32 | #define SOPHIST_linux64 | 32 | #define SOPHIST_linux64 |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | /* basic types */ | 35 | /* basic types */ |
36 | typedef signed char SOPHIST_int8; | 36 | typedef signed char SOPHIST_int8; |
37 | typedef unsigned char SOPHIST_uint8; | 37 | typedef unsigned char SOPHIST_uint8; |
38 | 38 | ||
39 | typedef signed short SOPHIST_int16; | 39 | typedef signed short SOPHIST_int16; |
40 | typedef unsigned short SOPHIST_uint16; | 40 | typedef unsigned short SOPHIST_uint16; |
41 | 41 | ||
42 | #ifdef __palmos__ | 42 | #ifdef __palmos__ |
43 | typedef signed long SOPHIST_int32; | 43 | typedef signed long SOPHIST_int32; |
44 | typedef unsigned long SOPHIST_uint32; | 44 | typedef unsigned long SOPHIST_uint32; |
45 | #else | 45 | #else |
46 | typedef signed int SOPHIST_int32; | 46 | typedef signed int SOPHIST_int32; |
47 | typedef unsigned int SOPHIST_uint32; | 47 | typedef unsigned int SOPHIST_uint32; |
48 | #endif | 48 | #endif |
49 | 49 | ||
50 | #ifndef SOPHIST_NO_64 | 50 | #ifndef SOPHIST_NO_64 |
51 | #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ | 51 | #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) \ |
52 | || (defined(__alpha) && defined(__DECC)) | 52 | || (defined(__alpha) && defined(__DECC)) |
53 | 53 | ||
54 | typedef signed __int64 SOPHIST_int64; | 54 | typedef signed __int64 SOPHIST_int64; |
55 | typedef unsigned __int64 SOPHIST_uint64; | 55 | typedef unsigned __int64 SOPHIST_uint64; |
56 | #define SOPHIST_has_64 1 | 56 | #define SOPHIST_has_64 1 |
57 | #define SOPHIST_int64_constant(x) (x##i64) | 57 | #define SOPHIST_int64_constant(x) (x##i64) |
58 | #define SOPHIST_uint64_constant(x) (x##ui64) | 58 | #define SOPHIST_uint64_constant(x) (x##ui64) |
59 | #define SOPHIST_printf_format64 "I64" | 59 | #define SOPHIST_printf_format64 "I64" |
60 | 60 | ||
61 | #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) | 61 | #elif defined(__LP64__) || defined(__powerpc64__) || defined(SOPHIST_sparc64) |
62 | 62 | ||
63 | typedef signed long SOPHIST_int64; | 63 | typedef signed long SOPHIST_int64; |
64 | typedef unsigned long SOPHIST_uint64; | 64 | typedef unsigned long SOPHIST_uint64; |
65 | 65 | ||
66 | #define SOPHIST_has_64 1 | 66 | #define SOPHIST_has_64 1 |
67 | #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) | 67 | #define SOPHIST_int64_constant(x) ((SOPHIST_int64) x) |
68 | #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) | 68 | #define SOPHIST_uint64_constant(x) ((SOPHIST_uint64) x) |
69 | #define SOPHIST_printf_format64 "l" | 69 | #define SOPHIST_printf_format64 "l" |
70 | 70 | ||
71 | #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ | 71 | #elif defined(_LONG_LONG) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) \ |
72 | || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ | 72 | || defined(__GNUC__) || defined(__MWERKS__) || defined(__APPLE_CC__) \ |
73 | || defined(sgi) || defined (__sgi) || defined(__sgi__) \ | 73 | || defined(sgi) || defined (__sgi) || defined(__sgi__) \ |
74 | || defined(_CRAYC) | 74 | || defined(_CRAYC) |
75 | 75 | ||
76 | typedef signed long long SOPHIST_int64; | 76 | typedef signed long long SOPHIST_int64; |
77 | typedef unsigned long long SOPHIST_uint64; | 77 | typedef unsigned long long SOPHIST_uint64; |
78 | 78 | ||
79 | #define SOPHIST_has_64 1 | 79 | #define SOPHIST_has_64 1 |
80 | #define SOPHIST_int64_constant(x) (x##LL) | 80 | #define SOPHIST_int64_constant(x) (x##LL) |
81 | #define SOPHIST_uint64_constant(x) (x##ULL) | 81 | #define SOPHIST_uint64_constant(x) (x##ULL) |
82 | #define SOPHIST_printf_format64 "ll" | 82 | #define SOPHIST_printf_format64 "ll" |
83 | #endif | 83 | #endif |
84 | #endif | 84 | #endif |
85 | 85 | ||
86 | #ifndef SOPHIST_has_64 | 86 | #ifndef SOPHIST_has_64 |
87 | #define SOPHIST_has_64 0 | 87 | #define SOPHIST_has_64 0 |
88 | #endif | 88 | #endif |
89 | 89 | ||
90 | SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); | 90 | SOPHIST_compiletime_assert( int8 , sizeof(SOPHIST_int8 ) == 1); |
91 | SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); | 91 | SOPHIST_compiletime_assert(uint16, sizeof(SOPHIST_int16) == 2); |
92 | SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); | 92 | SOPHIST_compiletime_assert( int32, sizeof(SOPHIST_int32 ) == 4); |
93 | SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); | 93 | SOPHIST_compiletime_assert(uint32, sizeof(SOPHIST_uint32) == 4); |
94 | 94 | ||
95 | #if SOPHIST_has_64 | 95 | #if SOPHIST_has_64 |
96 | SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); | 96 | SOPHIST_compiletime_assert( int64, sizeof(SOPHIST_int64 ) == 8); |
97 | SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); | 97 | SOPHIST_compiletime_assert(uint64, sizeof(SOPHIST_uint64) == 8); |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | /* determine whether pointers are 64-bit */ | 100 | /* determine whether pointers are 64-bit */ |
101 | 101 | ||
102 | #if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ | 102 | #if defined(SOPHIST_linux64) || defined(SOPHIST_sparc64) \ |
103 | || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ | 103 | || defined(__osf__) || (defined(_WIN64) && !defined(_XBOX)) \ |
104 | || defined(__64BIT__) \ | 104 | || defined(__64BIT__) \ |
105 | || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ | 105 | || defined(__LP64) || defined(__LP64__) || defined(_LP64) \ |
106 | || defined(_ADDR64) || defined(_CRAYC) \ | 106 | || defined(_ADDR64) || defined(_CRAYC) \ |
107 | 107 | ||
108 | #define SOPHIST_pointer64 1 | 108 | #define SOPHIST_pointer64 1 |
109 | 109 | ||
110 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); | 110 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) == 8); |
111 | 111 | ||
112 | typedef SOPHIST_int64 SOPHIST_intptr; | 112 | typedef SOPHIST_int64 SOPHIST_intptr; |
113 | typedef SOPHIST_uint64 SOPHIST_uintptr; | 113 | typedef SOPHIST_uint64 SOPHIST_uintptr; |
114 | #else | 114 | #else |
115 | 115 | ||
116 | #define SOPHIST_pointer64 0 | 116 | #define SOPHIST_pointer64 0 |
117 | 117 | ||
118 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); | 118 | SOPHIST_compiletime_assert(pointer64, sizeof(void*) <= 4); |
119 | 119 | ||
120 | /* do we care about pointers that are only 16-bit? */ | 120 | /* do we care about pointers that are only 16-bit? */ |
121 | typedef SOPHIST_int32 SOPHIST_intptr; | 121 | typedef SOPHIST_int32 SOPHIST_intptr; |
122 | typedef SOPHIST_uint32 SOPHIST_uintptr; | 122 | typedef SOPHIST_uint32 SOPHIST_uintptr; |
123 | 123 | ||
124 | #endif | 124 | #endif |
125 | 125 | ||
126 | SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); | 126 | SOPHIST_compiletime_assert(intptr, sizeof(SOPHIST_intptr) == sizeof(char *)); |
127 | 127 | ||
128 | /* enumerate known little endian cases; fallback to big-endian */ | 128 | /* enumerate known little endian cases; fallback to big-endian */ |
129 | 129 | ||
130 | #define SOPHIST_little_endian 1 | 130 | #define SOPHIST_little_endian 1 |
131 | #define SOPHIST_big_endian 2 | 131 | #define SOPHIST_big_endian 2 |
132 | 132 | ||
133 | #if defined(__386__) || defined(i386) || defined(__i386__) \ | 133 | #if defined(__386__) || defined(i386) || defined(__i386__) \ |
134 | || defined(__X86) || defined(_M_IX86) \ | 134 | || defined(__X86) || defined(_M_IX86) \ |
135 | || defined(_M_X64) || defined(__x86_64__) \ | 135 | || defined(_M_X64) || defined(__x86_64__) \ |
136 | || defined(alpha) || defined(__alpha) || defined(__alpha__) \ | 136 | || defined(alpha) || defined(__alpha) || defined(__alpha__) \ |
137 | || defined(_M_ALPHA) \ | 137 | || defined(_M_ALPHA) \ |
138 | || defined(ARM) || defined(_ARM) || defined(__arm__) \ | 138 | || defined(ARM) || defined(_ARM) || defined(__arm__) \ |
139 | || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ | 139 | || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ |
140 | || defined(_WIN32_WCE) || defined(__NT__) \ | 140 | || defined(_WIN32_WCE) || defined(__NT__) \ |
141 | || defined(__MIPSEL__) | 141 | || defined(__MIPSEL__) |
142 | #define SOPHIST_endian SOPHIST_little_endian | 142 | #define SOPHIST_endian SOPHIST_little_endian |
143 | #else | 143 | #else |
144 | #define SOPHIST_endian SOPHIST_big_endian | 144 | #define SOPHIST_endian SOPHIST_big_endian |
145 | #endif | 145 | #endif |
146 | 146 | ||
147 | #endif /* __INCLUDE_SOPHIST_H__ */ | 147 | #endif /* __INCLUDE_SOPHIST_H__ */ |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index e670126..5e70645 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -620,6 +620,7 @@ AST_END(Slice) | |||
620 | 620 | ||
621 | AST_NODE(Parens) | 621 | AST_NODE(Parens) |
622 | ast_ptr<true, Exp_t> expr; | 622 | ast_ptr<true, Exp_t> expr; |
623 | bool extra = false; | ||
623 | AST_MEMBER(Parens, &expr) | 624 | AST_MEMBER(Parens, &expr) |
624 | AST_END(Parens) | 625 | AST_END(Parens) |
625 | 626 | ||
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index a2a1864..68ce9b5 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -75,7 +75,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
75 | "close"s // Lua 5.4 | 75 | "close"s // Lua 5.4 |
76 | }; | 76 | }; |
77 | 77 | ||
78 | const std::string_view version = "0.27.3"sv; | 78 | const std::string_view version = "0.27.4"sv; |
79 | const std::string_view extension = "yue"sv; | 79 | const std::string_view extension = "yue"sv; |
80 | 80 | ||
81 | class CompileError : public std::logic_error { | 81 | class CompileError : public std::logic_error { |
@@ -1080,8 +1080,8 @@ private: | |||
1080 | if (unary->ops.empty()) { | 1080 | if (unary->ops.empty()) { |
1081 | Value_t* value = static_cast<Value_t*>(unary->expos.back()); | 1081 | Value_t* value = static_cast<Value_t*>(unary->expos.back()); |
1082 | if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) { | 1082 | if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) { |
1083 | if (auto exp = chain->get_by_path<Callable_t, Parens_t, Exp_t>()) { | 1083 | if (auto parens = chain->get_by_path<Callable_t, Parens_t>(); parens && parens->extra) { |
1084 | if (auto insideValue = singleValueFrom(exp)) { | 1084 | if (auto insideValue = singleValueFrom(parens->expr)) { |
1085 | return insideValue; | 1085 | return insideValue; |
1086 | } | 1086 | } |
1087 | } | 1087 | } |
@@ -3262,6 +3262,7 @@ private: | |||
3262 | } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { | 3262 | } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { |
3263 | auto p = destruct.value.get(); | 3263 | auto p = destruct.value.get(); |
3264 | auto parens = p->new_ptr<Parens_t>(); | 3264 | auto parens = p->new_ptr<Parens_t>(); |
3265 | parens->extra = true; | ||
3265 | if (auto tableBlock = ast_cast<TableBlock_t>(p)) { | 3266 | if (auto tableBlock = ast_cast<TableBlock_t>(p)) { |
3266 | auto tableLit = p->new_ptr<TableLit_t>(); | 3267 | auto tableLit = p->new_ptr<TableLit_t>(); |
3267 | tableLit->values.dup(tableBlock->values); | 3268 | tableLit->values.dup(tableBlock->values); |
@@ -4750,6 +4751,7 @@ private: | |||
4750 | newSimpleValue->value.set(funLit); | 4751 | newSimpleValue->value.set(funLit); |
4751 | auto newExpInParens = newExp(newSimpleValue, x); | 4752 | auto newExpInParens = newExp(newSimpleValue, x); |
4752 | auto newParens = x->new_ptr<Parens_t>(); | 4753 | auto newParens = x->new_ptr<Parens_t>(); |
4754 | newParens->extra = true; | ||
4753 | newParens->expr.set(newExpInParens); | 4755 | newParens->expr.set(newExpInParens); |
4754 | auto newCallable = x->new_ptr<Callable_t>(); | 4756 | auto newCallable = x->new_ptr<Callable_t>(); |
4755 | newCallable->item.set(newParens); | 4757 | newCallable->item.set(newParens); |
@@ -5570,6 +5572,7 @@ private: | |||
5570 | auto x = chainList.front(); | 5572 | auto x = chainList.front(); |
5571 | if (ast_is<ExistentialOp_t>(chainList.back())) { | 5573 | if (ast_is<ExistentialOp_t>(chainList.back())) { |
5572 | auto parens = x->new_ptr<Parens_t>(); | 5574 | auto parens = x->new_ptr<Parens_t>(); |
5575 | parens->extra = true; | ||
5573 | { | 5576 | { |
5574 | auto chainValue = x->new_ptr<ChainValue_t>(); | 5577 | auto chainValue = x->new_ptr<ChainValue_t>(); |
5575 | for (auto item : chainList) { | 5578 | for (auto item : chainList) { |
@@ -6163,6 +6166,7 @@ private: | |||
6163 | ++next; | 6166 | ++next; |
6164 | if (next != chainList.end()) { | 6167 | if (next != chainList.end()) { |
6165 | auto paren = x->new_ptr<Parens_t>(); | 6168 | auto paren = x->new_ptr<Parens_t>(); |
6169 | paren->extra = true; | ||
6166 | paren->expr.set(newExp(chainValue, x)); | 6170 | paren->expr.set(newExp(chainValue, x)); |
6167 | auto ncallable = x->new_ptr<Callable_t>(); | 6171 | auto ncallable = x->new_ptr<Callable_t>(); |
6168 | ncallable->item.set(paren); | 6172 | ncallable->item.set(paren); |
@@ -6215,6 +6219,7 @@ private: | |||
6215 | simpleValue->value.set(funLit); | 6219 | simpleValue->value.set(funLit); |
6216 | auto exp = newExp(simpleValue, x); | 6220 | auto exp = newExp(simpleValue, x); |
6217 | auto paren = x->new_ptr<Parens_t>(); | 6221 | auto paren = x->new_ptr<Parens_t>(); |
6222 | paren->extra = true; | ||
6218 | paren->expr.set(exp); | 6223 | paren->expr.set(exp); |
6219 | auto callable = x->new_ptr<Callable_t>(); | 6224 | auto callable = x->new_ptr<Callable_t>(); |
6220 | callable->item.set(paren); | 6225 | callable->item.set(paren); |
@@ -6631,6 +6636,7 @@ private: | |||
6631 | exp.set(info.node); | 6636 | exp.set(info.node); |
6632 | if (!exp->opValues.empty() || (chainList.size() > 2 || (chainList.size() == 2 && !ast_is<Invoke_t, InvokeArgs_t>(chainList.back())))) { | 6637 | if (!exp->opValues.empty() || (chainList.size() > 2 || (chainList.size() == 2 && !ast_is<Invoke_t, InvokeArgs_t>(chainList.back())))) { |
6633 | auto paren = x->new_ptr<Parens_t>(); | 6638 | auto paren = x->new_ptr<Parens_t>(); |
6639 | paren->extra = true; | ||
6634 | paren->expr.set(exp); | 6640 | paren->expr.set(exp); |
6635 | auto callable = x->new_ptr<Callable_t>(); | 6641 | auto callable = x->new_ptr<Callable_t>(); |
6636 | callable->item.set(paren); | 6642 | callable->item.set(paren); |