@@ -802,7 +802,7 @@ open class FileManager : NSObject {
802
802
}
803
803
804
804
#if os(Windows)
805
- private func joinPath( prefix: String , suffix: String ) -> String {
805
+ fileprivate func joinPath( prefix: String , suffix: String ) -> String {
806
806
var pszPath : PWSTR ?
807
807
_ = prefix. withCString ( encodedAs: UTF16 . self) { prefix in
808
808
_ = suffix. withCString ( encodedAs: UTF16 . self) { suffix in
@@ -2377,46 +2377,126 @@ extension FileManager {
2377
2377
self . innerEnumerator = ie
2378
2378
}
2379
2379
2380
- @available ( Windows, deprecated, message: " Not Yet Implemented " )
2381
2380
override func nextObject( ) -> Any ? {
2382
2381
let o = innerEnumerator. nextObject ( )
2383
2382
guard let url = o as? URL else {
2384
2383
return nil
2385
2384
}
2386
2385
2387
2386
#if os(Windows)
2388
- NSUnimplemented ( )
2387
+ var relativePath = UnsafeMutableBufferPointer< WCHAR> . allocate( capacity: Int ( MAX_PATH) )
2388
+ defer { relativePath. deallocate ( ) }
2389
+ func withURLCString< Result> ( url: URL , _ f: ( UnsafePointer < WCHAR > ) -> Result ? ) -> Result ? {
2390
+ return url. withUnsafeFileSystemRepresentation { fsr in
2391
+ ( fsr. flatMap { String ( utf8String: $0) } ) ? . withCString ( encodedAs: UTF16 . self) { f ( $0) }
2392
+ }
2393
+ }
2394
+ let result = withURLCString ( url: baseURL) { pszFrom -> BOOL ? in
2395
+ withURLCString ( url: url) { pszTo in
2396
+ let fromAttrs = GetFileAttributesW ( pszFrom)
2397
+ let toAttrs = GetFileAttributesW ( pszTo)
2398
+ guard fromAttrs != INVALID_FILE_ATTRIBUTES, toAttrs != INVALID_FILE_ATTRIBUTES else {
2399
+ return FALSE
2400
+ }
2401
+ return PathRelativePathToW ( relativePath. baseAddress, pszFrom, fromAttrs, pszTo, toAttrs)
2402
+ }
2403
+ }
2404
+
2405
+ guard result == TRUE, let ( path, _) = String . decodeCString ( relativePath. baseAddress, as: UTF16 . self) else {
2406
+ return nil
2407
+ }
2389
2408
#else
2390
2409
let path = url. path. replacingOccurrences ( of: baseURL. path+ " / " , with: " " )
2391
- _currentItemPath = path
2392
- return path
2393
2410
#endif
2411
+ _currentItemPath = path
2412
+ return _currentItemPath
2394
2413
}
2395
2414
}
2396
2415
2397
- #if os(Windows)
2398
2416
internal class NSURLDirectoryEnumerator : DirectoryEnumerator {
2399
- internal typealias ErrorHandler = /* @escaping */ ( URL , Error ) -> Bool
2417
+ #if os(Windows)
2418
+ var _options : FileManager . DirectoryEnumerationOptions
2419
+ var _errorHandler : ( ( URL , Error ) -> Bool ) ?
2420
+ var _stack : [ URL ]
2421
+ var _current : URL ?
2422
+ var _rootDepth : Int
2400
2423
2401
- init ( url: URL , options: FileManager . DirectoryEnumerationOptions , errorHandler: ErrorHandler ? ) {
2424
+ init ( url: URL , options: FileManager . DirectoryEnumerationOptions , errorHandler: ( /* @escaping */ ( URL , Error ) -> Bool ) ? ) {
2425
+ _options = options
2426
+ _errorHandler = errorHandler
2427
+ _stack = [ url]
2428
+ _rootDepth = url. pathComponents. count
2429
+ }
2430
+
2431
+ override func nextObject( ) -> Any ? {
2432
+ func contentsOfDir( directory: URL ) -> [ URL ] ? {
2433
+ var ffd : WIN32_FIND_DATAW = WIN32_FIND_DATAW ( )
2434
+ guard let dirFSR = directory. withUnsafeFileSystemRepresentation ( { $0. flatMap { fsr in String ( utf8String: fsr) } } )
2435
+ else { return nil }
2436
+ let dirPath = FileManager ( ) . joinPath ( prefix: dirFSR, suffix: " * " )
2437
+ let h : HANDLE = dirPath. withCString ( encodedAs: UTF16 . self) {
2438
+ FindFirstFileW ( $0, & ffd)
2439
+ }
2440
+ guard h != INVALID_HANDLE_VALUE else { return nil }
2441
+ defer { FindClose ( h) }
2442
+
2443
+ var files : [ URL ] = [ ]
2444
+ repeat {
2445
+ let fileArr = Array < WCHAR > (
2446
+ UnsafeBufferPointer ( start: & ffd. cFileName. 0 ,
2447
+ count: MemoryLayout . size ( ofValue: ffd. cFileName) ) )
2448
+ let file = String ( decodingCString: fileArr, as: UTF16 . self)
2449
+ if file != " . "
2450
+ && file != " .. "
2451
+ && ( !_options. contains ( . skipsHiddenFiles)
2452
+ || ( ffd. dwFileAttributes & DWORD ( FILE_ATTRIBUTE_HIDDEN) == 0 ) ) {
2453
+ files. append ( URL ( fileURLWithPath: FileManager ( ) . joinPath ( prefix: dirFSR, suffix: file) ) )
2454
+ }
2455
+ } while ( FindNextFileW ( h, & ffd) != 0 )
2456
+ return files
2457
+ }
2458
+ while let url = _stack. popLast ( ) {
2459
+ if url. hasDirectoryPath && !_options. contains ( . skipsSubdirectoryDescendants) {
2460
+ guard let dirContents = contentsOfDir ( directory: url) ? . reversed ( ) else {
2461
+ if let handler = _errorHandler {
2462
+ let dirFSR = url. withUnsafeFileSystemRepresentation { $0. flatMap { fsr in String ( utf8String: fsr) } }
2463
+ let keepGoing = handler ( URL ( fileURLWithPath: dirFSR ?? " " ) ,
2464
+ _NSErrorWithWindowsError ( GetLastError ( ) , reading: true ) )
2465
+ if !keepGoing { return nil }
2466
+ }
2467
+ continue
2468
+ }
2469
+ _stack. append ( contentsOf: dirContents)
2470
+ }
2471
+ _current = url
2472
+ return url
2473
+ }
2474
+ return nil
2475
+ }
2476
+
2477
+ override var level : Int {
2478
+ return _rootDepth - ( _current? . pathComponents. count ?? _rootDepth)
2479
+ }
2480
+
2481
+ override func skipDescendants( ) {
2482
+ _options. insert ( . skipsSubdirectoryDescendants)
2402
2483
}
2403
- }
2404
2484
#else
2405
- internal class NSURLDirectoryEnumerator : DirectoryEnumerator {
2406
2485
var _url : URL
2407
2486
var _options : FileManager . DirectoryEnumerationOptions
2408
2487
var _errorHandler : ( ( URL , Error ) -> Bool ) ?
2409
2488
var _stream : UnsafeMutablePointer < FTS > ? = nil
2410
2489
var _current : UnsafeMutablePointer < FTSENT > ? = nil
2411
2490
var _rootError : Error ? = nil
2412
2491
var _gotRoot : Bool = false
2413
-
2492
+
2493
+
2414
2494
// See @escaping comments above.
2415
2495
init ( url: URL , options: FileManager . DirectoryEnumerationOptions , errorHandler: ( /* @escaping */ ( URL , Error ) -> Bool ) ? ) {
2416
2496
_url = url
2417
2497
_options = options
2418
2498
_errorHandler = errorHandler
2419
-
2499
+
2420
2500
if FileManager . default. fileExists ( atPath: _url. path) {
2421
2501
let fsRep = FileManager . default. fileSystemRepresentation ( withPath: _url. path)
2422
2502
let ps = UnsafeMutablePointer< UnsafeMutablePointer< Int8>?> . allocate( capacity: 2 )
@@ -2430,15 +2510,15 @@ extension FileManager {
2430
2510
_rootError = _NSErrorWithErrno ( ENOENT, reading: true , url: url)
2431
2511
}
2432
2512
}
2433
-
2513
+
2434
2514
deinit {
2435
2515
if let stream = _stream {
2436
2516
fts_close ( stream)
2437
2517
}
2438
2518
}
2439
-
2440
- override func nextObject( ) -> Any ? {
2441
2519
2520
+
2521
+ override func nextObject( ) -> Any ? {
2442
2522
func match( filename: String , to options: DirectoryEnumerationOptions , isDir: Bool ) -> ( Bool , Bool ) {
2443
2523
var showFile = true
2444
2524
var skipDescendants = false
@@ -2459,10 +2539,10 @@ extension FileManager {
2459
2539
2460
2540
2461
2541
if let stream = _stream {
2462
-
2542
+
2463
2543
if !_gotRoot {
2464
2544
_gotRoot = true
2465
-
2545
+
2466
2546
// Skip the root.
2467
2547
_current = fts_read ( stream)
2468
2548
}
@@ -2504,7 +2584,7 @@ extension FileManager {
2504
2584
_current = fts_read ( stream)
2505
2585
}
2506
2586
// TODO: Error handling if fts_read fails.
2507
-
2587
+
2508
2588
} else if let error = _rootError {
2509
2589
// Was there an error opening the stream?
2510
2590
if let handler = _errorHandler {
@@ -2513,24 +2593,21 @@ extension FileManager {
2513
2593
}
2514
2594
return nil
2515
2595
}
2516
-
2517
- override var directoryAttributes : [ FileAttributeKey : Any ] ? {
2518
- return nil
2519
- }
2520
-
2521
- override var fileAttributes : [ FileAttributeKey : Any ] ? {
2522
- return nil
2523
- }
2524
-
2525
2596
override var level : Int {
2526
2597
return Int ( _current? . pointee. fts_level ?? 0 )
2527
2598
}
2528
-
2599
+
2529
2600
override func skipDescendants( ) {
2530
2601
if let stream = _stream, let current = _current {
2531
2602
fts_set ( stream, current, FTS_SKIP)
2532
2603
}
2533
2604
}
2534
- }
2535
2605
#endif
2606
+ override var directoryAttributes : [ FileAttributeKey : Any ] ? {
2607
+ return nil
2608
+ }
2609
+ override var fileAttributes : [ FileAttributeKey : Any ] ? {
2610
+ return nil
2611
+ }
2612
+ }
2536
2613
}
0 commit comments