mirror of
https://git.eta.st/eta/rsp6-decoder.git
synced 2024-11-24 18:45:40 +00:00
additional fields
This commit is contained in:
parent
11b41c3281
commit
1bb6e5cff8
@ -91,7 +91,7 @@ fn main() -> anyhow::Result<()> {
|
||||
} else {
|
||||
eprintln!("[+] checksum ok");
|
||||
}
|
||||
let ticket = Rsp6Ticket::decode(unpadded)?;
|
||||
let ticket = Rsp6Ticket::decode(unpadded, issuer_id.into())?;
|
||||
serde_json::to_writer_pretty(std::io::stdout(), &ticket)?;
|
||||
return Ok(());
|
||||
} else {
|
||||
|
@ -17,6 +17,13 @@ pub enum CouponType {
|
||||
ReturnInbound = 3,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize)]
|
||||
pub enum DepartTimeFlag {
|
||||
Mystery = 1,
|
||||
Specific = 2,
|
||||
Suggested = 3,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct TicketPurchaseDetails {
|
||||
pub purchase_time: PrimitiveDateTime,
|
||||
@ -32,6 +39,7 @@ pub struct Reservation {
|
||||
pub seat_number: u8,
|
||||
pub seat_letter: Option<char>,
|
||||
}
|
||||
|
||||
impl Reservation {
|
||||
pub fn decode(resv: &BitSlice<u8, Msb0>) -> anyhow::Result<Self> {
|
||||
if resv.len() != 45 {
|
||||
@ -57,6 +65,7 @@ impl Reservation {
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct Rsp6Ticket {
|
||||
pub manually_inspect: bool,
|
||||
pub issuer_id: String,
|
||||
pub ticket_reference: String,
|
||||
pub checksum: char,
|
||||
pub version: u8,
|
||||
@ -71,7 +80,7 @@ pub struct Rsp6Ticket {
|
||||
pub discount_code: u16,
|
||||
pub route_code: u32,
|
||||
pub start_date: Date,
|
||||
pub depart_time_flag: u8,
|
||||
pub depart_time_flag: Option<DepartTimeFlag>,
|
||||
pub depart_time: Time,
|
||||
pub passenger_id: Option<String>,
|
||||
pub passenger_name: Option<String>,
|
||||
@ -82,6 +91,9 @@ pub struct Rsp6Ticket {
|
||||
pub purchase_details: Option<TicketPurchaseDetails>,
|
||||
pub reservations: Vec<Reservation>,
|
||||
pub free_text: Option<String>,
|
||||
pub osi_nlc: Option<String>,
|
||||
pub mystery_flag: bool,
|
||||
pub mystery_header: String,
|
||||
}
|
||||
|
||||
impl Rsp6Ticket {
|
||||
@ -132,10 +144,12 @@ impl Rsp6Ticket {
|
||||
Some(format!("{}{:04}", prefix, (id % 10000)))
|
||||
}
|
||||
|
||||
pub fn decode(tkt: &[u8]) -> anyhow::Result<Self> {
|
||||
pub fn decode(tkt: &[u8], issuer_id: String) -> anyhow::Result<Self> {
|
||||
let bit_tkt = tkt.view_bits::<Msb0>();
|
||||
|
||||
let manually_inspect = bit_tkt[0];
|
||||
let mystery_header: u8 = bit_tkt[1..8].load_be();
|
||||
let mystery_header = format!("{:07b}", mystery_header);
|
||||
let ticket_reference = Self::base64(tkt, 8, 62);
|
||||
let checksum = Self::base64(tkt, 62, 68).chars().next().unwrap();
|
||||
let version: u8 = bit_tkt[68..72].load_be();
|
||||
@ -162,18 +176,29 @@ impl Rsp6Ticket {
|
||||
let start_time_secs: u32 = bit_tkt[225..236].load_be();
|
||||
let start_time: PrimitiveDateTime =
|
||||
CapitalismDateTime::new(start_time_days, start_time_secs).into();
|
||||
let depart_time_flag: u8 = bit_tkt[236..238].load_be();
|
||||
let depart_time_flag = match bit_tkt[236..238].load_be::<u8>() {
|
||||
0 => None,
|
||||
1 => Some(DepartTimeFlag::Mystery),
|
||||
2 => Some(DepartTimeFlag::Specific),
|
||||
3 => Some(DepartTimeFlag::Suggested),
|
||||
_ => unreachable!(), // only 2-bit int
|
||||
};
|
||||
let depart_time = start_time.time();
|
||||
let start_date = start_time.date();
|
||||
|
||||
let passenger_id = Self::decode_passenger_id(bit_tkt[238..255].load_be());
|
||||
let passenger_name = Self::base64(tkt, 255, 327);
|
||||
let passenger_name = (!passenger_name.trim().is_empty()).then_some(passenger_name);
|
||||
let passenger_name =
|
||||
(!passenger_name.trim().is_empty()).then(|| passenger_name.trim().to_owned());
|
||||
let passenger_gender: u8 = bit_tkt[327..329].load_be();
|
||||
let passenger_gender = (passenger_gender != 0).then_some(passenger_gender);
|
||||
|
||||
let restriction_code = Self::base64(tkt, 329, 347);
|
||||
let restriction_code = (!restriction_code.trim().is_empty()).then_some(restriction_code);
|
||||
let osi_nlc = Self::base64(tkt, 347, 371);
|
||||
let osi_nlc = (!osi_nlc.trim().is_empty()).then(|| osi_nlc.trim().to_owned());
|
||||
let mystery_flag = bit_tkt[371];
|
||||
let restriction_code =
|
||||
(!restriction_code.trim().is_empty()).then(|| restriction_code.trim().to_owned());
|
||||
let bidirectional = bit_tkt[372];
|
||||
let limited_duration = Self::decode_limited_duration(bit_tkt[379..383].load_be());
|
||||
|
||||
@ -186,8 +211,8 @@ impl Rsp6Ticket {
|
||||
CapitalismDateTime::new(purchase_time_days, purchase_time_secs).into();
|
||||
let price_pence: u32 = bit_tkt[415..436].load_be();
|
||||
let purchase_reference = Self::base64(tkt, 449, 497);
|
||||
let purchase_reference =
|
||||
(!purchase_reference.trim().is_empty()).then_some(purchase_reference);
|
||||
let purchase_reference = (!purchase_reference.trim().is_empty())
|
||||
.then(|| purchase_reference.trim().to_owned());
|
||||
let mut days_of_validity = bit_tkt[497..506].load_be();
|
||||
if days_of_validity == 0 {
|
||||
days_of_validity = 1;
|
||||
@ -212,8 +237,22 @@ impl Rsp6Ticket {
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let has_free_text = bit_tkt[385];
|
||||
let free_text_is_extended = bit_tkt[383];
|
||||
let mut free_text = None;
|
||||
if has_free_text {
|
||||
let reservations_end = reservations_start + (45 * reservations_count as usize);
|
||||
let end = if free_text_is_extended { 863 } else { 783 };
|
||||
let length = 6 * ((end - reservations_end) / 6);
|
||||
let text = Self::base64(tkt, reservations_end, reservations_end + length);
|
||||
if !text.trim().is_empty() {
|
||||
free_text = Some(text.trim().to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
manually_inspect,
|
||||
issuer_id,
|
||||
ticket_reference,
|
||||
checksum,
|
||||
version,
|
||||
@ -238,7 +277,10 @@ impl Rsp6Ticket {
|
||||
limited_duration,
|
||||
purchase_details,
|
||||
reservations,
|
||||
free_text: None,
|
||||
free_text,
|
||||
osi_nlc,
|
||||
mystery_flag,
|
||||
mystery_header,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user