feat: implement deku binary reading
This commit is contained in:
parent
f424f02d83
commit
7f825cb9bc
@ -2,3 +2,8 @@
|
|||||||
name = "services-sesam-vitale-sys"
|
name = "services-sesam-vitale-sys"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitvec = "1.0.1"
|
||||||
|
deku = "0.17.0"
|
||||||
|
libc = "0.2.155"
|
||||||
|
@ -1,3 +1 @@
|
|||||||
pub(crate) mod types;
|
|
||||||
pub mod common;
|
|
||||||
pub mod serialization_types;
|
pub mod serialization_types;
|
||||||
|
@ -1,210 +1,79 @@
|
|||||||
use core::panic;
|
use bitvec::index::BitIdx;
|
||||||
use std::io::Cursor;
|
use std::{error::Error, vec::Vec};
|
||||||
|
|
||||||
use binrw::{
|
use deku::{
|
||||||
binread,
|
bitvec::{BitStore, Msb0},
|
||||||
helpers::{read_u24, write_u24},
|
ctx::ByteSize,
|
||||||
BinRead, BinReaderExt, BinResult, BinWriterExt, Endian,
|
deku_derive,
|
||||||
|
reader::{Reader, ReaderRet},
|
||||||
|
DekuError, DekuReader,
|
||||||
};
|
};
|
||||||
|
|
||||||
const U8_MAX: u32 = u8::MAX as u32;
|
#[deku_derive(DekuRead)]
|
||||||
const U16_MAX: u32 = u16::MAX as u32;
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
const U24_MAX: u32 = 16_777_215;
|
#[deku(endian = "big")]
|
||||||
|
pub struct GroupId(u16);
|
||||||
|
|
||||||
#[binrw::parser(reader)]
|
trait MapToDekuParseError<T> {
|
||||||
fn parse_data_size() -> BinResult<u32> {
|
fn map_to_deku_parse_error(self) -> Result<T, DekuError>;
|
||||||
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,
|
|
||||||
|
|
||||||
// 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"),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw::writer(writer)]
|
impl<T, E: Error> MapToDekuParseError<T> for Result<T, E> {
|
||||||
fn write_data_size(memory_size: &u32) -> BinResult<()> {
|
fn map_to_deku_parse_error(self) -> Result<T, DekuError> {
|
||||||
match memory_size {
|
self.map_err(|e| DekuError::Parse(e.to_string().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))
|
|
||||||
}
|
|
||||||
..=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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// To parse the data
|
#[deku_derive(DekuRead)]
|
||||||
// allocate the multiple buffers
|
#[derive(Debug, PartialEq)]
|
||||||
// chain them to make a single buffer
|
pub struct DekuDataField {
|
||||||
// use the parse_data_size function to get a size
|
#[deku(reader = "read_size(deku::reader)")]
|
||||||
// use take method to limit number of bytes read
|
data_size: ByteSize,
|
||||||
// use binread implementaiton on each struct/enum de structure it
|
|
||||||
// do this recursively until there is no more data
|
|
||||||
|
|
||||||
// Memory has three embricked concepts:
|
#[deku(bytes_read = "data_size.0")]
|
||||||
// Memory Zone(s) -Contains-> DataBlock(s) -Contains-> DataField(s)
|
pub data: Vec<u8>,
|
||||||
// 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>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binread]
|
#[deku_derive(DekuRead)]
|
||||||
pub struct DataField<T>
|
#[derive(Debug, PartialEq)]
|
||||||
where
|
pub struct BlockHeader {
|
||||||
for<'a> T: BinRead<Args<'a>= ()>,
|
pub group_id: GroupId,
|
||||||
{
|
|
||||||
#[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
|
#[deku(reader = "read_size(deku::reader)")]
|
||||||
// corresponding enum
|
pub data_size: ByteSize,
|
||||||
//
|
|
||||||
// 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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//// Memory allocation functions
|
#[deku_derive(DekuRead)]
|
||||||
//trait DataMaxSize {
|
#[derive(Debug, PartialEq)]
|
||||||
// fn max_size(&self) -> usize;
|
pub struct DataBlock {
|
||||||
//}
|
pub header: BlockHeader,
|
||||||
//
|
|
||||||
//pub struct Real;
|
#[deku(bytes_read = "header.data_size.0")]
|
||||||
//pub struct Test;
|
pub data: Vec<DekuDataField>,
|
||||||
//pub struct Demo;
|
}
|
||||||
//
|
|
||||||
//// Trait for categories
|
fn read_size<R: std::io::Read>(reader: &mut Reader<R>) -> Result<ByteSize, DekuError> {
|
||||||
//pub trait Category: 'static {
|
let first_byte: u8 = u8::from_reader_with_ctx(reader, ())?;
|
||||||
// const NAME: &'static str;
|
|
||||||
//}
|
let is_length_expanded = first_byte.get_bit::<Msb0>(BitIdx::new(0).map_to_deku_parse_error()?);
|
||||||
//
|
|
||||||
//impl Category for Real {
|
match is_length_expanded {
|
||||||
// const NAME: &'static str = "Real";
|
true => {
|
||||||
//}
|
let size_of_data_size: ByteSize = ByteSize((first_byte & 0b0111_1111) as usize);
|
||||||
//impl Category for Test {
|
|
||||||
// const NAME: &'static str = "Test";
|
if size_of_data_size.0 > 4 {
|
||||||
//}
|
return Err(DekuError::Parse("Size of the length encoding is > 4, this is not normal. Probable parsing error".to_string().into()));
|
||||||
//impl Category for Demo {
|
};
|
||||||
// const NAME: &'static str = "Demo";
|
|
||||||
//}
|
// maximum size of the buffer is 4, we use the offset to read values less than 4 bytes
|
||||||
//
|
let buffer: &mut [u8; 4] = &mut [0; 4];
|
||||||
//// Enum for runtime category representation
|
let write_offset = 4 - size_of_data_size.0;
|
||||||
//pub enum CategoryType {
|
|
||||||
// Real(Real),
|
match reader.read_bytes(size_of_data_size.0, &mut buffer[write_offset..])? {
|
||||||
// Test(Test),
|
ReaderRet::Bits(_bit_vec) => Err(DekuError::Parse("Got bits when trying to read bytes -> reader is unaligned, this is not normal.".to_string().into())),
|
||||||
// Demo(Demo),
|
ReaderRet::Bytes => Ok(ByteSize(u32::from_be_bytes(*buffer) as usize)),
|
||||||
//}
|
}
|
||||||
//
|
}
|
||||||
//// Card type with generic category
|
false => Ok(ByteSize(first_byte as usize)),
|
||||||
//#[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