Type of expression is ambiguous without more context - objective-c

I'm trying to convert the code of objective C mentioned here - https://gist.github.com/Coeur/1409855/f6df10c79f8cdd0fcb2a0735b99f4b3a74b9f954
to swift
The code I've wrote till now in swift -
class func getMacAddress(_ ifName: String?) -> String? {
var mgmtInfoBase = [Int32](repeating: 0, count: 6)
var msgBuffer: Int8? = nil
var length: size_t
var macAddress = [UInt8](repeating: 0, count: 6)
var interfaceMsgStruct: if_msghdr?
var socketStruct: sockaddr_dl?
var errorFlag: String? = nil
// Setup the management Information Base (mib)
mgmtInfoBase[0] = Int32(Int(CTL_NET)) // Request network subsystem
mgmtInfoBase[1] = Int32(Int(AF_ROUTE)) // Routing table info
mgmtInfoBase[2] = 0
mgmtInfoBase[3] = Int32(Int(AF_LINK)) // Request link layer information
mgmtInfoBase[4] = Int32(Int(NET_RT_IFLIST)) // Request all configured interfaces
mgmtInfoBase[5] = Int32(if_nametoindex(ifName?.utf8CString)) //ERROR: Type of expression is ambiguous without more context
// With all configured interfaces requested, get handle index
if ( mgmtInfoBase[5] == 0) {
errorFlag = "if_nametoindex failure"
} else {
// Get the size of the data available (store in len)
if sysctl(&mgmtInfoBase, 6, nil, &length, nil, 0) < 0 {
errorFlag = "sysctl mgmtInfoBase failure"
} else {
// Alloc memory based on above call
if (msgBuffer = Int8((length))) == nil {
errorFlag = "buffer allocation failure"
} else {
// Get system information, store in buffer
if sysctl(&mgmtInfoBase, 6, &msgBuffer, &length, nil, 0) < 0 {
errorFlag = "sysctl msgBuffer failure"
}
}
}
}
// Before going any further...
if errorFlag != nil {
// Release the buffer memory
if (msgBuffer != nil) {
free(&msgBuffer)
}
return nil
}
// Map msgbuffer to interface message structure
interfaceMsgStruct = msgBuffer as? if_msghdr
// Map to link-level socket structure
socketStruct = (interfaceMsgStruct + 1) as? sockaddr_dl // ERROR: Cannot convert value of type 'if_msghdr?' to expected argument type 'Int'
// Copy link layer address data in socket structure to an array
if socketStruct == nil {
return nil
}
memcpy(&macAddress, socketStruct.sdl_data + socketStruct.sdl_nlen, 6) // ERROR: Type of expression is ambiguous without more context
// Read from char array into a string object, into traditional Mac address format
let macAddressString = String(format: "%02X:%02X:%02X:%02X:%02X:%02X", macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5])
// Release the buffer memory
free(&msgBuffer)
return macAddressString
}
I'm getting the errors that I've mentioned. I searched and tried every possible thing and read articles from the documentation but still I couldn't get away with these errors. Please help.
The definitions of the functions for which I'm getting error as mentioned in Darwin.posix.net.if -
public func if_nametoindex(_: UnsafePointer<Int8>!) -> UInt32
public struct if_msghdr {
public var ifm_msglen: UInt16 /* to skip non-understood messages */
public var ifm_version: UInt8 /* future binary compatability */
public var ifm_type: UInt8 /* message type */
public var ifm_addrs: Int32 /* like rtm_addrs */
public var ifm_flags: Int32 /* value of if_flags */
public var ifm_index: UInt16 /* index for associated ifp */
public var ifm_data: if_data /* statistics and other data about if */
public init()
public init(ifm_msglen: UInt16, ifm_version: UInt8, ifm_type: UInt8, ifm_addrs: Int32, ifm_flags: Int32, ifm_index: UInt16, ifm_data: if_data)
}
public func memcpy(_ __dst: UnsafeMutableRawPointer!, _ __src: UnsafeRawPointer!, _ __n: Int) -> UnsafeMutableRawPointer!````

Related

Type bytes32 is not implicitly convertible to expected type string memory. Operator == not compatible with types string memory and string memory

I am new to Solidity and building a Todo List project.
I still got below error messages in the deductTask function even after using keccak256(abi.encodePacked())
to pack my string variables
error 1 . Type bytes32 is not implicitly convertible to expected type string memory.
error 2 . Operator == not compatible with types string memory and string memory
pragma solidity >=0.4.22 <0.9.0;
contract myTodoList {
// Model a Task
struct Task {
uint id;
string content;
bool completed;
}
// Read/write Tasks
mapping(uint => Task) public Tasks;
// Store Tasks Count
uint public TasksCount = 0;
function addTask (string memory _content) public {
TasksCount ++;
Tasks[TasksCount] = Task(TasksCount, _content, false);
}
Task TaskTemp;
function deductTask (string memory _contentClicked) public {
string memory comparedContent;
uint i ;
for(i = 1; i <= TasksCount; i++) {
TaskTemp = Tasks[i];
comparedContent = TaskTemp.content;
comparedContent = keccak256(abi.encodePacked(comparedContent));
//comparedContent = keccak256(abi.encodePacked(comparedContent));
_contentClicked = keccak256(abi.encodePacked(_contentClicked));
//_contentClicked = keccak256(abi.encodePacked(_contentClicked));
if(_contentClicked == comparedContent ){
delete Tasks[i];
}
}
TasksCount --;
}
constructor () public {
addTask("my first task");
addTask("my second task");
}
}

USB device send/receive data

I have implemented function to detect USB device. It works and now i need to send/read data.
I started look over a lot of obj-c sources and found only one good article in apple documentation, that describes how do we can send package to our USB device:
IOReturn WriteToDevice(IOUSBDeviceInterface **dev, UInt16 deviceAddress,
UInt16 length, UInt8 writeBuffer[])
{
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor,
kUSBDevice);
request.bRequest = 0xa0;
request.wValue = deviceAddress;
request.wIndex = 0;
request.wLength = length;
request.pData = writeBuffer;
return (*dev)->DeviceRequest(dev, &request);
}
But I didn't find a way how to create and send data with Swift. The struct on Swift looks like:
public struct IOUSBDevRequest {
public var bmRequestType: UInt8
public var bRequest: UInt8
public var wValue: UInt16
public var wIndex: UInt16
public var wLength: UInt16
public var pData: UnsafeMutableRawPointer!
public var wLenDone: UInt32
public init()
public init(bmRequestType: UInt8, bRequest: UInt8, wValue: UInt16, wIndex: UInt16, wLength: UInt16, pData: UnsafeMutableRawPointer!, wLenDone: UInt32)
}
I can't figure out what parameters is pData, zwLenDone.
This is data that i need to send:
{
'direction':'in',
'recipient':'device',
'requestType': 'standard',
'request': 6,
'value': 0x300,
'index': 0,
'length': 255
}
The next question is: How i can receive data. I know the answer is in this article, but i can't convert it to Swift.
Here is what i could converted on Swift 3. My class detects USB device, get his configuration:
class DFUDevice: NSObject {
let vendorId = 0x0483
let productId = 0xdf11
static let sharedInstance = DFUDevice()
var deviceName:String = ""
private func deviceAdded(iterator: io_iterator_t) {
var plugInInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOCFPlugInInterface>?>?
var deviceInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOUSBDeviceInterface>?>?
var configPtr:IOUSBConfigurationDescriptorPtr?
var score: Int32 = 0
while case let usbDevice = IOIteratorNext(iterator), usbDevice != 0 {
// io_name_t imports to swift as a tuple (Int8, ..., Int8) 128 ints
// although in device_types.h it's defined:
// typedef char io_name_t[128];
var deviceNameCString: [CChar] = [CChar](repeating: 0, count: 128)
let deviceNameResult = IORegistryEntryGetName(usbDevice, &deviceNameCString)
if(deviceNameResult != kIOReturnSuccess) {
print("Error getting device name")
}
self.deviceName = String.init(cString: &deviceNameCString)
print("usb Device Name: \(deviceName)")
// Get plugInInterface for current USB device
let plugInInterfaceResult = IOCreatePlugInInterfaceForService(
usbDevice,
kIOUSBDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugInInterfacePtrPtr,
&score)
// dereference pointer for the plug in interface
guard plugInInterfaceResult == kIOReturnSuccess,
let plugInInterface = plugInInterfacePtrPtr?.pointee?.pointee else {
print("Unable to get Plug-In Interface")
continue
}
// use plug in interface to get a device interface
let deviceInterfaceResult = withUnsafeMutablePointer(to: &deviceInterfacePtrPtr) {
$0.withMemoryRebound(to: Optional<LPVOID>.self, capacity: 1) {
plugInInterface.QueryInterface(
plugInInterfacePtrPtr,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
$0)
}
}
// dereference pointer for the device interface
guard deviceInterfaceResult == kIOReturnSuccess,
let deviceInterface = deviceInterfacePtrPtr?.pointee?.pointee else {
print("Unable to get Device Interface")
continue
}
var ret = deviceInterface.USBDeviceOpen(deviceInterfacePtrPtr)
if (ret == kIOReturnSuccess)
{
// set first configuration as active
ret = deviceInterface.GetConfigurationDescriptorPtr(deviceInterfacePtrPtr, 0, &configPtr)
if (ret != kIOReturnSuccess)
{
print("Could not set active configuration (error: %x)\n", ret);
continue
}
guard let config = configPtr?.pointee else {
continue
}
if config.bLength > 0 {
//HERE I NEED SEND DATA
} else {
print("ConfigurationDescriptor not valid")
}
print(config.bLength)
}
else if (ret == kIOReturnExclusiveAccess)
{
// this is not a problem as we can still do some things
}
else
{
print("Could not open device (error: %x)\n", ret)
continue
}
IOObjectRelease(usbDevice)
}
}
func initUsb() {
var matchedIterator:io_iterator_t = 0
var removalIterator:io_iterator_t = 0
let notifyPort:IONotificationPortRef = IONotificationPortCreate(kIOMasterPortDefault)
IONotificationPortSetDispatchQueue(notifyPort, DispatchQueue(label: "IODetector"))
let matchingDict = IOServiceMatching(kIOUSBDeviceClassName)
as NSMutableDictionary
matchingDict[kUSBVendorID] = NSNumber(value: self.vendorId)
matchingDict[kUSBProductID] = NSNumber(value: self.productId)
let matchingCallback:IOServiceMatchingCallback = { (userData, iterator) in
let this = Unmanaged<DFUDevice>
.fromOpaque(userData!).takeUnretainedValue()
this.deviceAdded(iterator: iterator)
this.connected(iterator: iterator)
}
let removalCallback: IOServiceMatchingCallback = {
(userData, iterator) in
let this = Unmanaged<DFUDevice>
.fromOpaque(userData!).takeUnretainedValue()
this.disconnected(iterator: iterator)
}
let selfPtr = Unmanaged.passUnretained(self).toOpaque()
IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, matchingDict, matchingCallback, selfPtr, &matchedIterator)
IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, matchingDict, removalCallback, selfPtr, &removalIterator)
self.deviceAdded(iterator: matchedIterator)
self.deviceAdded(iterator: removalIterator)
RunLoop.current.run()
}
}
I call it like:
let DFUDeviceDaemon = Thread(target: DFUDevice.sharedInstance, selector:#selector(DFUDevice.initUsb), object: nil)
DFUDeviceDaemon.start()
The article you reference has a function called WriteToDevice. One of its parameters is
UInt8 writeBuffer[]
This writeBuffer, the data that you want to send, is a C array of bytes:
uint8_t msgLength = 3;
uint8_t writeBuffer[msgLength];
writeBuffer[0] = 0x41; // ASCII 'A'
writeBuffer[1] = 0x42; // ASCII 'B'
writeBuffer[2] = 0x43; // ASCII 'C'
What bytes do you need to send? That really depends on the device at the other end -- the technical data from the manufacturer should tell you that.
To pass the C-array as NSData, which is probably what pData is, you'd use:
NSData *data = [NSData dataWithBytes:&writeBuffer length:3];
The (z)wLenDone is probably what I called the msgLength, 3. C-array's have no knowledge of their own length, so most functions require the length as a separate parameter.
As for receiving data, I would guess that happens in the matchingCallback: you use the iterator to receive the bytes and then parse them.
ANSWER TO COMMENT:
I'm not familiar with C#, and I'm no expert at this stuff, but maybe this will help:
var package = new UsbSetupPacket(
(byte)(UsbCtrlFlags.Direction_In |
UsbCtrlFlags.Recipient_Device |
UsbCtrlFlags.RequestType_Standard), // Index
6, // length of data, second phase
0x200, // Request
0, // RequestType
(short)length); // Value
A few observations: know nothing of C#, but should not the package be typed to struct? RequestType is 0, so you will receive no response -- is that what you want? Or did you want to send UsbCtrlFlags.RequestType_Standard as the fourth parameter? Why send the length as a value?
Anyway, what you do now is send the package to the USB device and see what happens.
After a lot of questions on stackoverflow and learning sources i figure it out:
First define not implemented functions
import Foundation
import IOKit
import IOKit.usb
import IOKit.usb.IOUSBLib
//from IOUSBLib.h
let kIOUSBDeviceUserClientTypeID = CFUUIDGetConstantUUIDWithBytes(nil,
0x9d, 0xc7, 0xb7, 0x80, 0x9e, 0xc0, 0x11, 0xD4,
0xa5, 0x4f, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61)
let kIOUSBDeviceInterfaceID = CFUUIDGetConstantUUIDWithBytes(nil,
0x5c, 0x81, 0x87, 0xd0, 0x9e, 0xf3, 0x11, 0xD4,
0x8b, 0x45, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61)
//from IOCFPlugin.h
let kIOCFPlugInInterfaceID = CFUUIDGetConstantUUIDWithBytes(nil,
0xC2, 0x44, 0xE8, 0x58, 0x10, 0x9C, 0x11, 0xD4,
0x91, 0xD4, 0x00, 0x50, 0xE4, 0xC6, 0x42, 0x6F)
/*!
#defined USBmakebmRequestType
#discussion Macro to encode the bRequest field of a Device Request. It is used when constructing an IOUSBDevRequest.
*/
func USBmakebmRequestType(direction:Int, type:Int, recipient:Int) -> UInt8 {
return UInt8((direction & kUSBRqDirnMask) << kUSBRqDirnShift)|UInt8((type & kUSBRqTypeMask) << kUSBRqTypeShift)|UInt8(recipient & kUSBRqRecipientMask)
}
Then create our class:
extension Notification.Name {
static let dfuDeviceConnected = Notification.Name("DFUDeviceConnected")
static let dfuDeviceDisconnected = Notification.Name("DFUDeviceDisconnected")
}
class DFUDevice: NSObject {
let vendorId = 0x0483
let productId = 0xdf11
static let sharedInstance = DFUDevice()
var deviceInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOUSBDeviceInterface>?>?
var plugInInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOCFPlugInInterface>?>?
var interfacePtrPtr:UnsafeMutablePointer<UnsafeMutablePointer<IOUSBInterfaceInterface>?>?
private func rawDeviceAdded(iterator: io_iterator_t) {
var score:Int32 = 0
var kr:Int32 = 0
while case let usbDevice = IOIteratorNext(iterator), usbDevice != 0 {
// io_name_t imports to swift as a tuple (Int8, ..., Int8) 128 ints
// although in device_types.h it's defined:
// typedef char io_name_t[128];
var deviceNameCString: [CChar] = [CChar](repeating: 0, count: 128)
let deviceNameResult = IORegistryEntryGetName(usbDevice, &deviceNameCString)
if(deviceNameResult != kIOReturnSuccess) {
print("Error getting device name")
}
let deviceName = String.init(cString: &deviceNameCString)
print("usb Device Name: \(deviceName)")
// Get plugInInterface for current USB device
let plugInInterfaceResult = IOCreatePlugInInterfaceForService(
usbDevice,
kIOUSBDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugInInterfacePtrPtr,
&score)
// USB device object is no longer needed.
IOObjectRelease(usbDevice)
// Dereference pointer for the plug-in interface
guard plugInInterfaceResult == kIOReturnSuccess,
let plugInInterface = plugInInterfacePtrPtr?.pointee?.pointee else {
print("Unable to get Plug-In Interface")
continue
}
// use plug in interface to get a device interface
let deviceInterfaceResult = withUnsafeMutablePointer(to: &deviceInterfacePtrPtr) {
$0.withMemoryRebound(to: Optional<LPVOID>.self, capacity: 1) {
plugInInterface.QueryInterface(
plugInInterfacePtrPtr,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
$0)
}
}
// dereference pointer for the device interface
guard deviceInterfaceResult == kIOReturnSuccess,
let deviceInterface = deviceInterfacePtrPtr?.pointee?.pointee else {
print("Unable to get Device Interface")
continue
}
kr = deviceInterface.USBDeviceOpen(deviceInterfacePtrPtr)
if (kr != kIOReturnSuccess)
{
print("Could not open device (error: \(kr))")
continue
}
else if (kr == kIOReturnExclusiveAccess)
{
// this is not a problem as we can still do some things
continue
}
self.connected()
}
}
private func rawDeviceRemoved(iterator: io_iterator_t) {
var kr:Int32 = 0
while case let usbDevice = IOIteratorNext(iterator), usbDevice != 0 {
// USB device object is no longer needed.
kr = IOObjectRelease(usbDevice)
if (kr != kIOReturnSuccess)
{
print("Couldn’t release raw device object (error: \(kr))")
continue
}
self.disconnected()
}
}
func getStatus() throws -> [UInt8] {
guard let deviceInterface = self.deviceInterfacePtrPtr?.pointee?.pointee else {
throw DFUDeviceError.DeviceInterfaceNotFound
}
var kr:Int32 = 0
let length:Int = 6
var requestPtr:[UInt8] = [UInt8](repeating: 0, count: length)
var request = IOUSBDevRequest(bmRequestType: USBmakebmRequestType(direction: kUSBIn, type: kUSBDevice, recipient: kUSBStandard),
bRequest: DFUREQUEST.GETSTATUS.rawValue,
wValue: 0,
wIndex: 0,
wLength: UInt16(length),
pData: &requestPtr,
wLenDone: 255)
kr = deviceInterface.DeviceRequest(self.deviceInterfacePtrPtr, &request)
if (kr != kIOReturnSuccess) {
throw DFUDeviceError.RequestError(desc: "Get device status request error: \(kr)")
}
return requestPtr
}
private func configureDevice() -> Int32 {
var kr:Int32 = 0
guard let deviceInterface = deviceInterfacePtrPtr?.pointee?.pointee else {
print("Unable to get Device Interface")
return -1
}
var numConfig:UInt8 = 0
kr = deviceInterface.GetNumberOfConfigurations(deviceInterfacePtrPtr, &numConfig)
if numConfig == 0 {
print("Device Number Of Configurations: 0")
return -1
}
var configPtr:IOUSBConfigurationDescriptorPtr?
// set first configuration as active
kr = deviceInterface.GetConfigurationDescriptorPtr(deviceInterfacePtrPtr, 0, &configPtr)
if (kr != kIOReturnSuccess)
{
print("Couldn’t get configuration descriptor for index (error: %x)\n", kr);
return -1
}
guard let config = configPtr?.pointee else {
return -1
}
//Set the device’s configuration. The configuration value is found in
//the bConfigurationValue field of the configuration descriptor
kr = deviceInterface.SetConfiguration(deviceInterfacePtrPtr, config.bConfigurationValue)
if (kr != kIOReturnSuccess)
{
print("Couldn’t set configuration to value (error: %x)\n", kr);
return -1
}
return kIOReturnSuccess
}
func connected() {
NotificationCenter.default.post(name: .dfuDeviceConnected, object: nil)
globalLogPost("DFU device has been device connected")
}
func disconnected() {
NotificationCenter.default.post(name: .dfuDeviceDisconnected, object: nil)
globalLogPost("DFU device has been disconnected")
}
func initUsb() {
var matchedIterator:io_iterator_t = 0
var removalIterator:io_iterator_t = 0
let notifyPort:IONotificationPortRef = IONotificationPortCreate(kIOMasterPortDefault)
IONotificationPortSetDispatchQueue(notifyPort, DispatchQueue(label: "IODetector"))
let matchingDict = IOServiceMatching(kIOUSBDeviceClassName)
as NSMutableDictionary
matchingDict[kUSBVendorID] = NSNumber(value: self.vendorId)
matchingDict[kUSBProductID] = NSNumber(value: self.productId)
let matchingCallback:IOServiceMatchingCallback = { (userData, iterator) in
let this = Unmanaged<DFUDevice>
.fromOpaque(userData!).takeUnretainedValue()
this.rawDeviceAdded(iterator: iterator)
}
let removalCallback: IOServiceMatchingCallback = {
(userData, iterator) in
let this = Unmanaged<DFUDevice>
.fromOpaque(userData!).takeUnretainedValue()
this.rawDeviceRemoved(iterator: iterator)
}
let selfPtr = Unmanaged.passUnretained(self).toOpaque()
IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, matchingDict, matchingCallback, selfPtr, &matchedIterator)
IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, matchingDict, removalCallback, selfPtr, &removalIterator)
self.rawDeviceAdded(iterator: matchedIterator)
self.rawDeviceRemoved(iterator: removalIterator)
RunLoop.current.run()
}
}
You can look on method getStatus where i create a USBRequest and send it to device. Then in requestPtr:[UInt8] i received answer from device. Thank you for helping guys.
We can use ore device pointer anywhere in project, for example:
func upload(value:UInt16, length:UInt16) throws -> [UInt8] {
guard let deviceInterface = DFUDevice.sharedInstance.deviceInterfacePtrPtr?.pointee?.pointee else {
throw DFUDeviceError.DeviceInterfaceNotFound
}
var kr:Int32 = 0
var requestPtr:[UInt8] = [UInt8](repeating: 0, count: Int(length))
var request = IOUSBDevRequest(bmRequestType: 161,
bRequest: DFUREQUEST.UPLOAD.rawValue,
wValue: value,
wIndex: 0,
wLength: length,
pData: &requestPtr,
wLenDone: 255)
kr = deviceInterface.DeviceRequest(DFUDevice.sharedInstance.deviceInterfacePtrPtr, &request)
if (kr != kIOReturnSuccess) {
throw DFUDeviceError.RequestError(desc: "Upload request error: \(kr), request data: \(request)")
}
return requestPtr
}

Swift equivalent to Objective-C FourCharCode single quote literals (e.g. 'TEXT')

I am trying replicate some Objective C cocoa in Swift. All is good until I come across the following:
// Set a new type and creator:
unsigned long type = 'TEXT';
unsigned long creator = 'pdos';
How can I create Int64s (or the correct Swift equivalent) from single quote character literals like this?
Types:
public typealias AEKeyword = FourCharCode
public typealias OSType = FourCharCode
public typealias FourCharCode = UInt32
I'm using this in my Cocoa Scripting apps, it considers characters > 0x80 correctly
func OSTypeFrom(string : String) -> UInt {
var result : UInt = 0
if let data = string.dataUsingEncoding(NSMacOSRomanStringEncoding) {
let bytes = UnsafePointer<UInt8>(data.bytes)
for i in 0..<data.length {
result = result << 8 + UInt(bytes[i])
}
}
return result
}
Edit:
Alternatively
func fourCharCodeFrom(string : String) -> FourCharCode
{
assert(string.count == 4, "String length must be 4")
var result : FourCharCode = 0
for char in string.utf16 {
result = (result << 8) + FourCharCode(char)
}
return result
}
or still swiftier
func fourCharCode(from string : String) -> FourCharCode
{
return string.utf16.reduce(0, {$0 << 8 + FourCharCode($1)})
}
I found the following typealiases from the Swift API:
typealias FourCharCode = UInt32
typealias OSType = FourCharCode
And the following functions:
func NSFileTypeForHFSTypeCode(hfsFileTypeCode: OSType) -> String!
func NSHFSTypeCodeFromFileType(fileTypeString: String!) -> OSType
This should allow me to create the equivalent code:
let type : UInt32 = UInt32(NSHFSTypeCodeFromFileType("TEXT"))
let creator : UInt32 = UInt32(NSHFSTypeCodeFromFileType("pdos"))
But those 4-character strings doesn't work and return 0.
If you wrap each string in ' single quotes ' and call the same functions, you will get the correct return values:
let type : UInt32 = UInt32(NSHFSTypeCodeFromFileType("'TEXT'"))
let creator : UInt32 = UInt32(NSHFSTypeCodeFromFileType("'pdos'"))
Adopt the ExpressibleByStringLiteral protocol to use four-character string literals directly:
extension FourCharCode: ExpressibleByStringLiteral {
public init(stringLiteral value: StringLiteralType) {
if let data = value.data(using: .macOSRoman), data.count == 4 {
self = data.reduce(0, {$0 << 8 + Self($1)})
} else {
self = 0
}
}
}
Now you can just pass a string literal as the FourCharCode / OSType / UInt32 parameter:
let record = NSAppleEventDescriptor.record()
record.setDescriptor(NSAppleEventDescriptor(boolean: true), forKeyword: "test")
In Swift 4 or later, I use this code - if the string is not 4 characters in size, it will return an OSType(0):
extension String {
public func osType() -> OSType {
var result:UInt = 0
if let data = self.data(using: .macOSRoman), data.count == 4
{
data.withUnsafeBytes { (ptr:UnsafePointer<UInt8>) in
for i in 0..<data.count {
result = result << 8 + UInt(ptr[i])
}
}
}
return OSType(result)
}
}
let type = "APPL".osType() // 1095782476
// check if this is OK in a playground
let hexStr = String(format: "0x%lx", type) // 0x4150504c -> "APPL" in ASCII
Swift 5 Update:
extension String {
func osType() -> OSType {
return OSType(
data(using: .macOSRoman)?
.withUnsafeBytes {
$0.reduce(into: UInt(0)) { $0 = $0 << 8 + UInt($1) }
} ?? 0
)
}
}
Here's a simple function
func mbcc(foo: String) -> Int
{
let chars = foo.utf8
var result: Int = 0
for aChar in chars
{
result = result << 8 + Int(aChar)
}
return result
}
let a = mbcc("TEXT")
print(String(format: "0x%lx", a)) // Prints 0x54455854
It will work for strings that will fit in an Int. Once they get longer it starts losing digits from the top.
If you use
result = result * 256 + Int(aChar)
you should get a crash when the string gets too big instead.
Using NSHFSTypeCodeFromFileType does work, but only for 4-character strings wrapped with single quotes, aka 6-character strings. It returns 0 for unquoted 4-character strings.
So wrap your 4-character string in ' ' before passing it to the function:
extension FourCharCode: ExpressibleByStringLiteral {
public init(stringLiteral value: StringLiteralType) {
switch (value.count, value.first, value.last) {
case (6, "'", "'"):
self = NSHFSTypeCodeFromFileType(value)
case (4, _, _):
self = NSHFSTypeCodeFromFileType("'\(value)'")
default:
self = 0
}
}
}
Using the above extension, you can use 4-character or single-quoted 6-character string literals:
let record = NSAppleEventDescriptor.record()
record.setDescriptor(NSAppleEventDescriptor(boolean: true), forKeyword: "4444")
record.setDescriptor(NSAppleEventDescriptor(boolean: true), forKeyword: "'6666'")
It would be even better to limit the string literal to 4-character strings at compile time. That does not seem to currently be possible, but is being discussed for Swift here:
Allow for Compile-Time Checked Intervals for Parameters Expecting Literal Values

How do I get the currently connected network interface name using Cocoa or Foundation?

I need to know the network interface name of the currently connected network interface, as in en0, lo0 and so on.
Is there a Cocoa/Foundation function that is going to give me this information?
You can cycle through network interfaces and get their names, IP addresses, etc.
#include <ifaddrs.h>
// you may need to include other headers
struct ifaddrs* interfaces = NULL;
struct ifaddrs* temp_addr = NULL;
// retrieve the current interfaces - returns 0 on success
NSInteger success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while (temp_addr != NULL)
{
if (temp_addr->ifa_addr->sa_family == AF_INET) // internetwork only
{
NSString* name = [NSString stringWithUTF8String:temp_addr->ifa_name];
NSString* address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
NSLog(#"interface name: %#; address: %#", name, address);
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
There are many other flags and data in the above structures, I hope you will find what you are looking for.
Since iOS works slightly differently to OSX, we had luck using the following code based on Davyd's answer to see the names of all available network interfaces on an iPhone: (also see here for full documentation on ifaddrs)
#include <ifaddrs.h>
struct ifaddrs* interfaces = NULL;
struct ifaddrs* temp_addr = NULL;
// retrieve the current interfaces - returns 0 on success
NSInteger success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while (temp_addr != NULL)
{
NSString* name = [NSString stringWithUTF8String:temp_addr->ifa_name];
NSLog(#"interface name: %#", name);
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
Alternatively you can also utilize if_indextoname() to get available interface names. Here is how Swift implementation would look like:
public func interfaceNames() -> [String] {
let MAX_INTERFACES = 128;
var interfaceNames = [String]()
let interfaceNamePtr = UnsafeMutablePointer<Int8>.alloc(Int(IF_NAMESIZE))
for interfaceIndex in 1...MAX_INTERFACES {
if (if_indextoname(UInt32(interfaceIndex), interfaceNamePtr) != nil){
if let interfaceName = String.fromCString(interfaceNamePtr) {
interfaceNames.append(interfaceName)
}
} else {
break
}
}
interfaceNamePtr.dealloc(Int(IF_NAMESIZE))
return interfaceNames
}
Ported the sample code of #ambientlight to iOS 13:
public func interfaceNames() -> [String] {
let MAX_INTERFACES = 128;
var interfaceNames = [String]()
let interfaceNamePtr = UnsafeMutablePointer<Int8>.allocate(capacity: Int(Int(IF_NAMESIZE)))
for interfaceIndex in 1...MAX_INTERFACES {
if (if_indextoname(UInt32(interfaceIndex), interfaceNamePtr) != nil){
let interfaceName = String(cString: interfaceNamePtr)
interfaceNames.append(interfaceName)
} else {
break
}
}
interfaceNamePtr.deallocate()
return interfaceNames
}
Most likely leaking memory - Use with caution.
Output:
▿ 20 elements
- 0 : "lo0"
- 1 : "pdp_ip0"
- 2 : "pdp_ip1"
- 3 : "pdp_ip2"
- 4 : "pdp_ip3"
- 5 : "pdp_ip5"
- 6 : "pdp_ip4"
- 7 : "pdp_ip6"
- 8 : "pdp_ip7"
- 9 : "ap1"
- 10 : "en0"
- 11 : "en1"
- 12 : "en2"
- 13 : "ipsec0"
- 14 : "ipsec1"
- 15 : "ipsec2"
- 16 : "ipsec3"
- 17 : "awdl0"
- 18 : "utun0"
- 19 : "utun1"

Creating a custom CFType

Is it possible to create opaque types not derived from CFTypeRef which can be retained/released with CFRetain/CFRelease? Or how do I derive a new type from a CFType?
I've never done this, but it is possible using private API. In all likelihood it will be dependent on a specific dot release of OS X, since the CF runtime could change from release to release. In any case, CF is open source so I took a look at what CFRuntime does. I was happy to see Apple included an example:
// ========================= EXAMPLE =========================
// Example: EXRange -- a "range" object, which keeps the starting
// location and length of the range. ("EX" as in "EXample").
// ---- API ----
typedef const struct __EXRange * EXRangeRef;
CFTypeID EXRangeGetTypeID(void);
EXRangeRef EXRangeCreate(CFAllocatorRef allocator, uint32_t location, uint32_t length);
uint32_t EXRangeGetLocation(EXRangeRef rangeref);
uint32_t EXRangeGetLength(EXRangeRef rangeref);
// ---- implementation ----
#include <CoreFoundation/CFBase.h>
#include <CoreFoundation/CFString.h>
struct __EXRange {
CFRuntimeBase _base;
uint32_t _location;
uint32_t _length;
};
static Boolean __EXRangeEqual(CFTypeRef cf1, CFTypeRef cf2) {
EXRangeRef rangeref1 = (EXRangeRef)cf1;
EXRangeRef rangeref2 = (EXRangeRef)cf2;
if (rangeref1->_location != rangeref2->_location) return false;
if (rangeref1->_length != rangeref2->_length) return false;
return true;
}
static CFHashCode __EXRangeHash(CFTypeRef cf) {
EXRangeRef rangeref = (EXRangeRef)cf;
return (CFHashCode)(rangeref->_location + rangeref->_length);
}
static CFStringRef __EXRangeCopyFormattingDesc(CFTypeRef cf, CFDictionaryRef formatOpts) {
EXRangeRef rangeref = (EXRangeRef)cf;
return CFStringCreateWithFormat(CFGetAllocator(rangeref), formatOpts,
CFSTR("[%u, %u)"),
rangeref->_location,
rangeref->_location + rangeref->_length);
}
static CFStringRef __EXRangeCopyDebugDesc(CFTypeRef cf) {
EXRangeRef rangeref = (EXRangeRef)cf;
return CFStringCreateWithFormat(CFGetAllocator(rangeref), NULL,
CFSTR("<EXRange %p [%p]>{loc = %u, len = %u}"),
rangeref,
CFGetAllocator(rangeref),
rangeref->_location,
rangeref->_length);
}
static void __EXRangeEXRangeFinalize(CFTypeRef cf) {
EXRangeRef rangeref = (EXRangeRef)cf;
// nothing to finalize
}
static CFTypeID _kEXRangeID = _kCFRuntimeNotATypeID;
static CFRuntimeClass _kEXRangeClass = {0};
/* Something external to this file is assumed to call this
* before the EXRange class is used.
*/
void __EXRangeClassInitialize(void) {
_kEXRangeClass.version = 0;
_kEXRangeClass.className = "EXRange";
_kEXRangeClass.init = NULL;
_kEXRangeClass.copy = NULL;
_kEXRangeClass.finalize = __EXRangeEXRangeFinalize;
_kEXRangeClass.equal = __EXRangeEqual;
_kEXRangeClass.hash = __EXRangeHash;
_kEXRangeClass.copyFormattingDesc = __EXRangeCopyFormattingDesc;
_kEXRangeClass.copyDebugDesc = __EXRangeCopyDebugDesc;
_kEXRangeID = _CFRuntimeRegisterClass((const CFRuntimeClass * const)&_kEXRangeClass);
}
CFTypeID EXRangeGetTypeID(void) {
return _kEXRangeID;
}
EXRangeRef EXRangeCreate(CFAllocatorRef allocator, uint32_t location, uint32_t length) {
struct __EXRange *newrange;
uint32_t extra = sizeof(struct __EXRange) - sizeof(CFRuntimeBase);
newrange = (struct __EXRange *)_CFRuntimeCreateInstance(allocator, _kEXRangeID, extra, NULL);
if (NULL == newrange) {
return NULL;
}
newrange->_location = location;
newrange->_length = length;
return (EXRangeRef)newrange;
}
uint32_t EXRangeGetLocation(EXRangeRef rangeref) {
return rangeref->_location;
}
uint32_t EXRangeGetLength(EXRangeRef rangeref) {
return rangeref->_length;
}
#endif
CoreFoundation itself does not provide any such mechanism, but all Cocoa objects will work with CFRetain and CFRelease. So the only supported answer is: Create a class based on Foundation and CoreFoundation will recognize it as a CFTypeRef.