From 512a7f0c3c8c866d38f442d61f126ce08b8195a1 Mon Sep 17 00:00:00 2001 From: Christian Meusel Date: Sun, 22 Sep 2024 22:31:10 +0200 Subject: [PATCH] Start using core-foundation for more convenience on macOS The code in question still builds fine for aarch64-apple-ios. So there is no obvious reason for not pulling in more convenience. --- Cargo.toml | 1 + src/posix/enumerate.rs | 161 ++++++++++++----------------------------- 2 files changed, 47 insertions(+), 115 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad8f9772..749c49dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ libudev = { version = "0.3.0", optional = true } unescaper = "0.1.3" [target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies] +core-foundation = "0.10.0" core-foundation-sys = "0.8.4" io-kit-sys = "0.4.0" mach2 = "0.4.1" diff --git a/src/posix/enumerate.rs b/src/posix/enumerate.rs index cb769fc2..c3776e28 100644 --- a/src/posix/enumerate.rs +++ b/src/posix/enumerate.rs @@ -8,9 +8,12 @@ cfg_if! { cfg_if! { if #[cfg(any(target_os = "ios", target_os = "macos"))] { + use core_foundation::base::TCFType; + use core_foundation::base::CFType; + use core_foundation::number::CFNumber; + use core_foundation::string::CFString; use core_foundation_sys::base::*; use core_foundation_sys::dictionary::*; - use core_foundation_sys::number::*; use core_foundation_sys::string::*; use io_kit_sys::*; use io_kit_sys::keys::*; @@ -18,7 +21,6 @@ cfg_if! { use io_kit_sys::types::*; use io_kit_sys::usb::lib::*; use nix::libc::{c_char, c_void}; - use std::convert::TryInto; use std::ffi::{CStr, CString}; use std::mem::MaybeUninit; } @@ -299,123 +301,54 @@ fn get_parent_device_by_type( #[cfg(any(target_os = "ios", target_os = "macos"))] #[allow(non_upper_case_globals)] /// Returns a specific property of the given device as an integer. -fn get_int_property( - device_type: io_registry_entry_t, - property: &str, - cf_number_type: CFNumberType, -) -> Result { - unsafe { - let prop_str = CString::new(property).unwrap(); - let key = CFStringCreateWithCString( - kCFAllocatorDefault, - prop_str.as_ptr(), - kCFStringEncodingUTF8, - ); - if key.is_null() { - return Err(Error::new( - ErrorKind::Unknown, - "Failed to create CFString for key", - )); - } - let _key_guard = scopeguard::guard((), |_| { - CFRelease(key as *const c_void); - }); +fn get_int_property(device_type: io_registry_entry_t, property: &str) -> Result { + let cf_property = CFString::new(property); - let container = IORegistryEntryCreateCFProperty(device_type, key, kCFAllocatorDefault, 0); - if container.is_null() { - return Err(Error::new(ErrorKind::Unknown, "Failed to get property")); - } - let _container_guard = scopeguard::guard((), |_| { - CFRelease(container); - }); - - match cf_number_type { - kCFNumberSInt8Type => { - let mut num: u8 = 0; - let num_ptr: *mut c_void = &mut num as *mut _ as *mut c_void; - if CFNumberGetValue(container as CFNumberRef, cf_number_type, num_ptr) { - Ok(num as u32) - } else { - Err(Error::new( - ErrorKind::Unknown, - "Failed to get numerical value", - )) - } - } - kCFNumberSInt16Type => { - let mut num: u16 = 0; - let num_ptr: *mut c_void = &mut num as *mut _ as *mut c_void; - if CFNumberGetValue(container as CFNumberRef, cf_number_type, num_ptr) { - Ok(num as u32) - } else { - Err(Error::new( - ErrorKind::Unknown, - "Failed to get numerical value", - )) - } - } - kCFNumberSInt32Type => { - let mut num: u32 = 0; - let num_ptr: *mut c_void = &mut num as *mut _ as *mut c_void; - if CFNumberGetValue(container as CFNumberRef, cf_number_type, num_ptr) { - Ok(num) - } else { - Err(Error::new( - ErrorKind::Unknown, - "Failed to get numerical value", - )) - } - } - _ => Err(Error::new(ErrorKind::Unknown, "Unsupported CFNumberType")), - } + let cf_type_ref = unsafe { + IORegistryEntryCreateCFProperty( + device_type, + cf_property.as_concrete_TypeRef(), + kCFAllocatorDefault, + 0, + ) + }; + if cf_type_ref.is_null() { + return Err(Error::new(ErrorKind::Unknown, "Failed to get property")); } + + let cf_type = unsafe { CFType::wrap_under_create_rule(cf_type_ref) }; + cf_type + .downcast::() + .and_then(|n| n.to_i64()) + .map(|n| n as u32) + .ok_or(Error::new( + ErrorKind::Unknown, + "Failed to get numerical value", + )) } #[cfg(any(target_os = "ios", target_os = "macos"))] /// Returns a specific property of the given device as a string. fn get_string_property(device_type: io_registry_entry_t, property: &str) -> Result { - unsafe { - let prop_str = CString::new(property).unwrap(); - let key = CFStringCreateWithCString( - kCFAllocatorDefault, - prop_str.as_ptr(), - kCFStringEncodingUTF8, - ); - if key.is_null() { - return Err(Error::new( - ErrorKind::Unknown, - "Failed to create CFString for key", - )); - } - let _key_guard = scopeguard::guard((), |_| { - CFRelease(key as *const c_void); - }); + let cf_property = CFString::new(property); - let container = IORegistryEntryCreateCFProperty(device_type, key, kCFAllocatorDefault, 0); - if container.is_null() { - return Err(Error::new(ErrorKind::Unknown, "Failed to get property")); - } - let _container_guard = scopeguard::guard((), |_| { - CFRelease(container); - }); - - let mut buf = Vec::with_capacity(256); - if true as Boolean - == CFStringGetCString( - container as CFStringRef, - buf.as_mut_ptr(), - buf.capacity().try_into().unwrap(), - kCFStringEncodingUTF8, - ) - { - Ok(CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string()) - } else { - Err(Error::new( - ErrorKind::Unknown, - "Failed to get C string from property value", - )) - } + let cf_type_ref = unsafe { + IORegistryEntryCreateCFProperty( + device_type, + cf_property.as_concrete_TypeRef(), + kCFAllocatorDefault, + 0, + ) + }; + if cf_type_ref.is_null() { + return Err(Error::new(ErrorKind::Unknown, "Failed to get property")); } + + let cf_type = unsafe { CFType::wrap_under_create_rule(cf_type_ref) }; + cf_type + .downcast::() + .map(|s| s.to_string()) + .ok_or(Error::new(ErrorKind::Unknown, "Failed to get string value")) } #[cfg(any(target_os = "ios", target_os = "macos"))] @@ -430,10 +363,8 @@ fn port_type(service: io_object_t) -> SerialPortType { .or_else(|| get_parent_device_by_type(service, legacy_usb_device_class_name)); if let Some(usb_device) = maybe_usb_device { SerialPortType::UsbPort(UsbPortInfo { - vid: get_int_property(usb_device, "idVendor", kCFNumberSInt16Type).unwrap_or_default() - as u16, - pid: get_int_property(usb_device, "idProduct", kCFNumberSInt16Type).unwrap_or_default() - as u16, + vid: get_int_property(usb_device, "idVendor").unwrap_or_default() as u16, + pid: get_int_property(usb_device, "idProduct").unwrap_or_default() as u16, serial_number: get_string_property(usb_device, "USB Serial Number").ok(), manufacturer: get_string_property(usb_device, "USB Vendor Name").ok(), product: get_string_property(usb_device, "USB Product Name").ok(), @@ -444,7 +375,7 @@ fn port_type(service: io_object_t) -> SerialPortType { // https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_driverkit_transport_usb // https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/USBBook/USBOverview/USBOverview.html#//apple_ref/doc/uid/TP40002644-BBCEACAJ #[cfg(feature = "usbportinfo-interface")] - interface: get_int_property(usb_device, "bInterfaceNumber", kCFNumberSInt8Type) + interface: get_int_property(usb_device, "bInterfaceNumber") .map(|x| x as u8) .ok(), })