ironrdp_pdu/rdp/capability_sets/
general.rs

1#[cfg(test)]
2mod tests;
3
4use std::fmt;
5
6use bitflags::bitflags;
7use ironrdp_core::{
8    ensure_fixed_part_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor,
9};
10
11const GENERAL_LENGTH: usize = 20;
12pub const PROTOCOL_VER: u16 = 0x0200;
13
14#[derive(Clone, Copy, PartialEq, Eq)]
15pub struct MajorPlatformType(u16);
16
17impl fmt::Debug for MajorPlatformType {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        let name = match *self {
20            Self::UNSPECIFIED => "UNSPECIFIED",
21            Self::WINDOWS => "WINDOWS",
22            Self::OS2 => "OS2",
23            Self::MACINTOSH => "MACINTOSH",
24            Self::UNIX => "UNIX",
25            Self::IOS => "IOS",
26            Self::OSX => "OSX",
27            Self::ANDROID => "ANDROID",
28            Self::CHROMEOS => "CHROMEOS",
29            _ => "UNKNOWN",
30        };
31
32        write!(f, "MajorPlatformType(0x{:02X}-{name})", self.0)
33    }
34}
35
36impl MajorPlatformType {
37    pub const UNSPECIFIED: Self = Self(0);
38    pub const WINDOWS: Self = Self(1);
39    pub const OS2: Self = Self(2);
40    pub const MACINTOSH: Self = Self(3);
41    pub const UNIX: Self = Self(4);
42    pub const IOS: Self = Self(5);
43    pub const OSX: Self = Self(6);
44    pub const ANDROID: Self = Self(7);
45    pub const CHROMEOS: Self = Self(8);
46}
47
48#[derive(Clone, Copy, PartialEq, Eq)]
49pub struct MinorPlatformType(u16);
50
51impl fmt::Debug for MinorPlatformType {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        let name = match *self {
54            Self::UNSPECIFIED => "UNSPECIFIED",
55            Self::WINDOWS_31X => "WINDOWS_31X",
56            Self::WINDOWS_95 => "WINDOWS_95",
57            Self::WINDOWS_NT => "WINDOWS_NT",
58            Self::OS2V21 => "OS2_V21",
59            Self::POWER_PC => "POWER_PC",
60            Self::MACINTOSH => "MACINTOSH",
61            Self::NATIVE_XSERVER => "NATIVE_XSERVER",
62            Self::PSEUDO_XSERVER => "PSEUDO_XSERVER",
63            Self::WINDOWS_RT => "WINDOWS_RT",
64            _ => "UNKNOWN",
65        };
66
67        write!(f, "MinorPlatformType(0x{:02X}-{name})", self.0)
68    }
69}
70
71impl MinorPlatformType {
72    pub const UNSPECIFIED: Self = Self(0);
73    pub const WINDOWS_31X: Self = Self(1);
74    pub const WINDOWS_95: Self = Self(2);
75    pub const WINDOWS_NT: Self = Self(3);
76    pub const OS2V21: Self = Self(4);
77    pub const POWER_PC: Self = Self(5);
78    pub const MACINTOSH: Self = Self(6);
79    pub const NATIVE_XSERVER: Self = Self(7);
80    pub const PSEUDO_XSERVER: Self = Self(8);
81    pub const WINDOWS_RT: Self = Self(9);
82}
83
84bitflags! {
85    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
86    pub struct GeneralExtraFlags: u16 {
87        const FASTPATH_OUTPUT_SUPPORTED = 0x0001;
88        const NO_BITMAP_COMPRESSION_HDR = 0x0400;
89        const LONG_CREDENTIALS_SUPPORTED = 0x0004;
90        const AUTORECONNECT_SUPPORTED = 0x0008;
91        const ENC_SALTED_CHECKSUM = 0x0010;
92    }
93}
94
95#[derive(Debug, PartialEq, Eq, Clone)]
96pub struct General {
97    pub major_platform_type: MajorPlatformType,
98    pub minor_platform_type: MinorPlatformType,
99    pub protocol_version: u16,
100    pub extra_flags: GeneralExtraFlags,
101    pub refresh_rect_support: bool,
102    pub suppress_output_support: bool,
103}
104
105impl General {
106    const NAME: &'static str = "General";
107
108    const FIXED_PART_SIZE: usize = GENERAL_LENGTH;
109}
110
111impl Default for General {
112    fn default() -> Self {
113        Self {
114            major_platform_type: MajorPlatformType::UNSPECIFIED,
115            minor_platform_type: MinorPlatformType::UNSPECIFIED,
116            protocol_version: PROTOCOL_VER,
117            extra_flags: GeneralExtraFlags::empty(),
118            refresh_rect_support: Default::default(),
119            suppress_output_support: Default::default(),
120        }
121    }
122}
123
124impl Encode for General {
125    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
126        ensure_fixed_part_size!(in: dst);
127
128        dst.write_u16(self.major_platform_type.0);
129        dst.write_u16(self.minor_platform_type.0);
130        dst.write_u16(PROTOCOL_VER);
131        dst.write_u16(0); // padding
132        dst.write_u16(0); // generalCompressionTypes
133        dst.write_u16(self.extra_flags.bits());
134        dst.write_u16(0); // updateCapabilityFlag
135        dst.write_u16(0); // remoteUnshareFlag
136        dst.write_u16(0); // generalCompressionLevel
137        dst.write_u8(u8::from(self.refresh_rect_support));
138        dst.write_u8(u8::from(self.suppress_output_support));
139
140        Ok(())
141    }
142
143    fn name(&self) -> &'static str {
144        Self::NAME
145    }
146
147    fn size(&self) -> usize {
148        Self::FIXED_PART_SIZE
149    }
150}
151
152impl<'de> Decode<'de> for General {
153    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
154        ensure_fixed_part_size!(in: src);
155
156        let major_platform_type = MajorPlatformType(src.read_u16());
157        let minor_platform_type = MinorPlatformType(src.read_u16());
158
159        let protocol_version = src.read_u16();
160
161        let _padding = src.read_u16();
162
163        let compression_types = src.read_u16();
164        if compression_types != 0 {
165            return Err(invalid_field_err!("compressionTypes", "invalid compression types"));
166        }
167
168        let extra_flags = GeneralExtraFlags::from_bits_truncate(src.read_u16());
169
170        let update_cap_flags = src.read_u16();
171        if update_cap_flags != 0 {
172            return Err(invalid_field_err!("updateCapFlags", "invalid update cap flags"));
173        }
174
175        let remote_unshare_flag = src.read_u16();
176        if remote_unshare_flag != 0 {
177            return Err(invalid_field_err!("remoteUnshareFlags", "invalid remote unshare flag"));
178        }
179
180        let compression_level = src.read_u16();
181        if compression_level != 0 {
182            return Err(invalid_field_err!("compressionLevel", "invalid compression level"));
183        }
184
185        let refresh_rect_support = src.read_u8() != 0;
186        let suppress_output_support = src.read_u8() != 0;
187
188        Ok(General {
189            major_platform_type,
190            minor_platform_type,
191            protocol_version,
192            extra_flags,
193            refresh_rect_support,
194            suppress_output_support,
195        })
196    }
197}