updates
This commit is contained in:
@@ -14,3 +14,6 @@ path = "src/lib.rs"
|
||||
cdrustanoia_core.workspace = true
|
||||
cdrustanoia_capi_types.workspace = true
|
||||
libc.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
use cdrustanoia_capi_types::*;
|
||||
use cdrustanoia_core::device::discover;
|
||||
use cdrustanoia_core::device::image::ImageDrive;
|
||||
use cdrustanoia_core::device::{DiscToc, Drive, InterfaceKind, ReadError};
|
||||
use libc::{c_char, c_int, c_long, c_void};
|
||||
use std::ffi::CString;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
|
||||
pub struct BackendHolder {
|
||||
@@ -42,6 +44,12 @@ unsafe fn set_error(d: *mut CdromDrive, message: &str) {
|
||||
(*d).errorbuf = cstr(message);
|
||||
}
|
||||
|
||||
unsafe fn set_message(messages: *mut *mut c_char, message: &str) {
|
||||
if !messages.is_null() && (*messages).is_null() {
|
||||
*messages = cstr(message);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn holder<'a>(d: *mut CdromDrive) -> Option<&'a mut BackendHolder> {
|
||||
if d.is_null() {
|
||||
return None;
|
||||
@@ -65,6 +73,13 @@ pub unsafe fn make_drive(
|
||||
) -> *mut CdromDrive {
|
||||
let mut d = Box::new(CdromDrive::empty());
|
||||
d.drive_type = 0;
|
||||
d.is_atapi = backend.is_atapi() as c_int;
|
||||
d.is_mmc = backend.is_mmc() as c_int;
|
||||
d.density = backend.density();
|
||||
d.fua = backend.fua() as c_int;
|
||||
d.lun = backend.lun();
|
||||
d.adjust_ssize = backend.adjust_ssize() as c_int;
|
||||
d.bigbuff = backend.nsectors().max(0).saturating_mul(2352) as c_long;
|
||||
d.interface = match backend.interface() {
|
||||
InterfaceKind::SgIo => INTERFACE_SGIO_SCSI,
|
||||
InterfaceKind::Cooked => INTERFACE_COOKED_IOCTL,
|
||||
@@ -141,10 +156,23 @@ unsafe fn read_into(
|
||||
sectors: c_long,
|
||||
) -> Result<usize, ReadError> {
|
||||
let h = holder(d).ok_or_else(ReadError::closed)?;
|
||||
if !d.is_null() {
|
||||
h.drive.set_error_retry((*d).error_retry != 0);
|
||||
if (*d).nsectors > 0 {
|
||||
h.drive.set_nsectors((*d).nsectors as i64);
|
||||
}
|
||||
if (*d).bigendianp >= 0 {
|
||||
h.drive.set_bigendianp((*d).bigendianp);
|
||||
}
|
||||
}
|
||||
if p.is_null() {
|
||||
h.drive.read_audio_raw(None, begin as i64, sectors as i64)
|
||||
} else {
|
||||
let len = (sectors.max(0) as usize) * cdrustanoia_core::device::CD_FRAMESIZE_RAW;
|
||||
let Some(len) =
|
||||
(sectors.max(0) as usize).checked_mul(cdrustanoia_core::device::CD_FRAMESIZE_RAW)
|
||||
else {
|
||||
return Err(ReadError::new(libc::EINVAL, "Invalid read size"));
|
||||
};
|
||||
let buf = std::slice::from_raw_parts_mut(p as *mut u8, len);
|
||||
h.drive
|
||||
.read_audio_raw(Some(buf), begin as i64, sectors as i64)
|
||||
@@ -212,6 +240,7 @@ unsafe fn fill_toc(d: *mut CdromDrive) {
|
||||
(*d).audio_last_sector = toc.disc_lastsector() as c_long;
|
||||
(*d).bigendianp = h.drive.bigendianp();
|
||||
(*d).nsectors = h.drive.nsectors() as c_int;
|
||||
(*d).bigbuff = (*d).nsectors.max(0) as c_long * 2352;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -242,7 +271,13 @@ unsafe fn cdda_identify_impl(
|
||||
};
|
||||
match discover::identify_device(device, messagedest == CDDA_MESSAGE_PRINTIT) {
|
||||
Ok(drive) => make_drive(device, Some(device), drive),
|
||||
Err(_) => ptr::null_mut(),
|
||||
Err(e) => {
|
||||
set_message(
|
||||
messages,
|
||||
&format!("\tCould not identify {}: {}\n", device, e),
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +309,13 @@ unsafe fn cdda_identify_cooked_impl(
|
||||
};
|
||||
match discover::identify_cooked(device, messagedest == CDDA_MESSAGE_PRINTIT) {
|
||||
Ok(drive) => make_drive(device, Some(device), drive),
|
||||
Err(_) => ptr::null_mut(),
|
||||
Err(e) => {
|
||||
set_message(
|
||||
messages,
|
||||
&format!("\tCould not identify cooked device {}: {}\n", device, e),
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,9 +361,64 @@ unsafe fn cdda_identify_scsi_impl(
|
||||
return make_drive(dev, Some(dev), drive);
|
||||
}
|
||||
}
|
||||
set_message(
|
||||
messages,
|
||||
"\tCould not identify a usable SCSI/cooked device\n",
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn cdda_identify_test(
|
||||
filename: *const c_char,
|
||||
messagedest: c_int,
|
||||
messages: *mut *mut c_char,
|
||||
) -> *mut CdromDrive {
|
||||
ffi_guard(ptr::null_mut(), || {
|
||||
cdda_identify_test_impl(filename, messagedest, messages)
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn cdda_identify_test_impl(
|
||||
filename: *const c_char,
|
||||
messagedest: c_int,
|
||||
messages: *mut *mut c_char,
|
||||
) -> *mut CdromDrive {
|
||||
if !messages.is_null() {
|
||||
*messages = ptr::null_mut();
|
||||
}
|
||||
if filename.is_null() {
|
||||
set_message(messages, "\tNo filename supplied for test interface\n");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let filename = match std::ffi::CStr::from_ptr(filename).to_str() {
|
||||
Ok(value) => value,
|
||||
Err(_) => return ptr::null_mut(),
|
||||
};
|
||||
let verbose = messagedest == CDDA_MESSAGE_PRINTIT;
|
||||
if verbose {
|
||||
eprintln!("\tTesting {} for file/test interface", filename);
|
||||
}
|
||||
match ImageDrive::open_path(Path::new(filename)) {
|
||||
Ok(drive) => {
|
||||
if verbose {
|
||||
eprintln!("\t\tCDROM sensed: {}", drive.drive_model());
|
||||
}
|
||||
make_drive(filename, None, Box::new(drive))
|
||||
}
|
||||
Err(e) => {
|
||||
if verbose {
|
||||
eprintln!("\t\tCould not open file {}: {}", filename, e);
|
||||
}
|
||||
set_message(
|
||||
messages,
|
||||
&format!("\tCould not open file {}: {}\n", filename, e),
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn cdda_find_a_cdrom(
|
||||
messagedest: c_int,
|
||||
@@ -342,7 +438,10 @@ unsafe fn cdda_find_a_cdrom_impl(
|
||||
}
|
||||
match discover::find_a_cdrom(messagedest == CDDA_MESSAGE_PRINTIT) {
|
||||
Some(drive) => make_drive("auto", None, drive),
|
||||
None => ptr::null_mut(),
|
||||
None => {
|
||||
set_message(messages, "\tNo CD-ROM drive found\n");
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,6 +542,7 @@ unsafe fn cdda_read_timed_impl(
|
||||
return -400;
|
||||
}
|
||||
};
|
||||
h.drive.set_error_retry((*d).error_retry != 0);
|
||||
if (*d).bigendianp >= 0 {
|
||||
h.drive.set_bigendianp((*d).bigendianp);
|
||||
}
|
||||
@@ -452,7 +552,12 @@ unsafe fn cdda_read_timed_impl(
|
||||
let timed = if buffer.is_null() {
|
||||
h.drive.read_timed(None, beginsector as i64, sectors as i64)
|
||||
} else {
|
||||
let len = (sectors as usize) * cdrustanoia_core::device::CD_FRAMESIZE_RAW;
|
||||
let Some(len) = (sectors as usize).checked_mul(cdrustanoia_core::device::CD_FRAMESIZE_RAW)
|
||||
else {
|
||||
set_errno(libc::EINVAL);
|
||||
set_error(d, "Invalid read size\n");
|
||||
return -7;
|
||||
};
|
||||
let buf = std::slice::from_raw_parts_mut(buffer as *mut u8, len);
|
||||
h.drive
|
||||
.read_timed(Some(buf), beginsector as i64, sectors as i64)
|
||||
@@ -460,6 +565,9 @@ unsafe fn cdda_read_timed_impl(
|
||||
if !ms.is_null() {
|
||||
*ms = timed.milliseconds;
|
||||
}
|
||||
if !(*d).private.is_null() {
|
||||
(*(*d).private).last_milliseconds = timed.milliseconds;
|
||||
}
|
||||
if (*d).bigendianp < 0 {
|
||||
(*d).bigendianp = h.drive.bigendianp();
|
||||
}
|
||||
@@ -680,6 +788,7 @@ mod tests {
|
||||
TimedRead {
|
||||
result: Err(ReadError::closed()),
|
||||
milliseconds: -1,
|
||||
microseconds: -1,
|
||||
}
|
||||
}
|
||||
fn speed_set(&mut self, _speed: i32) -> i32 {
|
||||
@@ -702,6 +811,29 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn c_abi_version_stays_cdparanoia_compatible() {
|
||||
let version = unsafe { std::ffi::CStr::from_ptr(cdda_version()) };
|
||||
assert_eq!(version.to_str().unwrap(), "10.2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_interface_exposes_image_backend() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let image = dir.path().join("disc.raw");
|
||||
std::fs::write(&image, vec![0u8; 2352 * 10]).unwrap();
|
||||
let name = CString::new(image.to_string_lossy().as_bytes()).unwrap();
|
||||
unsafe {
|
||||
let d = cdda_identify_test(name.as_ptr(), CDDA_MESSAGE_FORGETIT, ptr::null_mut());
|
||||
assert!(!d.is_null());
|
||||
assert_eq!((*d).interface, INTERFACE_TEST);
|
||||
assert_eq!(cdda_open(d), 0);
|
||||
assert_eq!(cdda_tracks(d), 1);
|
||||
assert_eq!(cdda_disc_lastsector(d), 9);
|
||||
assert_eq!(cdda_close(d), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn c_api_catches_panics() {
|
||||
unsafe {
|
||||
|
||||
Reference in New Issue
Block a user