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::*;
|
||||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
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};
|
||||
|
||||
//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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
||||
mod tests {}
|
||||
|
@ -1,81 +1,210 @@
|
||||
use std::cmp::Ordering;
|
||||
use core::panic;
|
||||
use std::io::Cursor;
|
||||
|
||||
use binrw::{BinRead, BinResult};
|
||||
use bitreader::{BitReader, BitReaderError};
|
||||
use binrw::{
|
||||
binread,
|
||||
helpers::{read_u24, write_u24},
|
||||
BinRead, BinReaderExt, BinResult, BinWriterExt, Endian,
|
||||
};
|
||||
|
||||
fn parse_memory_zone_size_bitreader(bytes: &[u8; 5]) -> Result<u32, BitReaderError> {
|
||||
let mut reader = BitReader::new(bytes);
|
||||
|
||||
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)?)
|
||||
}
|
||||
const U8_MAX: u32 = u8::MAX as u32;
|
||||
const U16_MAX: u32 = u16::MAX as u32;
|
||||
const U24_MAX: u32 = 16_777_215;
|
||||
|
||||
#[binrw::parser(reader)]
|
||||
fn parse_memory_zone_size() -> BinResult<u32> {
|
||||
let mut value: u8 = 0;
|
||||
fn parse_data_size() -> BinResult<u32> {
|
||||
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
|
||||
match value.cmp(&128) {
|
||||
Ordering::Less => {
|
||||
Ok(value.into())
|
||||
#[binrw::writer(writer)]
|
||||
fn write_data_size(memory_size: &u32) -> BinResult<()> {
|
||||
match memory_size {
|
||||
..=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 => {
|
||||
let zone_size_encoding_byte_count = value - 128;
|
||||
let mut buf: Vec<u8> = vec![0; zone_size_encoding_byte_count.into()];
|
||||
reader.read_exact(&mut buf);
|
||||
|
||||
let mut result = 0u32;
|
||||
|
||||
for (i, &byte) in buf.iter().enumerate() {
|
||||
result += (byte as u32) << (8 * i);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
..=U24_MAX => {
|
||||
let size_encoding_length = 3u8 | 0b1000_0000;
|
||||
writer.write_be(&size_encoding_length)?;
|
||||
write_u24(memory_size, writer, Endian::Big, ())
|
||||
}
|
||||
_ => {
|
||||
let size_encoding_length = 4u8 | 0b1000_0000;
|
||||
writer.write_be(&size_encoding_length)?;
|
||||
writer.write_be(memory_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BinRead)]
|
||||
struct MemoryZone {
|
||||
#[br(parse_with = parse_memory_zone_size)]
|
||||
// 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
|
||||
//
|
||||
// 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,
|
||||
|
||||
// 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 {
|
||||
NumeroAdeliCabinet,
|
||||
NumeroFINESS,
|
||||
NumeroSIREN,
|
||||
NumeroSIRET,
|
||||
NumeroRPPSCabinet,
|
||||
#[binread]
|
||||
pub struct DataField<T>
|
||||
where
|
||||
for<'a> T: BinRead<Args<'a>= ()>,
|
||||
{
|
||||
#[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 {
|
||||
NumeroAdeli,
|
||||
NumeroAdeliCabinetNumeroEmploye,
|
||||
NumeroDRASS,
|
||||
NumeroFINESSNumeroEmploye,
|
||||
NumeroSIRENNumeroEmploye,
|
||||
NumeroSIRETNumeroEmploye,
|
||||
NumeroRPPSCabinetNumeroEmploye,
|
||||
NumeroRPPS,
|
||||
/// N° Etudiant Médecin type ADELI sur 9 caractères (information transmise par l’ANS)
|
||||
NumeroEtudiantMedecin,
|
||||
}
|
||||
pub(crate) enum TypeCartePS {
|
||||
/// 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,
|
||||
}
|
||||
//// Memory allocation functions
|
||||
//trait DataMaxSize {
|
||||
// fn max_size(&self) -> usize;
|
||||
//}
|
||||
//
|
||||
//pub struct Real;
|
||||
//pub struct Test;
|
||||
//pub struct Demo;
|
||||
//
|
||||
//// Trait for categories
|
||||
//pub trait Category: 'static {
|
||||
// const NAME: &'static str;
|
||||
//}
|
||||
//
|
||||
//impl Category for Real {
|
||||
// const NAME: &'static str = "Real";
|
||||
//}
|
||||
//impl Category for Test {
|
||||
// const NAME: &'static str = "Test";
|
||||
//}
|
||||
//impl Category for Demo {
|
||||
// const NAME: &'static str = "Demo";
|
||||
//}
|
||||
//
|
||||
//// 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