ironrdp_pdu/codecs/
rfx.rs

1mod data_messages;
2mod header_messages;
3
4use ironrdp_core::{
5    cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult,
6    ReadCursor, WriteCursor,
7};
8use num_derive::{FromPrimitive, ToPrimitive};
9use num_traits::{FromPrimitive as _, ToPrimitive as _};
10
11use crate::rdp::capability_sets::{RfxCaps, RfxCapset};
12
13#[rustfmt::skip]
14pub use self::data_messages::{
15    ContextPdu, EntropyAlgorithm, FrameBeginPdu, FrameEndPdu, OperatingMode, Quant, RegionPdu, RfxRectangle, Tile,
16    TileSetPdu,
17};
18pub use self::header_messages::{ChannelsPdu, CodecVersionsPdu, RfxChannel, SyncPdu};
19
20const CODEC_ID: u8 = 1;
21const CHANNEL_ID_FOR_CONTEXT: u8 = 0xFF;
22const CHANNEL_ID_FOR_OTHER_VALUES: u8 = 0x00;
23
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum Block<'a> {
26    Tile(Tile<'a>),
27    Caps(RfxCaps),
28    CapabilitySet(RfxCapset),
29    Sync(SyncPdu),
30    CodecVersions(CodecVersionsPdu),
31    Channels(ChannelsPdu),
32    CodecChannel(CodecChannel<'a>),
33}
34
35impl Block<'_> {
36    const NAME: &'static str = "RfxBlock";
37
38    const FIXED_PART_SIZE: usize = BlockHeader::FIXED_PART_SIZE;
39
40    pub fn block_type(&self) -> BlockType {
41        match self {
42            Block::Tile(_) => BlockType::Tile,
43            Block::Caps(_) => BlockType::Capabilities,
44            Block::CapabilitySet(_) => BlockType::CapabilitySet,
45            Block::Sync(_) => BlockType::Sync,
46            Block::Channels(_) => BlockType::Channels,
47            Block::CodecVersions(_) => BlockType::CodecVersions,
48            Block::CodecChannel(CodecChannel::Context(_)) => BlockType::Context,
49            Block::CodecChannel(CodecChannel::FrameBegin(_)) => BlockType::FrameBegin,
50            Block::CodecChannel(CodecChannel::FrameEnd(_)) => BlockType::FrameEnd,
51            Block::CodecChannel(CodecChannel::Region(_)) => BlockType::Region,
52            Block::CodecChannel(CodecChannel::TileSet(_)) => BlockType::Extension,
53        }
54    }
55}
56
57impl Encode for Block<'_> {
58    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
59        ensure_size!(in: dst, size: self.size());
60
61        let ty = self.block_type();
62        let data_length = self.size();
63        BlockHeader { ty, data_length }.encode(dst)?;
64
65        if let Block::CodecChannel(ref c) = self {
66            let channel_id = c.channel_id();
67            CodecChannelHeader { channel_id }.encode(dst)?;
68        }
69
70        match self {
71            Block::Tile(t) => t.encode(dst),
72            Block::Caps(c) => c.encode(dst),
73            Block::CapabilitySet(c) => c.encode(dst),
74            Block::Sync(s) => s.encode(dst),
75            Block::Channels(c) => c.encode(dst),
76            Block::CodecVersions(c) => c.encode(dst),
77            Block::CodecChannel(CodecChannel::Context(c)) => c.encode(dst),
78            Block::CodecChannel(CodecChannel::FrameBegin(f)) => f.encode(dst),
79            Block::CodecChannel(CodecChannel::FrameEnd(f)) => f.encode(dst),
80            Block::CodecChannel(CodecChannel::Region(r)) => r.encode(dst),
81            Block::CodecChannel(CodecChannel::TileSet(t)) => t.encode(dst),
82        }
83    }
84
85    fn name(&self) -> &'static str {
86        Self::NAME
87    }
88
89    fn size(&self) -> usize {
90        Self::FIXED_PART_SIZE
91            + if matches!(self, Block::CodecChannel(_)) {
92                CodecChannelHeader::FIXED_PART_SIZE
93            } else {
94                0
95            }
96            + match self {
97                Block::Tile(t) => t.size(),
98                Block::Caps(c) => c.size(),
99                Block::CapabilitySet(c) => c.size(),
100                Block::Sync(s) => s.size(),
101                Block::Channels(c) => c.size(),
102                Block::CodecVersions(c) => c.size(),
103                Block::CodecChannel(CodecChannel::Context(c)) => c.size(),
104                Block::CodecChannel(CodecChannel::FrameBegin(f)) => f.size(),
105                Block::CodecChannel(CodecChannel::FrameEnd(f)) => f.size(),
106                Block::CodecChannel(CodecChannel::Region(r)) => r.size(),
107                Block::CodecChannel(CodecChannel::TileSet(t)) => t.size(),
108            }
109    }
110}
111
112impl<'de> Decode<'de> for Block<'de> {
113    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
114        let header = BlockHeader::decode(src)?;
115        let mut len = header.size();
116        if header.ty.is_channel() {
117            let channel = CodecChannelHeader::decode(src)?;
118            let expected_id = if header.ty == BlockType::Context {
119                CHANNEL_ID_FOR_CONTEXT
120            } else {
121                CHANNEL_ID_FOR_OTHER_VALUES
122            };
123            if channel.channel_id != expected_id {
124                return Err(invalid_field_err!("channelId", "Invalid channel ID"));
125            }
126            len += channel.size();
127        }
128        let data_len = header
129            .data_length
130            .checked_sub(len)
131            .ok_or_else(|| invalid_field_err!("blockLen", "Invalid block length"))?;
132        ensure_size!(in: src, size: data_len);
133        let src = &mut ReadCursor::new(src.read_slice(data_len));
134        match header.ty {
135            BlockType::Tile => Ok(Self::Tile(Tile::decode(src)?)),
136            BlockType::Capabilities => Ok(Self::Caps(RfxCaps::decode(src)?)),
137            BlockType::CapabilitySet => Ok(Self::CapabilitySet(RfxCapset::decode(src)?)),
138            BlockType::Sync => Ok(Self::Sync(SyncPdu::decode(src)?)),
139            BlockType::Channels => Ok(Self::Channels(ChannelsPdu::decode(src)?)),
140            BlockType::CodecVersions => Ok(Self::CodecVersions(CodecVersionsPdu::decode(src)?)),
141            BlockType::Context => Ok(Self::CodecChannel(CodecChannel::Context(ContextPdu::decode(src)?))),
142            BlockType::FrameBegin => Ok(Self::CodecChannel(CodecChannel::FrameBegin(FrameBeginPdu::decode(
143                src,
144            )?))),
145            BlockType::FrameEnd => Ok(Self::CodecChannel(CodecChannel::FrameEnd(FrameEndPdu::decode(src)?))),
146            BlockType::Region => Ok(Self::CodecChannel(CodecChannel::Region(RegionPdu::decode(src)?))),
147            BlockType::Extension => Ok(Self::CodecChannel(CodecChannel::TileSet(TileSetPdu::decode(src)?))),
148        }
149    }
150}
151
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub enum CodecChannel<'a> {
154    Context(ContextPdu),
155    FrameBegin(FrameBeginPdu),
156    FrameEnd(FrameEndPdu),
157    Region(RegionPdu),
158    TileSet(TileSetPdu<'a>),
159}
160
161impl CodecChannel<'_> {
162    fn channel_id(&self) -> u8 {
163        if matches!(self, CodecChannel::Context(_)) {
164            CHANNEL_ID_FOR_CONTEXT
165        } else {
166            CHANNEL_ID_FOR_OTHER_VALUES
167        }
168    }
169}
170
171/// [2.2.2.1.1] TS_RFX_BLOCKT
172///
173/// [2.2.2.1.1]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/1e1b69a9-c2aa-4b13-bd44-23dcf96d4a74
174#[derive(Debug, Clone, PartialEq, Eq)]
175pub struct BlockHeader {
176    pub ty: BlockType,
177    pub data_length: usize,
178}
179
180impl BlockHeader {
181    const NAME: &'static str = "RfxBlockHeader";
182
183    const FIXED_PART_SIZE: usize = 2 /* blockType */ + 4 /* blockLen */;
184}
185
186impl Encode for BlockHeader {
187    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
188        ensure_fixed_part_size!(in: dst);
189
190        dst.write_u16(self.ty.to_u16().unwrap());
191        dst.write_u32(cast_length!("data len", self.data_length)?);
192
193        Ok(())
194    }
195
196    fn name(&self) -> &'static str {
197        Self::NAME
198    }
199
200    fn size(&self) -> usize {
201        Self::FIXED_PART_SIZE
202    }
203}
204
205impl<'de> Decode<'de> for BlockHeader {
206    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
207        ensure_fixed_part_size!(in: src);
208
209        let ty = src.read_u16();
210        let ty = BlockType::from_u16(ty).ok_or_else(|| invalid_field_err!("blockType", "Invalid block type"))?;
211        let data_length = src.read_u32() as usize;
212        data_length
213            .checked_sub(Self::FIXED_PART_SIZE)
214            .ok_or_else(|| invalid_field_err!("blockLen", "Invalid block length"))?;
215
216        Ok(Self { ty, data_length })
217    }
218}
219
220/// [2.2.2.1.2] TS_RFX_CODEC_CHANNELT
221///
222/// [2.2.2.1.2]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/56b78b0c-6eef-40cc-b9da-96d21f197c14
223#[derive(Debug, Clone, PartialEq, Eq)]
224pub struct CodecChannelHeader {
225    channel_id: u8,
226}
227
228impl CodecChannelHeader {
229    const NAME: &'static str = "CodecChannelHeader";
230
231    const FIXED_PART_SIZE: usize = 1 /* codecId */ + 1 /* channelId */;
232}
233
234impl Encode for CodecChannelHeader {
235    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
236        ensure_fixed_part_size!(in: dst);
237
238        dst.write_u8(CODEC_ID);
239        dst.write_u8(self.channel_id);
240
241        Ok(())
242    }
243
244    fn name(&self) -> &'static str {
245        Self::NAME
246    }
247
248    fn size(&self) -> usize {
249        Self::FIXED_PART_SIZE
250    }
251}
252
253impl Decode<'_> for CodecChannelHeader {
254    fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
255        ensure_fixed_part_size!(in: src);
256
257        let codec_id = src.read_u8();
258        if codec_id != CODEC_ID {
259            return Err(invalid_field_err!("codecId", "Invalid codec ID"));
260        }
261
262        let channel_id = src.read_u8();
263
264        Ok(Self { channel_id })
265    }
266}
267
268/// [2.2.3.1] TS_FRAME_ACKNOWLEDGE_PDU
269///
270/// [2.2.3.1]: https://learn.microsoft.com/pt-br/openspecs/windows_protocols/ms-rdprfx/24364aa2-9a7f-4d86-bcfb-67f5a6c19064
271#[derive(Debug, Clone, PartialEq, Eq)]
272pub struct FrameAcknowledgePdu {
273    pub frame_id: u32,
274}
275
276impl FrameAcknowledgePdu {
277    const NAME: &'static str = "FrameAcknowledgePdu";
278
279    const FIXED_PART_SIZE: usize = 4 /* frameId */;
280}
281
282impl Encode for FrameAcknowledgePdu {
283    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
284        ensure_fixed_part_size!(in: dst);
285
286        dst.write_u32(self.frame_id);
287
288        Ok(())
289    }
290
291    fn name(&self) -> &'static str {
292        Self::NAME
293    }
294
295    fn size(&self) -> usize {
296        Self::FIXED_PART_SIZE
297    }
298}
299
300impl<'de> Decode<'de> for FrameAcknowledgePdu {
301    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
302        ensure_fixed_part_size!(in: src);
303
304        let frame_id = src.read_u32();
305
306        Ok(Self { frame_id })
307    }
308}
309
310#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
311#[repr(u16)]
312pub enum BlockType {
313    Tile = 0xCAC3,
314    Capabilities = 0xCBC0,
315    CapabilitySet = 0xCBC1,
316    Sync = 0xCCC0,
317    CodecVersions = 0xCCC1,
318    Channels = 0xCCC2,
319    Context = 0xCCC3,
320    FrameBegin = 0xCCC4,
321    FrameEnd = 0xCCC5,
322    Region = 0xCCC6,
323    Extension = 0xCCC7,
324}
325
326impl BlockType {
327    fn is_channel(&self) -> bool {
328        matches!(
329            self,
330            BlockType::Context | BlockType::FrameBegin | BlockType::FrameEnd | BlockType::Region | BlockType::Extension
331        )
332    }
333}