Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
michael@0 | 1 | // Windows/FileFind.cpp |
michael@0 | 2 | |
michael@0 | 3 | #include "StdAfx.h" |
michael@0 | 4 | |
michael@0 | 5 | #include "FileFind.h" |
michael@0 | 6 | #ifndef _UNICODE |
michael@0 | 7 | #include "../Common/StringConvert.h" |
michael@0 | 8 | #endif |
michael@0 | 9 | |
michael@0 | 10 | #ifndef _UNICODE |
michael@0 | 11 | extern bool g_IsNT; |
michael@0 | 12 | #endif |
michael@0 | 13 | |
michael@0 | 14 | namespace NWindows { |
michael@0 | 15 | namespace NFile { |
michael@0 | 16 | namespace NFind { |
michael@0 | 17 | |
michael@0 | 18 | static const TCHAR kDot = TEXT('.'); |
michael@0 | 19 | |
michael@0 | 20 | bool CFileInfo::IsDots() const |
michael@0 | 21 | { |
michael@0 | 22 | if (!IsDirectory() || Name.IsEmpty()) |
michael@0 | 23 | return false; |
michael@0 | 24 | if (Name[0] != kDot) |
michael@0 | 25 | return false; |
michael@0 | 26 | return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | #ifndef _UNICODE |
michael@0 | 30 | bool CFileInfoW::IsDots() const |
michael@0 | 31 | { |
michael@0 | 32 | if (!IsDirectory() || Name.IsEmpty()) |
michael@0 | 33 | return false; |
michael@0 | 34 | if (Name[0] != kDot) |
michael@0 | 35 | return false; |
michael@0 | 36 | return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); |
michael@0 | 37 | } |
michael@0 | 38 | #endif |
michael@0 | 39 | |
michael@0 | 40 | static void ConvertWIN32_FIND_DATA_To_FileInfo( |
michael@0 | 41 | const WIN32_FIND_DATA &findData, |
michael@0 | 42 | CFileInfo &fileInfo) |
michael@0 | 43 | { |
michael@0 | 44 | fileInfo.Attributes = findData.dwFileAttributes; |
michael@0 | 45 | fileInfo.CreationTime = findData.ftCreationTime; |
michael@0 | 46 | fileInfo.LastAccessTime = findData.ftLastAccessTime; |
michael@0 | 47 | fileInfo.LastWriteTime = findData.ftLastWriteTime; |
michael@0 | 48 | fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; |
michael@0 | 49 | fileInfo.Name = findData.cFileName; |
michael@0 | 50 | #ifndef _WIN32_WCE |
michael@0 | 51 | fileInfo.ReparseTag = findData.dwReserved0; |
michael@0 | 52 | #else |
michael@0 | 53 | fileInfo.ObjectID = findData.dwOID; |
michael@0 | 54 | #endif |
michael@0 | 55 | } |
michael@0 | 56 | |
michael@0 | 57 | #ifndef _UNICODE |
michael@0 | 58 | |
michael@0 | 59 | static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } |
michael@0 | 60 | |
michael@0 | 61 | static void ConvertWIN32_FIND_DATA_To_FileInfo( |
michael@0 | 62 | const WIN32_FIND_DATAW &findData, |
michael@0 | 63 | CFileInfoW &fileInfo) |
michael@0 | 64 | { |
michael@0 | 65 | fileInfo.Attributes = findData.dwFileAttributes; |
michael@0 | 66 | fileInfo.CreationTime = findData.ftCreationTime; |
michael@0 | 67 | fileInfo.LastAccessTime = findData.ftLastAccessTime; |
michael@0 | 68 | fileInfo.LastWriteTime = findData.ftLastWriteTime; |
michael@0 | 69 | fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; |
michael@0 | 70 | fileInfo.Name = findData.cFileName; |
michael@0 | 71 | #ifndef _WIN32_WCE |
michael@0 | 72 | fileInfo.ReparseTag = findData.dwReserved0; |
michael@0 | 73 | #else |
michael@0 | 74 | fileInfo.ObjectID = findData.dwOID; |
michael@0 | 75 | #endif |
michael@0 | 76 | } |
michael@0 | 77 | |
michael@0 | 78 | static void ConvertWIN32_FIND_DATA_To_FileInfo( |
michael@0 | 79 | const WIN32_FIND_DATA &findData, |
michael@0 | 80 | CFileInfoW &fileInfo) |
michael@0 | 81 | { |
michael@0 | 82 | fileInfo.Attributes = findData.dwFileAttributes; |
michael@0 | 83 | fileInfo.CreationTime = findData.ftCreationTime; |
michael@0 | 84 | fileInfo.LastAccessTime = findData.ftLastAccessTime; |
michael@0 | 85 | fileInfo.LastWriteTime = findData.ftLastWriteTime; |
michael@0 | 86 | fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; |
michael@0 | 87 | fileInfo.Name = GetUnicodeString(findData.cFileName, GetCurrentCodePage()); |
michael@0 | 88 | #ifndef _WIN32_WCE |
michael@0 | 89 | fileInfo.ReparseTag = findData.dwReserved0; |
michael@0 | 90 | #else |
michael@0 | 91 | fileInfo.ObjectID = findData.dwOID; |
michael@0 | 92 | #endif |
michael@0 | 93 | } |
michael@0 | 94 | #endif |
michael@0 | 95 | |
michael@0 | 96 | //////////////////////////////// |
michael@0 | 97 | // CFindFile |
michael@0 | 98 | |
michael@0 | 99 | bool CFindFile::Close() |
michael@0 | 100 | { |
michael@0 | 101 | if(!_handleAllocated) |
michael@0 | 102 | return true; |
michael@0 | 103 | bool result = BOOLToBool(::FindClose(_handle)); |
michael@0 | 104 | _handleAllocated = !result; |
michael@0 | 105 | return result; |
michael@0 | 106 | } |
michael@0 | 107 | |
michael@0 | 108 | bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo) |
michael@0 | 109 | { |
michael@0 | 110 | Close(); |
michael@0 | 111 | WIN32_FIND_DATA findData; |
michael@0 | 112 | _handle = ::FindFirstFile(wildcard, &findData); |
michael@0 | 113 | if (_handleAllocated = (_handle != INVALID_HANDLE_VALUE)) |
michael@0 | 114 | ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
michael@0 | 115 | return _handleAllocated; |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | #ifndef _UNICODE |
michael@0 | 119 | bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo) |
michael@0 | 120 | { |
michael@0 | 121 | Close(); |
michael@0 | 122 | if (g_IsNT) |
michael@0 | 123 | { |
michael@0 | 124 | WIN32_FIND_DATAW findData; |
michael@0 | 125 | _handle = ::FindFirstFileW(wildcard, &findData); |
michael@0 | 126 | if (_handleAllocated = (_handle != INVALID_HANDLE_VALUE)) |
michael@0 | 127 | ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
michael@0 | 128 | } |
michael@0 | 129 | else |
michael@0 | 130 | { |
michael@0 | 131 | WIN32_FIND_DATAA findData; |
michael@0 | 132 | _handle = ::FindFirstFileA(UnicodeStringToMultiByte(wildcard, |
michael@0 | 133 | GetCurrentCodePage()), &findData); |
michael@0 | 134 | if (_handleAllocated = (_handle != INVALID_HANDLE_VALUE)) |
michael@0 | 135 | ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
michael@0 | 136 | } |
michael@0 | 137 | return _handleAllocated; |
michael@0 | 138 | } |
michael@0 | 139 | #endif |
michael@0 | 140 | |
michael@0 | 141 | bool CFindFile::FindNext(CFileInfo &fileInfo) |
michael@0 | 142 | { |
michael@0 | 143 | WIN32_FIND_DATA findData; |
michael@0 | 144 | bool result = BOOLToBool(::FindNextFile(_handle, &findData)); |
michael@0 | 145 | if (result) |
michael@0 | 146 | ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
michael@0 | 147 | return result; |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | #ifndef _UNICODE |
michael@0 | 151 | bool CFindFile::FindNext(CFileInfoW &fileInfo) |
michael@0 | 152 | { |
michael@0 | 153 | if (g_IsNT) |
michael@0 | 154 | { |
michael@0 | 155 | WIN32_FIND_DATAW findData; |
michael@0 | 156 | if (!::FindNextFileW(_handle, &findData)) |
michael@0 | 157 | return false; |
michael@0 | 158 | ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
michael@0 | 159 | } |
michael@0 | 160 | else |
michael@0 | 161 | { |
michael@0 | 162 | WIN32_FIND_DATAA findData; |
michael@0 | 163 | if (!::FindNextFileA(_handle, &findData)) |
michael@0 | 164 | return false; |
michael@0 | 165 | ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
michael@0 | 166 | } |
michael@0 | 167 | return true; |
michael@0 | 168 | } |
michael@0 | 169 | #endif |
michael@0 | 170 | |
michael@0 | 171 | bool FindFile(LPCTSTR wildcard, CFileInfo &fileInfo) |
michael@0 | 172 | { |
michael@0 | 173 | CFindFile finder; |
michael@0 | 174 | return finder.FindFirst(wildcard, fileInfo); |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | #ifndef _UNICODE |
michael@0 | 178 | bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo) |
michael@0 | 179 | { |
michael@0 | 180 | CFindFile finder; |
michael@0 | 181 | return finder.FindFirst(wildcard, fileInfo); |
michael@0 | 182 | } |
michael@0 | 183 | #endif |
michael@0 | 184 | |
michael@0 | 185 | bool DoesFileExist(LPCTSTR name) |
michael@0 | 186 | { |
michael@0 | 187 | CFileInfo fileInfo; |
michael@0 | 188 | return FindFile(name, fileInfo); |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | #ifndef _UNICODE |
michael@0 | 192 | bool DoesFileExist(LPCWSTR name) |
michael@0 | 193 | { |
michael@0 | 194 | CFileInfoW fileInfo; |
michael@0 | 195 | return FindFile(name, fileInfo); |
michael@0 | 196 | } |
michael@0 | 197 | #endif |
michael@0 | 198 | |
michael@0 | 199 | ///////////////////////////////////// |
michael@0 | 200 | // CEnumerator |
michael@0 | 201 | |
michael@0 | 202 | bool CEnumerator::NextAny(CFileInfo &fileInfo) |
michael@0 | 203 | { |
michael@0 | 204 | if(_findFile.IsHandleAllocated()) |
michael@0 | 205 | return _findFile.FindNext(fileInfo); |
michael@0 | 206 | else |
michael@0 | 207 | return _findFile.FindFirst(_wildcard, fileInfo); |
michael@0 | 208 | } |
michael@0 | 209 | |
michael@0 | 210 | bool CEnumerator::Next(CFileInfo &fileInfo) |
michael@0 | 211 | { |
michael@0 | 212 | while(true) |
michael@0 | 213 | { |
michael@0 | 214 | if(!NextAny(fileInfo)) |
michael@0 | 215 | return false; |
michael@0 | 216 | if(!fileInfo.IsDots()) |
michael@0 | 217 | return true; |
michael@0 | 218 | } |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | bool CEnumerator::Next(CFileInfo &fileInfo, bool &found) |
michael@0 | 222 | { |
michael@0 | 223 | if (Next(fileInfo)) |
michael@0 | 224 | { |
michael@0 | 225 | found = true; |
michael@0 | 226 | return true; |
michael@0 | 227 | } |
michael@0 | 228 | found = false; |
michael@0 | 229 | return (::GetLastError() == ERROR_NO_MORE_FILES); |
michael@0 | 230 | } |
michael@0 | 231 | |
michael@0 | 232 | #ifndef _UNICODE |
michael@0 | 233 | bool CEnumeratorW::NextAny(CFileInfoW &fileInfo) |
michael@0 | 234 | { |
michael@0 | 235 | if(_findFile.IsHandleAllocated()) |
michael@0 | 236 | return _findFile.FindNext(fileInfo); |
michael@0 | 237 | else |
michael@0 | 238 | return _findFile.FindFirst(_wildcard, fileInfo); |
michael@0 | 239 | } |
michael@0 | 240 | |
michael@0 | 241 | bool CEnumeratorW::Next(CFileInfoW &fileInfo) |
michael@0 | 242 | { |
michael@0 | 243 | while(true) |
michael@0 | 244 | { |
michael@0 | 245 | if(!NextAny(fileInfo)) |
michael@0 | 246 | return false; |
michael@0 | 247 | if(!fileInfo.IsDots()) |
michael@0 | 248 | return true; |
michael@0 | 249 | } |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | bool CEnumeratorW::Next(CFileInfoW &fileInfo, bool &found) |
michael@0 | 253 | { |
michael@0 | 254 | if (Next(fileInfo)) |
michael@0 | 255 | { |
michael@0 | 256 | found = true; |
michael@0 | 257 | return true; |
michael@0 | 258 | } |
michael@0 | 259 | found = false; |
michael@0 | 260 | return (::GetLastError() == ERROR_NO_MORE_FILES); |
michael@0 | 261 | } |
michael@0 | 262 | |
michael@0 | 263 | #endif |
michael@0 | 264 | |
michael@0 | 265 | //////////////////////////////// |
michael@0 | 266 | // CFindChangeNotification |
michael@0 | 267 | |
michael@0 | 268 | bool CFindChangeNotification::Close() |
michael@0 | 269 | { |
michael@0 | 270 | if(_handle == INVALID_HANDLE_VALUE || _handle == 0) |
michael@0 | 271 | return true; |
michael@0 | 272 | bool result = BOOLToBool(::FindCloseChangeNotification(_handle)); |
michael@0 | 273 | if (result) |
michael@0 | 274 | _handle = INVALID_HANDLE_VALUE; |
michael@0 | 275 | return result; |
michael@0 | 276 | } |
michael@0 | 277 | |
michael@0 | 278 | HANDLE CFindChangeNotification::FindFirst(LPCTSTR pathName, bool watchSubtree, |
michael@0 | 279 | DWORD notifyFilter) |
michael@0 | 280 | { |
michael@0 | 281 | _handle = ::FindFirstChangeNotification(pathName, |
michael@0 | 282 | BoolToBOOL(watchSubtree), notifyFilter); |
michael@0 | 283 | return _handle; |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | #ifndef _UNICODE |
michael@0 | 287 | HANDLE CFindChangeNotification::FindFirst(LPCWSTR pathName, bool watchSubtree, |
michael@0 | 288 | DWORD notifyFilter) |
michael@0 | 289 | { |
michael@0 | 290 | if (g_IsNT) |
michael@0 | 291 | return (_handle = ::FindFirstChangeNotificationW(pathName, BoolToBOOL(watchSubtree), notifyFilter)); |
michael@0 | 292 | return FindFirst(UnicodeStringToMultiByte(pathName, GetCurrentCodePage()), watchSubtree, notifyFilter); |
michael@0 | 293 | } |
michael@0 | 294 | #endif |
michael@0 | 295 | |
michael@0 | 296 | #ifndef _WIN32_WCE |
michael@0 | 297 | bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings) |
michael@0 | 298 | { |
michael@0 | 299 | driveStrings.Clear(); |
michael@0 | 300 | UINT32 size = GetLogicalDriveStrings(0, NULL); |
michael@0 | 301 | if(size == 0) |
michael@0 | 302 | return false; |
michael@0 | 303 | CSysString buffer; |
michael@0 | 304 | UINT32 newSize = GetLogicalDriveStrings(size, buffer.GetBuffer(size)); |
michael@0 | 305 | if(newSize == 0) |
michael@0 | 306 | return false; |
michael@0 | 307 | if(newSize > size) |
michael@0 | 308 | return false; |
michael@0 | 309 | CSysString string; |
michael@0 | 310 | for(UINT32 i = 0; i < newSize; i++) |
michael@0 | 311 | { |
michael@0 | 312 | TCHAR c = buffer[i]; |
michael@0 | 313 | if(c == TEXT('\0')) |
michael@0 | 314 | { |
michael@0 | 315 | driveStrings.Add(string); |
michael@0 | 316 | string.Empty(); |
michael@0 | 317 | } |
michael@0 | 318 | else |
michael@0 | 319 | string += c; |
michael@0 | 320 | } |
michael@0 | 321 | if(!string.IsEmpty()) |
michael@0 | 322 | return false; |
michael@0 | 323 | return true; |
michael@0 | 324 | } |
michael@0 | 325 | |
michael@0 | 326 | #ifndef _UNICODE |
michael@0 | 327 | bool MyGetLogicalDriveStrings(UStringVector &driveStrings) |
michael@0 | 328 | { |
michael@0 | 329 | driveStrings.Clear(); |
michael@0 | 330 | if (g_IsNT) |
michael@0 | 331 | { |
michael@0 | 332 | UINT32 size = GetLogicalDriveStringsW(0, NULL); |
michael@0 | 333 | if (size == 0) |
michael@0 | 334 | return false; |
michael@0 | 335 | UString buffer; |
michael@0 | 336 | UINT32 newSize = GetLogicalDriveStringsW(size, buffer.GetBuffer(size)); |
michael@0 | 337 | if(newSize == 0) |
michael@0 | 338 | return false; |
michael@0 | 339 | if(newSize > size) |
michael@0 | 340 | return false; |
michael@0 | 341 | UString string; |
michael@0 | 342 | for(UINT32 i = 0; i < newSize; i++) |
michael@0 | 343 | { |
michael@0 | 344 | WCHAR c = buffer[i]; |
michael@0 | 345 | if(c == L'\0') |
michael@0 | 346 | { |
michael@0 | 347 | driveStrings.Add(string); |
michael@0 | 348 | string.Empty(); |
michael@0 | 349 | } |
michael@0 | 350 | else |
michael@0 | 351 | string += c; |
michael@0 | 352 | } |
michael@0 | 353 | return string.IsEmpty(); |
michael@0 | 354 | } |
michael@0 | 355 | CSysStringVector driveStringsA; |
michael@0 | 356 | bool res = MyGetLogicalDriveStrings(driveStringsA); |
michael@0 | 357 | for (int i = 0; i < driveStringsA.Size(); i++) |
michael@0 | 358 | driveStrings.Add(GetUnicodeString(driveStringsA[i])); |
michael@0 | 359 | return res; |
michael@0 | 360 | } |
michael@0 | 361 | #endif |
michael@0 | 362 | |
michael@0 | 363 | #endif |
michael@0 | 364 | |
michael@0 | 365 | }}} |