ironrdp_pdu/codecs/clearcodec/
mod.rs1mod bands;
10mod residual;
11mod rlex;
12mod subcodec;
13
14use ironrdp_core::{DecodeResult, ReadCursor, cast_length, ensure_size, invalid_field_err};
15
16pub use self::bands::{
17 Band, MAX_BAND_HEIGHT, SHORT_VBAR_CACHE_SIZE, ShortVBarCacheMiss, VBAR_CACHE_SIZE, VBar, decode_bands_layer,
18};
19pub use self::residual::{RgbRunSegment, decode_residual_layer, encode_residual_layer};
20pub use self::rlex::{MAX_PALETTE_COUNT, RlexData, RlexSegment, decode_rlex};
21pub use self::subcodec::{Subcodec, SubcodecId, decode_subcodec_layer};
22
23pub const FLAG_GLYPH_INDEX: u8 = 0x01;
27pub const FLAG_GLYPH_HIT: u8 = 0x02;
29pub const FLAG_CACHE_RESET: u8 = 0x04;
31
32#[derive(Debug, Clone)]
36pub struct ClearCodecBitmapStream<'a> {
37 pub flags: u8,
39 pub seq_number: u8,
41 pub glyph_index: Option<u16>,
43 pub composite: Option<CompositePayload<'a>>,
45}
46
47impl<'a> ClearCodecBitmapStream<'a> {
48 const NAME: &'static str = "ClearCodecBitmapStream";
49
50 pub fn decode(src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
52 ensure_size!(ctx: Self::NAME, in: src, size: 2);
53 let flags = src.read_u8();
54 let seq_number = src.read_u8();
55
56 let glyph_index = if flags & FLAG_GLYPH_INDEX != 0 {
57 ensure_size!(ctx: Self::NAME, in: src, size: 2);
58 Some(src.read_u16())
59 } else {
60 None
61 };
62
63 let composite = if flags & FLAG_GLYPH_HIT != 0 {
65 None
66 } else if src.is_empty() {
67 None
69 } else {
70 Some(CompositePayload::decode(src)?)
71 };
72
73 Ok(Self {
74 flags,
75 seq_number,
76 glyph_index,
77 composite,
78 })
79 }
80
81 pub fn has_glyph_index(&self) -> bool {
82 self.flags & FLAG_GLYPH_INDEX != 0
83 }
84
85 pub fn is_glyph_hit(&self) -> bool {
86 self.flags & FLAG_GLYPH_HIT != 0
87 }
88
89 pub fn is_cache_reset(&self) -> bool {
90 self.flags & FLAG_CACHE_RESET != 0
91 }
92}
93
94#[derive(Debug, Clone)]
101pub struct CompositePayload<'a> {
102 pub residual_data: &'a [u8],
104 pub bands_data: &'a [u8],
106 pub subcodec_data: &'a [u8],
108}
109
110impl<'a> CompositePayload<'a> {
111 const NAME: &'static str = "CompositePayload";
112
113 const HEADER_SIZE: usize = 12;
115
116 pub fn decode(src: &mut ReadCursor<'a>) -> DecodeResult<Self> {
117 ensure_size!(ctx: Self::NAME, in: src, size: Self::HEADER_SIZE);
118
119 let residual_byte_count: usize = cast_length!("residualByteCount", src.read_u32())?;
120 let bands_byte_count: usize = cast_length!("bandsByteCount", src.read_u32())?;
121 let subcodec_byte_count: usize = cast_length!("subcodecByteCount", src.read_u32())?;
122
123 let total = residual_byte_count
124 .checked_add(bands_byte_count)
125 .and_then(|s| s.checked_add(subcodec_byte_count))
126 .ok_or_else(|| invalid_field_err!("byteCount", "layer byte counts overflow"))?;
127
128 ensure_size!(ctx: Self::NAME, in: src, size: total);
129
130 let residual_data = src.read_slice(residual_byte_count);
131 let bands_data = src.read_slice(bands_byte_count);
132 let subcodec_data = src.read_slice(subcodec_byte_count);
133
134 Ok(Self {
135 residual_data,
136 bands_data,
137 subcodec_data,
138 })
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn decode_glyph_hit() {
148 let data = [0x03, 0x05, 0x42, 0x00];
150 let mut cursor = ReadCursor::new(&data);
151 let stream = ClearCodecBitmapStream::decode(&mut cursor).unwrap();
152 assert!(stream.has_glyph_index());
153 assert!(stream.is_glyph_hit());
154 assert!(!stream.is_cache_reset());
155 assert_eq!(stream.seq_number, 5);
156 assert_eq!(stream.glyph_index, Some(0x0042));
157 assert!(stream.composite.is_none());
158 }
159
160 #[test]
161 fn decode_cache_reset_only() {
162 let data = [0x04, 0x00];
164 let mut cursor = ReadCursor::new(&data);
165 let stream = ClearCodecBitmapStream::decode(&mut cursor).unwrap();
166 assert!(stream.is_cache_reset());
167 assert!(!stream.has_glyph_index());
168 assert!(stream.composite.is_none());
169 }
170
171 #[test]
172 fn decode_composite_payload_empty_layers() {
173 let data = [
175 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
180 let mut cursor = ReadCursor::new(&data);
181 let stream = ClearCodecBitmapStream::decode(&mut cursor).unwrap();
182 let composite = stream.composite.unwrap();
183 assert!(composite.residual_data.is_empty());
184 assert!(composite.bands_data.is_empty());
185 assert!(composite.subcodec_data.is_empty());
186 }
187
188 #[test]
189 fn decode_composite_with_residual_data() {
190 let data = [
192 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, ];
198 let mut cursor = ReadCursor::new(&data);
199 let stream = ClearCodecBitmapStream::decode(&mut cursor).unwrap();
200 let composite = stream.composite.unwrap();
201 assert_eq!(composite.residual_data, &[0xFF, 0x00, 0x00, 0x01]);
202 }
203}