use crate::util::CRC_X25;
use super::{
common::{CloseResponse, EndOfSmlMessage, ListEntry, OpenResponse, Signature, Time},
octet_string::OctetStr,
tlf::{self, Ty, TypeLengthField},
OctetStrFormatter, ParseError, ResTy, SmlParse, SmlParseTlf,
};
pub struct Parser<'i> {
input: &'i [u8],
msg_input: &'i [u8],
pending_list_entries: u32,
}
impl<'i> Parser<'i> {
pub fn new(input: &'i [u8]) -> Self {
Parser {
input,
msg_input: &[],
pending_list_entries: 0,
}
}
fn parse_next(&mut self) -> Result<Option<ParseEvent<'i>>, ParseError> {
if self.input.is_empty() && self.pending_list_entries == 0 {
return Ok(None);
}
Ok(Some(match self.pending_list_entries {
0 => {
self.msg_input = self.input;
let (input, msg) = MessageStart::parse(self.input)?;
self.input = input;
if let MessageBody::GetListResponse(glr) = &msg.message_body {
self.pending_list_entries = glr.num_vals + 2;
} else {
self.pending_list_entries = 1;
}
ParseEvent::MessageStart(msg)
}
1 => {
let num_bytes_read = self.msg_input.len() - self.input.len();
let (input, crc) = u16::parse(self.input)?;
let (input, _) = EndOfSmlMessage::parse(input)?;
self.input = input;
let digest = CRC_X25
.checksum(&self.msg_input[0..num_bytes_read])
.swap_bytes();
if digest != crc {
return Err(ParseError::CrcMismatch);
}
self.pending_list_entries = 0;
return self.parse_next();
}
2 => {
let (input, glre) = GetListResponseEnd::parse(self.input)?;
self.input = input;
self.pending_list_entries = 1;
ParseEvent::GetListResponseEnd(glre)
}
x => {
let (input, le) = ListEntry::parse(self.input)?;
self.input = input;
self.pending_list_entries = x - 1;
ParseEvent::ListEntry(le)
}
}))
}
}
impl<'i> Iterator for Parser<'i> {
type Item = Result<ParseEvent<'i>, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
let res = self.parse_next();
if res.is_err() {
self.input = &[];
}
match res {
Ok(None) => None,
Ok(Some(x)) => Some(Ok(x)),
Err(e) => Some(Err(e)),
}
}
}
#[derive(Debug)]
pub enum ParseEvent<'i> {
MessageStart(MessageStart<'i>),
GetListResponseEnd(GetListResponseEnd<'i>),
ListEntry(ListEntry<'i>),
}
#[derive(PartialEq, Eq, Clone)]
pub struct MessageStart<'i> {
pub transaction_id: OctetStr<'i>,
pub group_no: u8,
pub abort_on_error: u8,
pub message_body: MessageBody<'i>,
}
impl<'i> SmlParse<'i> for MessageStart<'i> {
fn parse(input: &'i [u8]) -> ResTy<Self> {
let (input, tlf) = TypeLengthField::parse(input)?;
if tlf.ty != Ty::ListOf || tlf.len != 6 {
return Err(ParseError::TlfMismatch("Message"));
}
let (input, transaction_id) = OctetStr::parse(input)?;
let (input, group_no) = u8::parse(input)?;
let (input, abort_on_error) = u8::parse(input)?;
let (input, message_body) = MessageBody::parse(input)?;
let val = MessageStart {
transaction_id,
group_no,
abort_on_error,
message_body,
};
Ok((input, val))
}
}
impl<'i> core::fmt::Debug for MessageStart<'i> {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let mut x = f.debug_struct("MessageStart");
x.field("transaction_id", &OctetStrFormatter(self.transaction_id));
x.field("group_no", &self.group_no);
x.field("abort_on_error", &self.abort_on_error);
x.field("message_body", &self.message_body);
x.finish()
}
}
#[derive(PartialEq, Eq, Clone)]
pub enum MessageBody<'i> {
OpenResponse(OpenResponse<'i>),
CloseResponse(CloseResponse<'i>),
GetListResponse(GetListResponseStart<'i>),
}
impl<'i> core::fmt::Debug for MessageBody<'i> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::OpenResponse(arg0) => arg0.fmt(f),
Self::CloseResponse(arg0) => arg0.fmt(f),
Self::GetListResponse(arg0) => arg0.fmt(f),
}
}
}
impl<'i> SmlParseTlf<'i> for MessageBody<'i> {
fn check_tlf(tlf: &TypeLengthField) -> bool {
tlf.ty == tlf::Ty::ListOf && tlf.len == 2
}
fn parse_with_tlf(input: &'i [u8], _tlf: &TypeLengthField) -> ResTy<'i, Self> {
let (input, tag) = u32::parse(input)?;
match tag {
0x00000101 => {
let (input, x) = <OpenResponse<'i>>::parse(input)?;
Ok((input, MessageBody::OpenResponse(x)))
}
0x00000201 => {
let (input, x) = <CloseResponse<'i>>::parse(input)?;
Ok((input, MessageBody::CloseResponse(x)))
}
0x00000701 => {
let (input, x) = <GetListResponseStart<'i>>::parse(input)?;
Ok((input, MessageBody::GetListResponse(x)))
}
_ => Err(ParseError::UnexpectedVariant),
}
}
}
#[derive(PartialEq, Eq, Clone)]
pub struct GetListResponseStart<'i> {
pub client_id: Option<OctetStr<'i>>,
pub server_id: OctetStr<'i>,
pub list_name: Option<OctetStr<'i>>,
pub act_sensor_time: Option<Time>,
pub num_vals: u32,
}
impl<'i> crate::parser::SmlParseTlf<'i> for GetListResponseStart<'i> {
fn check_tlf(tlf: &TypeLengthField) -> bool {
*tlf == crate::parser::tlf::TypeLengthField::new(
crate::parser::tlf::Ty::ListOf,
7usize as u32,
)
}
fn parse_with_tlf(input: &'i [u8], _tlf: &TypeLengthField) -> ResTy<'i, Self> {
let (input, client_id) = <Option<OctetStr<'i>>>::parse(input)?;
let (input, server_id) = <OctetStr<'i>>::parse(input)?;
let (input, list_name) = <Option<OctetStr<'i>>>::parse(input)?;
let (input, act_sensor_time) = <Option<Time>>::parse(input)?;
let (input, tlf) = TypeLengthField::parse(input)?;
if !matches!(tlf.ty, Ty::ListOf) {
return Err(ParseError::TlfMismatch(core::any::type_name::<Self>()));
}
let val = GetListResponseStart {
client_id,
server_id,
list_name,
act_sensor_time,
num_vals: tlf.len,
};
Ok((input, val))
}
}
impl<'i> core::fmt::Debug for GetListResponseStart<'i> {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let mut x = f.debug_struct("GetListResponseStart");
if let Some(e) = &self.client_id {
x.field("client_id", &OctetStrFormatter(e));
}
x.field("server_id", &OctetStrFormatter(self.server_id));
if let Some(e) = &self.list_name {
x.field("list_name", &OctetStrFormatter(e));
}
if let Some(e) = &self.act_sensor_time {
x.field("act_sensor_time", &e);
}
x.field("num_values", &self.num_vals);
x.finish()
}
}
#[derive(PartialEq, Eq, Clone)]
pub struct GetListResponseEnd<'i> {
pub list_signature: Option<Signature<'i>>,
pub act_gateway_time: Option<Time>,
}
impl<'i> crate::parser::SmlParse<'i> for GetListResponseEnd<'i> {
fn parse(input: &'i [u8]) -> ResTy<'i, Self> {
let (input, list_signature) = <Option<Signature<'i>>>::parse(input)?;
let (input, act_gateway_time) = <Option<Time>>::parse(input)?;
let val = GetListResponseEnd {
list_signature,
act_gateway_time,
};
Ok((input, val))
}
}
impl<'i> core::fmt::Debug for GetListResponseEnd<'i> {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let mut x = f.debug_struct("GetListResponseEnd");
if let Some(e) = &self.list_signature {
x.field("list_signature", &e);
}
if let Some(e) = &self.act_gateway_time {
x.field("act_gateway_time", &e);
}
x.finish()
}
}