1use std::borrow::Cow;
2
3use ironrdp_core::{
4 ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, IntoOwned, ReadCursor, WriteCursor,
5};
6
7use crate::tpdu::{TpduCode, TpduHeader};
8use crate::tpkt::TpktHeader;
9use crate::{impl_x224_pdu_borrowing, Pdu};
10
11pub trait X224Pdu<'de>: Sized {
12 const X224_NAME: &'static str;
13
14 const TPDU_CODE: TpduCode;
15
16 fn x224_body_encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()>;
17
18 fn x224_body_decode(src: &mut ReadCursor<'de>, tpkt: &TpktHeader, tpdu: &TpduHeader) -> DecodeResult<Self>;
19
20 fn tpdu_header_variable_part_size(&self) -> usize;
21
22 fn tpdu_user_data_size(&self) -> usize;
23}
24
25impl<'de, T> Pdu for T
26where
27 T: X224Pdu<'de>,
28{
29 const NAME: &'static str = T::X224_NAME;
30}
31
32#[derive(Debug, Eq, PartialEq)]
33pub struct X224<T>(pub T);
34
35impl<'de, T> Encode for X224<T>
36where
37 T: X224Pdu<'de>,
38{
39 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
40 let packet_length = self.size();
41
42 ensure_size!(in: dst, size: packet_length);
43
44 TpktHeader {
45 packet_length: u16::try_from(packet_length).unwrap(),
46 }
47 .write(dst)?;
48
49 TpduHeader {
50 li: u8::try_from(T::TPDU_CODE.header_fixed_part_size() + self.0.tpdu_header_variable_part_size() - 1)
51 .unwrap(),
52 code: T::TPDU_CODE,
53 }
54 .write(dst)?;
55
56 self.0.x224_body_encode(dst)
57 }
58
59 fn name(&self) -> &'static str {
60 T::X224_NAME
61 }
62
63 fn size(&self) -> usize {
64 TpktHeader::SIZE
65 + T::TPDU_CODE.header_fixed_part_size()
66 + self.0.tpdu_header_variable_part_size()
67 + self.0.tpdu_user_data_size()
68 }
69}
70
71impl<'de, T> Decode<'de> for X224<T>
72where
73 T: X224Pdu<'de>,
74{
75 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
76 let tpkt = TpktHeader::read(src)?;
77
78 ensure_size!(in: src, size: tpkt.packet_length().saturating_sub(TpktHeader::SIZE));
79
80 let tpdu = TpduHeader::read(src, &tpkt)?;
81 tpdu.code.check_expected(T::TPDU_CODE)?;
82
83 if tpdu.size() < tpdu.fixed_part_size() {
84 return Err(invalid_field_err(
85 "TpduHeader",
86 "li",
87 "fixed part bigger than total header size",
88 ));
89 }
90
91 T::x224_body_decode(src, &tpkt, &tpdu).map(X224)
92 }
93}
94
95pub struct X224Data<'a> {
96 pub data: Cow<'a, [u8]>,
97}
98
99impl_x224_pdu_borrowing!(X224Data<'_>, OwnedX224Data);
100
101impl IntoOwned for X224Data<'_> {
102 type Owned = OwnedX224Data;
103
104 fn into_owned(self) -> Self::Owned {
105 X224Data {
106 data: Cow::Owned(self.data.into_owned()),
107 }
108 }
109}
110
111impl<'de> X224Pdu<'de> for X224Data<'de> {
112 const X224_NAME: &'static str = "X.224 Data";
113
114 const TPDU_CODE: TpduCode = TpduCode::DATA;
115
116 fn x224_body_encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
117 ensure_size!(in: dst, size: self.data.len());
118 dst.write_slice(&self.data);
119
120 Ok(())
121 }
122
123 fn x224_body_decode(src: &mut ReadCursor<'de>, tpkt: &TpktHeader, tpdu: &TpduHeader) -> DecodeResult<Self> {
124 let user_data_size = user_data_size(tpkt, tpdu);
125
126 ensure_size!(in: src, size: user_data_size);
127 let data = src.read_slice(user_data_size);
128
129 Ok(Self {
130 data: Cow::Borrowed(data),
131 })
132 }
133
134 fn tpdu_header_variable_part_size(&self) -> usize {
135 0
136 }
137
138 fn tpdu_user_data_size(&self) -> usize {
139 self.data.len()
140 }
141}
142
143pub fn user_data_size(tpkt: &TpktHeader, tpdu: &TpduHeader) -> usize {
144 tpkt.packet_length() - TpktHeader::SIZE - tpdu.size()
145}