Skip to content

Commit 5acae43

Browse files
authored
Merge pull request #1890 from spevans/pr_sr_7455_42
2 parents f7e9cd8 + adb7935 commit 5acae43

File tree

9 files changed

+118
-18
lines changed

9 files changed

+118
-18
lines changed

DarwinCompatibilityTests.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
B917D32620B0DE2000728EE0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = B917D32520B0DE2000728EE0 /* main.swift */; };
1313
B95788861F6FB9470003EB01 /* TestNSNumberBridging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B95788851F6FB9470003EB01 /* TestNSNumberBridging.swift */; };
1414
B9C89ED21F6BF67C00087AF4 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9C89ED11F6BF67C00087AF4 /* XCTest.framework */; };
15+
B987C65E2093C8AF0026B50D /* TestImports.swift in Sources */ = {isa = PBXBuildFile; fileRef = B987C65D2093C8AF0026B50D /* TestImports.swift */; };
16+
B98E33E02136AC120044EBE9 /* TestFileWithZeros.txt in Resources */ = {isa = PBXBuildFile; fileRef = B98E33DF2136AC120044EBE9 /* TestFileWithZeros.txt */; };
1517
B9C89F361F6BF89C00087AF4 /* TestScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C89EE61F6BF88F00087AF4 /* TestScanner.swift */; };
1618
B9C89F371F6BF89C00087AF4 /* TestNSValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C89EE71F6BF88F00087AF4 /* TestNSValue.swift */; };
1719
B9C89F381F6BF89C00087AF4 /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C89EE81F6BF88F00087AF4 /* TestUtils.swift */; };
@@ -132,6 +134,8 @@
132134
B917D32520B0DE2000728EE0 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = main.swift; path = TestFoundation/xdgTestHelper/main.swift; sourceTree = "<group>"; };
133135
B95788851F6FB9470003EB01 /* TestNSNumberBridging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TestNSNumberBridging.swift; path = TestFoundation/TestNSNumberBridging.swift; sourceTree = "<group>"; };
134136
B9C89EC11F6BF47D00087AF4 /* DarwinCompatibilityTests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DarwinCompatibilityTests; sourceTree = BUILT_PRODUCTS_DIR; };
137+
B987C65D2093C8AF0026B50D /* TestImports.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TestImports.swift; path = TestFoundation/TestImports.swift; sourceTree = "<group>"; };
138+
B98E33DF2136AC120044EBE9 /* TestFileWithZeros.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TestFileWithZeros.txt; path = TestFoundation/Resources/TestFileWithZeros.txt; sourceTree = "<group>"; };
135139
B9C89ED11F6BF67C00087AF4 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
136140
B9C89ED71F6BF77E00087AF4 /* DarwinCompatibilityTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DarwinCompatibilityTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
137141
B9C89EDB1F6BF77E00087AF4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -283,6 +287,10 @@
283287
B9C89FA91F6DCAE700087AF4 /* NSXMLDTDTestData.xml */,
284288
B9C89FB81F6DCAEB00087AF4 /* PropertyList-1.0.dtd */,
285289
B9C89FB91F6DCAEB00087AF4 /* Test.plist */,
290+
B98E33DF2136AC120044EBE9 /* TestFileWithZeros.txt */,
291+
B917D32520B0DE2000728EE0 /* main.swift */,
292+
B987C65D2093C8AF0026B50D /* TestImports.swift */,
293+
B95788851F6FB9470003EB01 /* TestNSNumberBridging.swift */,
286294
B9C89F891F6D4D9D00087AF4 /* HTTPServer.swift */,
287295
B9C89F321F6BF89B00087AF4 /* TestAffineTransform.swift */,
288296
B9C89EFB1F6BF89200087AF4 /* TestBundle.swift */,
@@ -486,6 +494,7 @@
486494
B9C89FC11F6DCAEB00087AF4 /* Info.plist in Resources */,
487495
B9C89FC21F6DCAEB00087AF4 /* NSKeyedUnarchiver-ArrayTest.plist in Resources */,
488496
B9C89FC31F6DCAEB00087AF4 /* NSStringTestData.txt in Resources */,
497+
B98E33E02136AC120044EBE9 /* TestFileWithZeros.txt in Resources */,
489498
B9C89FC41F6DCAEB00087AF4 /* NSKeyedUnarchiver-OrderedSetTest.plist in Resources */,
490499
B9C89FC51F6DCAEB00087AF4 /* NSString-UTF32-BE-data.txt in Resources */,
491500
B9C89FC61F6DCAEB00087AF4 /* NSKeyedUnarchiver-URLTest.plist in Resources */,
@@ -515,6 +524,7 @@
515524
isa = PBXSourcesBuildPhase;
516525
buildActionMask = 2147483647;
517526
files = (
527+
B987C65E2093C8AF0026B50D /* TestImports.swift in Sources */,
518528
B95788861F6FB9470003EB01 /* TestNSNumberBridging.swift in Sources */,
519529
B9C89F8B1F6D4DA900087AF4 /* HTTPServer.swift in Sources */,
520530
B9C89F8C1F6D4DA900087AF4 /* TestHTTPCookieStorage.swift in Sources */,

Foundation.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@
338338
B933A79E1F3055F700FE6846 /* NSString-UTF32-BE-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = B933A79C1F3055F600FE6846 /* NSString-UTF32-BE-data.txt */; };
339339
B933A79F1F3055F700FE6846 /* NSString-UTF32-LE-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = B933A79D1F3055F600FE6846 /* NSString-UTF32-LE-data.txt */; };
340340
B951B5EC1F4E2A2000D8B332 /* TestNSLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B951B5EB1F4E2A2000D8B332 /* TestNSLock.swift */; };
341+
B98E33DD2136AA740044EBE9 /* TestFileWithZeros.txt in Resources */ = {isa = PBXBuildFile; fileRef = B98E33DC2136AA740044EBE9 /* TestFileWithZeros.txt */; };
341342
B9974B961EDF4A22007F15B8 /* TransferState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9974B8F1EDF4A22007F15B8 /* TransferState.swift */; };
342343
B9974B971EDF4A22007F15B8 /* MultiHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9974B901EDF4A22007F15B8 /* MultiHandle.swift */; };
343344
B9974B981EDF4A22007F15B8 /* libcurlHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9974B911EDF4A22007F15B8 /* libcurlHelpers.swift */; };
@@ -821,6 +822,7 @@
821822
B933A79C1F3055F600FE6846 /* NSString-UTF32-BE-data.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NSString-UTF32-BE-data.txt"; sourceTree = "<group>"; };
822823
B933A79D1F3055F600FE6846 /* NSString-UTF32-LE-data.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NSString-UTF32-LE-data.txt"; sourceTree = "<group>"; };
823824
B951B5EB1F4E2A2000D8B332 /* TestNSLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestNSLock.swift; sourceTree = "<group>"; };
825+
B98E33DC2136AA740044EBE9 /* TestFileWithZeros.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TestFileWithZeros.txt; sourceTree = "<group>"; };
824826
B9974B8F1EDF4A22007F15B8 /* TransferState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransferState.swift; sourceTree = "<group>"; };
825827
B9974B901EDF4A22007F15B8 /* MultiHandle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiHandle.swift; sourceTree = "<group>"; };
826828
B9974B911EDF4A22007F15B8 /* libcurlHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = libcurlHelpers.swift; sourceTree = "<group>"; };
@@ -1446,6 +1448,7 @@
14461448
EA66F6391BF1619600136161 /* Resources */ = {
14471449
isa = PBXGroup;
14481450
children = (
1451+
B98E33DC2136AA740044EBE9 /* TestFileWithZeros.txt */,
14491452
D370696D1C394FBF00295652 /* NSKeyedUnarchiver-RangeTest.plist */,
14501453
D3E8D6D41C36AC0C00295652 /* NSKeyedUnarchiver-RectTest.plist */,
14511454
D3E8D6D21C36982700295652 /* NSKeyedUnarchiver-EdgeInsetsTest.plist */,
@@ -2143,6 +2146,7 @@
21432146
isa = PBXResourcesBuildPhase;
21442147
buildActionMask = 2147483647;
21452148
files = (
2149+
B98E33DD2136AA740044EBE9 /* TestFileWithZeros.txt in Resources */,
21462150
B933A79E1F3055F700FE6846 /* NSString-UTF32-BE-data.txt in Resources */,
21472151
B933A79F1F3055F700FE6846 /* NSString-UTF32-LE-data.txt in Resources */,
21482152
D3A597F41C34142600295652 /* NSKeyedUnarchiver-NotificationTest.plist in Resources */,

Foundation/String.swift

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,31 @@ extension String : _ObjectiveCBridgeable {
2929
result = source._storage
3030
} else if type(of: source) == _NSCFString.self {
3131
let cf = unsafeBitCast(source, to: CFString.self)
32-
if let str = CFStringGetCStringPtr(cf, CFStringEncoding(kCFStringEncodingUTF8)) {
33-
result = String(cString: str)
32+
let length = CFStringGetLength(cf)
33+
if length == 0 {
34+
result = ""
35+
} else if let ptr = CFStringGetCStringPtr(cf, CFStringEncoding(kCFStringEncodingASCII)) {
36+
// ASCII encoding has 1 byte per code point and CFStringGetLength() returned the length in
37+
// codepoints so length should be the length of the ASCII string in bytes. We cant ask for the UTF-8
38+
// encoding as some codepoints are multi-byte in UTF8 so the buffer length wouldn't be known.
39+
// Note: CFStringGetCStringPtr(cf, CFStringEncoding(kCFStringEncodingUTF8)) does seems to return NULL
40+
// for strings with multibyte UTF-8 but this isnt guaranteed or documented so ASCII is safer.
41+
result = ptr.withMemoryRebound(to: UInt8.self, capacity: length) {
42+
return String(decoding: UnsafeBufferPointer(start: $0, count: length), as: UTF8.self)
43+
}
44+
} else if let ptr = CFStringGetCharactersPtr(cf) {
45+
result = String(decoding: UnsafeBufferPointer(start: ptr, count: length), as: UTF16.self)
3446
} else {
35-
let length = CFStringGetLength(cf)
3647
let buffer = UnsafeMutablePointer<UniChar>.allocate(capacity: length)
3748
CFStringGetCharacters(cf, CFRangeMake(0, length), buffer)
3849

39-
let str = String(decoding: UnsafeBufferPointer(start: buffer, count: length), as: UTF16.self)
50+
result = String(decoding: UnsafeBufferPointer(start: buffer, count: length), as: UTF16.self)
4051
buffer.deinitialize(count: length)
4152
buffer.deallocate()
42-
result = str
4353
}
4454
} else if type(of: source) == _NSCFConstantString.self {
4555
let conststr = unsafeDowncast(source, to: _NSCFConstantString.self)
46-
let str = String(decoding: UnsafeBufferPointer(start: conststr._ptr, count: Int(conststr._length)), as: UTF8.self)
47-
result = str
56+
result = String(decoding: UnsafeBufferPointer(start: conststr._ptr, count: Int(conststr._length)), as: UTF8.self)
4857
} else {
4958
let len = source.length
5059
var characters = [unichar](repeating: 0, count: len)
45 Bytes
Binary file not shown.

TestFoundation/TestJSONSerialization.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,7 @@ extension TestJSONSerialization {
13671367
let result = try JSONSerialization.writeJSONObject(dict, toStream: outputStream, options: [])
13681368
outputStream.close()
13691369
if(result > -1) {
1370-
XCTAssertEqual(NSString(bytes: buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue), "{\"a\":{\"b\":1}}")
1370+
XCTAssertEqual(NSString(bytes: buffer, length: buffer.firstIndex(of: 0) ?? buffer.count, encoding: String.Encoding.utf8.rawValue), "{\"a\":{\"b\":1}}")
13711371
}
13721372
} catch {
13731373
XCTFail("Error thrown: \(error)")
@@ -1390,7 +1390,7 @@ extension TestJSONSerialization {
13901390
let resultRead: Int = fileStream.read(&buffer, maxLength: buffer.count)
13911391
fileStream.close()
13921392
if(resultRead > -1){
1393-
XCTAssertEqual(NSString(bytes: buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue), "{\"a\":{\"b\":1}}")
1393+
XCTAssertEqual(NSString(bytes: buffer, length: buffer.firstIndex(of: 0) ?? buffer.count, encoding: String.Encoding.utf8.rawValue), "{\"a\":{\"b\":1}}")
13941394
}
13951395
}
13961396
removeTestFile(filePath)

TestFoundation/TestNSData.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,11 +1466,12 @@ extension TestNSData {
14661466
if let contents = contents {
14671467
XCTAssertTrue(contents.length > 0)
14681468
let ptr = UnsafeMutableRawPointer(mutating: contents.bytes)
1469-
let str = String(bytesNoCopy: ptr, length: contents.length,
1470-
encoding: .ascii, freeWhenDone: false)
1471-
XCTAssertNotNil(str)
1472-
if let str = str {
1469+
var zeroIdx = contents.range(of: Data([0]), in: NSMakeRange(0, contents.length)).location
1470+
if zeroIdx == NSNotFound { zeroIdx = contents.length }
1471+
if let str = String(bytesNoCopy: ptr, length: zeroIdx, encoding: .ascii, freeWhenDone: false) {
14731472
XCTAssertTrue(str.hasSuffix("TestFoundation"))
1473+
} else {
1474+
XCTFail("Cant create String")
14741475
}
14751476
}
14761477

TestFoundation/TestNSString.swift

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class TestNSString: LoopbackServerTest {
3131

3232
static var allTests: [(String, (TestNSString) -> () throws -> Void)] {
3333
return [
34+
("test_initData", test_initData),
3435
("test_boolValue", test_boolValue ),
3536
("test_BridgeConstruction", test_BridgeConstruction ),
3637
("test_integerValue", test_integerValue ),
@@ -95,6 +96,70 @@ class TestNSString: LoopbackServerTest {
9596
]
9697
}
9798

99+
func test_initData() {
100+
let testString = "\u{00} This is a test string"
101+
let data = testString.data(using: .utf8)!
102+
XCTAssertEqual(data.count, 23)
103+
_ = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
104+
if let text1 = NSString(bytes: bytes , length: data.count, encoding: String.Encoding.utf8.rawValue) {
105+
XCTAssertEqual(text1.length, data.count)
106+
XCTAssertEqual(text1, testString as NSString)
107+
} else {
108+
XCTFail("Cant convert Data to NSString")
109+
}
110+
}
111+
112+
if let text2 = String(data: data, encoding: .utf8) {
113+
XCTAssertEqual(text2.count, data.count)
114+
XCTAssertEqual(text2, testString)
115+
} else {
116+
XCTFail("Cant convert Data to String")
117+
}
118+
119+
// Test multibyte UTF8 and UTF16
120+
// kra ("ĸ") has codepoint value 312,
121+
// as UTF-8 bytes it is 0xC4 0xB8
122+
// as UTF-16 bytes it is 0x1, 0x38
123+
let kra = "ĸ"
124+
let utf8KraData = Data(bytes: [0xc4, 0xb8])
125+
if let utf8kra = utf8KraData.withUnsafeBytes( { (bytes: UnsafePointer<UInt8>) in
126+
return NSString(bytes: bytes, length: utf8KraData.count, encoding: String.Encoding.utf8.rawValue)
127+
}) {
128+
XCTAssertEqual(kra.count, 1)
129+
XCTAssertEqual(kra.utf8.count, 2)
130+
XCTAssertEqual(kra.utf16.count, 1)
131+
XCTAssertEqual(kra, utf8kra as String)
132+
} else {
133+
XCTFail("Cant create UTF8 kra")
134+
}
135+
136+
let utf16KraData = Data(bytes: [0x1, 0x38])
137+
if let utf16kra = utf16KraData.withUnsafeBytes( { (bytes: UnsafePointer<UInt8>) in
138+
return NSString(bytes: bytes, length: utf16KraData.count, encoding: String.Encoding.utf16.rawValue)
139+
}) {
140+
XCTAssertEqual(kra.count, 1)
141+
XCTAssertEqual(kra.utf8.count, 2)
142+
XCTAssertEqual(kra.utf16.count, 1)
143+
XCTAssertEqual(kra, utf16kra as String)
144+
} else {
145+
XCTFail("Cant create UTF16 kra")
146+
}
147+
148+
// Test a large string > 255 characters
149+
let largeString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut at tincidunt arcu. Suspendisse nec sodales erat, sit amet imperdiet ipsum. Etiam sed ornare felis. Nunc mauris turpis, bibendum non lectus quis, malesuada placerat turpis. Nam adipiscing non massa et semper. Nulla convallis semper bibendum."
150+
XCTAssertTrue(largeString.count > 255)
151+
let largeData = largeString.data(using: .utf8)!
152+
if let largeText = largeData.withUnsafeBytes( { (bytes: UnsafePointer<UInt8>) in
153+
return NSString(bytes: bytes, length: largeData.count, encoding: String.Encoding.ascii.rawValue)
154+
}) {
155+
XCTAssertEqual(largeText.length, largeString.count)
156+
XCTAssertEqual(largeText.length, largeData.count)
157+
XCTAssertEqual(largeString, largeText as String)
158+
} else {
159+
XCTFail("Cant convert large Data string to String")
160+
}
161+
}
162+
98163
func test_boolValue() {
99164
let trueStrings: [NSString] = ["t", "true", "TRUE", "tRuE", "yes", "YES", "1", "+000009"]
100165
for string in trueStrings {
@@ -303,6 +368,16 @@ class TestNSString: LoopbackServerTest {
303368
if let contents = contents {
304369
XCTAssertEqual(contents, "This file is encoded as ISO-8859-1\nÀÁÂÃÄÅÿ\n±\n")
305370
}
371+
372+
guard let zeroFileURL = testBundle().url(forResource: "TestFileWithZeros", withExtension: "txt") else {
373+
XCTFail("Cant get URL for TestFileWithZeros.txt")
374+
return
375+
}
376+
guard let zeroString = try? String(contentsOf: zeroFileURL, encoding: .utf8) else {
377+
XCTFail("Cant create string from \(zeroFileURL)")
378+
return
379+
}
380+
XCTAssertEqual(zeroString, "Some\u{00}text\u{00}with\u{00}NUL\u{00}bytes\u{00}instead\u{00}of\u{00}spaces.\u{00}\n")
306381
}
307382

308383
func test_FromContentOfFileUsedEncodingIgnored() {

TestFoundation/TestStream.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class TestStream : XCTestCase {
3636
let result: Int = dataStream.read(&buffer, maxLength: buffer.count)
3737
dataStream.close()
3838
XCTAssertEqual(Stream.Status.closed, dataStream.streamStatus)
39-
if(result > 0){
40-
let output = NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue)
39+
if(result > 0) {
40+
let output = NSString(bytes: &buffer, length: buffer.firstIndex(of: 0) ?? buffer.count, encoding: String.Encoding.utf8.rawValue)
4141
XCTAssertEqual(message, output!)
4242
}
4343
}
@@ -64,7 +64,7 @@ class TestStream : XCTestCase {
6464
XCTAssertEqual(Stream.Status.closed, urlStream.streamStatus)
6565
XCTAssertEqual(messageData.count, result)
6666
if(result > 0) {
67-
let output = NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue)
67+
let output = NSString(bytes: &buffer, length: buffer.firstIndex(of: 0) ?? buffer.count, encoding: String.Encoding.utf8.rawValue)
6868
XCTAssertEqual(message, output!)
6969
}
7070
}
@@ -90,8 +90,8 @@ class TestStream : XCTestCase {
9090
fileStream.close()
9191
XCTAssertEqual(Stream.Status.closed, fileStream.streamStatus)
9292
XCTAssertEqual(messageData.count, result)
93-
if(result > 0){
94-
let output = NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue)
93+
if(result > 0) {
94+
let output = NSString(bytes: &buffer, length: buffer.firstIndex(of: 0) ?? buffer.count, encoding: String.Encoding.utf8.rawValue)
9595
XCTAssertEqual(message, output!)
9696
}
9797
}

build.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@
515515
'TestFoundation/Resources/NSKeyedUnarchiver-URLTest.plist',
516516
'TestFoundation/Resources/NSKeyedUnarchiver-UUIDTest.plist',
517517
'TestFoundation/Resources/NSKeyedUnarchiver-OrderedSetTest.plist',
518+
'TestFoundation/Resources/TestFileWithZeros.txt',
518519
])
519520

520521
# TODO: Probably this should be another 'product', but for now it's simply a phase

0 commit comments

Comments
 (0)