-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Support internal null characters in NSString initializers [SR-2225] #496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1221,10 +1221,7 @@ extension NSString { | |
} | ||
|
||
public convenience init?(data: Data, encoding: UInt) { | ||
guard let cf = data.withUnsafeBytes({ (bytes: UnsafePointer<UInt8>) -> CFString? in | ||
return CFStringCreateWithBytes(kCFAllocatorDefault, bytes, data.count, CFStringConvertNSStringEncodingToEncoding(encoding), true) | ||
}) else { return nil } | ||
|
||
guard let cf = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data._cfObject, CFStringConvertNSStringEncodingToEncoding(encoding)) else { return nil } | ||
var str: String? | ||
if String._conditionallyBridgeFromObject(cf._nsObject, result: &str) { | ||
self.init(str!) | ||
|
@@ -1234,8 +1231,8 @@ extension NSString { | |
} | ||
|
||
public convenience init?(bytes: UnsafeRawPointer, length len: Int, encoding: UInt) { | ||
let bytePtr = bytes.bindMemory(to: UInt8.self, capacity: len) | ||
guard let cf = CFStringCreateWithBytes(kCFAllocatorDefault, bytePtr, len, CFStringConvertNSStringEncodingToEncoding(encoding), true) else { | ||
let extRep = NSData(bytesNoCopy: UnsafeMutableRawPointer(mutating: bytes), length: len, freeWhenDone: false)._cfObject | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But this one should remain using the bytes function: - initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding {
return (id)CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)bytes, len, CFStringConvertNSStringEncodingToEncoding(encoding), true);
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's interesting. I'm not in front of a computer at the moment, but IIRC, testing on OS X showed that Apple Foundation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may depend on exactly how you're calling it. Those are from the placeholder string, which is the result of calling alloc on NSString, but not on a subclass of NSString. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not quite sure I understand what you mean by placeholder string. However, it's clear that Apple Foundation reads past the internal null character with echo -e "This is a string.\0This is another string." > /Users/xwu/Desktop/test.txt let url = URL(fileURLWithPath: "/Users/xwu/Desktop/test.txt")
let data = try Data(contentsOf: url)
data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
let string = NSString(bytes: bytes, length: data.count, encoding: String.Encoding.ascii.rawValue)
// "This is a string.\0This is another string."
} Not sure what it would take to achieve this result if we are to use |
||
guard let cf = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, extRep, CFStringConvertNSStringEncodingToEncoding(encoding)) else { | ||
return nil | ||
} | ||
var str: String? | ||
|
@@ -1265,12 +1262,10 @@ extension NSString { | |
return nil | ||
} | ||
} | ||
|
||
public convenience init(contentsOf url: URL, encoding enc: UInt) throws { | ||
let readResult = try NSData(contentsOf: url, options: []) | ||
|
||
let bytePtr = readResult.bytes.bindMemory(to: UInt8.self, capacity: readResult.length) | ||
guard let cf = CFStringCreateWithBytes(kCFAllocatorDefault, bytePtr, readResult.length, CFStringConvertNSStringEncodingToEncoding(enc), true) else { | ||
guard let cf = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, readResult._cfObject, CFStringConvertNSStringEncodingToEncoding(enc)) else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This actually calls through to |
||
throw NSError(domain: NSCocoaErrorDomain, code: NSCocoaError.FileReadInapplicableStringEncodingError.rawValue, userInfo: [ | ||
"NSDebugDescription" : "Unable to create a string using the specified encoding." | ||
]) | ||
|
@@ -1284,7 +1279,7 @@ extension NSString { | |
]) | ||
} | ||
} | ||
|
||
public convenience init(contentsOfFile path: String, encoding enc: UInt) throws { | ||
try self.init(contentsOf: URL(fileURLWithPath: path), encoding: enc) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The story of what happens on Darwin here is fairly complicated, which is probably why this was different in the first place, but it boils down to this:
So this change looks correct.