use libmtp_sys as ffi;
use std::ffi::CStr;
use std::fmt::{self, Debug};
use std::mem::MaybeUninit;
use crate::device::MtpDevice;
use crate::error::{Error, MtpErrorKind};
use crate::internals::{maybe_init, DeviceEntry};
use crate::Result;
pub struct RawDevice {
pub(crate) inner: ffi::LIBMTP_raw_device_struct,
}
impl Debug for RawDevice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RawDevice")
.field("bus_number", &self.bus_number())
.field("dev_number", &self.dev_number())
.field("device_entry", &self.device_entry())
.finish()
}
}
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
}