@@ -11,27 +11,27 @@ import ReadiumShared
11
11
final class Paths {
12
12
private init ( ) { }
13
13
14
- static let home : URL =
15
- . init ( fileURLWithPath: NSHomeDirectory ( ) , isDirectory: true )
14
+ static let home : FileURL =
15
+ URL ( fileURLWithPath: NSHomeDirectory ( ) , isDirectory: true ) . fileURL!
16
16
17
- static let temporary : URL =
18
- . init ( fileURLWithPath: NSTemporaryDirectory ( ) , isDirectory: true )
17
+ static let temporary : FileURL =
18
+ URL ( fileURLWithPath: NSTemporaryDirectory ( ) , isDirectory: true ) . fileURL!
19
19
20
- static let documents : URL =
21
- FileManager . default. urls ( for: . documentDirectory, in: . userDomainMask) . first!
20
+ static let documents : FileURL =
21
+ FileManager . default. urls ( for: . documentDirectory, in: . userDomainMask) . first!. fileURL!
22
22
23
- static let library : URL =
24
- FileManager . default. urls ( for: . libraryDirectory, in: . userDomainMask) . first!
23
+ static let library : FileURL =
24
+ FileManager . default. urls ( for: . libraryDirectory, in: . userDomainMask) . first!. fileURL!
25
25
26
- static let covers : URL = {
27
- let url = library. appendingPathComponent ( " Covers " )
28
- try ! FileManager . default. createDirectory ( at: url, withIntermediateDirectories: true )
26
+ static let covers : FileURL = {
27
+ let url = library. appendingPath ( " Covers " , isDirectory : true )
28
+ try ! FileManager . default. createDirectory ( at: url. url , withIntermediateDirectories: true )
29
29
return url
30
30
} ( )
31
31
32
- static func makeDocumentURL( for source: URL ? = nil , title: String ? , mediaType: MediaType ) -> URL {
32
+ static func makeDocumentURL( for source: FileURL ? = nil , title: String ? , mediaType: MediaType ) -> FileURL {
33
33
// Is the file already in Documents/?
34
- if let source = source, source . standardizedFileURL . deletingLastPathComponent ( ) == documents . standardizedFileURL {
34
+ if let source = source, documents . isParent ( of : source ) {
35
35
return source
36
36
} else {
37
37
let title = title. takeIf { !$0. isEmpty } ?? UUID ( ) . uuidString
@@ -41,12 +41,42 @@ final class Paths {
41
41
}
42
42
}
43
43
44
- static func makeTemporaryURL( ) -> URL {
44
+ static func makeTemporaryURL( ) -> FileURL {
45
45
temporary. appendingUniquePathComponent ( )
46
46
}
47
47
48
48
/// Returns whether the given `url` locates a file that is under the app's home directory.
49
- static func isAppFile( at url: URL ) -> Bool {
50
- home. isParentOf ( url)
49
+ static func isAppFile( at url: FileURL ) -> Bool {
50
+ home. isParent ( of: url)
51
+ }
52
+ }
53
+
54
+ extension FileURL {
55
+ func appendingUniquePathComponent( _ pathComponent: String ? = nil ) -> FileURL {
56
+ /// Returns the first path component matching the given `validation` closure.
57
+ /// Numbers are appended to the path component until a valid candidate is found.
58
+ func uniquify( _ pathComponent: String ? , validation: ( String ) -> Bool ) -> String {
59
+ let pathComponent = pathComponent ?? UUID ( ) . uuidString
60
+ var ext = ( pathComponent as NSString ) . pathExtension
61
+ if !ext. isEmpty {
62
+ ext = " . \( ext) "
63
+ }
64
+ let pathComponentWithoutExtension = ( pathComponent as NSString ) . deletingPathExtension
65
+
66
+ var candidate = pathComponent
67
+ var i = 0
68
+ while !validation( candidate) {
69
+ i += 1
70
+ candidate = " \( pathComponentWithoutExtension) \( i) \( ext) "
71
+ }
72
+ return candidate
73
+ }
74
+
75
+ let pathComponent = uniquify ( pathComponent) { candidate in
76
+ let destination = appendingPath ( candidate, isDirectory: false )
77
+ return !( ( try ? destination. url. checkResourceIsReachable ( ) ) ?? false )
78
+ }
79
+
80
+ return appendingPath ( pathComponent, isDirectory: false )
51
81
}
52
82
}
0 commit comments