Skip to content
9 changes: 9 additions & 0 deletions DarwinCompatibilityTests.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
B907F36F20BB188800013CBE /* NSString-ISO-8859-1-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = B907F36E20BB188800013CBE /* NSString-ISO-8859-1-data.txt */; };
B917D32420B0DB9700728EE0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B917D32320B0DB9700728EE0 /* Foundation.framework */; };
B917D32620B0DE2000728EE0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = B917D32520B0DE2000728EE0 /* main.swift */; };
B95788861F6FB9470003EB01 /* TestNSNumberBridging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B95788851F6FB9470003EB01 /* TestNSNumberBridging.swift */; };
B9C89ED21F6BF67C00087AF4 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9C89ED11F6BF67C00087AF4 /* XCTest.framework */; };
B9C89F361F6BF89C00087AF4 /* TestScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C89EE61F6BF88F00087AF4 /* TestScanner.swift */; };
Expand Down Expand Up @@ -123,6 +126,10 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
B907F36E20BB188800013CBE /* NSString-ISO-8859-1-data.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "NSString-ISO-8859-1-data.txt"; path = "TestFoundation/Resources/NSString-ISO-8859-1-data.txt"; sourceTree = "<group>"; };
B917D31C20B0DB8B00728EE0 /* xdgTestHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xdgTestHelper; sourceTree = BUILT_PRODUCTS_DIR; };
B917D32320B0DB9700728EE0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
B917D32520B0DE2000728EE0 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = main.swift; path = TestFoundation/xdgTestHelper/main.swift; sourceTree = "<group>"; };
B95788851F6FB9470003EB01 /* TestNSNumberBridging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TestNSNumberBridging.swift; path = TestFoundation/TestNSNumberBridging.swift; sourceTree = "<group>"; };
B9C89EC11F6BF47D00087AF4 /* DarwinCompatibilityTests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DarwinCompatibilityTests; sourceTree = BUILT_PRODUCTS_DIR; };
B9C89ED11F6BF67C00087AF4 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
Expand Down Expand Up @@ -269,6 +276,7 @@
B9C89FAA1F6DCAE700087AF4 /* NSString-UTF16-LE-data.txt */,
B9C89FB01F6DCAE900087AF4 /* NSString-UTF32-BE-data.txt */,
B9C89FA51F6DCAE500087AF4 /* NSString-UTF32-LE-data.txt */,
B907F36E20BB188800013CBE /* NSString-ISO-8859-1-data.txt */,
B9C89FAE1F6DCAE800087AF4 /* NSStringTestData.txt */,
B9C89FB21F6DCAE900087AF4 /* NSURLTestData.plist */,
B9C89FB61F6DCAEA00087AF4 /* NSXMLDocumentTestData.xml */,
Expand Down Expand Up @@ -467,6 +475,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B907F36F20BB188800013CBE /* NSString-ISO-8859-1-data.txt in Resources */,
B9C89FBA1F6DCAEB00087AF4 /* NSString-UTF32-LE-data.txt in Resources */,
B9C89FBB1F6DCAEB00087AF4 /* NSKeyedUnarchiver-EdgeInsetsTest.plist in Resources */,
B9C89FBC1F6DCAEB00087AF4 /* NSKeyedUnarchiver-ConcreteValueTest.plist in Resources */,
Expand Down
4 changes: 4 additions & 0 deletions Foundation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@
9F0DD3571ECD783500F68030 /* SwiftFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5D885D1BBC938800234F36 /* SwiftFoundation.framework */; };
A058C2021E529CF100B07AA1 /* TestMassFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A058C2011E529CF100B07AA1 /* TestMassFormatter.swift */; };
AE35A1861CBAC85E0042DB84 /* SwiftFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
B907F36B20BB07A700013CBE /* NSString-ISO-8859-1-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = B907F36A20BB07A700013CBE /* NSString-ISO-8859-1-data.txt */; };
B90C57BB1EEEEA5A005208AE /* TestFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525AECEB1BF2C96400D15BB0 /* TestFileManager.swift */; };
B90C57BC1EEEEA5A005208AE /* TestThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E5835F31C20C9B500C81317 /* TestThread.swift */; };
B910957A1EEF237800A71930 /* NSString-UTF16-LE-data.txt in Resources */ = {isa = PBXBuildFile; fileRef = B91095781EEF237800A71930 /* NSString-UTF16-LE-data.txt */; };
Expand Down Expand Up @@ -814,6 +815,7 @@
A5A34B551C18C85D00FD972B /* TestByteCountFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestByteCountFormatter.swift; sourceTree = "<group>"; };
AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftFoundation.h; sourceTree = "<group>"; };
B167A6641ED7303F0040B09A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
B907F36A20BB07A700013CBE /* NSString-ISO-8859-1-data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "NSString-ISO-8859-1-data.txt"; sourceTree = "<group>"; };
B91095781EEF237800A71930 /* NSString-UTF16-LE-data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "NSString-UTF16-LE-data.txt"; sourceTree = "<group>"; };
B91095791EEF237800A71930 /* NSString-UTF16-BE-data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "NSString-UTF16-BE-data.txt"; sourceTree = "<group>"; };
B933A79C1F3055F600FE6846 /* NSString-UTF32-BE-data.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "NSString-UTF32-BE-data.txt"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1460,6 +1462,7 @@
B91095791EEF237800A71930 /* NSString-UTF16-BE-data.txt */,
B933A79C1F3055F600FE6846 /* NSString-UTF32-BE-data.txt */,
B933A79D1F3055F600FE6846 /* NSString-UTF32-LE-data.txt */,
B907F36A20BB07A700013CBE /* NSString-ISO-8859-1-data.txt */,
528776181BF27D9500CB0090 /* Test.plist */,
EA66F63B1BF1619600136161 /* NSURLTestData.plist */,
E1A3726E1C31EBFB0023AF4D /* NSXMLDocumentTestData.xml */,
Expand Down Expand Up @@ -2153,6 +2156,7 @@
D3E8D6D51C36AC0C00295652 /* NSKeyedUnarchiver-RectTest.plist in Resources */,
D3A597F81C3415CC00295652 /* NSKeyedUnarchiver-URLTest.plist in Resources */,
D3E8D6D31C36982700295652 /* NSKeyedUnarchiver-EdgeInsetsTest.plist in Resources */,
B907F36B20BB07A700013CBE /* NSString-ISO-8859-1-data.txt in Resources */,
D370696E1C394FBF00295652 /* NSKeyedUnarchiver-RangeTest.plist in Resources */,
D3A597F71C3415CC00295652 /* NSKeyedUnarchiver-ArrayTest.plist in Resources */,
CE19A88C1C23AA2300B4CB6A /* NSStringTestData.txt in Resources */,
Expand Down
61 changes: 33 additions & 28 deletions Foundation/HTTPCookie.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,54 +266,55 @@ open class HTTPCookie : NSObject {
}
_version = version

if let portString = properties[.port] as? String, _version == 1 {
_portList = portString.split(separator: ",")
if let portString = properties[.port] as? String {
let portList = portString.split(separator: ",")
.compactMap { Int(String($0)) }
.map { NSNumber(value: $0) }
if version == 1 {
_portList = portList
} else {
// Version 0 only stores a single port number
_portList = portList.count > 0 ? [portList[0]] : nil
}
} else {
_portList = nil
}

// TODO: factor into a utility function
if version == 0 {
var expDate: Date? = nil
// Maximum-Age is prefered over expires-Date but only version 1 cookies use Maximum-Age
if let maximumAge = properties[.maximumAge] as? String,
let secondsFromNow = Int(maximumAge) {
if version == 1 {
expDate = Date(timeIntervalSinceNow: Double(secondsFromNow))
}
} else {
let expiresProperty = properties[.expires]
if let date = expiresProperty as? Date {
_expiresDate = date
expDate = date
} else if let dateString = expiresProperty as? String {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss O" // per RFC 6265 '<rfc1123-date, defined in [RFC2616], Section 3.3.1>'
let timeZone = TimeZone(abbreviation: "GMT")
formatter.timeZone = timeZone
_expiresDate = formatter.date(from: dateString)
} else {
_expiresDate = nil
expDate = formatter.date(from: dateString)
}
} else if
let maximumAge = properties[.maximumAge] as? String,
let secondsFromNow = Int(maximumAge), _version == 1 {
_expiresDate = Date(timeIntervalSinceNow: Double(secondsFromNow))
} else {
_expiresDate = nil
}
_expiresDate = expDate

if let discardString = properties[.discard] as? String {
_sessionOnly = discardString == "TRUE"
} else {
_sessionOnly = properties[.maximumAge] == nil && version >= 1
}
if version == 0 {
_comment = nil
_commentURL = nil

_comment = properties[.comment] as? String
if let commentURL = properties[.commentURL] as? URL {
_commentURL = commentURL
} else if let commentURL = properties[.commentURL] as? String {
_commentURL = URL(string: commentURL)
} else {
_comment = properties[.comment] as? String
if let commentURL = properties[.commentURL] as? URL {
_commentURL = commentURL
} else if let commentURL = properties[.commentURL] as? String {
_commentURL = URL(string: commentURL)
} else {
_commentURL = nil
}
_commentURL = nil
}
_HTTPOnly = false

Expand Down Expand Up @@ -363,7 +364,11 @@ open class HTTPCookie : NSObject {
cookieString.removeLast()
cookieString.removeLast()
}
return ["Cookie": cookieString]
if cookieString == "" {
return [:]
} else {
return ["Cookie": cookieString]
}
}

/// Return an array of cookies parsed from the specified response header fields and URL.
Expand Down Expand Up @@ -418,9 +423,9 @@ open class HTTPCookie : NSObject {
properties[canonicalize(name)] = value
}

//if domain wasn't provided use the URL
// If domain wasn't provided, extract it from the URL
if properties[.domain] == nil {
properties[.domain] = url.absoluteString
properties[.domain] = url.host
}

//the default Path is "/"
Expand Down
35 changes: 26 additions & 9 deletions Foundation/NSData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,41 +185,58 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
/// Initializes a data object with the data from the location specified by a given URL.
public init(contentsOf url: URL, options readOptionsMask: ReadingOptions = []) throws {
super.init()
try _contentsOf(url: url, options: readOptionsMask)
let (data, _) = try NSData.contentsOf(url: url, options: readOptionsMask)
_init(bytes: UnsafeMutableRawPointer(mutating: data.bytes), length: data.length, copy: true)
}

/// Initializes a data object with the data from the location specified by a given URL.
public init?(contentsOf url: URL) {
super.init()
do {
try _contentsOf(url: url)
let (data, _) = try NSData.contentsOf(url: url)
_init(bytes: UnsafeMutableRawPointer(mutating: data.bytes), length: data.length, copy: true)
} catch {
return nil
}
}

/// Initializes a data object with the data from the location specified by a given URL.
private func _contentsOf(url: URL, options readOptionsMask: ReadingOptions = []) throws {
internal static func contentsOf(url: URL, options readOptionsMask: ReadingOptions = []) throws -> (NSData, URLResponse?) {
let readResult: NSData
var urlResponse: URLResponse?

if url.isFileURL {
let readResult = try NSData.readBytesFromFileWithExtendedAttributes(url.path, options: readOptionsMask)
_init(bytes: readResult.bytes, length: readResult.length, copy: false, deallocator: readResult.deallocator)
let data = try NSData.readBytesFromFileWithExtendedAttributes(url.path, options: readOptionsMask)
readResult = NSData(bytesNoCopy: data.bytes, length: data.length, deallocator: data.deallocator)
} else {
let session = URLSession(configuration: URLSessionConfiguration.default)
let cond = NSCondition()
cond.lock()

var resError: Error?
var resData: Data?
var taskFinished = false
let task = session.dataTask(with: url, completionHandler: { data, response, error in
cond.lock()
resData = data
urlResponse = response
resError = error
cond.broadcast()
taskFinished = true
cond.signal()
cond.unlock()
})

task.resume()
cond.wait()
while taskFinished == false {
cond.wait()
}
cond.unlock()

guard let data = resData else {
throw resError!
}
_init(bytes: UnsafeMutableRawPointer(mutating: data._nsObject.bytes), length: data.count, copy: true)
readResult = NSData(bytes: UnsafeMutableRawPointer(mutating: data._nsObject.bytes), length: data.count)
}
return (readResult, urlResponse)
}

/// Initializes a data object with the given Base64 encoded string.
Expand Down
18 changes: 13 additions & 5 deletions Foundation/NSString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,10 @@ open class NSString : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSC
}

internal func _fastCStringContents(_ nullTerminated: Bool) -> UnsafePointer<Int8>? {
guard !nullTerminated else {
// There is no way to fastly and safely retrieve a pointer to a null-terminated string from a String of Swift.
return nil
}
if type(of: self) == NSString.self || type(of: self) == NSMutableString.self {
if _storage._guts._isContiguousASCII {
return unsafeBitCast(_storage._guts.startASCII, to: UnsafePointer<Int8>.self)
Expand Down Expand Up @@ -1254,12 +1258,14 @@ extension NSString {
public convenience init(contentsOfFile path: String, encoding enc: UInt) throws {
try self.init(contentsOf: URL(fileURLWithPath: path), encoding: enc)
}

public convenience init(contentsOf url: URL, usedEncoding enc: UnsafeMutablePointer<UInt>?) throws {
let readResult = try NSData(contentsOf: url, options:[])
let (readResult, urlResponse) = try NSData.contentsOf(url: url)

let encoding: UInt
let offset: Int
// Look for a BOM (Byte Order Marker) to try and determine the text Encoding, this also skips
// over the bytes. This takes precedence over the textEncoding in the http header
let bytePtr = readResult.bytes.bindMemory(to: UInt8.self, capacity:readResult.length)
if readResult.length >= 4 && bytePtr[0] == 0xFF && bytePtr[1] == 0xFE && bytePtr[2] == 0x00 && bytePtr[3] == 0x00 {
encoding = String.Encoding.utf32LittleEndian.rawValue
Expand All @@ -1277,14 +1283,15 @@ extension NSString {
encoding = String.Encoding.utf32BigEndian.rawValue
offset = 4
}
else {
else if let charSet = urlResponse?.textEncodingName, let textEncoding = String.Encoding(charSet: charSet) {
encoding = textEncoding.rawValue
offset = 0
} else {
//Need to work on more conditions. This should be the default
encoding = String.Encoding.utf8.rawValue
offset = 0
}

enc?.pointee = encoding

// Since the encoding being passed includes the byte order the BOM wont be checked or skipped, so pass offset to
// manually skip the BOM header.
guard let cf = CFStringCreateWithBytes(kCFAllocatorDefault, bytePtr + offset, readResult.length - offset,
Expand All @@ -1301,6 +1308,7 @@ extension NSString {
"NSDebugDescription" : "Unable to bridge CFString to String."
])
}
enc?.pointee = encoding
}

public convenience init(contentsOfFile path: String, usedEncoding enc: UnsafeMutablePointer<UInt>?) throws {
Expand Down
2 changes: 1 addition & 1 deletion Foundation/Process.swift
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,8 @@ open class Process: NSObject {

self.processIdentifier = pid

self.processLaunchedCondition.unlock()
self.processLaunchedCondition.broadcast()
self.processLaunchedCondition.unlock()
}

open func interrupt() { NSUnimplemented() } // Not always possible. Sends SIGINT.
Expand Down
34 changes: 34 additions & 0 deletions Foundation/StringEncodings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,39 @@ extension String {
public static let utf32 = Encoding(rawValue: 0x8c000100)
public static let utf32BigEndian = Encoding(rawValue: 0x98000100)
public static let utf32LittleEndian = Encoding(rawValue: 0x9c000100)

// Map selected IANA character set names to encodings, see
// https://www.iana.org/assignments/character-sets/character-sets.xhtml
internal init?(charSet: String) {
let encoding: Encoding?

switch charSet.lowercased() {
case "us-ascii": encoding = .ascii
case "utf-8": encoding = .utf8
case "utf-16": encoding = .utf16
case "utf-16be": encoding = .utf16BigEndian
case "utf-16le": encoding = .utf16LittleEndian
case "utf-32": encoding = .utf32
case "utf-32be": encoding = .utf32BigEndian
case "utf-32le": encoding = .utf32LittleEndian
case "iso-8859-1": encoding = .isoLatin1
case "iso-8859-2": encoding = .isoLatin2
case "iso-2022-jp": encoding = .iso2022JP
case "windows-1250": encoding = .windowsCP1250
case "windows-1251": encoding = .windowsCP1251
case "windows-1252": encoding = .windowsCP1252
case "windows-1253": encoding = .windowsCP1253
case "windows-1254": encoding = .windowsCP1254
case "shift_jis": encoding = .shiftJIS
case "euc-jp": encoding = .japaneseEUC
case "macintosh": encoding = .macOSRoman
default: encoding = nil
}
guard let value = encoding?.rawValue else {
return nil
}
rawValue = value
}
}

public typealias EncodingConversionOptions = NSString.EncodingConversionOptions
Expand All @@ -50,6 +83,7 @@ extension String.Encoding : CustomStringConvertible {
}
}


@available(*, unavailable, renamed: "String.Encoding")
public typealias NSStringEncoding = UInt

Expand Down
Loading