592bffbd3a
- This is here for devices that may falsely request bus encryption due to bit flips in MPEG-2 PACK headers. - Not yet made an optional feature; need to figure out how to even talk with a drive over SCSI.
163 lines
4.2 KiB
Rust
163 lines
4.2 KiB
Rust
use std::ffi::{CStr, c_int, c_void};
|
|
use std::path::Path;
|
|
|
|
use crate::error::{Error, Result};
|
|
|
|
mod dvdcss;
|
|
mod error;
|
|
|
|
use dvdcss::*;
|
|
use semver::Version;
|
|
|
|
pub const BLOCK_SIZE: u32 = DVDCSS_BLOCK_SIZE;
|
|
pub const DVDCSS_VERSION: semver::Version = Version::new(
|
|
DVDCSS_VERSION_MAJOR as u64,
|
|
DVDCSS_VERSION_MINOR as u64,
|
|
DVDCSS_VERSION_MICRO as u64,
|
|
);
|
|
|
|
#[repr(u32)]
|
|
#[derive(Debug, Default)]
|
|
pub enum SeekFlag {
|
|
#[default]
|
|
None = DVDCSS_NOFLAGS,
|
|
Key = DVDCSS_SEEK_KEY,
|
|
Mpeg = DVDCSS_SEEK_MPEG,
|
|
}
|
|
|
|
// I dislike this as technically, 2 should be Unknown/Reserved and 3 as CPRM.
|
|
#[repr(i32)]
|
|
#[derive(Debug, Default)]
|
|
pub enum EncryptionScheme {
|
|
#[default]
|
|
None = 0,
|
|
CssCppm = 1,
|
|
//Reserved,
|
|
Cprm = 2,
|
|
Unknown,
|
|
}
|
|
|
|
impl TryFrom<i32> for EncryptionScheme {
|
|
type Error = Error;
|
|
|
|
fn try_from(value: i32) -> std::result::Result<Self, Self::Error> {
|
|
if !(0..=2).contains(&value) {
|
|
return Err(Error::I32ToEnumCastError {
|
|
value,
|
|
enum_: "EncryptionScheme".to_string(),
|
|
});
|
|
}
|
|
|
|
Ok(match value {
|
|
0 => Self::None,
|
|
1 => Self::CssCppm,
|
|
2 => Self::Cprm,
|
|
_ => unreachable!(),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[repr(transparent)]
|
|
pub struct DVD {
|
|
ptr: dvdcss_t,
|
|
}
|
|
|
|
impl DVD {
|
|
pub fn new<P: AsRef<Path>>(src: P) -> Option<Self> {
|
|
// Cast the path to a CStr (*const char), returning early if there's any issue.
|
|
let c_path = CStr::from_bytes_with_nul(src.as_ref().as_os_str().as_encoded_bytes())
|
|
.ok()?
|
|
.as_ptr();
|
|
|
|
// Make the FFI call.
|
|
let ptr = unsafe { dvdcss_open(c_path) };
|
|
|
|
if ptr.is_null() {
|
|
None
|
|
} else {
|
|
Some(Self { ptr })
|
|
}
|
|
}
|
|
|
|
// Seek in blocks (See: `BLOCK_SIZE`).
|
|
pub fn seek(&self, blocks: u32, flag: SeekFlag) -> Result<u32> {
|
|
// Although this call generally returns a negative value on fail, as of writing
|
|
// it can only return -1, so there's no point in expanding this fail result into
|
|
// a proper enum.
|
|
let retval = unsafe { dvdcss_seek(self.ptr, blocks as c_int, flag as c_int) };
|
|
|
|
if retval < 0 {
|
|
Err(Error::SeekError)
|
|
} else {
|
|
Ok(retval as u32)
|
|
}
|
|
}
|
|
|
|
pub fn read(&self, buf: &mut [u8], blocks: u32, decrypt: bool) -> Result<u32> {
|
|
// If the user has provided a wonk buffer size that's not a multiple of BLOCK_SIZE,
|
|
// I'm not fixing it for them.
|
|
// But ensure that buffer is big enough to safely read the data.
|
|
if buf.len() < (blocks * BLOCK_SIZE) as usize {
|
|
return Err(Error::InsufficientBufferLength);
|
|
}
|
|
|
|
let i_flags = if decrypt {
|
|
DVDCSS_READ_DECRYPT
|
|
} else {
|
|
DVDCSS_NOFLAGS
|
|
} as i32;
|
|
|
|
let retval = unsafe {
|
|
dvdcss_read(
|
|
self.ptr,
|
|
buf.as_mut_ptr() as *mut c_void,
|
|
blocks as c_int,
|
|
i_flags,
|
|
)
|
|
};
|
|
|
|
if retval < 0 {
|
|
// I can't track back the error return values for pf_read,
|
|
// so this is good enough for now.
|
|
return Err(Error::ReadError { value: retval });
|
|
}
|
|
|
|
Ok(retval as u32)
|
|
}
|
|
|
|
// Return the error message string from dvdcss_error
|
|
pub fn error(&self) -> &CStr {
|
|
unsafe { CStr::from_ptr(dvdcss_error(self.ptr)) }
|
|
}
|
|
|
|
// Return the error message string from dvdcss_error with lossy conversion.
|
|
pub fn error_lossy(&self) -> String {
|
|
self.error().to_string_lossy().to_string()
|
|
}
|
|
|
|
pub fn is_scrambled(&self) -> bool {
|
|
match unsafe { dvdcss_is_scrambled(self.ptr) } {
|
|
0 => false,
|
|
1 => true,
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
/*
|
|
pub fn encryption_type(&self) -> EncryptionScheme {
|
|
unsafe { dvdcss_get_encryption_type(self.ptr) }
|
|
.try_into()
|
|
.unwrap_or_default()
|
|
}
|
|
*/
|
|
}
|
|
|
|
impl Drop for DVD {
|
|
fn drop(&mut self) {
|
|
// Right... so drop can't handle return values.
|
|
// So... best option is ...panic?
|
|
let retval = unsafe { dvdcss_close(self.ptr) };
|
|
assert!(retval == 0);
|
|
}
|
|
}
|