ironrdp_pdu/basic_output/pointer/
mod.rs1use ironrdp_core::{
2 cast_int, cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode,
3 EncodeResult, ReadCursor, WriteCursor,
4};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct Point16 {
9 pub x: u16,
10 pub y: u16,
11}
12
13impl Point16 {
14 const NAME: &'static str = "TS_POINT16";
15 const FIXED_PART_SIZE: usize = 2 + 2 ;
16}
17
18impl Encode for Point16 {
19 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
20 ensure_size!(in: dst, size: self.size());
21
22 dst.write_u16(self.x);
23 dst.write_u16(self.y);
24 Ok(())
25 }
26
27 fn name(&self) -> &'static str {
28 Self::NAME
29 }
30
31 fn size(&self) -> usize {
32 Self::FIXED_PART_SIZE
33 }
34}
35
36impl Decode<'_> for Point16 {
37 fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
38 ensure_fixed_part_size!(in: src);
39
40 let x = src.read_u16();
41 let y = src.read_u16();
42
43 Ok(Self { x, y })
44 }
45}
46
47pub type PointerPositionAttribute = Point16;
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct ColorPointerAttribute<'a> {
54 pub cache_index: u16,
55 pub hot_spot: Point16,
56 pub width: u16,
57 pub height: u16,
58 pub xor_mask: &'a [u8],
59 pub and_mask: &'a [u8],
60}
61
62impl ColorPointerAttribute<'_> {
63 const NAME: &'static str = "TS_COLORPOINTERATTRIBUTE";
64 const FIXED_PART_SIZE: usize =
65 2 + 2 + 2 + 2 + 2 + Point16::FIXED_PART_SIZE;
66}
67
68macro_rules! check_masks_alignment {
69 ($and_mask:expr, $xor_mask:expr, $pointer_height:expr, $large_ptr:expr) => {{
70 const AND_MASK_SIZE_FIELD: &str = "lengthAndMask";
71 const XOR_MASK_SIZE_FIELD: &str = "lengthXorMask";
72 const U32_MAX: usize = 0xFFFFFFFF;
73
74 let pointer_height: usize = cast_int!("pointer height", $pointer_height)?;
75
76 let check_mask = |mask: &[u8], field: &'static str| {
77 if $pointer_height == 0 {
78 return Err(invalid_field_err!(field, "pointer height cannot be zero"));
79 }
80 if $large_ptr && (mask.len() > U32_MAX) {
81 return Err(invalid_field_err!(field, "pointer mask is too big for u32 size"));
82 }
83 if !$large_ptr && (mask.len() > usize::from(u16::MAX)) {
84 return Err(invalid_field_err!(field, "pointer mask is too big for u16 size"));
85 }
86 if (mask.len() % pointer_height) != 0 {
87 return Err(invalid_field_err!(field, "pointer mask have incomplete scanlines"));
88 }
89 if (mask.len() / pointer_height) % 2 != 0 {
90 return Err(invalid_field_err!(
91 field,
92 "pointer mask scanlines should be aligned to 16 bits"
93 ));
94 }
95 Ok(())
96 };
97
98 check_mask($and_mask, AND_MASK_SIZE_FIELD)?;
99 check_mask($xor_mask, XOR_MASK_SIZE_FIELD)
100 }};
101}
102
103impl Encode for ColorPointerAttribute<'_> {
104 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
105 ensure_size!(in: dst, size: self.size());
106
107 check_masks_alignment!(self.and_mask, self.xor_mask, self.height, false)?;
108
109 dst.write_u16(self.cache_index);
110 self.hot_spot.encode(dst)?;
111 dst.write_u16(self.width);
112 dst.write_u16(self.height);
113
114 dst.write_u16(cast_length!("and mask length", self.and_mask.len())?);
115 dst.write_u16(cast_length!("xor mask length", self.xor_mask.len())?);
116 dst.write_slice(self.xor_mask);
119 dst.write_slice(self.and_mask);
120
121 Ok(())
122 }
123
124 fn name(&self) -> &'static str {
125 Self::NAME
126 }
127
128 fn size(&self) -> usize {
129 Self::FIXED_PART_SIZE + self.xor_mask.len() + self.and_mask.len()
130 }
131}
132
133impl<'a> Decode<'a> for ColorPointerAttribute<'a> {
134 fn decode(src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
135 ensure_fixed_part_size!(in: src);
136
137 let cache_index = src.read_u16();
138 let hot_spot = Point16::decode(src)?;
139 let width = src.read_u16();
140 let height = src.read_u16();
141 let length_and_mask = usize::from(src.read_u16());
143 let length_xor_mask = usize::from(src.read_u16());
144
145 let expected_masks_size = length_and_mask + length_xor_mask;
146 ensure_size!(in: src, size: expected_masks_size);
147
148 let xor_mask = src.read_slice(length_xor_mask);
149 let and_mask = src.read_slice(length_and_mask);
150
151 check_masks_alignment!(and_mask, xor_mask, height, false)?;
152
153 Ok(Self {
154 cache_index,
155 hot_spot,
156 width,
157 height,
158 xor_mask,
159 and_mask,
160 })
161 }
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166pub struct PointerAttribute<'a> {
167 pub xor_bpp: u16,
168 pub color_pointer: ColorPointerAttribute<'a>,
169}
170
171impl PointerAttribute<'_> {
172 const NAME: &'static str = "TS_POINTERATTRIBUTE";
173 const FIXED_PART_SIZE: usize = 2 ;
174}
175
176impl Encode for PointerAttribute<'_> {
177 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
178 ensure_size!(in: dst, size: self.size());
179
180 dst.write_u16(self.xor_bpp);
181 self.color_pointer.encode(dst)?;
182
183 Ok(())
184 }
185
186 fn name(&self) -> &'static str {
187 Self::NAME
188 }
189
190 fn size(&self) -> usize {
191 Self::FIXED_PART_SIZE + self.color_pointer.size()
192 }
193}
194
195impl<'a> Decode<'a> for PointerAttribute<'a> {
196 fn decode(src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
197 ensure_fixed_part_size!(in: src);
198
199 let xor_bpp = src.read_u16();
200 let color_pointer = ColorPointerAttribute::decode(src)?;
201
202 Ok(Self { xor_bpp, color_pointer })
203 }
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
208pub struct CachedPointerAttribute {
209 pub cache_index: u16,
210}
211
212impl CachedPointerAttribute {
213 const NAME: &'static str = "TS_CACHEDPOINTERATTRIBUTE";
214 const FIXED_PART_SIZE: usize = 2 ;
215}
216
217impl Encode for CachedPointerAttribute {
218 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
219 ensure_size!(in: dst, size: self.size());
220
221 dst.write_u16(self.cache_index);
222
223 Ok(())
224 }
225
226 fn name(&self) -> &'static str {
227 Self::NAME
228 }
229
230 fn size(&self) -> usize {
231 Self::FIXED_PART_SIZE
232 }
233}
234
235impl Decode<'_> for CachedPointerAttribute {
236 fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
237 ensure_fixed_part_size!(in: src);
238
239 let cache_index = src.read_u16();
240
241 Ok(Self { cache_index })
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247pub struct LargePointerAttribute<'a> {
248 pub xor_bpp: u16,
249 pub cache_index: u16,
250 pub hot_spot: Point16,
251 pub width: u16,
252 pub height: u16,
253 pub xor_mask: &'a [u8],
254 pub and_mask: &'a [u8],
255}
256
257impl LargePointerAttribute<'_> {
258 const NAME: &'static str = "TS_FP_LARGEPOINTERATTRIBUTE";
259 const FIXED_PART_SIZE: usize =
260 2 + 2 + 4 + 2 + 2 +
261 4 + 4 ;
262}
263
264impl Encode for LargePointerAttribute<'_> {
265 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
266 ensure_size!(in: dst, size: self.size());
267
268 check_masks_alignment!(self.and_mask, self.xor_mask, self.height, true)?;
269
270 dst.write_u16(self.xor_bpp);
271 dst.write_u16(self.cache_index);
272 self.hot_spot.encode(dst)?;
273 dst.write_u16(self.width);
274 dst.write_u16(self.height);
275
276 dst.write_u32(cast_length!("and mask length", self.and_mask.len())?);
277 dst.write_u32(cast_length!("xor mask length", self.xor_mask.len())?);
278 dst.write_slice(self.xor_mask);
280 dst.write_slice(self.and_mask);
281
282 Ok(())
283 }
284
285 fn name(&self) -> &'static str {
286 Self::NAME
287 }
288
289 fn size(&self) -> usize {
290 Self::FIXED_PART_SIZE + self.xor_mask.len() + self.and_mask.len()
291 }
292}
293
294impl<'a> Decode<'a> for LargePointerAttribute<'a> {
295 fn decode(src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
296 ensure_fixed_part_size!(in: src);
297
298 let xor_bpp = src.read_u16();
299 let cache_index = src.read_u16();
300 let hot_spot = Point16::decode(src)?;
301 let width = src.read_u16();
302 let height = src.read_u16();
303 let length_and_mask = cast_length!("and mask length", src.read_u32())?;
305 let length_xor_mask = cast_length!("xor mask length", src.read_u32())?;
306
307 let expected_masks_size = length_and_mask + length_xor_mask;
308 ensure_size!(in: src, size: expected_masks_size);
309
310 let xor_mask = src.read_slice(length_xor_mask);
311 let and_mask = src.read_slice(length_and_mask);
312
313 check_masks_alignment!(and_mask, xor_mask, height, true)?;
314
315 Ok(Self {
316 xor_bpp,
317 cache_index,
318 hot_spot,
319 width,
320 height,
321 xor_mask,
322 and_mask,
323 })
324 }
325}
326
327#[derive(Debug, Clone, Copy, PartialEq, Eq)]
329pub enum PointerUpdateData<'a> {
330 SetHidden,
331 SetDefault,
332 SetPosition(PointerPositionAttribute),
333 Color(ColorPointerAttribute<'a>),
334 Cached(CachedPointerAttribute),
335 New(PointerAttribute<'a>),
336 Large(LargePointerAttribute<'a>),
337}