|
7 | 7 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
8 | 8 | // |
9 | 9 |
|
10 | | - |
| 10 | +@_spi(SwiftCorelibsFoundation) @_exported import FoundationEssentials |
11 | 11 | @_implementationOnly import CoreFoundation |
12 | 12 | internal import Synchronization |
13 | 13 |
|
@@ -160,32 +160,19 @@ internal func _createRegexForPattern(_ pattern: String, _ options: NSRegularExpr |
160 | 160 | return regex |
161 | 161 | } |
162 | 162 |
|
163 | | -internal func _bytesInEncoding(_ str: NSString, _ encoding: String.Encoding, _ fatalOnError: Bool, _ externalRep: Bool, _ lossy: Bool) -> UnsafePointer<Int8>? { |
164 | | - let theRange = NSRange(location: 0, length: str.length) |
| 163 | +// Caller must free, or leak, the pointer |
| 164 | +fileprivate func _allocateBytesInEncoding(_ str: NSString, _ encoding: String.Encoding) -> UnsafeMutableBufferPointer<Int8>? { |
| 165 | + let theRange: NSRange = NSRange(location: 0, length: str.length) |
165 | 166 | var cLength = 0 |
166 | | - var used = 0 |
167 | | - var options: NSString.EncodingConversionOptions = [] |
168 | | - if externalRep { |
169 | | - options.formUnion(.externalRepresentation) |
170 | | - } |
171 | | - if lossy { |
172 | | - options.formUnion(.allowLossy) |
173 | | - } |
174 | | - if !str.getBytes(nil, maxLength: Int.max - 1, usedLength: &cLength, encoding: encoding.rawValue, options: options, range: theRange, remaining: nil) { |
175 | | - if fatalOnError { |
176 | | - fatalError("Conversion on encoding failed") |
177 | | - } |
| 167 | + if !str.getBytes(nil, maxLength: Int.max - 1, usedLength: &cLength, encoding: encoding.rawValue, options: [], range: theRange, remaining: nil) { |
178 | 168 | return nil |
179 | 169 | } |
180 | 170 |
|
181 | | - let buffer = malloc(cLength + 1)!.bindMemory(to: Int8.self, capacity: cLength + 1) |
182 | | - if !str.getBytes(buffer, maxLength: cLength, usedLength: &used, encoding: encoding.rawValue, options: options, range: theRange, remaining: nil) { |
183 | | - fatalError("Internal inconsistency; previously claimed getBytes returned success but failed with similar invocation") |
184 | | - } |
| 171 | + let buffer = UnsafeMutableBufferPointer<Int8>.allocate(capacity: cLength + 1) |
| 172 | + buffer.initialize(repeating: 0) |
| 173 | + _ = str.getBytes(buffer.baseAddress, maxLength: cLength, usedLength: nil, encoding: encoding.rawValue, options: [], range: theRange, remaining: nil) |
185 | 174 |
|
186 | | - buffer.advanced(by: cLength).initialize(to: 0) |
187 | | - |
188 | | - return UnsafePointer(buffer) // leaked and should be autoreleased via a NSData backing but we cannot here |
| 175 | + return buffer |
189 | 176 | } |
190 | 177 |
|
191 | 178 | internal func isALineSeparatorTypeCharacter(_ ch: unichar) -> Bool { |
@@ -903,8 +890,13 @@ extension NSString { |
903 | 890 | } |
904 | 891 | } |
905 | 892 |
|
| 893 | + @available(*, deprecated, message: "On platforms without Objective-C autorelease pools, use withCString instead") |
906 | 894 | public var utf8String: UnsafePointer<Int8>? { |
907 | | - return _bytesInEncoding(self, .utf8, false, false, false) |
| 895 | + guard let buffer = _allocateBytesInEncoding(self, .utf8) else { |
| 896 | + return nil |
| 897 | + } |
| 898 | + // leaked. On Darwin, freed via an autorelease |
| 899 | + return UnsafePointer<Int8>(buffer.baseAddress) |
908 | 900 | } |
909 | 901 |
|
910 | 902 | public var fastestEncoding: UInt { |
@@ -961,8 +953,24 @@ extension NSString { |
961 | 953 | 0, nil, 0, nil) == length |
962 | 954 | } |
963 | 955 |
|
964 | | - public func cString(using encoding: UInt) -> UnsafePointer<Int8>? { |
965 | | - return _bytesInEncoding(self, String.Encoding(rawValue: encoding), false, false, false) |
| 956 | + @available(*, deprecated, message: "On platforms without Objective-C autorelease pools, use withCString(encodedAs:_) instead") |
| 957 | + public func cString(using encoding: UInt) -> UnsafePointer<Int8>? { |
| 958 | + // leaked. On Darwin, freed via an autorelease |
| 959 | + guard let buffer = _allocateBytesInEncoding(self, String.Encoding(rawValue: encoding)) else { |
| 960 | + return nil |
| 961 | + } |
| 962 | + // leaked. On Darwin, freed via an autorelease |
| 963 | + return UnsafePointer<Int8>(buffer.baseAddress) |
| 964 | + } |
| 965 | + |
| 966 | + internal func _withCString<T>(using encoding: UInt, closure: (UnsafePointer<Int8>?) -> T) -> T { |
| 967 | + let buffer = _allocateBytesInEncoding(self, String.Encoding(rawValue: encoding)) |
| 968 | + let result = closure(buffer?.baseAddress) |
| 969 | + if let buffer { |
| 970 | + buffer.deinitialize() |
| 971 | + buffer.deallocate() |
| 972 | + } |
| 973 | + return result |
966 | 974 | } |
967 | 975 |
|
968 | 976 | public func getCString(_ buffer: UnsafeMutablePointer<Int8>, maxLength maxBufferCount: Int, encoding: UInt) -> Bool { |
@@ -1258,16 +1266,29 @@ extension NSString { |
1258 | 1266 | data = mData |
1259 | 1267 | } |
1260 | 1268 |
|
| 1269 | + #if os(WASI) |
| 1270 | + @available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories") |
| 1271 | + #endif |
1261 | 1272 | internal func _writeTo(_ url: URL, _ useAuxiliaryFile: Bool, _ enc: UInt) throws { |
| 1273 | + #if os(WASI) |
| 1274 | + throw CocoaError(.featureUnsupported) |
| 1275 | + #else |
1262 | 1276 | var data = Data() |
1263 | 1277 | try _getExternalRepresentation(&data, url, enc) |
1264 | 1278 | try data.write(to: url, options: useAuxiliaryFile ? .atomic : []) |
| 1279 | + #endif |
1265 | 1280 | } |
1266 | 1281 |
|
| 1282 | + #if os(WASI) |
| 1283 | + @available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories") |
| 1284 | + #endif |
1267 | 1285 | public func write(to url: URL, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws { |
1268 | 1286 | try _writeTo(url, useAuxiliaryFile, enc) |
1269 | 1287 | } |
1270 | 1288 |
|
| 1289 | + #if os(WASI) |
| 1290 | + @available(*, unavailable, message: "WASI does not support atomic file-writing as it does not have temporary directories") |
| 1291 | + #endif |
1271 | 1292 | public func write(toFile path: String, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws { |
1272 | 1293 | try _writeTo(URL(fileURLWithPath: path), useAuxiliaryFile, enc) |
1273 | 1294 | } |
@@ -1669,3 +1690,14 @@ extension String : CVarArg, _CVarArgObject { |
1669 | 1690 | } |
1670 | 1691 | } |
1671 | 1692 | #endif |
| 1693 | + |
| 1694 | +// Upcall from swift-foundation for conversion of less frequently-used encodings |
| 1695 | +@_dynamicReplacement(for: _cfStringEncodingConvert(string:using:allowLossyConversion:)) |
| 1696 | +private func _cfStringEncodingConvert_corelibs_foundation(string: String, using encoding: UInt, allowLossyConversion: Bool) -> Data? { |
| 1697 | + return (string as NSString).data(using: encoding, allowLossyConversion: allowLossyConversion) |
| 1698 | +} |
| 1699 | + |
| 1700 | +@_dynamicReplacement(for: _cfMakeStringFromBytes(_:encoding:)) |
| 1701 | +private func _cfMakeStringFromBytes_corelibs_foundation(_ bytes: UnsafeBufferPointer<UInt8>, encoding: UInt) -> String? { |
| 1702 | + return NSString(bytes: bytes.baseAddress!, length: bytes.count, encoding: encoding) as? String |
| 1703 | +} |
0 commit comments