Skip to content

Commit 5a990a9

Browse files
authored
(180053987) Return CFString from certain Swift CFURL methods to avoid bridging (#2060)
1 parent c617f18 commit 5a990a9

3 files changed

Lines changed: 29 additions & 14 deletions

File tree

Sources/FoundationEssentials/URL/URL_C+Encoding.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ extension NSURL {
109109
return URLEncoder.percentEncode(string: path, encoding: encoding, component: component, skipAlreadyEncoded: false)
110110
}
111111

112-
static func __copySwiftEncodedFSRPath(_ path: String) -> String? {
112+
static func __copySwiftEncodedFSRPath(_ path: String) -> Unmanaged<CFString>? {
113113
guard !path.isEmpty else {
114-
return path
114+
return _createCFStringFromASCIIString(path)
115115
}
116116
// Convert path to its decomposed file system representation then encode
117117
let maxFSRSize = 3 * path.utf8.count
118-
return withUnsafeTemporaryAllocation(of: UInt8.self, capacity: maxFSRSize) { pathBuffer -> String? in
118+
return withUnsafeTemporaryAllocation(of: UInt8.self, capacity: maxFSRSize) { pathBuffer in
119119
guard var pathLength = path._decomposed(.hfsPlus, into: pathBuffer) else {
120120
return nil
121121
}
@@ -124,15 +124,14 @@ extension NSURL {
124124
while pathLength > rootLength && pathBuffer[pathLength - 1] == UInt8(ascii: "/") {
125125
pathLength -= 1
126126
}
127-
return withUnsafeTemporaryAllocation(of: UInt8.self, capacity: 3 * pathLength) { encodedBuffer in
128-
let encodedLength = URLEncoder.percentEncodeUnchecked(
127+
return _createCFStringFromASCIIBuffer(capacity: 3 * pathLength) { encodedBuffer in
128+
URLEncoder.percentEncodeUnchecked(
129129
input: UnsafeBufferPointer(rebasing: pathBuffer[..<pathLength]),
130130
output: encodedBuffer,
131131
// Encode ";" for compatibility
132132
component: .pathNoSemicolon,
133133
skipAlreadyEncoded: false
134134
)
135-
return String(decoding: encodedBuffer[..<encodedLength], as: UTF8.self)
136135
}
137136
}
138137
}

Sources/FoundationEssentials/URL/URL_C+File.swift

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,13 @@ extension NSURL {
3535
assert(false, "Unexpected path style: \(pathStyle)")
3636
return false
3737
}
38-
guard let urlString else {
38+
guard let urlString, let cfString = _createCFStringFromASCIIString(urlString) else {
3939
return false
4040
}
4141

4242
assert(flags.isDisjoint(with: .nonFileImplFlags))
4343
impl.pointee._header._flags = flags
44-
impl.pointee._header._string = Unmanaged<CFString>.passRetained(
45-
urlString as CFString
46-
)
44+
impl.pointee._header._string = cfString
4745
return true
4846
}
4947

@@ -55,15 +53,14 @@ extension NSURL {
5553

5654
var flags = __CFURLFlags.fileImplFlags
5755
let buffer = UnsafeBufferPointer(start: fsr, count: length)
58-
guard let urlString = parseFileSystemRepresentation(buffer: buffer, flags: &flags, isDirectory: isDirectory) else {
56+
guard let urlString = parseFileSystemRepresentation(buffer: buffer, flags: &flags, isDirectory: isDirectory),
57+
let cfString = _createCFStringFromASCIIString(urlString) else {
5958
return false
6059
}
6160

6261
assert(flags.isDisjoint(with: .nonFileImplFlags))
6362
impl.pointee._header._flags = flags
64-
impl.pointee._header._string = Unmanaged<CFString>.passRetained(
65-
urlString as CFString
66-
)
63+
impl.pointee._header._string = cfString
6764
return true
6865
}
6966

Sources/FoundationEssentials/URL/URL_C+Spans.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,23 @@ internal func _createCFStringFromCharacterBuffer(
160160
}
161161
}
162162

163+
internal func _createCFStringFromASCIIString(_ string: String) -> Unmanaged<CFString>? {
164+
let ascii = CFStringBuiltInEncodings.ASCII.rawValue
165+
guard !string.isEmpty else {
166+
guard let empty = CFStringCreateWithCString(kCFAllocatorDefault, "", ascii) else {
167+
return nil
168+
}
169+
return Unmanaged.passRetained(empty)
170+
}
171+
var mut = string
172+
return mut.withUTF8 { utf8 in
173+
guard let result = CFStringCreateWithBytes(
174+
kCFAllocatorDefault, utf8.baseAddress!, utf8.count, ascii, false
175+
) else {
176+
return nil
177+
}
178+
return Unmanaged.passRetained(result)
179+
}
180+
}
181+
163182
#endif // FOUNDATION_FRAMEWORK

0 commit comments

Comments
 (0)