22//
33// This source file is part of the Swift.org open source project
44//
5- // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5+ // Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
66// Licensed under Apache License v2.0 with Runtime Library Exception
77//
88// See https://swift.org/LICENSE.txt for license information
2020// This file is shared between two projects:
2121//
2222// 1. https://github.com/apple/swift/tree/master/stdlib/public/Darwin/Foundation
23- // 2. https://github.com/apple/swift-corelibs-foundation/tree/master /Foundation
23+ // 2. https://github.com/apple/swift-corelibs-foundation/tree/main /Foundation
2424//
2525// If you change this file, you must update it in both places.
2626
@@ -176,7 +176,7 @@ extension String {
176176 // + (instancetype)stringWithUTF8String:(const char *)bytes
177177
178178 /// Creates a string by copying the data from a given
179- /// C array of UTF8-encoded bytes.
179+ /// null-terminated C array of UTF8-encoded bytes.
180180 public init ? ( utf8String bytes: UnsafePointer < CChar > ) {
181181 if let str = String ( validatingUTF8: bytes) {
182182 self = str
@@ -188,6 +188,54 @@ extension String {
188188 return nil
189189 }
190190 }
191+
192+ /// Creates a string by copying the data from a given
193+ /// null-terminated array of UTF8-encoded bytes.
194+ @_alwaysEmitIntoClient
195+ public init ? ( utf8String bytes: [ CChar ] ) {
196+ // the stdlib's validatingUTF8 [CChar] overload checks for null termination.
197+ if let str = String ( validatingUTF8: bytes) {
198+ self = str
199+ return
200+ }
201+ guard let nullPosition = bytes. firstIndex ( of: 0 ) else {
202+ fatalError (
203+ " input of String.init(utf8String:) must be null-terminated "
204+ )
205+ }
206+ let ns = bytes. withUnsafeBytes {
207+ NSString ( bytes: $0. baseAddress!,
208+ length: nullPosition,
209+ encoding: Encoding . utf8. rawValue)
210+ }
211+ guard let ns = ns else {
212+ return nil
213+ }
214+ self = String . _unconditionallyBridgeFromObjectiveC ( ns)
215+ }
216+
217+ @_alwaysEmitIntoClient
218+ @available ( * , deprecated, message: " Use a copy of the String argument " )
219+ public init ? ( utf8String bytes: String ) {
220+ var decoded = bytes
221+ decoded. makeContiguousUTF8 ( )
222+ if let null = decoded. firstIndex ( of: " \0 " ) {
223+ decoded = String ( decoded [ ..< null] )
224+ }
225+ self = decoded
226+ }
227+
228+ @_alwaysEmitIntoClient
229+ @available ( * , deprecated, message: " Use String(_ scalar: Unicode.Scalar) " )
230+ public init ? ( utf8String bytes: inout CChar ) {
231+ // a byte interpreted as a buffer is valid only if the value is zero.
232+ guard bytes == 0 else {
233+ fatalError (
234+ " input of String.init(utf8String:) must be null-terminated "
235+ )
236+ }
237+ self = " "
238+ }
191239}
192240
193241extension String {
@@ -369,15 +417,16 @@ extension String {
369417 // initWithCString:(const char *)nullTerminatedCString
370418 // encoding:(NSStringEncoding)encoding
371419
372- /// Produces a string containing the bytes in a given C array,
373- /// interpreted according to a given encoding.
374- public init ? (
375- cString: UnsafePointer < CChar > ,
376- encoding enc: Encoding
377- ) {
378- if enc == . utf8, let str = String ( validatingUTF8: cString) {
379- self = str
380- return
420+ /// Produces a string by copying the null-terminated bytes
421+ /// in a given C array, interpreted according to a given encoding.
422+ public init ? ( cString: UnsafePointer < CChar > , encoding enc: Encoding ) {
423+ if enc == . utf8 || enc == . ascii {
424+ if let str = String ( validatingUTF8: cString) {
425+ if enc == . utf8 || str. _guts. _isContiguousASCII {
426+ self = str
427+ return
428+ }
429+ }
381430 }
382431 if let ns = NSString ( cString: cString, encoding: enc. rawValue) {
383432 self = String . _unconditionallyBridgeFromObjectiveC ( ns)
@@ -386,6 +435,64 @@ extension String {
386435 }
387436 }
388437
438+ /// Produces a string by copying the null-terminated bytes
439+ /// in a given array, interpreted according to a given encoding.
440+ @_alwaysEmitIntoClient
441+ public init ? ( cString: [ CChar ] , encoding enc: Encoding ) {
442+ if enc == . utf8 || enc == . ascii {
443+ // the stdlib's validatingUTF8 [CChar] overload checks for null termination.
444+ if let str = String ( validatingUTF8: cString) {
445+ if enc == . utf8 || str. _guts. _isContiguousASCII {
446+ self = str
447+ return
448+ }
449+ }
450+ }
451+ guard let nullPosition = cString. firstIndex ( of: 0 ) else {
452+ fatalError (
453+ " input of String.init(cString:encoding:) must be null-terminated "
454+ )
455+ }
456+ let ns = cString. withUnsafeBytes {
457+ NSString ( bytes: $0. baseAddress!,
458+ length: nullPosition,
459+ encoding: enc. rawValue)
460+ }
461+ guard let ns = ns else {
462+ return nil
463+ }
464+ self = String . _unconditionallyBridgeFromObjectiveC ( ns)
465+ }
466+
467+ @_alwaysEmitIntoClient
468+ @available ( * , deprecated, message: " Use a copy of the String argument " )
469+ public init ? ( cString: String , encoding enc: Encoding ) {
470+ if enc == . utf8 || enc == . ascii {
471+ var decoded = cString
472+ decoded. makeContiguousUTF8 ( )
473+ if let null = decoded. firstIndex ( of: " \0 " ) {
474+ decoded = String ( decoded [ ..< null] )
475+ }
476+ if enc == . utf8 || decoded. utf8. allSatisfy ( { $0 < 128 } ) {
477+ self = decoded
478+ return
479+ }
480+ }
481+ return nil
482+ }
483+
484+ @_alwaysEmitIntoClient
485+ @available ( * , deprecated, message: " Use String(_ scalar: Unicode.Scalar) " )
486+ public init ? ( cString: inout CChar , encoding enc: Encoding ) {
487+ // a byte interpreted as a buffer is valid only if the value is zero.
488+ guard cString == 0 else {
489+ fatalError (
490+ " input of String.init(cString:encoding:) must be null-terminated "
491+ )
492+ }
493+ self = " "
494+ }
495+
389496 // FIXME: handle optional locale with default arguments
390497
391498 // - (instancetype)
@@ -463,7 +570,7 @@ extension String {
463570 }
464571}
465572
466- extension StringProtocol where Index == String . Index {
573+ extension StringProtocol {
467574 //===--- Bridging Helpers -----------------------------------------------===//
468575 //===--------------------------------------------------------------------===//
469576
0 commit comments