ironrdp_pdu/basic_output/bitmap/
mod.rs

1#[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/// 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        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/// TS_BITMAP_DATA
87#[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 /* width */ + 2 /* height */ + 2 /* bpp */ + 2 /* flags */ + 2 /* len */;
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        // A 16-bit, unsigned integer. The size in bytes of the data in the bitmapComprHdr
148        // and bitmapDataStream fields.
149        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            // Check if encoded_bitmap_data_length is at least CompressedDataHeader::ENCODED_SIZE
157            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/// TS_CD_HEADER
199#[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 /* row_size */ + 2 /* body_size */ + 2 /* scan_width */ + 2 /* uncompressed_size */;
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}