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 {
@@ -369,15 +417,16 @@ extension String {
369
417
// initWithCString:(const char *)nullTerminatedCString
370
418
// encoding:(NSStringEncoding)encoding
371
419
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
+ }
381
430
}
382
431
if let ns = NSString ( cString: cString, encoding: enc. rawValue) {
383
432
self = String . _unconditionallyBridgeFromObjectiveC ( ns)
@@ -386,6 +435,64 @@ extension String {
386
435
}
387
436
}
388
437
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
+
389
496
// FIXME: handle optional locale with default arguments
390
497
391
498
// - (instancetype)
@@ -463,7 +570,7 @@ extension String {
463
570
}
464
571
}
465
572
466
- extension StringProtocol where Index == String . Index {
573
+ extension StringProtocol {
467
574
//===--- Bridging Helpers -----------------------------------------------===//
468
575
//===--------------------------------------------------------------------===//
469
576
0 commit comments