ironrdp_pdu/basic_output/
surface_commands.rs

1#[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// TS_SURFCMD
17#[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 /* cmdType */;
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// TS_SURFCMD_STREAM_SURF_BITS and TS_SURFCMD_SET_SURF_BITS
74#[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// TS_FRAME_MARKER
114#[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 /* frameAction */ + 4 /* frameId */;
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            // Sometimes Windows 10 RDP server sends not complete FrameMarker PDU (without frame ID),
155            // so we made frame ID field as optional (not officially)
156
157            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// TS_BITMAP_DATA_EX
168#[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 /* bpp */ + 1 /* flags */ + 1 /* reserved */ + 1 /* codecId */ + 2 /* width */ + 2 /* height */ + 4 /* len */;
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); // reserved
212        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// TS_COMPRESSED_BITMAP_HEADER_EX
273#[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 /* highUniqueId */ + 4 /* lowUniqueId */ + 8 /* tmMilli */ + 8 /* tmSeconds */;
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}