In swift 2 I had an NSURL extension for working with extended attributes and it included this:
func setAttribute(name: String, value: String) {
let data = value.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
setxattr(self.path!, name, data.bytes, data.length, 0, 0)
}
func getAttribute(name: String) -> String? {
let length = getxattr(self.path!, name, nil, 0, 0, 0)
if length == -1 {
return nil
}
let bytes = malloc(length)
if getxattr(self.path!, name, bytes, length, 0, 0) == -1 {
return nil
}
return (String(data: NSData(bytes: bytes, length: length),
encoding: NSUTF8StringEncoding))
}
func attributes() -> [String : String]? {
let length = listxattr(self.path!, nil, 0, 0)
if length == -1 {
return nil
}
let bytes = UnsafeMutablePointer<Int8>(malloc(length))
if listxattr(self.path!, bytes, length, 0) == -1 {
return nil
}
if var names = NSString(bytes: bytes, length: length,
encoding: NSUTF8StringEncoding)?.componentsSeparatedByString("\0") {
names.removeLast()
var attributes: [String : String] = [:]
for name in names {
attributes[name] = getAttribute(name)!
}
return attributes
}
return nil
}
Now I'm trying to convert it to Swift 3, but Xcode keeps complaining.
I changed the first two functions into this, but I'm not sure I'm doing it right:
func setAttribute(_ name: String, value: String) {
let data = value.data(using: String.Encoding.utf8, allowLossyConversion: false)!
setxattr(self.path, name, (data as NSData).bytes, data.count, 0, 0)
}
func getAttribute(_ name: String) -> String? {
let length = getxattr(self.path, name, nil, 0, 0, 0)
if length < 0 {
return nil
}
guard let bytes = malloc(length),
getxattr(self.path, name, bytes, length, 0, 0) >= 0 else {
return nil
}
if getxattr(self.path, name, bytes, length, 0, 0) < 0 {
return nil
}
return (String(data: Data(bytes: bytes, count: length),
encoding: String.Encoding.utf8))
}
Do I have to cast Data
to NSData
there at the first function? Is there a better way to go about all this?
And that last function was converted by Xcode into this:
func attributes() -> [String : String]? {
let length = listxattr(self.path, nil, 0, 0)
if length == -1 {
return nil
}
let bytes = UnsafeMutablePointer<Int8>(malloc(length))
if listxattr(self.path, bytes, length, 0) == -1 {
return nil
}
if var names = NSString(bytes: bytes, length: length,
encoding: String.Encoding.utf8)?.components(separatedBy: "\0") {
names.removeLast()
var attributes: [String : String] = [:]
for name in names {
attributes[name] = getAttribute(name)!
}
return attributes
}
return nil
}
But I get
Cannot invoke initializer for type 'UnsafeMutablePointer' with an argument list of type '(UnsafeMutableRawPointer!)'
And I don't know what to do. Also Xcode's conversion sticks to NSString
. Couldn't I use String
there?
If it's not obvious already, I have no idea what I'm doing, haha. I based my original code on this, but I couldn't understand how all that malloc
, length
and bytes
stuff work. I tried reading the documentation for Data
and UnsafeMutablePointer
and so on, but it didn't help much.
If somebody could help me convert this code I'd be really grateful, but even just pointing me in the right direction to understand all this would already be a huge help. I don't know where else to look and all that stuff seems really cryptic to me. The few recent sources I found assume I know a lot of stuff I have no idea about, and I don't even know what to look for.
Thanks!