use alloc::vec::Vec;
use core::cmp;
use rat_rdp_core::{DecodeResult, cast_length, invalid_field_err};
use tracing::error;
use crate::pdu::{DataFirstPdu, DataPdu, DrdynvcDataPdu};
#[derive(Debug, PartialEq)]
pub(crate) struct CompleteData {
total_size: usize,
data: Vec<u8>,
}
impl CompleteData {
pub(crate) fn new() -> Self {
Self {
total_size: 0,
data: Vec::new(),
}
}
pub(crate) fn process_data(&mut self, pdu: DrdynvcDataPdu) -> DecodeResult<Option<Vec<u8>>> {
match pdu {
DrdynvcDataPdu::DataFirst(data_first) => self.process_data_first_pdu(data_first),
DrdynvcDataPdu::Data(data) => self.process_data_pdu(data),
}
}
fn process_data_first_pdu(&mut self, data_first: DataFirstPdu) -> DecodeResult<Option<Vec<u8>>> {
let total_data_size: DecodeResult<_> = cast_length!("DataFirstPdu::length", data_first.length());
let total_data_size = total_data_size?;
if self.total_size != 0 || !self.data.is_empty() {
error!("Incomplete DVC message, it will be skipped");
self.data.clear();
}
if total_data_size == data_first.data().len() {
Ok(Some(data_first.into_data()))
} else {
self.total_size = total_data_size;
self.data = data_first.into_data();
Ok(None)
}
}
fn process_data_pdu(&mut self, mut data: DataPdu) -> DecodeResult<Option<Vec<u8>>> {
if self.total_size == 0 && self.data.is_empty() {
return Ok(Some(data.into_data()));
}
match self.data.len().checked_add(data.data().len()) {
Some(actual_data_length) => {
match actual_data_length.cmp(&(self.total_size)) {
cmp::Ordering::Less => {
self.data.append(data.data_mut());
Ok(None)
}
cmp::Ordering::Equal => {
self.total_size = 0;
self.data.append(data.data_mut());
Ok(Some(self.data.drain(..).collect()))
}
cmp::Ordering::Greater => {
error!("Actual DVC message size is grater than expected total DVC message size");
self.total_size = 0;
self.data.clear();
Ok(None)
}
}
}
_ => Err(invalid_field_err!("DVC message", "data", "overflow occurred")),
}
}
}