Compare commits

..

No commits in common. "c9b1895e0caebfeaaebadbded8ed8c3ae3cfc5c6" and "473212c2e617b1131e055f2dd05274c22819ffaf" have entirely different histories.

3 changed files with 74 additions and 176 deletions

View File

@ -1,32 +0,0 @@
# État d'avancement de l'implémentation des bindings FSV
| Module | Progression |
|-------------|------------------------------------|
| [SSV](#ssv) | ![](https://geps.dev/progress/5) |
| [SGD](#sgd) | ![](https://geps.dev/progress/0) |
| [SRT](#srt) | ![](https://geps.dev/progress/0) |
| [STS](#sts) | ![](https://geps.dev/progress/0) |
## SSV
| Fonctions implémentées |
|------------------------|
| SSV_InitLIB2 |
| SSV_LireConfig |
| SSV_LireCartePS |
## SGD
| Fonctions implémentées |
|------------------------|
## SRT
| Fonctions implémentées |
|------------------------|
## STS
| Fonctions implémentées |
|------------------------|

View File

@ -1,25 +1,5 @@
# FSV-sys, bindings Rust pour le package FSV SESAM-Vitale
## Librairies FSV
### Versions supportées
| Version FSV |
|-------------|
| 1.40.14 |
| 1.40.13 |
### État d'avancement de l'implémentation des bindings FSV
Les détails de l'avancement de l'implémentation des bindings FSV sont donnés dans le fichier [PROGRESS.md](PROGRESS.md)
| Module | Progression |
|-------------|------------------------------------|
| [SSV](#ssv) | ![](https://geps.dev/progress/5) |
| [SGD](#sgd) | ![](https://geps.dev/progress/0) |
| [SRT](#srt) | ![](https://geps.dev/progress/0) |
| [STS](#sts) | ![](https://geps.dev/progress/0) |
## Utilisation
### Pré-requis

View File

@ -2,9 +2,7 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use std::marker::PhantomData;
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum SUPPORTED_FSV_VERSIONS {
V1_40_14, // 1.40.14
V1_40_13, // 1.40.13
@ -19,12 +17,30 @@ impl SUPPORTED_FSV_VERSIONS {
}
}
mod BINDINGS_V1_40_14 {
include!(concat!(env!("OUT_DIR"), "/bindings_1.40.14.rs"));
pub mod BINDINGS {
include!(concat!(env!("OUT_DIR"), "/bindings_1.40.13.rs"));
}
mod BINDINGS_V1_40_13 {
include!(concat!(env!("OUT_DIR"), "/bindings_1.40.13.rs"));
// We need to keep the this use statement to get `ssv_function` macro working well
use BINDINGS::*;
/// 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 func_struct: libloading::Symbol<'_, $binding> =
unsafe { self.library.get(stringify!($binding).as_bytes())? };
let func = match *func_struct {
Some(func) => func,
None => return Err(Error::SymbolMissing(stringify!($binding))),
};
Ok(func($($arg_name),*))
}
};
}
#[derive(thiserror::Error, Debug)]
@ -35,121 +51,15 @@ pub enum Error {
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 SSVLibrary_Common {
fn new(path: &str) -> Result<Self, Error> where Self: Sized;
}
pub trait SSVLibrary_Version: sealed::Sealed {}
pub struct V1_40_13 {}
impl sealed::Sealed for V1_40_13 {}
impl SSVLibrary_Version for V1_40_13 {}
pub struct V1_40_14 {}
impl sealed::Sealed for V1_40_14 {}
impl SSVLibrary_Version for V1_40_14 {}
pub struct SSVLibrary<Version: SSVLibrary_Version> {
_version: PhantomData<Version>,
#[derive(Debug)]
pub struct SSVLibrary {
version: SUPPORTED_FSV_VERSIONS,
library: libloading::Library,
}
impl<Version: SSVLibrary_Version> SSVLibrary_Common 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: &SUPPORTED_FSV_VERSIONS) -> 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: &SUPPORTED_FSV_VERSIONS) -> 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"
@ -163,6 +73,48 @@ fn get_sesam_ini_root_path() -> &'static str {
"/etc/opt/santesocial/fsv"
}
impl SSVLibrary {
pub fn new(version: SUPPORTED_FSV_VERSIONS) -> Result<Self, Error> {
let library_path = Self::get_library_path(&version);
let library = unsafe { libloading::Library::new(library_path)? };
Ok(SSVLibrary { version, library })
}
pub fn library(&self) -> &libloading::Library {
&self.library
}
pub fn sesam_ini_path(&self) -> String {
let root_path = get_sesam_ini_root_path();
let version = self.version.as_str();
format!("{root_path}/{version}/conf/sesam.ini")
}
pub fn get_library_path(version: &SUPPORTED_FSV_VERSIONS) -> 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}")
}
ssv_function!(SSV_InitLIB2, ssv_init_lib2, {
pcFichierSesam: *const i8
});
ssv_function!(SSV_LireConfig, ssv_lire_config, {
pZDataOut: *mut *mut libc::c_void,
psTailleDataOut: *mut usize
});
ssv_function!(SSV_LireCartePS, ssv_lire_carte_ps, {
NomRessourcePS: *const i8,
NomRessourceLecteur: *const i8,
CodePorteurPS: *const i8,
pZDataOut: *mut *mut libc::c_void,
pTailleZone: *mut usize
});
}
#[cfg(test)]
mod test {
use std::{ffi::CString, ptr};
@ -171,22 +123,22 @@ mod test {
#[test]
fn test_initlib2() {
let lib_path = &get_library_path(&SUPPORTED_FSV_VERSIONS::V1_40_13);
let ssv_library = SSVLibrary::<V1_40_13>::new(lib_path).expect("SSVLibrary::new failed");
let ssv_library =
SSVLibrary::new(SUPPORTED_FSV_VERSIONS::V1_40_13).expect("SSVLibrary::new failed");
let sesam_ini_str =
CString::new(sesam_ini_path(&SUPPORTED_FSV_VERSIONS::V1_40_13)).expect("CString::new failed");
CString::new(ssv_library.sesam_ini_path()).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(&SUPPORTED_FSV_VERSIONS::V1_40_13);
let ssv_library = SSVLibrary::<V1_40_13>::new(lib_path).expect("SSVLibrary::new failed");
let ssv_library =
SSVLibrary::new(SUPPORTED_FSV_VERSIONS::V1_40_13).expect("SSVLibrary::new failed");
let sesam_ini_str =
CString::new(sesam_ini_path(&SUPPORTED_FSV_VERSIONS::V1_40_13)).expect("CString::new failed");
CString::new(ssv_library.sesam_ini_path()).expect("CString::new failed");
let result = unsafe { ssv_library.ssv_init_lib2(sesam_ini_str.as_ptr()) }.unwrap();
assert_eq!(result, 0);
@ -194,7 +146,6 @@ mod test {
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");
@ -214,6 +165,5 @@ mod test {
}
.unwrap();
assert_eq!(result, 0);
unsafe { libc::free(buffer_ptr) };
}
}