ironrdp_pdu/basic_output/bitmap/
mod.rs1#[cfg(test)]
2mod tests;
3
4pub mod rdp6;
5
6use core::fmt::{self, Debug};
7
8use bitflags::bitflags;
9use ironrdp_core::{
10 cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult,
11 ReadCursor, WriteCursor,
12};
13
14use crate::geometry::InclusiveRectangle;
15
16const FIRST_ROW_SIZE_VALUE: u16 = 0;
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct BitmapUpdateData<'a> {
21 pub rectangles: Vec<BitmapData<'a>>,
22}
23
24impl BitmapUpdateData<'_> {
25 const NAME: &'static str = "TS_UPDATE_BITMAP_DATA";
26 const FIXED_PART_SIZE: usize = 2 + 2 ;
27}
28
29impl BitmapUpdateData<'_> {
30 pub fn encode_header(rectangles: u16, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
31 ensure_size!(in: dst, size: 2);
32
33 dst.write_u16(BitmapFlags::BITMAP_UPDATE_TYPE.bits());
34 dst.write_u16(rectangles);
35
36 Ok(())
37 }
38}
39
40impl Encode for BitmapUpdateData<'_> {
41 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
42 ensure_size!(in: dst, size: self.size());
43
44 let rectangle_count = cast_length!("number of rectangles", self.rectangles.len())?;
45
46 Self::encode_header(rectangle_count, dst)?;
47
48 for bitmap_data in self.rectangles.iter() {
49 bitmap_data.encode(dst)?;
50 }
51
52 Ok(())
53 }
54
55 fn name(&self) -> &'static str {
56 Self::NAME
57 }
58
59 fn size(&self) -> usize {
60 self.rectangles
61 .iter()
62 .fold(Self::FIXED_PART_SIZE, |size, new| size + new.size())
63 }
64}
65
66impl<'de> Decode<'de> for BitmapUpdateData<'de> {
67 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
68 ensure_fixed_part_size!(in: src);
69
70 let update_type = BitmapFlags::from_bits_truncate(src.read_u16());
71 if !update_type.contains(BitmapFlags::BITMAP_UPDATE_TYPE) {
72 return Err(invalid_field_err!("updateType", "invalid update type"));
73 }
74
75 let rectangle_count = usize::from(src.read_u16());
76 let mut rectangles = Vec::with_capacity(rectangle_count);
77
78 for _ in 0..rectangle_count {
79 rectangles.push(BitmapData::decode(src)?);
80 }
81
82 Ok(Self { rectangles })
83 }
84}
85
86#[derive(Clone, PartialEq, Eq)]
88pub struct BitmapData<'a> {
89 pub rectangle: InclusiveRectangle,
90 pub width: u16,
91 pub height: u16,
92 pub bits_per_pixel: u16,
93 pub compression_flags: Compression,
94 pub compressed_data_header: Option<CompressedDataHeader>,
95 pub bitmap_data: &'a [u8],
96}
97
98impl BitmapData<'_> {
99 const NAME: &'static str = "TS_BITMAP_DATA";
100 const FIXED_PART_SIZE: usize = InclusiveRectangle::ENCODED_SIZE + 2 + 2 + 2 + 2 + 2 ;
101
102 fn encoded_bitmap_data_length(&self) -> usize {
103 self.bitmap_data.len() + self.compressed_data_header.as_ref().map(|hdr| hdr.size()).unwrap_or(0)
104 }
105}
106
107impl Encode for BitmapData<'_> {
108 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
109 ensure_size!(in: dst, size: self.size());
110
111 let encoded_bitmap_data_length = self.encoded_bitmap_data_length();
112 let encoded_bitmap_data_length = cast_length!("bitmap data length", encoded_bitmap_data_length)?;
113
114 self.rectangle.encode(dst)?;
115 dst.write_u16(self.width);
116 dst.write_u16(self.height);
117 dst.write_u16(self.bits_per_pixel);
118 dst.write_u16(self.compression_flags.bits());
119 dst.write_u16(encoded_bitmap_data_length);
120 if let Some(compressed_data_header) = &self.compressed_data_header {
121 compressed_data_header.encode(dst)?;
122 };
123 dst.write_slice(self.bitmap_data);
124
125 Ok(())
126 }
127
128 fn name(&self) -> &'static str {
129 Self::NAME
130 }
131
132 fn size(&self) -> usize {
133 Self::FIXED_PART_SIZE + self.encoded_bitmap_data_length()
134 }
135}
136
137impl<'de> Decode<'de> for BitmapData<'de> {
138 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
139 ensure_fixed_part_size!(in: src);
140
141 let rectangle = InclusiveRectangle::decode(src)?;
142 let width = src.read_u16();
143 let height = src.read_u16();
144 let bits_per_pixel = src.read_u16();
145 let compression_flags = Compression::from_bits_truncate(src.read_u16());
146
147 let encoded_bitmap_data_length = usize::from(src.read_u16());
150
151 ensure_size!(in: src, size: encoded_bitmap_data_length);
152
153 let (compressed_data_header, buffer_length) = if compression_flags.contains(Compression::BITMAP_COMPRESSION)
154 && !compression_flags.contains(Compression::NO_BITMAP_COMPRESSION_HDR)
155 {
156 if encoded_bitmap_data_length < CompressedDataHeader::ENCODED_SIZE {
158 return Err(invalid_field_err!(
159 "cbCompEncodedBitmapDataLength",
160 "length is less than CompressedDataHeader::ENCODED_SIZE"
161 ));
162 }
163
164 let buffer_length = encoded_bitmap_data_length - CompressedDataHeader::ENCODED_SIZE;
165 (Some(CompressedDataHeader::decode(src)?), buffer_length)
166 } else {
167 (None, encoded_bitmap_data_length)
168 };
169
170 let bitmap_data = src.read_slice(buffer_length);
171
172 Ok(BitmapData {
173 rectangle,
174 width,
175 height,
176 bits_per_pixel,
177 compression_flags,
178 compressed_data_header,
179 bitmap_data,
180 })
181 }
182}
183
184impl Debug for BitmapData<'_> {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 f.debug_struct("BitmapData")
187 .field("rectangle", &self.rectangle)
188 .field("width", &self.width)
189 .field("height", &self.height)
190 .field("bits_per_pixel", &self.bits_per_pixel)
191 .field("compression_flags", &self.compression_flags)
192 .field("compressed_data_header", &self.compressed_data_header)
193 .field("bitmap_data.len()", &self.bitmap_data.len())
194 .finish()
195 }
196}
197
198#[derive(Debug, Clone, PartialEq, Eq)]
200pub struct CompressedDataHeader {
201 pub main_body_size: u16,
202 pub scan_width: u16,
203 pub uncompressed_size: u16,
204}
205
206impl CompressedDataHeader {
207 const NAME: &'static str = "TS_CD_HEADER";
208 const FIXED_PART_SIZE: usize = 2 + 2 + 2 + 2 ;
209
210 pub const ENCODED_SIZE: usize = Self::FIXED_PART_SIZE;
211}
212
213impl<'de> Decode<'de> for CompressedDataHeader {
214 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
215 ensure_fixed_part_size!(in: src);
216
217 let size = src.read_u16();
218 if size != FIRST_ROW_SIZE_VALUE {
219 return Err(invalid_field_err!("cbCompFirstRowSize", "invalid first row size"));
220 }
221
222 let main_body_size = src.read_u16();
223 let scan_width = src.read_u16();
224
225 if scan_width % 4 != 0 {
226 return Err(invalid_field_err!(
227 "cbScanWidth",
228 "The width of the bitmap must be divisible by 4"
229 ));
230 }
231 let uncompressed_size = src.read_u16();
232
233 Ok(Self {
234 main_body_size,
235 scan_width,
236 uncompressed_size,
237 })
238 }
239}
240
241impl Encode for CompressedDataHeader {
242 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
243 ensure_fixed_part_size!(in: dst);
244
245 if self.scan_width % 4 != 0 {
246 return Err(invalid_field_err!(
247 "cbScanWidth",
248 "The width of the bitmap must be divisible by 4"
249 ));
250 }
251 dst.write_u16(FIRST_ROW_SIZE_VALUE);
252 dst.write_u16(self.main_body_size);
253 dst.write_u16(self.scan_width);
254 dst.write_u16(self.uncompressed_size);
255
256 Ok(())
257 }
258
259 fn name(&self) -> &'static str {
260 Self::NAME
261 }
262
263 fn size(&self) -> usize {
264 Self::FIXED_PART_SIZE
265 }
266}
267
268bitflags! {
269 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
270 pub struct BitmapFlags: u16{
271 const BITMAP_UPDATE_TYPE = 0x0001;
272 }
273}
274
275bitflags! {
276 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
277 pub struct Compression: u16 {
278 const BITMAP_COMPRESSION = 0x0001;
279 const NO_BITMAP_COMPRESSION_HDR = 0x0400;
280 }
281}