Implémentation du parsing des données issues de la lecture de la carte CPS (SSV_LireCartePS) #77
@ -54,6 +54,8 @@ pub struct GroupId(
|
|||||||
#[deku(ctx = "group_id: u16", id = "group_id")]
|
#[deku(ctx = "group_id: u16", id = "group_id")]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum DataGroup {
|
pub enum DataGroup {
|
||||||
|
#[deku(id = 1)]
|
||||||
|
LireCartePS_Group1_Holder(groups::ssv_lire_carte_ps::group_1_holder::Holder),
|
||||||
#[deku(id = 60)]
|
#[deku(id = 60)]
|
||||||
LireConfig_Group60_ConfigHeader(groups::ssv_lire_config::group_60_header_config::ConfigHeader),
|
LireConfig_Group60_ConfigHeader(groups::ssv_lire_config::group_60_header_config::ConfigHeader),
|
||||||
#[deku(id = 61)]
|
#[deku(id = 61)]
|
||||||
|
@ -4,6 +4,7 @@ use deku::{deku_derive, DekuError};
|
|||||||
|
|
||||||
use super::{ size_read, map_bytes_to_lossy_string };
|
use super::{ size_read, map_bytes_to_lossy_string };
|
||||||
|
|
||||||
|
pub mod ssv_lire_carte_ps;
|
||||||
pub mod ssv_lire_config;
|
pub mod ssv_lire_config;
|
||||||
|
|
||||||
/// # Convert a DataField to a specific type
|
/// # Convert a DataField to a specific type
|
||||||
@ -43,6 +44,11 @@ pub struct NumericString(
|
|||||||
#[deku(map = "map_from_data_field")]
|
#[deku(map = "map_from_data_field")]
|
||||||
String
|
String
|
||||||
);
|
);
|
||||||
|
impl From<&str> for NumericString {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
NumericString(s.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[deku_derive(DekuRead)]
|
#[deku_derive(DekuRead)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
145
crates/fsv/src/fsv_parsing/groups/ssv_lire_carte_ps.rs
Normal file
145
crates/fsv/src/fsv_parsing/groups/ssv_lire_carte_ps.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
//! # Structures de parsing des données de la fonction SSV_LireCartePS
|
||||||
|
|
||||||
|
use deku::deku_derive;
|
||||||
|
|
||||||
|
use crate::fsv_parsing::groups::NumericString;
|
||||||
|
|
||||||
|
/// # Titulaire
|
||||||
|
/// 1 occurence
|
||||||
|
pub mod group_1_holder {
|
||||||
|
|
||||||
|
use crate::fsv_parsing::groups::AlphaNumericString;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Groupe 1 - Titulaire
|
||||||
|
#[deku_derive(DekuRead)]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct Holder {
|
||||||
|
pub card_type: CardPSType,
|
||||||
|
pub national_id_type: NationalIDType,
|
||||||
|
pub national_id: AlphaNumericString, // /!\ CE and not CA
|
||||||
|
pub national_id_key: AlphaNumericString,
|
||||||
|
pub civility_code: CivilityCode,
|
||||||
|
pub holder_lastname: AlphaNumericString, // /!\ CE and not CA
|
||||||
|
pub holder_firstname: AlphaNumericString, // /!\ CE and not CA
|
||||||
|
pub category_card: AlphaNumericString,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
#[deku_derive(DekuRead)]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct CardPSType(pub NumericString);
|
||||||
|
|
||||||
|
#[deku_derive(DekuRead)]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct NationalIDType(pub NumericString);
|
||||||
|
|
||||||
|
#[deku_derive(DekuRead)]
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct CivilityCode(pub NumericString);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use deku::DekuContainerRead as _;
|
||||||
|
|
||||||
|
use crate::fsv_parsing::blocks::BlockHeader;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
mod data {
|
||||||
|
pub const BUFFER: &[u8] = &[
|
||||||
|
0, 1, // Block ID
|
||||||
|
53, // Block size
|
||||||
|
1, // Type de carte PS, 2 CN
|
||||||
|
48, // 0
|
||||||
|
1, // Type d'identification nationale, 1 CN
|
||||||
|
56, // 8
|
||||||
|
11, // N° d'identification nationale, 8-30 CE
|
||||||
|
57, 57, 55, 48, 48, 53, 57, 51, 54, 56, 54,
|
||||||
|
1, // Clé du N° d'identification nationale, 1 CN
|
||||||
|
54, // 6
|
||||||
|
2, // Code civilité, 2 CN
|
||||||
|
51, 49, // 31
|
||||||
|
23, // Nom du PS, 27 CE
|
||||||
|
80, 72, 65, 82, 77, 79, 70, 70, 73, 67,
|
||||||
|
69, 32, 82, 80, 80, 83, 48, 48, 53, 57,
|
||||||
|
51, 54, 56,
|
||||||
|
7, // Prénom du PS, 27 CE
|
||||||
|
71, 73, 76, 66, 69, 82, 84,
|
||||||
|
// ??? Missing ??? Catégorie Carte, 1 CA
|
||||||
|
0, 2, // Block ID
|
||||||
|
93, // Block size
|
||||||
|
1, // N° logique de la situation de facturation du PS, 1 CB
|
||||||
|
1,
|
||||||
|
1, // Mode d'exercice, 2 CN
|
||||||
|
48,
|
||||||
|
1, // Statut d'exercice, 3 CN
|
||||||
|
49,
|
||||||
|
2, // Secteur d'activité, 3 CN
|
||||||
|
56, 54,
|
||||||
|
1, // Type d'identification structure, 1 CN
|
||||||
|
49,
|
||||||
|
9, // N° d'identification structure, 14 CA
|
||||||
|
48, 66, 48, 50, 52, 54, 50, 56, 54,
|
||||||
|
1, // Clé du N° d'identification structure, 1 CN
|
||||||
|
54,
|
||||||
|
34, // Raison sociale structure, 40 CE
|
||||||
|
80, 72, 65, 82, 77, 65, 67, 73, 69, 32,
|
||||||
|
68, 69, 32, 76, 65, 32, 71, 65, 82, 69,
|
||||||
|
32, 82, 79, 85, 84, 73, 69, 82, 69, 50,
|
||||||
|
52, 54, 50, 56,
|
||||||
|
8, // N° d'identification de facturation du PS, 8 CN
|
||||||
|
48, 48, 50, 48, 57, 51, 54, 56,
|
||||||
|
1, // Clé du N° d'identification de facturation du PS, 1 CN
|
||||||
|
48,
|
||||||
|
0, // N° d'identification du PS remplaçant, 30 CA
|
||||||
|
1, // Clé du N° d'identification du PS remplaçant, 1 CN
|
||||||
|
48,
|
||||||
|
1, // Code conventionnel, 1 CN
|
||||||
|
49,
|
||||||
|
2, // Code spécialité, 2 CN
|
||||||
|
53, 48,
|
||||||
|
2, // Code zone tarifaire, 2 CN
|
||||||
|
49, 48,
|
||||||
|
2, // Code zone IK
|
||||||
|
48, 48,
|
||||||
|
1, // Code agrément 1, 1 CN
|
||||||
|
48,
|
||||||
|
1, // Code agrément 2, 1 CN
|
||||||
|
48,
|
||||||
|
1, // Code agrément 3, 1 CN
|
||||||
|
48,
|
||||||
|
1, // Habilitation à signer une Facture // 1 CN
|
||||||
|
49,
|
||||||
|
1, // Habilitation à signer un lot // 1 CN
|
||||||
|
49
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lire_carte_ps_first_header() {
|
||||||
|
// env_logger::init(); // Uncomment and run with RUST_LOG=trace for deku debugging
|
||||||
|
let ((_rest, _offset), block_header) = BlockHeader::from_bytes((data::BUFFER, 0)).unwrap();
|
||||||
|
assert_eq!(block_header.group_id.0, 1, "Header ID");
|
||||||
|
assert_eq!(block_header.data_size, 53, "Header Size");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_group_1_holder() {
|
||||||
|
env_logger::init(); // Uncomment and run with RUST_LOG=trace for deku debugging
|
||||||
|
let offset = 3*8;
|
||||||
|
let (_rest, holder) = group_1_holder::Holder::from_bytes((data::BUFFER, offset)).unwrap();
|
||||||
|
assert_eq!(holder.card_type.0.0, "0", "Card type");
|
||||||
|
assert_eq!(holder.national_id_type.0.0, "8", "National ID type");
|
||||||
|
assert_eq!(holder.national_id.0, "99700593686", "National Id");
|
||||||
|
assert_eq!(holder.national_id_key.0, "6", "National ID Key");
|
||||||
|
assert_eq!(holder.civility_code.0.0, "31", "Civility Code");
|
||||||
|
assert_eq!(holder.holder_lastname.0, "PHARMOFFICE RPPS0059368", "Holder Lastname");
|
||||||
|
assert_eq!(holder.holder_firstname.0, "GILBERT", "Holder Firstname");
|
||||||
|
assert!(holder.category_card.0.is_empty(), "Category card");
|
||||||
|
}
|
||||||
|
}
|
@ -209,7 +209,7 @@ mod tests {
|
|||||||
|
|
||||||
let ((_rest, _offset), block_header) = BlockHeader::from_bytes((buffer, offset)).unwrap();
|
let ((_rest, _offset), block_header) = BlockHeader::from_bytes((buffer, offset)).unwrap();
|
||||||
assert_eq!(block_header.group_id.0, 60, "Header ID");
|
assert_eq!(block_header.group_id.0, 60, "Header ID");
|
||||||
// assert_eq!(block_header.data_size, 15, "Header Size");
|
assert_eq!(block_header.data_size, 15, "Header Size");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -289,6 +289,7 @@ mod tests {
|
|||||||
assert_eq!(content.name.0.0, "Gemalto PC Twin Reader (645D94C3) 00 00", "Reader Name");
|
assert_eq!(content.name.0.0, "Gemalto PC Twin Reader (645D94C3) 00 00", "Reader Name");
|
||||||
assert_eq!(content.card_type.0.0, "2", "Card Type");
|
assert_eq!(content.card_type.0.0, "2", "Card Type");
|
||||||
},
|
},
|
||||||
|
_ => panic!("Unexpected data block type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ impl SSV {
|
|||||||
|
|
||||||
/// # Read the CPS card
|
/// # Read the CPS card
|
||||||
/// Implement: SSV_LireCartePS
|
/// Implement: SSV_LireCartePS
|
||||||
pub fn read_professional_card(&self, pin_code: &str) -> Result<(), Error> {
|
pub fn read_professional_card(&self, pin_code: &str) -> Result<Data, Error> {
|
||||||
let pcsc_reader_name = "Gemalto PC Twin Reader (645D94C3) 00 00";
|
let pcsc_reader_name = "Gemalto PC Twin Reader (645D94C3) 00 00";
|
||||||
|
|
||||||
let pin_code = CString::new(pin_code).expect("CString::new failed");
|
let pin_code = CString::new(pin_code).expect("CString::new failed");
|
||||||
@ -111,12 +111,13 @@ impl SSV {
|
|||||||
let error = SSVErrorCodes::from(result);
|
let error = SSVErrorCodes::from(result);
|
||||||
return Err(Error::SSVError(error));
|
return Err(Error::SSVError(error));
|
||||||
}
|
}
|
||||||
// Print 10 bytes of the buffer
|
// Parse the buffer into a Data struct
|
||||||
let buffer = unsafe { std::slice::from_raw_parts(out_buffer_ptr as *const u8, 10) };
|
let buffer = unsafe { std::slice::from_raw_parts(out_buffer_ptr as *const u8, out_buffer_size) };
|
||||||
println!("{:?}", buffer);
|
let (_rest, cps_blocks) = Data::from_bytes((buffer, 0)).unwrap();
|
||||||
|
|
||||||
// Free memory
|
// Free memory
|
||||||
unsafe { libc::free(out_buffer_ptr) };
|
unsafe { libc::free(out_buffer_ptr) };
|
||||||
Ok(())
|
Ok(cps_blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Get the configuration of the SSV library
|
/// # Get the configuration of the SSV library
|
||||||
|
Loading…
Reference in New Issue
Block a user