@@ -160,32 +160,19 @@ internal func _createRegexForPattern(_ pattern: String, _ options: NSRegularExpr
160160 return regex
161161}
162162
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)
165166 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 ) {
178168 return nil
179169 }
180170
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 )
185174
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
189176}
190177
191178internal func isALineSeparatorTypeCharacter( _ ch: unichar ) -> Bool {
@@ -903,8 +890,13 @@ extension NSString {
903890 }
904891 }
905892
893+ @available ( * , deprecated, message: " On platforms without Objective-C autorelease pools, use withCString instead " )
906894 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)
908900 }
909901
910902 public var fastestEncoding : UInt {
@@ -961,8 +953,24 @@ extension NSString {
961953 0 , nil , 0 , nil ) == length
962954 }
963955
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
966974 }
967975
968976 public func getCString( _ buffer: UnsafeMutablePointer < Int8 > , maxLength maxBufferCount: Int , encoding: UInt ) -> Bool {
0 commit comments