WIP: creation-sys-crate-ssv #69
@ -1,122 +1,46 @@
|
||||
// to include std in docs, need to remove later
|
||||
#[doc(inline)]
|
||||
pub use std;
|
||||
|
||||
mod bindings;
|
||||
pub mod types;
|
||||
use std::io::Cursor;
|
||||
|
||||
use bindings::SSV_LireConfig;
|
||||
use binrw::BinRead;
|
||||
use std::ptr;
|
||||
use types::serialization_types::{DataBlock, DataField};
|
||||
use std::{fmt, ptr};
|
||||
use types::serialization_types::{read_from_buffer, Configuration};
|
||||
|
||||
//pub fn read_carte_professionnel_sante() -> Result<CarteProfessionnelSante, _> {
|
||||
// // how to init buffer and give it to library
|
||||
// // https://stackoverflow.com/questions/58231215/what-is-proper-rust-way-to-allocate-opaque-buffer-for-external-c-library
|
||||
// //
|
||||
// // when init memory zones and they are too large to be a single memory zone -> https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0c1f0fca7d98a97bbc70dba786bbedd9
|
||||
// unsafe {
|
||||
// let nom_ressource_ps;
|
||||
// let nom_ressource_lecteur;
|
||||
// let code_porteur_ps;
|
||||
// let p_zdata_out;
|
||||
// let p_taille_zone;
|
||||
// let status_code: u16 = SSV_LireCartePS(
|
||||
// nom_ressource_ps,
|
||||
// nom_ressource_lecteur,
|
||||
// code_porteur_ps,
|
||||
// p_zdata_out,
|
||||
// p_taille_zone,
|
||||
// );
|
||||
//
|
||||
// if status_code != 0 {
|
||||
// return Err(());
|
||||
// }
|
||||
// };
|
||||
//}
|
||||
|
||||
// To parse the data
|
||||
// allocate the multiple buffers
|
||||
// chain them to make a single buffer
|
||||
// use the parse_data_size function to get a size
|
||||
// use take method to limit number of bytes read
|
||||
// use binread implementaiton on each struct/enum de structure it
|
||||
// do this recursively until there is no more data
|
||||
|
||||
// Memory has three embricked concepts:
|
||||
// Memory Zone(s) -Contains-> DataBlock(s) -Contains-> DataField(s)
|
||||
// DataBlocks (and DataFields) can be cut off by the end of a memory zone
|
||||
// the data continues on the following memory zone
|
||||
//#[binread]
|
||||
pub struct DataBlock2 {
|
||||
//<T> {
|
||||
data_struct_id: u16,
|
||||
|
||||
// #[br(temp, parse_with = parse_data_size)]
|
||||
memory_size: u32,
|
||||
// spec indicates the DataBlock can be very large (up to 4GB)
|
||||
// in this case, we can use memmap2 to use the disk to store the data
|
||||
// pub data: Vec<DataField<T>>,
|
||||
#[derive(Debug)]
|
||||
pub struct SesamVitaleError {
|
||||
code: u16,
|
||||
}
|
||||
|
||||
pub enum SSVError {
|
||||
Error(u16),
|
||||
}
|
||||
|
||||
struct Parseable<T: BinRead>(T);
|
||||
|
||||
impl<T> BinRead for Parseable<T>
|
||||
where
|
||||
for<'a> T: BinRead<Args<'a> = ()>,
|
||||
{
|
||||
type Args<'a> = <DataField<T> as BinRead>::Args<'a>;
|
||||
|
||||
fn read_options<R: std::io::prelude::Read + std::io::prelude::Seek>(
|
||||
reader: &mut R,
|
||||
endian: binrw::Endian,
|
||||
args: Self::Args<'_>,
|
||||
) -> binrw::prelude::BinResult<Self> {
|
||||
let field = DataField::<T>::read_options(reader, endian, args)?;
|
||||
Ok(Parseable(field.value))
|
||||
impl fmt::Display for SesamVitaleError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Got error code {} from SSV_LireConfig", self.code)
|
||||
}
|
||||
}
|
||||
#[derive(BinRead)]
|
||||
struct ConfigHeader {
|
||||
ssv_version: Parseable<u16>,
|
||||
galss_version: Parseable<u16>,
|
||||
pss_version: Parseable<u16>,
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct ReaderConfig {
|
||||
// manufacturer_name: Parseable<String>
|
||||
}
|
||||
|
||||
pub fn read_config() -> Result<(), SSVError> {
|
||||
pub fn read_config() -> Result<Configuration, SesamVitaleError> {
|
||||
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
|
||||
let mut size: libc::size_t = 0;
|
||||
|
||||
let buffer: &[u8] = unsafe {
|
||||
match SSV_LireConfig(&mut buffer_ptr, &mut size) {
|
||||
0 => (),
|
||||
error_code => return Err(SSVError::Error(error_code)),
|
||||
}
|
||||
let buffer_ptr_ptr: *mut *mut libc::c_void = &mut buffer_ptr;
|
||||
let size_ptr: *mut libc::size_t = &mut size;
|
||||
|
||||
std::slice::from_raw_parts(buffer_ptr as *const u8, size)
|
||||
// Need to add proper error handling -> return a result with error code pointing to an error
|
||||
// enum
|
||||
let exit_code: u16 = unsafe { SSV_LireConfig(buffer_ptr_ptr, size_ptr) };
|
||||
|
||||
if exit_code != 0 {
|
||||
let error = SesamVitaleError { code: exit_code };
|
||||
return Err(error);
|
||||
};
|
||||
|
||||
let buffer: &[u8] = unsafe { std::slice::from_raw_parts(buffer_ptr as *const u8, size) };
|
||||
|
||||
// TODO: Improve error handling
|
||||
let configuration: Configuration = read_from_buffer(buffer).unwrap();
|
||||
|
||||
// TODO: Call library function for memory delocating
|
||||
unsafe { libc::free(buffer_ptr) };
|
||||
|
||||
println!("Buffer data: {:?}", buffer);
|
||||
|
||||
let cursor = &mut Cursor::new(buffer);
|
||||
while size > 0 {
|
||||
let data_block = DataBlock::read(cursor).expect("");
|
||||
size -= data_block.data.len();
|
||||
println!("{}", String::from_utf8(data_block.data).expect(""));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(configuration)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,176 +0,0 @@
|
||||
struct Identification<T> {
|
||||
value: T,
|
||||
// Key to check the validity of the value
|
||||
// TODO: implement checking algorithm
|
||||
key: u8,
|
||||
}
|
||||
type Byte = u8;
|
||||
|
||||
enum IdentificationNationale {
|
||||
NumeroAdeli(String),
|
||||
NumeroEmployeeDansStructure(IdentificationStructure, String),
|
||||
NumeroDRASS(String),
|
||||
NumeroRPPS(String),
|
||||
/// N° Etudiant Médecin type ADELI sur 9 caractères (information transmise par l’ANS)
|
||||
NumeroEtudiantMedecin(String),
|
||||
}
|
||||
|
||||
enum TypeCarteProfessionnelSante {
|
||||
/// Carte de Professionnel de Santé (CPS)
|
||||
CarteDeProfessionnelSante,
|
||||
/// Carte de Professionnel de Santé en Formation (CPF)
|
||||
CarteDeProfessionnelSanteEnFormation,
|
||||
/// Carte de Personnel d'Établissement de Santé (CDE/CPE)
|
||||
CarteDePersonnelEtablissementSante,
|
||||
/// Carte de Personnel Autorisé (CDA/CPA)
|
||||
CarteDePersonnelAutorise,
|
||||
/// Carte de Personne Morale
|
||||
CarteDePersonneMorale,
|
||||
}
|
||||
|
||||
enum CategorieCarteProfessionnelSante {
|
||||
Reelle,
|
||||
Test,
|
||||
Demonstration,
|
||||
}
|
||||
|
||||
enum CodeCivilite {
|
||||
Adjudant,
|
||||
Amiral,
|
||||
Aspirant,
|
||||
Aumônier,
|
||||
Capitaine,
|
||||
Cardinal,
|
||||
Chanoine,
|
||||
Colonel,
|
||||
Commandant,
|
||||
Commissaire,
|
||||
Conseiller,
|
||||
Directeur,
|
||||
Docteur,
|
||||
Douanier,
|
||||
Epouxse, // Epoux(se)
|
||||
Evêque,
|
||||
Général,
|
||||
Gouverneur,
|
||||
Ingénieur,
|
||||
Inspecteur,
|
||||
Lieutenant,
|
||||
Madame,
|
||||
Mademoiselle,
|
||||
Maître,
|
||||
Maréchal,
|
||||
Médecin,
|
||||
Mesdames,
|
||||
Mesdemoiselles,
|
||||
Messieurs,
|
||||
Monseigneur,
|
||||
Monsieur,
|
||||
NotreDame,
|
||||
Pasteur,
|
||||
Préfet,
|
||||
Président,
|
||||
Professeur,
|
||||
Recteur,
|
||||
Sergent,
|
||||
SousPréfet,
|
||||
Technicien,
|
||||
Veuve,
|
||||
}
|
||||
|
||||
struct CarteProfessionnelSante {
|
||||
type_carte: TypeCarteProfessionnelSante,
|
||||
categorie_carte: CategorieCarteProfessionnelSante,
|
||||
professionnel_sante: ProfessionnelDeSante,
|
||||
}
|
||||
|
||||
struct ProfessionnelDeSante {
|
||||
prenom: String,
|
||||
nom: String,
|
||||
code_civilite: CodeCivilite,
|
||||
identification_nationale: Identification<IdentificationNationale>,
|
||||
situations_execice: Vec<SituationDExercice>,
|
||||
}
|
||||
|
||||
enum IdentificationStructure {
|
||||
NumeroAdeliCabinet(String),
|
||||
NumeroFINESS(String),
|
||||
NumeroSIREN(String),
|
||||
NumeroSIRET(String),
|
||||
NumeroRPPSCabinet(String),
|
||||
}
|
||||
|
||||
struct StructureMedicale {
|
||||
identification: Identification<IdentificationStructure>,
|
||||
raison_sociale: String, // Nom Entreprise
|
||||
}
|
||||
|
||||
enum ModeExercice {
|
||||
LiberalExploitantCommercant, // Libéral, exploitant, commerçant
|
||||
Salarie,
|
||||
Remplacant,
|
||||
Benevole,
|
||||
}
|
||||
|
||||
enum StatutExercice {
|
||||
// TAB-Statuts géré par l’ANS il faut trouver la donnee
|
||||
PLACEHOLDER(u8),
|
||||
}
|
||||
|
||||
enum SecteurActivite {
|
||||
EtablissementPublicDeSanté,
|
||||
HopitauxMilitaires,
|
||||
EtablissementPrivePSPH, // Participant au Service Public Hospitalier
|
||||
EtablissementPriveNonPSPH,
|
||||
DispensaireDeSoins,
|
||||
AutresStructuresDeSoinsRelevantDuServiceDeSanteDesArmees,
|
||||
CabinetIndividuel,
|
||||
CabinetDeGroupe,
|
||||
ExerciceEnSociete,
|
||||
SecteurPrivePHTempsPlein,
|
||||
TransportSanitaire,
|
||||
EntrepriseDInterim,
|
||||
EtablissementDeSoinsEtPrevention,
|
||||
PreventionEtSoinsEnEntreprise,
|
||||
SanteScolaireEtUniversitaire,
|
||||
RecrutementEtGestionRH,
|
||||
PMIPlanificationFamiliale,
|
||||
EtablissementPourHandicapes,
|
||||
ComMarketingConsultingMedia,
|
||||
EtablissementPersonnesAgees,
|
||||
EtablissementAideaLaFamille,
|
||||
EtablissementDEnseignement,
|
||||
EtablissementsDeProtectionDeLEnfance,
|
||||
EtablissementsDHebergementEtDeReadaptation,
|
||||
Recherche,
|
||||
AssurancePrivee,
|
||||
OrganismeDeSecuriteSociale,
|
||||
MinistèreEtServicesDeconcentres,
|
||||
CollectivitesTerritoriales,
|
||||
AssociationsEtOrganitationsHumanitaire,
|
||||
LaboratoireDeBiologieMedicale,
|
||||
AutreEtablissementSanitaire,
|
||||
ProductionCommercialisationGrosBienMedicaux,
|
||||
CommerceDétailDeBiensMédicaux,
|
||||
PharmacieDOfficine,
|
||||
CentreDeDialyse,
|
||||
ParaPharmacie,
|
||||
AutreSecteurDActivité,
|
||||
SecteurNonDefini,
|
||||
CentreAntiCancer,
|
||||
CentreDeTransfusionSanguine,
|
||||
RépartitionDistribributionFabricationExploitationImportationMedicamentsEtDispositifsMédicaux,
|
||||
IncendiesEtSecours,
|
||||
EntreprisesIndustriellesEtTertiairesHorsIndustriesPharmaceutiques,
|
||||
|
||||
EntiteDUnTOM,
|
||||
FabricationExploitationImportationMedicamentsEtDispositifsMedicaux,
|
||||
}
|
||||
struct SituationDExercice {
|
||||
/// Numéro identifiant la situation du PS parmi ses autres situations inscrites sur sa CPS
|
||||
identifiant_situation: Byte,
|
||||
mode_exercice: Option<ModeExercice>,
|
||||
statut_exercice: Option<StatutExercice>,
|
||||
secteur_activite: Option<SecteurActivite>,
|
||||
structure_d_exercice: Option<StructureMedicale>,
|
||||
}
|
@ -1,18 +1,14 @@
|
||||
use bitvec::index::BitIdx;
|
||||
use std::{error::Error, str::FromStr, vec::Vec};
|
||||
use std::{error::Error, fmt, str::FromStr, vec::Vec};
|
||||
|
||||
use deku::{
|
||||
bitvec::{BitStore, Msb0},
|
||||
ctx::ByteSize,
|
||||
deku_derive,
|
||||
reader::{Reader, ReaderRet},
|
||||
DekuError, DekuReader,
|
||||
bitvec::{BitStore, Msb0}, ctx::ByteSize, deku_derive, reader::{Reader, ReaderRet}, DekuContainerRead, DekuError, DekuReader
|
||||
};
|
||||
|
||||
#[deku_derive(DekuRead)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[deku(endian = "big")]
|
||||
pub struct GroupId(u16);
|
||||
pub(crate) struct GroupId(u16);
|
||||
|
||||
trait MapToDekuParseError<T> {
|
||||
fn map_to_deku_parse_error(self) -> Result<T, DekuError>;
|
||||
@ -26,30 +22,30 @@ impl<T, E: Error> MapToDekuParseError<T> for Result<T, E> {
|
||||
|
||||
#[deku_derive(DekuRead)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct DataField {
|
||||
pub(crate) struct DataField {
|
||||
#[deku(reader = "read_size(deku::reader)")]
|
||||
data_size: ByteSize,
|
||||
pub(crate) data_size: ByteSize,
|
||||
|
||||
#[deku(bytes_read = "data_size.0")]
|
||||
pub data: Vec<u8>,
|
||||
pub(crate) data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[deku_derive(DekuRead)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct BlockHeader {
|
||||
pub group_id: GroupId,
|
||||
pub(crate) struct BlockHeader {
|
||||
pub(crate) group_id: GroupId,
|
||||
|
||||
#[deku(reader = "read_size(deku::reader)")]
|
||||
pub data_size: ByteSize,
|
||||
pub(crate) data_size: ByteSize,
|
||||
}
|
||||
|
||||
#[deku_derive(DekuRead)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct DataBlock {
|
||||
pub header: BlockHeader,
|
||||
pub(crate) struct DataBlock {
|
||||
pub(crate) header: BlockHeader,
|
||||
|
||||
#[deku(ctx = "header.group_id")]
|
||||
pub inner: DataGroup,
|
||||
pub(crate) inner: DataGroup,
|
||||
}
|
||||
|
||||
fn read_size<R: std::io::Read>(reader: &mut Reader<R>) -> Result<ByteSize, DekuError> {
|
||||
@ -144,14 +140,109 @@ pub struct SESAMVitaleComponent {
|
||||
pub version: SESAMVitaleComponentVersion,
|
||||
}
|
||||
|
||||
#[deku_derive(DekuRead)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct ReaderConfiguration {}
|
||||
|
||||
#[deku_derive(DekuRead)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[deku(ctx = "group_id: GroupId", id = "group_id.0")]
|
||||
pub enum DataGroup {
|
||||
#[deku(id = 60)]
|
||||
ConfigurationHeader(ConfigurationHeader),
|
||||
#[deku(id = 67)]
|
||||
PCSCReader(PCSCReader),
|
||||
#[deku(id = 61)]
|
||||
ReaderConfiguration(ReaderConfiguration),
|
||||
#[deku(id = 64)]
|
||||
SESAMVitaleComponent(SESAMVitaleComponent),
|
||||
#[deku(id = 67)]
|
||||
PCSCReader(PCSCReader),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConfigurationError {
|
||||
MultipleConfigurationHeaders,
|
||||
MissingConfigurationHeader,
|
||||
}
|
||||
|
||||
impl fmt::Display for ConfigurationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ConfigurationError::MultipleConfigurationHeaders => {
|
||||
write!(f, "Multiple ConfigurationHeader blocks found")
|
||||
}
|
||||
ConfigurationError::MissingConfigurationHeader => {
|
||||
write!(f, "Missing ConfigurationHeader block")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ConfigurationError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Configuration {
|
||||
pub configuration_header: ConfigurationHeader,
|
||||
pub reader_configurations: Vec<ReaderConfiguration>,
|
||||
pub sesam_vitale_components: Vec<SESAMVitaleComponent>,
|
||||
pub pcsc_readers: Vec<PCSCReader>,
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<DataBlock>> for Configuration {
|
||||
type Error = ConfigurationError;
|
||||
|
||||
fn try_from(data_blocks: Vec<DataBlock>) -> Result<Self, Self::Error> {
|
||||
let mut configuration_header: Option<ConfigurationHeader> = None;
|
||||
let mut reader_configurations: Vec<ReaderConfiguration> = Vec::new();
|
||||
let mut sesam_vitale_components: Vec<SESAMVitaleComponent> = Vec::new();
|
||||
let mut pcsc_readers: Vec<PCSCReader> = Vec::new();
|
||||
|
||||
for block in data_blocks {
|
||||
match block.inner {
|
||||
DataGroup::ConfigurationHeader(header) => {
|
||||
if configuration_header.is_some() {
|
||||
return Err(ConfigurationError::MultipleConfigurationHeaders);
|
||||
}
|
||||
configuration_header = Some(header);
|
||||
}
|
||||
DataGroup::ReaderConfiguration(configuration) => {
|
||||
reader_configurations.push(configuration)
|
||||
}
|
||||
DataGroup::SESAMVitaleComponent(component) => {
|
||||
sesam_vitale_components.push(component);
|
||||
}
|
||||
DataGroup::PCSCReader(reader) => {
|
||||
pcsc_readers.push(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
let configuration_header = match configuration_header {
|
||||
Some(header) => header,
|
||||
None => return Err(ConfigurationError::MissingConfigurationHeader),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
configuration_header,
|
||||
reader_configurations,
|
||||
sesam_vitale_components,
|
||||
pcsc_readers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_from_buffer<T: TryFrom<Vec<DataBlock>>>(buffer: &[u8]) -> Result<T, T::Error>{
|
||||
let mut data_blocks: Vec<DataBlock> = Vec::new();
|
||||
let mut offset = 0;
|
||||
|
||||
let mut remaining_buffer = buffer;
|
||||
|
||||
while !remaining_buffer.is_empty() {
|
||||
// TODO: properly handle errors
|
||||
let (rest, data_block) = DataBlock::from_bytes((remaining_buffer, offset)).unwrap();
|
||||
|
||||
data_blocks.push(data_block);
|
||||
|
||||
(remaining_buffer, offset) = rest;
|
||||
};
|
||||
|
||||
T::try_from(data_blocks)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user