WIP: creation-sys-crate-ssv #69
@ -1,17 +1,123 @@
|
|||||||
mod types;
|
// to include std in docs, need to remove later
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use std;
|
||||||
|
|
||||||
use types::*;
|
mod bindings;
|
||||||
pub fn add(left: usize, right: usize) -> usize {
|
pub mod types;
|
||||||
left + right
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use bindings::SSV_LireConfig;
|
||||||
|
use binrw::BinRead;
|
||||||
|
use std::ptr;
|
||||||
|
use types::serialization_types::{DataBlock, DataField};
|
||||||
|
|
||||||
|
//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>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[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> {
|
||||||
|
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)),
|
||||||
|
}
|
||||||
|
|
||||||
|
std::slice::from_raw_parts(buffer_ptr as *const u8, size)
|
||||||
|
};
|
||||||
|
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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {}
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
|
||||||
let result = add(2, 2);
|
|
||||||
assert_eq!(result, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,81 +1,210 @@
|
|||||||
use std::cmp::Ordering;
|
use core::panic;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
use binrw::{BinRead, BinResult};
|
use binrw::{
|
||||||
use bitreader::{BitReader, BitReaderError};
|
binread,
|
||||||
|
helpers::{read_u24, write_u24},
|
||||||
|
BinRead, BinReaderExt, BinResult, BinWriterExt, Endian,
|
||||||
|
};
|
||||||
|
|
||||||
fn parse_memory_zone_size_bitreader(bytes: &[u8; 5]) -> Result<u32, BitReaderError> {
|
const U8_MAX: u32 = u8::MAX as u32;
|
||||||
let mut reader = BitReader::new(bytes);
|
const U16_MAX: u32 = u16::MAX as u32;
|
||||||
|
const U24_MAX: u32 = 16_777_215;
|
||||||
let zone_size_bit_count = match reader.read_bool()? {
|
|
||||||
true => 7,
|
|
||||||
false => reader.read_u8(7)? * 8,
|
|
||||||
};
|
|
||||||
Ok(reader.read_u32(zone_size_bit_count)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binrw::parser(reader)]
|
#[binrw::parser(reader)]
|
||||||
fn parse_memory_zone_size() -> BinResult<u32> {
|
fn parse_data_size() -> BinResult<u32> {
|
||||||
let mut value: u8 = 0;
|
let first_byte: u8 = reader.read_be()?;
|
||||||
|
|
||||||
|
let first_bit: bool = (first_byte & 0b1000_0000) == 0;
|
||||||
|
Ok(match first_bit {
|
||||||
|
// first bit is 0 -> size is encoded in the first byte
|
||||||
|
true => first_byte as u32,
|
||||||
|
|
||||||
reader.read_exact(std::slice::from_mut(&mut value));
|
// first bit is 1 -> size is encoded on N bytes
|
||||||
|
// N being encoded by the first byte
|
||||||
|
false => match first_byte {
|
||||||
|
0 => 0,
|
||||||
|
1 => reader.read_be::<u8>()? as u32,
|
||||||
|
2 => reader.read_be::<u16>()? as u32,
|
||||||
|
3 => read_u24(reader, Endian::Big, ())?,
|
||||||
|
4 => reader.read_be::<u32>()?,
|
||||||
|
_ => panic!("Length should not be more than 4 bytes"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// first bit s 0 <=> value < 128
|
#[binrw::writer(writer)]
|
||||||
match value.cmp(&128) {
|
fn write_data_size(memory_size: &u32) -> BinResult<()> {
|
||||||
Ordering::Less => {
|
match memory_size {
|
||||||
Ok(value.into())
|
..=U8_MAX => writer.write_be(&(*memory_size as u8)),
|
||||||
|
// Since size is not encodable on a single byte
|
||||||
|
// We write the length encoding the size first, marking it with a flipped first bit
|
||||||
|
// Then write the size on the following bytes
|
||||||
|
..=U16_MAX => {
|
||||||
|
let size_encoding_length = 2u8 | 0b1000_0000;
|
||||||
|
writer.write_be(&size_encoding_length)?;
|
||||||
|
writer.write_be(&(*memory_size as u16))
|
||||||
}
|
}
|
||||||
Ordering::Equal | Ordering::Greater => {
|
..=U24_MAX => {
|
||||||
let zone_size_encoding_byte_count = value - 128;
|
let size_encoding_length = 3u8 | 0b1000_0000;
|
||||||
let mut buf: Vec<u8> = vec![0; zone_size_encoding_byte_count.into()];
|
writer.write_be(&size_encoding_length)?;
|
||||||
reader.read_exact(&mut buf);
|
write_u24(memory_size, writer, Endian::Big, ())
|
||||||
|
}
|
||||||
let mut result = 0u32;
|
_ => {
|
||||||
|
let size_encoding_length = 4u8 | 0b1000_0000;
|
||||||
for (i, &byte) in buf.iter().enumerate() {
|
writer.write_be(&size_encoding_length)?;
|
||||||
result += (byte as u32) << (8 * i);
|
writer.write_be(memory_size)
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BinRead)]
|
// To parse the data
|
||||||
struct MemoryZone {
|
// allocate the multiple buffers
|
||||||
#[br(parse_with = parse_memory_zone_size)]
|
// 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
|
||||||
|
//
|
||||||
|
// will probably not be used
|
||||||
|
#[binread]
|
||||||
|
pub struct DataBlock{//<T: From<Vec<u8>>> {
|
||||||
|
data_struct_id: u16,
|
||||||
|
|
||||||
|
#[br(temp, parse_with = parse_data_size)]
|
||||||
memory_size: u32,
|
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>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TypeIdentificationStructure {
|
#[binread]
|
||||||
NumeroAdeliCabinet,
|
pub struct DataField<T>
|
||||||
NumeroFINESS,
|
where
|
||||||
NumeroSIREN,
|
for<'a> T: BinRead<Args<'a>= ()>,
|
||||||
NumeroSIRET,
|
{
|
||||||
NumeroRPPSCabinet,
|
#[br(parse_with = parse_data_size)]
|
||||||
|
memory_size: u32,
|
||||||
|
|
||||||
|
// using data -> not using the parser fw well, I think we can directly parse to the
|
||||||
|
// corresponding enum
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
#[br(count = memory_size)]
|
||||||
|
#[br(try_map = |data: Vec<u8>| T::read_be(&mut Cursor::new(data)))]
|
||||||
|
pub value: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TypeDIdentificationNationale {
|
//// Memory allocation functions
|
||||||
NumeroAdeli,
|
//trait DataMaxSize {
|
||||||
NumeroAdeliCabinetNumeroEmploye,
|
// fn max_size(&self) -> usize;
|
||||||
NumeroDRASS,
|
//}
|
||||||
NumeroFINESSNumeroEmploye,
|
//
|
||||||
NumeroSIRENNumeroEmploye,
|
//pub struct Real;
|
||||||
NumeroSIRETNumeroEmploye,
|
//pub struct Test;
|
||||||
NumeroRPPSCabinetNumeroEmploye,
|
//pub struct Demo;
|
||||||
NumeroRPPS,
|
//
|
||||||
/// N° Etudiant Médecin type ADELI sur 9 caractères (information transmise par l’ANS)
|
//// Trait for categories
|
||||||
NumeroEtudiantMedecin,
|
//pub trait Category: 'static {
|
||||||
}
|
// const NAME: &'static str;
|
||||||
pub(crate) enum TypeCartePS {
|
//}
|
||||||
/// Carte de Professionnel de Santé (CPS)
|
//
|
||||||
CarteDeProfessionnelSante,
|
//impl Category for Real {
|
||||||
/// Carte de Professionnel de Santé en Formation (CPF)
|
// const NAME: &'static str = "Real";
|
||||||
CarteDeProfessionnelSanteEnFormation,
|
//}
|
||||||
/// Carte de Personnel d'Établissement de Santé (CDE/CPE)
|
//impl Category for Test {
|
||||||
CarteDePersonnelEtablissementSante,
|
// const NAME: &'static str = "Test";
|
||||||
/// Carte de Personnel Autorisé (CDA/CPA)
|
//}
|
||||||
CarteDePersonnelAutorise,
|
//impl Category for Demo {
|
||||||
/// Carte de Personne Morale
|
// const NAME: &'static str = "Demo";
|
||||||
CarteDePersonneMorale,
|
//}
|
||||||
}
|
//
|
||||||
|
//// Enum for runtime category representation
|
||||||
|
//pub enum CategoryType {
|
||||||
|
// Real(Real),
|
||||||
|
// Test(Test),
|
||||||
|
// Demo(Demo),
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// Card type with generic category
|
||||||
|
//#[derive(Debug)]
|
||||||
|
//pub enum CartePS<C: CategoryType> {
|
||||||
|
// CPS {
|
||||||
|
// reader_port: u32,
|
||||||
|
// _category: std::marker::PhantomData<C >,
|
||||||
|
// },
|
||||||
|
// CPF {
|
||||||
|
// some_cpf_data: String,
|
||||||
|
// _category: std::marker::PhantomData<C>,
|
||||||
|
// },
|
||||||
|
// CPE {
|
||||||
|
// some_cpe_data: bool,
|
||||||
|
// _category: std::marker::PhantomData<C>,
|
||||||
|
// },
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//// Function that only accepts Real CPS cards
|
||||||
|
//fn process_real_cps_card(card: CartePS<>) {
|
||||||
|
// if let CartePS::CPS { reader_port, .. } = card {
|
||||||
|
// println!(
|
||||||
|
// "Processing a real CPS card with reader port: {}",
|
||||||
|
// reader_port
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//fn main() {
|
||||||
|
// let cps = CartePS::<Real>::CPS {
|
||||||
|
// reader_port: 1,
|
||||||
|
// _category: std::marker::PhantomData,
|
||||||
|
// };
|
||||||
|
// process_real_cps_card(cps);
|
||||||
|
//}
|
||||||
|
//// need to see how to interface enums with binrw
|
||||||
|
//enum IdentificationStructure {
|
||||||
|
// NumeroAdeliCabinet,
|
||||||
|
// NumeroFINESS,
|
||||||
|
// NumeroSIREN,
|
||||||
|
// NumeroSIRET,
|
||||||
|
// NumeroRPPSCabinet,
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//pub enum TypeDIdentificationNationale {
|
||||||
|
// NumeroAdeli,
|
||||||
|
// NumeroAdeliCabinetNumeroEmploye,
|
||||||
|
// NumeroDRASS,
|
||||||
|
// NumeroFINESSNumeroEmploye,
|
||||||
|
// NumeroSIRENNumeroEmploye,
|
||||||
|
// NumeroSIRETNumeroEmploye,
|
||||||
|
// NumeroRPPSCabinetNumeroEmploye,
|
||||||
|
// NumeroRPPS,
|
||||||
|
// /// N° Etudiant Médecin type ADELI sur 9 caractères (information transmise par l’ANS)
|
||||||
|
// NumeroEtudiantMedecin,
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
////#[derive(BinRead)]
|
||||||
|
////#[br(repr = [char;2], map = |[u8;2]| )]
|
||||||
|
//pub(crate) enum TypeCartePS {
|
||||||
|
// /// Carte de Professionnel de Santé (CPS)
|
||||||
|
// // CarteDeProfessionnelSante = ('0', '0'),
|
||||||
|
// /// Carte de Professionnel de Santé en Formation (CPF)
|
||||||
|
// // CarteDeProfessionnelSanteEnFormation = ('0', '1'),
|
||||||
|
// /// Carte de Personnel d'Établissement de Santé (CDE/CPE)
|
||||||
|
// CarteDePersonnelEtablissementSante,
|
||||||
|
// /// Carte de Personnel Autorisé (CDA/CPA)
|
||||||
|
// CarteDePersonnelAutorise,
|
||||||
|
// /// Carte de Personne Morale
|
||||||
|
// CarteDePersonneMorale,
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl DataMaxSize for TypeCartePS {
|
||||||
|
// fn max_size(&self) -> usize {
|
||||||
|
// 2
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
Loading…
Reference in New Issue
Block a user