2
2
//
3
3
// This source file is part of the Swift.org open source project
4
4
//
5
- // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5
+ // Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6
6
// Licensed under Apache License v2.0 with Runtime Library Exception
7
7
//
8
8
// See https://swift.org/LICENSE.txt for license information
20
20
// This file is shared between two projects:
21
21
//
22
22
// 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
24
24
//
25
25
// If you change this file, you must update it in both places.
26
26
@@ -176,7 +176,7 @@ extension String {
176
176
// + (instancetype)stringWithUTF8String:(const char *)bytes
177
177
178
178
/// 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.
180
180
public init ? ( utf8String bytes: UnsafePointer < CChar > ) {
181
181
if let str = String ( validatingUTF8: bytes) {
182
182
self = str
@@ -188,6 +188,54 @@ extension String {
188
188
return nil
189
189
}
190
190
}
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
+ }
191
239
}
192
240
193
241
extension String {
@@ -371,15 +419,16 @@ extension String {
371
419
// initWithCString:(const char *)nullTerminatedCString
372
420
// encoding:(NSStringEncoding)encoding
373
421
374
- /// Produces a string containing the bytes in a given C array,
375
- /// interpreted according to a given encoding.
376
- public init ? (
377
- cString: UnsafePointer < CChar > ,
378
- encoding enc: Encoding
379
- ) {
380
- if enc == . utf8, let str = String ( validatingUTF8: cString) {
381
- self = str
382
- return
422
+ /// Produces a string by copying the null-terminated bytes
423
+ /// in a given C array, interpreted according to a given encoding.
424
+ public init ? ( cString: UnsafePointer < CChar > , encoding enc: Encoding ) {
425
+ if enc == . utf8 || enc == . ascii {
426
+ if let str = String ( validatingUTF8: cString) {
427
+ if enc == . utf8 || str. _guts. _isContiguousASCII {
428
+ self = str
429
+ return
430
+ }
431
+ }
383
432
}
384
433
if let ns = NSString ( cString: cString, encoding: enc. rawValue) {
385
434
self = String . _unconditionallyBridgeFromObjectiveC ( ns)
@@ -388,6 +437,64 @@ extension String {
388
437
}
389
438
}
390
439
440
+ /// Produces a string by copying the null-terminated bytes
441
+ /// in a given array, interpreted according to a given encoding.
442
+ @_alwaysEmitIntoClient
443
+ public init ? ( cString: [ CChar ] , encoding enc: Encoding ) {
444
+ if enc == . utf8 || enc == . ascii {
445
+ // the stdlib's validatingUTF8 [CChar] overload checks for null termination.
446
+ if let str = String ( validatingUTF8: cString) {
447
+ if enc == . utf8 || str. _guts. _isContiguousASCII {
448
+ self = str
449
+ return
450
+ }
451
+ }
452
+ }
453
+ guard let nullPosition = cString. firstIndex ( of: 0 ) else {
454
+ fatalError (
455
+ " input of String.init(cString:encoding:) must be null-terminated "
456
+ )
457
+ }
458
+ let ns = cString. withUnsafeBytes {
459
+ NSString ( bytes: $0. baseAddress!,
460
+ length: nullPosition,
461
+ encoding: enc. rawValue)
462
+ }
463
+ guard let ns = ns else {
464
+ return nil
465
+ }
466
+ self = String . _unconditionallyBridgeFromObjectiveC ( ns)
467
+ }
468
+
469
+ @_alwaysEmitIntoClient
470
+ @available ( * , deprecated, message: " Use a copy of the String argument " )
471
+ public init ? ( cString: String , encoding enc: Encoding ) {
472
+ if enc == . utf8 || enc == . ascii {
473
+ var decoded = cString
474
+ decoded. makeContiguousUTF8 ( )
475
+ if let null = decoded. firstIndex ( of: " \0 " ) {
476
+ decoded = String ( decoded [ ..< null] )
477
+ }
478
+ if enc == . utf8 || decoded. utf8. allSatisfy ( { $0 < 128 } ) {
479
+ self = decoded
480
+ return
481
+ }
482
+ }
483
+ return nil
484
+ }
485
+
486
+ @_alwaysEmitIntoClient
487
+ @available ( * , deprecated, message: " Use String(_ scalar: Unicode.Scalar) " )
488
+ public init ? ( cString: inout CChar , encoding enc: Encoding ) {
489
+ // a byte interpreted as a buffer is valid only if the value is zero.
490
+ guard cString == 0 else {
491
+ fatalError (
492
+ " input of String.init(cString:encoding:) must be null-terminated "
493
+ )
494
+ }
495
+ self = " "
496
+ }
497
+
391
498
// FIXME: handle optional locale with default arguments
392
499
393
500
// - (instancetype)
@@ -465,7 +572,7 @@ extension String {
465
572
}
466
573
}
467
574
468
- extension StringProtocol where Index == String . Index {
575
+ extension StringProtocol {
469
576
//===--- Bridging Helpers -----------------------------------------------===//
470
577
//===--------------------------------------------------------------------===//
471
578
0 commit comments