ironrdp_pdu/basic_output/
bitmap.rs

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