1use core::cmp;
2use std::io::{Read as _, Write as _};
3
4use byteorder::ReadBytesExt as _;
5use ironrdp_core::WriteCursor;
6
7const MAX_DECODED_SEGMENT_SIZE: usize = 47;
10
11#[derive(Debug)]
12pub enum RleDecodeError {
13 ReadCompressedData(std::io::Error),
14 WriteDecompressedData(std::io::Error),
15 InvalidSegmentHeader,
16 SegmentDoNotFitScanline,
17}
18
19impl core::fmt::Display for RleDecodeError {
20 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
21 match self {
22 RleDecodeError::ReadCompressedData(_error) => write!(f, "failed to read RLE-compressed data"),
23 RleDecodeError::WriteDecompressedData(_error) => write!(f, "failed to write decompressed data"),
24 RleDecodeError::InvalidSegmentHeader => write!(f, "invalid RLE segment header"),
25 RleDecodeError::SegmentDoNotFitScanline => {
26 write!(f, "decoded scanline segments length exceeds scanline length")
27 }
28 }
29 }
30}
31
32impl core::error::Error for RleDecodeError {
33 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
34 match self {
35 RleDecodeError::ReadCompressedData(error) => Some(error),
36 RleDecodeError::WriteDecompressedData(error) => Some(error),
37 RleDecodeError::InvalidSegmentHeader => None,
38 RleDecodeError::SegmentDoNotFitScanline => None,
39 }
40 }
41}
42
43#[derive(Debug)]
44pub enum RleEncodeError {
45 NotEnoughBytes,
46 BufferTooSmall,
47}
48
49impl core::fmt::Display for RleEncodeError {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 match self {
52 RleEncodeError::NotEnoughBytes => write!(f, "not enough data to compress"),
53 RleEncodeError::BufferTooSmall => write!(f, "destination buffer is too small"),
54 }
55 }
56}
57
58impl core::error::Error for RleEncodeError {}
59
60#[derive(Debug)]
62struct RlePlaneDecoder {
63 last_decoded_byte: u8,
66
67 width: usize,
68 height: usize,
69
70 decoded_data: [u8; MAX_DECODED_SEGMENT_SIZE],
71 decoded_data_len: usize,
72}
73
74impl RlePlaneDecoder {
75 fn new(width: usize, height: usize) -> Self {
76 Self {
77 last_decoded_byte: 0,
78 width,
79 height,
80 decoded_data: [0; MAX_DECODED_SEGMENT_SIZE],
81 decoded_data_len: 0,
82 }
83 }
84
85 fn decompress_next_segment(&mut self, mut src: &[u8]) -> Result<usize, RleDecodeError> {
86 let control_byte = src.read_u8().map_err(RleDecodeError::ReadCompressedData)?;
87
88 if control_byte == 0 {
89 return Err(RleDecodeError::InvalidSegmentHeader);
90 }
91
92 let rle_bytes_field = control_byte & 0x0F;
93 let raw_bytes_field = (control_byte >> 4) & 0x0F;
94
95 let (run_length, raw_bytes_count) = match rle_bytes_field {
96 1 => (16 + usize::from(raw_bytes_field), 0),
97 2 => (32 + usize::from(raw_bytes_field), 0),
98 rle_control => (usize::from(rle_control), usize::from(raw_bytes_field)),
99 };
100
101 self.decoded_data_len = raw_bytes_count + run_length;
102
103 src.read_exact(&mut self.decoded_data[..raw_bytes_count])
104 .map_err(RleDecodeError::ReadCompressedData)?;
105
106 if raw_bytes_count > 0 {
107 self.last_decoded_byte = self.decoded_data[raw_bytes_count - 1];
109 }
110
111 self.decoded_data[raw_bytes_count..self.decoded_data_len].fill(self.last_decoded_byte);
112
113 Ok(raw_bytes_count + 1)
114 }
115
116 fn decode_scanline(&mut self, src: &[u8], mut dst: &mut [u8]) -> Result<usize, RleDecodeError> {
118 let mut decoded_columns = 0;
119 let mut read_bytes = 0;
120
121 self.last_decoded_byte = 0;
122
123 while decoded_columns < self.width {
124 read_bytes += self.decompress_next_segment(&src[read_bytes..])?;
125
126 if decoded_columns + self.decoded_data_len > self.width {
127 return Err(RleDecodeError::SegmentDoNotFitScanline);
128 }
129
130 dst.write_all(&self.decoded_data[..self.decoded_data_len])
131 .map_err(RleDecodeError::WriteDecompressedData)?;
132
133 decoded_columns += self.decoded_data_len;
134 }
135
136 Ok(read_bytes)
137 }
138
139 fn resolve_scanline_delta(prev_line: &[u8], current_scanline: &mut [u8]) {
141 assert!(prev_line.len() == current_scanline.len());
142
143 current_scanline
144 .iter_mut()
145 .zip(prev_line.iter())
146 .for_each(|(dst, src)| {
147 let delta = *dst;
148 let value_above = *src;
149
150 let transformed_delta = if delta % 2 == 1 {
151 255u8.wrapping_sub((delta.wrapping_sub(1)) >> 1)
152 } else {
153 delta >> 1
154 };
155
156 *dst = value_above.wrapping_add(transformed_delta);
157 });
158 }
159
160 fn decode(mut self, src: &[u8], dst: &mut [u8]) -> Result<usize, RleDecodeError> {
161 let mut read_bytes = 0;
162
163 read_bytes += self.decode_scanline(src, dst)?;
164
165 let (mut prev_scanline, mut dst) = dst.split_at_mut(self.width);
166
167 for _ in 1..self.height {
168 let current_scanline = &mut dst[..self.width];
169
170 read_bytes += self.decode_scanline(&src[read_bytes..], current_scanline)?;
171 Self::resolve_scanline_delta(prev_scanline, current_scanline);
172
173 (prev_scanline, dst) = dst.split_at_mut(self.width);
174 }
175
176 Ok(read_bytes)
177 }
178}
179
180pub(crate) fn decompress_8bpp_plane(
186 src: &[u8],
187 dst: &mut [u8],
188 width: usize,
189 height: usize,
190) -> Result<usize, RleDecodeError> {
191 RlePlaneDecoder::new(width, height).decode(src, dst)
192}
193
194struct RleEncoderScanlineIterator<I> {
195 inner: core::iter::Enumerate<I>,
196 width: usize,
197 prev_scanline: Vec<u8>,
198}
199
200impl<I: Iterator> RleEncoderScanlineIterator<I> {
201 fn new(width: usize, inner: I) -> Self {
202 Self {
203 width,
204 inner: inner.enumerate(),
205 prev_scanline: vec![0; width],
206 }
207 }
208
209 fn delta_value(prev: u8, next: u8) -> u8 {
210 let mut result = u8::try_from((i16::from(next) - i16::from(prev)) & 0xFF)
211 .expect("masking with 0xFF ensures that the value fits into u8");
212
213 if result < 128 {
215 result <<= 1;
216 } else {
217 result = (255u8.wrapping_sub(result) << 1).wrapping_add(1);
218 }
219
220 result
221 }
222}
223
224impl<I: Iterator<Item = u8>> Iterator for RleEncoderScanlineIterator<I> {
225 type Item = I::Item;
226
227 fn next(&mut self) -> Option<Self::Item> {
228 let (idx, mut next) = self.inner.next()?;
229
230 let prev = core::mem::replace(&mut self.prev_scanline[idx % self.width], next);
231 if idx >= self.width {
232 next = Self::delta_value(prev, next);
233 }
234
235 Some(next)
236 }
237
238 fn size_hint(&self) -> (usize, Option<usize>) {
239 self.inner.size_hint()
240 }
241}
242
243#[derive(Debug)]
244struct RlePlaneEncoder {
245 width: usize,
246 height: usize,
247}
248
249macro_rules! ensure_size {
250 (dst: $buf:ident, size: $expected:expr) => {{
251 let available = $buf.len();
252 let needed = $expected;
253 if !(needed <= available) {
254 return Err(RleEncodeError::BufferTooSmall);
255 }
256 }};
257}
258
259impl RlePlaneEncoder {
260 fn new(width: usize, height: usize) -> Self {
261 Self { width, height }
262 }
263
264 fn encode(&self, mut src: impl Iterator<Item = u8>, dst: &mut WriteCursor<'_>) -> Result<usize, RleEncodeError> {
265 let mut written = 0;
266
267 for _ in 0..self.height {
268 written += self.encode_scanline((&mut src).take(self.width), dst)?;
269 }
270
271 Ok(written)
272 }
273
274 fn encode_scanline(
275 &self,
276 mut src: impl Iterator<Item = u8>,
277 dst: &mut WriteCursor<'_>,
278 ) -> Result<usize, RleEncodeError> {
279 let mut written = 0;
280 let first = src.next().ok_or(RleEncodeError::NotEnoughBytes)?;
281
282 let mut raw = vec![first];
283 let mut seq = (first, 0);
284
285 for byte in src {
286 let (last, count) = seq;
287
288 seq = if byte == last {
289 (byte, count + 1)
290 } else {
291 match count {
292 3.. => {
293 written += self.encode_segment(&raw, count, dst)?;
294 raw.clear();
295 }
296 2 => raw.extend_from_slice(&[last, last]),
297 1 => raw.push(last),
298 _ => {}
299 }
300
301 raw.push(byte);
302
303 (byte, 0)
304 }
305 }
306
307 let (last, mut count) = seq;
308 if count < 3 {
309 raw.extend(vec![last; count]);
310 count = 0;
311 }
312
313 written += self.encode_segment(&raw, count, dst)?;
314
315 Ok(written)
316 }
317
318 fn encode_segment(&self, mut raw: &[u8], run: usize, dst: &mut WriteCursor<'_>) -> Result<usize, RleEncodeError> {
319 if raw.is_empty() {
320 return Err(RleEncodeError::NotEnoughBytes);
321 }
322
323 let mut extra_bytes = 0;
324
325 while raw.len() > 15 {
326 extra_bytes += self.encode_segment(&raw[0..15], 0, dst)?;
327 raw = &raw[15..];
328 }
329
330 let raw_len = u8::try_from(raw.len()).expect("max value is guaranteed to be 15 due to the prior while loop");
331 let run_capped = u8::try_from(cmp::min(run, 15)).expect("max value is guaranteed to be 15");
332
333 let control = (raw_len << 4) + run_capped;
334
335 ensure_size!(dst: dst, size: raw.len() + 1);
336
337 dst.write_u8(control);
338 dst.write_slice(raw);
339
340 if run > 15 {
341 let last = raw.last().expect("buffer cannot be empty");
342 extra_bytes += self.encode_long_sequence(run - 15, *last, dst)?;
343 }
344
345 Ok(1 + raw.len() + extra_bytes)
346 }
347
348 fn encode_long_sequence(
349 &self,
350 mut run: usize,
351 last: u8,
352 dst: &mut WriteCursor<'_>,
353 ) -> Result<usize, RleEncodeError> {
354 let mut written = 0;
355
356 while run >= 16 {
357 ensure_size!(dst: dst, size: 1);
358
359 let current = u8::try_from(cmp::min(run, MAX_DECODED_SEGMENT_SIZE))
360 .expect("max value is guaranteed to be MAX_DECODED_SEGMENT_SIZE (47)");
361
362 let c_raw_bytes = cmp::min(current / 16, 2);
363 let n_run_length = current - c_raw_bytes * 16;
364
365 let control = (n_run_length << 4) + c_raw_bytes;
366 dst.write_u8(control);
367 written += 1;
368
369 run -= usize::from(current);
370 }
371
372 if run > 0 {
373 match run {
374 short @ 1..=3 => {
375 written += self.encode_segment(&vec![last; short], 0, dst)?;
376 }
377 long => {
378 written += self.encode_segment(&[last], long - 1, dst)?;
379 }
380 }
381 }
382
383 Ok(written)
384 }
385}
386
387pub(crate) fn compress_8bpp_plane(
393 src: impl Iterator<Item = u8>,
394 dst: &mut WriteCursor<'_>,
395 width: usize,
396 height: usize,
397) -> Result<usize, RleEncodeError> {
398 let iter = RleEncoderScanlineIterator::new(width, src);
399 RlePlaneEncoder::new(width, height).encode(iter, dst)
400}
401
402#[cfg(test)]
403#[expect(
404 clippy::needless_raw_strings,
405 reason = "the lint is disable to not interfere with expect! macro"
406)]
407mod tests {
408 use expect_test::expect;
409
410 use super::*;
411
412 fn decompress(src: &[u8], dst: &mut Vec<u8>, width: usize, height: usize) -> Result<usize, RleDecodeError> {
414 dst.resize(width * height, 0);
416
417 decompress_8bpp_plane(src, dst.as_mut_slice(), width, height)
418 }
419
420 fn compress(src: &[u8], dst: &mut [u8], width: usize, height: usize) -> Result<usize, RleEncodeError> {
421 compress_8bpp_plane(src.iter().copied(), &mut WriteCursor::new(dst), width, height)
422 }
423
424 #[test]
425 fn simple_encode() {
426 let src = [65, 65, 65, 65, 66, 66, 67, 67, 67, 67, 67, 68];
428
429 let width = src.len();
430 let height = 1usize;
431
432 let expected = &[0x13, 65, 0x34, 66, 66, 67, 0x10, 68];
433
434 let mut compressed = vec![0; 255];
435 let len = compress(&src, &mut compressed, width, height).unwrap();
436
437 assert_eq!(&compressed[..len], expected);
438 }
439
440 #[test]
441 fn long_sequence_encode() {
442 let src = [0x41u8; 100];
444
445 let width = 100usize;
446 let height = 1usize;
447
448 let expected = &[0x1F, 0x41, 0xF2, 0x52];
449
450 let mut compressed = vec![0; 255];
451 let len = compress(&src, &mut compressed, width, height).unwrap();
452
453 assert_eq!(&compressed[..len], expected);
454 }
455
456 #[test]
457 fn multiline_encode() {
458 let src = [
460 255, 255, 255, 255, 254, 253, 254, 192, 132, 96, 75, 25, 253, 140, 62, 14, 135, 193,
461 ];
462
463 let width = 6usize;
464 let height = 3usize;
465
466 let expected = &[
467 0x13, 0xFF, 0x20, 0xFE, 0xFD, 0x60, 0x01, 0x7D, 0xF5, 0xC2, 0x9A, 0x38, 0x60, 0x01, 0x67, 0x8B, 0xA3, 0x78,
468 0xAF,
469 ];
470
471 let mut compressed = vec![0; 255];
472 let len = compress(&src, &mut compressed, width, height).unwrap();
473
474 assert_eq!(&compressed[..len], expected);
475 }
476
477 #[test]
478 fn long_sequence_decode() {
479 let src = [0x1F, 0x41, 0xF2, 0x52];
481
482 let width = 100usize;
483 let height = 1usize;
484
485 let expected = &[0x41u8; 100];
486
487 let mut actual = Vec::new();
488 decompress(&src, &mut actual, width, height).unwrap();
489 assert_eq!(actual, expected);
490 }
491
492 #[test]
493 fn multiline_decode() {
494 let src = [
496 0x13, 0xFF, 0x20, 0xFE, 0xFD, 0x60, 0x01, 0x7D, 0xF5, 0xC2, 0x9A, 0x38, 0x60, 0x01, 0x67, 0x8B, 0xA3, 0x78,
497 0xAF,
498 ];
499
500 let width = 6usize;
501 let height = 3usize;
502
503 let expected = &[
504 255, 255, 255, 255, 254, 253, 254, 192, 132, 96, 75, 25, 253, 140, 62, 14, 135, 193,
505 ];
506
507 let mut actual = Vec::new();
508 decompress(&src, &mut actual, width, height).unwrap();
509 assert_eq!(actual, expected);
510 }
511
512 #[test]
513 fn long_sequence_encode_decode() {
514 let src = [0x41u8; 100];
516
517 let width = 100usize;
518 let height = 1usize;
519
520 let mut compressed = vec![0; 255];
521 let len = compress(&src, &mut compressed, width, height).unwrap();
522
523 let mut actual = Vec::new();
524 decompress(&compressed[..len], &mut actual, width, height).unwrap();
525
526 assert_eq!(actual.as_slice(), src.as_slice());
527 }
528
529 #[test]
530 fn complex_encode_decode() {
531 let src = [
532 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 19, 19, 18, 18, 18,
533 18, 18, 18, 18, 18,
534 ];
535
536 let width = src.len();
537 let height = 1usize;
538
539 let mut compressed = vec![0; 255];
540 let len = compress(&src, &mut compressed, width, height).unwrap();
541
542 let mut actual = Vec::new();
543 decompress(&compressed[..len], &mut actual, width, height).unwrap();
544
545 assert_eq!(actual.as_slice(), src.as_slice());
546 }
547
548 #[test]
549 fn multiline_encode_decode() {
550 let src = [
552 255, 255, 255, 255, 254, 253, 254, 192, 132, 96, 75, 25, 253, 140, 62, 14, 135, 193,
553 ];
554
555 let width = 6usize;
556 let height = 3usize;
557
558 let mut compressed = vec![0; 255];
559 let len = compress(&src, &mut compressed, width, height).unwrap();
560
561 let mut actual = Vec::new();
562 decompress(&compressed[..len], &mut actual, width, height).unwrap();
563
564 assert_eq!(actual.as_slice(), src.as_slice());
565 }
566
567 #[test]
568 fn each_scanline_resets_last_decoded_byte() {
569 let src = [0x17, 0xFF, 0x04, 0x40, 0x01, 0x02, 0x03, 0x04];
570
571 let width = 8usize;
572 let height = 2usize;
573
574 let mut actual = Vec::new();
575
576 let expected = &[
577 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 0, 253, 1,
578 ];
579
580 decompress(&src, &mut actual, width, height).unwrap();
581 assert_eq!(actual, expected);
582 }
583
584 #[test]
585 fn segments_out_of_scanline_produce_error() {
586 let src = [
587 0x18, 0xFF, 0x04, 0x40, 0x01, 0x02, 0x03, 0x04,
589 ];
590
591 let width = 8usize;
592 let height = 2usize;
593
594 let mut actual = Vec::new();
595 expect![[r#"
596 Err(
597 SegmentDoNotFitScanline,
598 )
599 "#]]
600 .assert_debug_eq(&decompress(&src, &mut actual, width, height));
601
602 let src = [
604 0x17, 0xFF, 0x18, 0xFF, ];
606
607 let width = 8usize;
608 let height = 2usize;
609
610 let mut actual = Vec::new();
611 expect![[r#"
612 Err(
613 SegmentDoNotFitScanline,
614 )
615 "#]]
616 .assert_debug_eq(&decompress(&src, &mut actual, width, height));
617 }
618
619 #[test]
620 fn insufficient_raw_bytes_handled() {
621 let src = [0x18]; let width = 8usize;
624 let height = 2usize;
625
626 let mut actual = Vec::new();
627 expect![[r#"
628 Err(
629 ReadCompressedData(
630 Error {
631 kind: UnexpectedEof,
632 message: "failed to fill whole buffer",
633 },
634 ),
635 )
636 "#]]
637 .assert_debug_eq(&decompress(&src, &mut actual, width, height));
638 }
639
640 #[test]
641 fn empty_buffer_handled() {
642 let src = [];
643
644 let width = 8usize;
645 let height = 2usize;
646
647 let mut actual = Vec::new();
648 expect![[r#"
649 Err(
650 ReadCompressedData(
651 Error {
652 kind: UnexpectedEof,
653 message: "failed to fill whole buffer",
654 },
655 ),
656 )
657 "#]]
658 .assert_debug_eq(&decompress(&src, &mut actual, width, height));
659 }
660
661 #[test]
662 fn buffer_too_small_encode() {
663 let src = [
664 255, 255, 255, 255, 254, 253, 254, 192, 132, 96, 75, 25, 253, 140, 62, 14, 135, 193,
665 ];
666
667 let width = 6usize;
668 let height = 3usize;
669
670 let mut compressed = vec![0; 4];
671
672 expect![[r#"
673 Err(
674 BufferTooSmall,
675 )
676 "#]]
677 .assert_debug_eq(&compress(&src, &mut compressed, width, height));
678 }
679
680 #[test]
681 fn not_enough_bytes_to_encode() {
682 let src = [255, 255, 255, 255, 254, 253, 254, 192, 132, 96, 75, 25, 253];
683
684 let width = 8usize;
685 let height = 3usize;
686
687 let mut compressed = vec![0; 255];
688
689 expect![[r#"
690 Err(
691 NotEnoughBytes,
692 )
693 "#]]
694 .assert_debug_eq(&compress(&src, &mut compressed, width, height));
695 }
696
697 #[test]
698 fn too_small_dest_buffer_handled() {
699 let src = [0x17, 0xFF, 0x04, 0x40, 0x01, 0x02, 0x03, 0x04];
700
701 let width = 8usize;
702 let height = 2usize;
703
704 let mut actual = vec![0u8; 7];
705
706 expect![[r#"
707 Err(
708 WriteDecompressedData(
709 Error {
710 kind: WriteZero,
711 message: "failed to write whole buffer",
712 },
713 ),
714 )
715 "#]]
716 .assert_debug_eq(&decompress_8bpp_plane(&src, &mut actual, width, height));
717
718 }
720}