213 lines
6.8 KiB
Rust
213 lines
6.8 KiB
Rust
#![allow(non_snake_case)]
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
mod bindings;
|
|
use bindings::*;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum SupportedFsvVersion {
|
|
V1_40_14, // 1.40.14
|
|
V1_40_13, // 1.40.13
|
|
}
|
|
|
|
impl SupportedFsvVersion {
|
|
fn as_str(&self) -> &'static str {
|
|
match self {
|
|
Self::V1_40_14 => "1.40.14",
|
|
Self::V1_40_13 => "1.40.13",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
pub enum Error {
|
|
#[error(transparent)]
|
|
LibLoading(#[from] libloading::Error),
|
|
#[error("Symbol missing: {0}")]
|
|
SymbolMissing(&'static str),
|
|
}
|
|
|
|
/// Macro to generate a function that implements a call to an external function in BINDINGS
|
|
macro_rules! ssv_function {
|
|
($binding:ty, $func_name:ident, {$($arg_name:ident: $arg_type:ty),*}) => {
|
|
/// # Safety
|
|
/// This function is unsafe because it calls an external function through FFI.
|
|
/// The caller must ensure that the provided arguments are valid and that the
|
|
/// external function is safe to call.
|
|
pub unsafe fn $func_name(&self, $($arg_name: $arg_type),*) -> Result<u16, Error> {
|
|
let symbol_name = match stringify!($binding)
|
|
.split(&[' ', ':'])
|
|
.last() {
|
|
Some(name) => name,
|
|
None => return Err(Error::SymbolMissing(stringify!($binding))),
|
|
};
|
|
let func_struct: libloading::Symbol<'_, $binding> =
|
|
unsafe { self.library.get(symbol_name.as_bytes())? };
|
|
let func = match *func_struct {
|
|
Some(func) => func,
|
|
None => return Err(Error::SymbolMissing(stringify!($binding))),
|
|
};
|
|
Ok(func($($arg_name),*))
|
|
}
|
|
};
|
|
}
|
|
|
|
/// `sealed::Sealed` trait is used to prevent external crates from implementing the LibVersion trait.
|
|
mod sealed { pub trait Sealed {}}
|
|
|
|
/// Wrapper around the SESAM-VITALE library
|
|
/// This struct is responsible for loading the library and providing an interface to call its functions.
|
|
/// The library is loaded at creation and kept in memory until the struct is dropped.
|
|
pub trait SSVLibraryCommon {
|
|
fn new(path: &str) -> Result<Self, Error> where Self: Sized;
|
|
}
|
|
|
|
pub trait SSVLibraryVersion: sealed::Sealed {}
|
|
|
|
pub struct V1_40_13 {}
|
|
impl sealed::Sealed for V1_40_13 {}
|
|
impl SSVLibraryVersion for V1_40_13 {}
|
|
|
|
pub struct V1_40_14 {}
|
|
impl sealed::Sealed for V1_40_14 {}
|
|
impl SSVLibraryVersion for V1_40_14 {}
|
|
|
|
pub struct SSVLibrary<Version: SSVLibraryVersion> {
|
|
_version: PhantomData<Version>,
|
|
library: libloading::Library,
|
|
}
|
|
|
|
impl<Version: SSVLibraryVersion> SSVLibraryCommon for SSVLibrary<Version> {
|
|
fn new(path: &str) -> Result<Self, Error> {
|
|
let library = unsafe { libloading::Library::new(path)?};
|
|
Ok(Self {
|
|
_version: PhantomData,
|
|
library
|
|
})
|
|
}
|
|
}
|
|
|
|
impl SSVLibrary<V1_40_14> {
|
|
pub fn library(&self) -> &libloading::Library {
|
|
&self.library
|
|
}
|
|
|
|
ssv_function!(BINDINGS_V1_40_14::SSV_InitLIB2, ssv_init_lib2, {
|
|
pcFichierSesam: *const i8
|
|
});
|
|
|
|
ssv_function!(BINDINGS_V1_40_14::SSV_LireConfig, ssv_lire_config, {
|
|
pZDataOut: *mut *mut libc::c_void,
|
|
psTailleDataOut: *mut usize
|
|
});
|
|
|
|
ssv_function!(BINDINGS_V1_40_14::SSV_LireCartePS, ssv_lire_carte_ps, {
|
|
NomRessourcePS: *const i8,
|
|
NomRessourceLecteur: *const i8,
|
|
CodePorteurPS: *const i8,
|
|
pZDataOut: *mut *mut libc::c_void,
|
|
pTailleZone: *mut usize
|
|
});
|
|
}
|
|
|
|
impl SSVLibrary<V1_40_13> {
|
|
ssv_function!(BINDINGS_V1_40_13::SSV_InitLIB2, ssv_init_lib2, {
|
|
pcFichierSesam: *const i8
|
|
});
|
|
|
|
ssv_function!(BINDINGS_V1_40_13::SSV_LireConfig, ssv_lire_config, {
|
|
pZDataOut: *mut *mut libc::c_void,
|
|
psTailleDataOut: *mut usize
|
|
});
|
|
|
|
ssv_function!(BINDINGS_V1_40_13::SSV_LireCartePS, ssv_lire_carte_ps, {
|
|
NomRessourcePS: *const i8,
|
|
NomRessourceLecteur: *const i8,
|
|
CodePorteurPS: *const i8,
|
|
pZDataOut: *mut *mut libc::c_void,
|
|
pTailleZone: *mut usize
|
|
});
|
|
}
|
|
|
|
pub fn get_library_path(version: &SupportedFsvVersion) -> String {
|
|
let root_path = get_library_root_path();
|
|
let library_name = get_library_name();
|
|
let version = version.as_str();
|
|
format!("{root_path}/{version}/lib/{library_name}")
|
|
}
|
|
|
|
pub fn sesam_ini_path(version: &SupportedFsvVersion) -> String {
|
|
let root_path = get_sesam_ini_root_path();
|
|
let version = version.as_str();
|
|
format!("{root_path}/{version}/conf/sesam.ini")
|
|
}
|
|
|
|
fn get_library_name() -> &'static str {
|
|
// TODO : Use libloading::library_filename to get platform-specific filename ?
|
|
"libssvlux64.so"
|
|
}
|
|
|
|
fn get_library_root_path() -> &'static str {
|
|
"/opt/santesocial/fsv"
|
|
}
|
|
|
|
fn get_sesam_ini_root_path() -> &'static str {
|
|
"/etc/opt/santesocial/fsv"
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use std::{ffi::CString, ptr};
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_initlib2() {
|
|
let lib_path = &get_library_path(&SupportedFsvVersion::V1_40_13);
|
|
let ssv_library = SSVLibrary::<V1_40_13>::new(lib_path).expect("SSVLibrary::new failed");
|
|
|
|
let sesam_ini_str =
|
|
CString::new(sesam_ini_path(&SupportedFsvVersion::V1_40_13)).expect("CString::new failed");
|
|
let result = unsafe { ssv_library.ssv_init_lib2(sesam_ini_str.as_ptr()) }.unwrap();
|
|
assert_eq!(result, 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_lire_config_and_carte_ps() {
|
|
let lib_path = &get_library_path(&SupportedFsvVersion::V1_40_13);
|
|
let ssv_library = SSVLibrary::<V1_40_13>::new(lib_path).expect("SSVLibrary::new failed");
|
|
|
|
let sesam_ini_str =
|
|
CString::new(sesam_ini_path(&SupportedFsvVersion::V1_40_13)).expect("CString::new failed");
|
|
let result = unsafe { ssv_library.ssv_init_lib2(sesam_ini_str.as_ptr()) }.unwrap();
|
|
assert_eq!(result, 0);
|
|
|
|
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
|
|
let mut size: libc::size_t = 0;
|
|
let result = unsafe { ssv_library.ssv_lire_config(&mut buffer_ptr, &mut size) }.unwrap();
|
|
assert_eq!(result, 0);
|
|
unsafe { libc::free(buffer_ptr) };
|
|
|
|
let nom_ressource_ps =
|
|
CString::new("Gemalto PC Twin Reader (645D94C3) 00 00").expect("CString::new failed");
|
|
let nom_ressource_lecteur =
|
|
CString::new("Gemalto PC Twin Reader (645D94C3) 00 00").expect("CString::new failed");
|
|
let code_porteur_ps = CString::new("1234").expect("CString::new failed");
|
|
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
|
|
let mut size: libc::size_t = 0;
|
|
let result = unsafe {
|
|
ssv_library.ssv_lire_carte_ps(
|
|
nom_ressource_ps.as_ptr(),
|
|
nom_ressource_lecteur.as_ptr(),
|
|
code_porteur_ps.as_ptr(),
|
|
&mut buffer_ptr,
|
|
&mut size,
|
|
)
|
|
}
|
|
.unwrap();
|
|
assert_eq!(result, 0);
|
|
unsafe { libc::free(buffer_ptr) };
|
|
}
|
|
}
|