ironrdp_pdu/basic_output/
pointer.rs1use ironrdp_core::{
2 ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor,
3 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
73 let check_mask = |mask: &[u8], field: &'static str| {
74 if $pointer_height == 0 {
75 return Err(invalid_field_err!(field, "pointer height cannot be zero"));
76 }
77 if $large_ptr && (mask.len() > u32::MAX as usize) {
78 return Err(invalid_field_err!(field, "pointer mask is too big for u32 size"));
79 }
80 if !$large_ptr && (mask.len() > u16::MAX as usize) {
81 return Err(invalid_field_err!(field, "pointer mask is too big for u16 size"));
82 }
83 if (mask.len() % $pointer_height as usize) != 0 {
84 return Err(invalid_field_err!(field, "pointer mask have incomplete scanlines"));
85 }
86 if (mask.len() / $pointer_height as usize) % 2 != 0 {
87 return Err(invalid_field_err!(
88 field,
89 "pointer mask scanlines should be aligned to 16 bits"
90 ));
91 }
92 Ok(())
93 };
94
95 check_mask($and_mask, AND_MASK_SIZE_FIELD)?;
96 check_mask($xor_mask, XOR_MASK_SIZE_FIELD)
97 }};
98}
99
100impl Encode for ColorPointerAttribute<'_> {
101 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
102 ensure_size!(in: dst, size: self.size());
103
104 check_masks_alignment!(self.and_mask, self.xor_mask, self.height, false)?;
105
106 dst.write_u16(self.cache_index);
107 self.hot_spot.encode(dst)?;
108 dst.write_u16(self.width);
109 dst.write_u16(self.height);
110
111 dst.write_u16(self.and_mask.len() as u16);
112 dst.write_u16(self.xor_mask.len() as u16);
113 dst.write_slice(self.xor_mask);
116 dst.write_slice(self.and_mask);
117
118 Ok(())
119 }
120
121 fn name(&self) -> &'static str {
122 Self::NAME
123 }
124
125 fn size(&self) -> usize {
126 Self::FIXED_PART_SIZE + self.xor_mask.len() + self.and_mask.len()
127 }
128}
129
130impl<'a> Decode<'a> for ColorPointerAttribute<'a> {
131 fn decode(src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
132 ensure_fixed_part_size!(in: src);
133
134 let cache_index = src.read_u16();
135 let hot_spot = Point16::decode(src)?;
136 let width = src.read_u16();
137 let height = src.read_u16();
138 let length_and_mask = src.read_u16();
139 let length_xor_mask = src.read_u16();
140
141 let expected_masks_size = (length_and_mask as usize) + (length_xor_mask as usize);
143 ensure_size!(in: src, size: expected_masks_size);
144
145 let xor_mask = src.read_slice(length_xor_mask as usize);
146 let and_mask = src.read_slice(length_and_mask as usize);
147
148 check_masks_alignment!(and_mask, xor_mask, height, false)?;
149
150 Ok(Self {
151 cache_index,
152 hot_spot,
153 width,
154 height,
155 xor_mask,
156 and_mask,
157 })
158 }
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub struct PointerAttribute<'a> {
164 pub xor_bpp: u16,
165 pub color_pointer: ColorPointerAttribute<'a>,
166}
167
168impl PointerAttribute<'_> {
169 const NAME: &'static str = "TS_POINTERATTRIBUTE";
170 const FIXED_PART_SIZE: usize = 2 ;
171}
172
173impl Encode for PointerAttribute<'_> {
174 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
175 ensure_size!(in: dst, size: self.size());
176
177 dst.write_u16(self.xor_bpp);
178 self.color_pointer.encode(dst)?;
179
180 Ok(())
181 }
182
183 fn name(&self) -> &'static str {
184 Self::NAME
185 }
186
187 fn size(&self) -> usize {
188 Self::FIXED_PART_SIZE + self.color_pointer.size()
189 }
190}
191
192impl<'a> Decode<'a> for PointerAttribute<'a> {
193 fn decode(src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
194 ensure_fixed_part_size!(in: src);
195
196 let xor_bpp = src.read_u16();
197 let color_pointer = ColorPointerAttribute::decode(src)?;
198
199 Ok(Self { xor_bpp, color_pointer })
200 }
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq)]
205pub struct CachedPointerAttribute {
206 pub cache_index: u16,
207}
208
209impl CachedPointerAttribute {
210 const NAME: &'static str = "TS_CACHEDPOINTERATTRIBUTE";
211 const FIXED_PART_SIZE: usize = 2 ;
212}
213
214impl Encode for CachedPointerAttribute {
215 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
216 ensure_size!(in: dst, size: self.size());
217
218 dst.write_u16(self.cache_index);
219
220 Ok(())
221 }
222
223 fn name(&self) -> &'static str {
224 Self::NAME
225 }
226
227 fn size(&self) -> usize {
228 Self::FIXED_PART_SIZE
229 }
230}
231
232impl Decode<'_> for CachedPointerAttribute {
233 fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> {
234 ensure_fixed_part_size!(in: src);
235
236 let cache_index = src.read_u16();
237
238 Ok(Self { cache_index })
239 }
240}
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq)]
244pub struct LargePointerAttribute<'a> {
245 pub xor_bpp: u16,
246 pub cache_index: u16,
247 pub hot_spot: Point16,
248 pub width: u16,
249 pub height: u16,
250 pub xor_mask: &'a [u8],
251 pub and_mask: &'a [u8],
252}
253
254impl LargePointerAttribute<'_> {
255 const NAME: &'static str = "TS_FP_LARGEPOINTERATTRIBUTE";
256 const FIXED_PART_SIZE: usize =
257 2 + 2 + 4 + 2 + 2 +
258 4 + 4 ;
259}
260
261impl Encode for LargePointerAttribute<'_> {
262 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
263 ensure_size!(in: dst, size: self.size());
264
265 check_masks_alignment!(self.and_mask, self.xor_mask, self.height, true)?;
266
267 dst.write_u16(self.xor_bpp);
268 dst.write_u16(self.cache_index);
269 self.hot_spot.encode(dst)?;
270 dst.write_u16(self.width);
271 dst.write_u16(self.height);
272
273 dst.write_u32(self.and_mask.len() as u32);
274 dst.write_u32(self.xor_mask.len() as u32);
275 dst.write_slice(self.xor_mask);
277 dst.write_slice(self.and_mask);
278
279 Ok(())
280 }
281
282 fn name(&self) -> &'static str {
283 Self::NAME
284 }
285
286 fn size(&self) -> usize {
287 Self::FIXED_PART_SIZE + self.xor_mask.len() + self.and_mask.len()
288 }
289}
290
291impl<'a> Decode<'a> for LargePointerAttribute<'a> {
292 fn decode(src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
293 ensure_fixed_part_size!(in: src);
294
295 let xor_bpp = src.read_u16();
296 let cache_index = src.read_u16();
297 let hot_spot = Point16::decode(src)?;
298 let width = src.read_u16();
299 let height = src.read_u16();
300 let length_and_mask = src.read_u32() as usize;
302 let length_xor_mask = src.read_u32() as usize;
303
304 let expected_masks_size = length_and_mask + length_xor_mask;
305 ensure_size!(in: src, size: expected_masks_size);
306
307 let xor_mask = src.read_slice(length_xor_mask);
308 let and_mask = src.read_slice(length_and_mask);
309
310 check_masks_alignment!(and_mask, xor_mask, height, true)?;
311
312 Ok(Self {
313 xor_bpp,
314 cache_index,
315 hot_spot,
316 width,
317 height,
318 xor_mask,
319 and_mask,
320 })
321 }
322}
323
324#[derive(Debug, Clone, Copy, PartialEq, Eq)]
326pub enum PointerUpdateData<'a> {
327 SetHidden,
328 SetDefault,
329 SetPosition(PointerPositionAttribute),
330 Color(ColorPointerAttribute<'a>),
331 Cached(CachedPointerAttribute),
332 New(PointerAttribute<'a>),
333 Large(LargePointerAttribute<'a>),
334}