use libmtp_sys as ffi;
use std::{ffi::CStr, mem::MaybeUninit};
use crate::{
error::{Error, MtpErrorKind},
internals::{maybe_init, DeviceEntry},
Result,
};
use super::MtpDevice;
pub struct RawDevice {
pub(crate) inner: ffi::LIBMTP_raw_device_struct,
}
impl RawDevice {
pub fn open(&self) -> Option<MtpDevice> {
unsafe {
let ptr = &self.inner as *const _;
let device = ffi::LIBMTP_Open_Raw_Device(ptr as *mut _);
if device.is_null() {
None
} else {
Some(MtpDevice { inner: device })
}
}
}
pub fn open_uncached(&self) -> Option<MtpDevice> {
unsafe {
let ptr = &self.inner as *const _;
let device = ffi::LIBMTP_Open_Raw_Device_Uncached(ptr as *mut _);
if device.is_null() {
None
} else {
Some(MtpDevice { inner: device })
}
}
}
pub fn bus_number(&self) -> u32 {
self.inner.bus_location
}
pub fn dev_number(&self) -> u8 {
self.inner.devnum
}
pub fn device_entry(&self) -> DeviceEntry {
let vendor;
let product;
unsafe {
vendor = CStr::from_ptr(self.inner.device_entry.vendor);
product = CStr::from_ptr(self.inner.device_entry.product);
}
DeviceEntry {
vendor: vendor.to_str().expect("Invalid UTF-8 in music-players.h?"),
vendor_id: self.inner.device_entry.vendor_id,
product: product.to_str().expect("Invalid UTF-8 in music-players.h?"),
product_id: self.inner.device_entry.product_id,
device_flags: self.inner.device_entry.device_flags,
}
}
}
pub fn detect_raw_devices() -> Result<Vec<RawDevice>> {
maybe_init();
unsafe {
let mut devices = std::ptr::null_mut();
let mut len = 0;
let res = ffi::LIBMTP_Detect_Raw_Devices(&mut devices, &mut len);
if let Some(kind) = MtpErrorKind::from_error_number(res) {
Err(Error::MtpError {
kind,
text: "Failed to detect raw devices".to_string(),
})
} else {
let mut devices_vec = Vec::with_capacity(len as usize);
for i in 0..(len as isize) {
let mut new = MaybeUninit::zeroed().assume_init();
std::ptr::copy_nonoverlapping(devices.offset(i), &mut new, 1);
devices_vec.push(RawDevice { inner: new });
}
libc::free(devices as *mut _);
Ok(devices_vec)
}
}
}
pub fn check_specific_device(bus_number: u32, dev_number: u32) -> bool {
let res = unsafe { ffi::LIBMTP_Check_Specific_Device(bus_number as i32, dev_number as i32) };
res == 1
}