ironrdp_pdu/basic_output/
surface_commands.rs1#[cfg(test)]
2mod tests;
3
4use bitflags::bitflags;
5use ironrdp_core::{
6 ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor,
7 WriteCursor,
8};
9use num_derive::{FromPrimitive, ToPrimitive};
10use num_traits::{FromPrimitive as _, ToPrimitive as _};
11
12use crate::geometry::ExclusiveRectangle;
13
14pub const SURFACE_COMMAND_HEADER_SIZE: usize = 2;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum SurfaceCommand<'a> {
19 SetSurfaceBits(SurfaceBitsPdu<'a>),
20 FrameMarker(FrameMarkerPdu),
21 StreamSurfaceBits(SurfaceBitsPdu<'a>),
22}
23
24impl SurfaceCommand<'_> {
25 const NAME: &'static str = "TS_SURFCMD";
26 const FIXED_PART_SIZE: usize = 2 ;
27}
28
29impl Encode for SurfaceCommand<'_> {
30 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
31 ensure_size!(in: dst, size: self.size());
32
33 let cmd_type = SurfaceCommandType::from(self);
34 dst.write_u16(cmd_type.to_u16().unwrap());
35
36 match self {
37 Self::SetSurfaceBits(pdu) | Self::StreamSurfaceBits(pdu) => pdu.encode(dst),
38 Self::FrameMarker(pdu) => pdu.encode(dst),
39 }?;
40
41 Ok(())
42 }
43
44 fn name(&self) -> &'static str {
45 Self::NAME
46 }
47
48 fn size(&self) -> usize {
49 SURFACE_COMMAND_HEADER_SIZE
50 + match self {
51 Self::SetSurfaceBits(pdu) | Self::StreamSurfaceBits(pdu) => pdu.size(),
52 Self::FrameMarker(pdu) => pdu.size(),
53 }
54 }
55}
56
57impl<'de> Decode<'de> for SurfaceCommand<'de> {
58 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
59 ensure_fixed_part_size!(in: src);
60
61 let cmd_type = src.read_u16();
62 let cmd_type = SurfaceCommandType::from_u16(cmd_type)
63 .ok_or_else(|| invalid_field_err!("cmdType", "invalid surface command"))?;
64
65 match cmd_type {
66 SurfaceCommandType::SetSurfaceBits => Ok(Self::SetSurfaceBits(SurfaceBitsPdu::decode(src)?)),
67 SurfaceCommandType::FrameMarker => Ok(Self::FrameMarker(FrameMarkerPdu::decode(src)?)),
68 SurfaceCommandType::StreamSurfaceBits => Ok(Self::StreamSurfaceBits(SurfaceBitsPdu::decode(src)?)),
69 }
70 }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct SurfaceBitsPdu<'a> {
76 pub destination: ExclusiveRectangle,
77 pub extended_bitmap_data: ExtendedBitmapDataPdu<'a>,
78}
79
80impl SurfaceBitsPdu<'_> {
81 const NAME: &'static str = "TS_SURFCMD_x_SURFACE_BITS_PDU";
82}
83
84impl Encode for SurfaceBitsPdu<'_> {
85 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
86 self.destination.encode(dst)?;
87 self.extended_bitmap_data.encode(dst)?;
88
89 Ok(())
90 }
91
92 fn name(&self) -> &'static str {
93 Self::NAME
94 }
95
96 fn size(&self) -> usize {
97 self.destination.size() + self.extended_bitmap_data.size()
98 }
99}
100
101impl<'de> Decode<'de> for SurfaceBitsPdu<'de> {
102 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
103 let destination = ExclusiveRectangle::decode(src)?;
104 let extended_bitmap_data = ExtendedBitmapDataPdu::decode(src)?;
105
106 Ok(Self {
107 destination,
108 extended_bitmap_data,
109 })
110 }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct FrameMarkerPdu {
116 pub frame_action: FrameAction,
117 pub frame_id: Option<u32>,
118}
119
120impl FrameMarkerPdu {
121 const NAME: &'static str = "TS_FRAME_MARKER_PDU";
122 const FIXED_PART_SIZE: usize = 2 + 4 ;
123}
124
125impl Encode for FrameMarkerPdu {
126 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
127 ensure_fixed_part_size!(in: dst);
128
129 dst.write_u16(self.frame_action as u16);
130 dst.write_u32(self.frame_id.unwrap_or(0));
131
132 Ok(())
133 }
134
135 fn name(&self) -> &'static str {
136 Self::NAME
137 }
138
139 fn size(&self) -> usize {
140 Self::FIXED_PART_SIZE
141 }
142}
143
144impl<'de> Decode<'de> for FrameMarkerPdu {
145 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
146 ensure_size!(in: src, size: 2);
147
148 let frame_action = src.read_u16();
149
150 let frame_action = FrameAction::from_u16(frame_action)
151 .ok_or_else(|| invalid_field_err!("frameAction", "invalid frame action"))?;
152
153 let frame_id = if src.is_empty() {
154 None
158 } else {
159 ensure_size!(in: src, size: 4);
160 Some(src.read_u32())
161 };
162
163 Ok(Self { frame_action, frame_id })
164 }
165}
166
167#[derive(Clone, PartialEq, Eq)]
169pub struct ExtendedBitmapDataPdu<'a> {
170 pub bpp: u8,
171 pub codec_id: u8,
172 pub width: u16,
173 pub height: u16,
174 pub header: Option<BitmapDataHeader>,
175 pub data: &'a [u8],
176}
177
178impl core::fmt::Debug for ExtendedBitmapDataPdu<'_> {
179 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
180 f.debug_struct("ExtendedBitmapDataPdu")
181 .field("bpp", &self.bpp)
182 .field("codec_id", &self.codec_id)
183 .field("width", &self.width)
184 .field("height", &self.height)
185 .field("header", &self.header)
186 .field("data_len", &self.data.len())
187 .finish()
188 }
189}
190
191impl ExtendedBitmapDataPdu<'_> {
192 const NAME: &'static str = "TS_BITMAP_DATA_EX";
193 const FIXED_PART_SIZE: usize = 1 + 1 + 1 + 1 + 2 + 2 + 4 ;
194}
195
196impl Encode for ExtendedBitmapDataPdu<'_> {
197 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
198 ensure_size!(in: dst, size: self.size());
199
200 if self.data.len() > u32::MAX as usize {
201 return Err(invalid_field_err!("bitmapDataLength", "bitmap data is too big"));
202 }
203
204 dst.write_u8(self.bpp);
205 let flags = if self.header.is_some() {
206 BitmapDataFlags::COMPRESSED_BITMAP_HEADER_PRESENT
207 } else {
208 BitmapDataFlags::empty()
209 };
210 dst.write_u8(flags.bits());
211 dst.write_u8(0); dst.write_u8(self.codec_id);
213 dst.write_u16(self.width);
214 dst.write_u16(self.height);
215 dst.write_u32(self.data.len() as u32);
216 if let Some(header) = &self.header {
217 header.encode(dst)?;
218 }
219 dst.write_slice(self.data);
220
221 Ok(())
222 }
223
224 fn name(&self) -> &'static str {
225 Self::NAME
226 }
227
228 fn size(&self) -> usize {
229 Self::FIXED_PART_SIZE + self.header.as_ref().map_or(0, |h| h.size()) + self.data.len()
230 }
231}
232
233impl<'de> Decode<'de> for ExtendedBitmapDataPdu<'de> {
234 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
235 ensure_fixed_part_size!(in: src);
236
237 let bpp = src.read_u8();
238 let flags = BitmapDataFlags::from_bits_truncate(src.read_u8());
239 let _reserved = src.read_u8();
240 let codec_id = src.read_u8();
241 let width = src.read_u16();
242 let height = src.read_u16();
243 let data_length = src.read_u32() as usize;
244
245 let expected_remaining_size = if flags.contains(BitmapDataFlags::COMPRESSED_BITMAP_HEADER_PRESENT) {
246 data_length + BitmapDataHeader::ENCODED_SIZE
247 } else {
248 data_length
249 };
250
251 ensure_size!(in: src, size: expected_remaining_size);
252
253 let header = if flags.contains(BitmapDataFlags::COMPRESSED_BITMAP_HEADER_PRESENT) {
254 Some(BitmapDataHeader::decode(src)?)
255 } else {
256 None
257 };
258
259 let data = src.read_slice(data_length);
260
261 Ok(Self {
262 bpp,
263 codec_id,
264 width,
265 height,
266 header,
267 data,
268 })
269 }
270}
271
272#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct BitmapDataHeader {
275 pub high_unique_id: u32,
276 pub low_unique_id: u32,
277 pub tm_milliseconds: u64,
278 pub tm_seconds: u64,
279}
280
281impl BitmapDataHeader {
282 const NAME: &'static str = "TS_COMPRESSED_BITMAP_HEADER_EX";
283 const FIXED_PART_SIZE: usize = 4 + 4 + 8 + 8 ;
284
285 pub const ENCODED_SIZE: usize = Self::FIXED_PART_SIZE;
286}
287
288impl Encode for BitmapDataHeader {
289 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
290 ensure_fixed_part_size!(in: dst);
291
292 dst.write_u32(self.high_unique_id);
293 dst.write_u32(self.low_unique_id);
294 dst.write_u64(self.tm_milliseconds);
295 dst.write_u64(self.tm_seconds);
296
297 Ok(())
298 }
299
300 fn name(&self) -> &'static str {
301 Self::NAME
302 }
303
304 fn size(&self) -> usize {
305 Self::FIXED_PART_SIZE
306 }
307}
308
309impl Decode<'_> for BitmapDataHeader {
310 fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
311 ensure_fixed_part_size!(in: src);
312
313 let high_unique_id = src.read_u32();
314 let low_unique_id = src.read_u32();
315 let tm_milliseconds = src.read_u64();
316 let tm_seconds = src.read_u64();
317
318 Ok(Self {
319 high_unique_id,
320 low_unique_id,
321 tm_milliseconds,
322 tm_seconds,
323 })
324 }
325}
326
327#[derive(Debug, Copy, Clone, PartialEq, FromPrimitive, ToPrimitive)]
328#[repr(u16)]
329enum SurfaceCommandType {
330 SetSurfaceBits = 0x01,
331 FrameMarker = 0x04,
332 StreamSurfaceBits = 0x06,
333}
334
335impl From<&SurfaceCommand<'_>> for SurfaceCommandType {
336 fn from(command: &SurfaceCommand<'_>) -> Self {
337 match command {
338 SurfaceCommand::SetSurfaceBits(_) => Self::SetSurfaceBits,
339 SurfaceCommand::FrameMarker(_) => Self::FrameMarker,
340 SurfaceCommand::StreamSurfaceBits(_) => Self::StreamSurfaceBits,
341 }
342 }
343}
344
345#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
346#[repr(u16)]
347pub enum FrameAction {
348 Begin = 0x00,
349 End = 0x01,
350}
351
352bitflags! {
353 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
354 struct BitmapDataFlags: u8 {
355 const COMPRESSED_BITMAP_HEADER_PRESENT = 0x01;
356 }
357}