WIP commit to set working base

This commit is contained in:
theo 2024-08-10 12:10:21 +02:00 committed by Florian Briand
parent 20e16f6ae2
commit 34bdea2269
Signed by: florian_briand
GPG Key ID: CC981B9E6B98E70B
2 changed files with 313 additions and 78 deletions

View File

@ -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);
}
}

View File

@ -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 lANS) //// 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 lANS)
// 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
// }
//}