Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions crates/ironrdp-graphics/src/rlgr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<
clippy::as_conversions,
reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop"
)]
#![expect(clippy::missing_panics_doc, reason = "unreachable panics (prior checks)")]

if input.is_empty() {
return Err(RlgrError::EmptyTile);
Expand All @@ -83,15 +84,23 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<
while input.peek().is_some() {
match CompressionMode::from(k) {
CompressionMode::RunLength => {
let mut nz = 0;
while let Some(&&x) = input.peek() {
if x == 0 {
nz += 1;
input.next();
} else {
// Read the first value (guaranteed Some by the while condition).
// This mirrors FreeRDP's GetNextInput before the zero-counting loop.
let mut val = *input
.next()
.expect("value is guaranteed to be `Some` due to the prior check");
let mut nz: u32 = 0;

// Count zeros: while current value is zero and more data exists,
// count it as a run zero and read the next value.
while val == 0 {
if input.peek().is_none() {
break;
}
nz += 1;
val = *input.next().expect("peek confirmed Some");
}

let mut runmax: u32 = 1 << k;
while nz >= runmax {
bits.output_bit(1, false);
Expand All @@ -103,16 +112,16 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<
bits.output_bit(1, true);
bits.output_bits(k as usize, nz);

if let Some(val) = input.next() {
let mag = u32::from(val.unsigned_abs());
bits.output_bit(1, *val < 0);
code_gr(&mut bits, &mut krp, mag - 1);
}
// Always encode the value after the run (even if it's 0 due
// to exhausted input). This matches the reference encoder.
let mag = u32::from(val.unsigned_abs());
bits.output_bit(1, val < 0);
code_gr(&mut bits, &mut krp, if mag > 0 { mag - 1 } else { 0 });

kp = kp.saturating_sub(DN_GR);
k = kp >> LS_GR;
}
CompressionMode::GolombRice => {
#[expect(clippy::missing_panics_doc, reason = "unreachable panic (prior check)")]
let input_first = *input
.next()
.expect("value is guaranteed to be `Some` due to the prior check");
Expand All @@ -122,15 +131,15 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<
let two_ms = get_2magsign(input_first);
code_gr(&mut bits, &mut krp, two_ms);
if two_ms == 0 {
kp = min(kp + UP_GR, KP_MAX);
kp = min(kp + UQ_GR, KP_MAX);
} else {
kp = kp.saturating_sub(DQ_GR);
}
k = kp >> LS_GR;
}
EntropyAlgorithm::Rlgr3 => {
let two_ms1 = get_2magsign(input_first);
let two_ms2 = input.next().map(|&n| get_2magsign(n)).unwrap_or(1);
let two_ms2 = input.next().map(|&n| get_2magsign(n)).unwrap_or(0);
let sum2ms = two_ms1 + two_ms2;
code_gr(&mut bits, &mut krp, sum2ms);

Expand Down
2 changes: 1 addition & 1 deletion crates/ironrdp-testsuite-core/tests/graphics/rlgr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ const Y_DATA_ENCODED: [u8; 942] = [
0x42, 0x02, 0xd9, 0x37, 0x11, 0xde, 0x2d, 0xd4, 0x3f, 0xfe, 0x61, 0xe7, 0x33, 0xd7, 0x89, 0x4a, 0xdd, 0xb0, 0x34,
0x47, 0xf4, 0xdc, 0xad, 0xaa, 0xc9, 0x9d, 0x7e, 0x6d, 0x4b, 0xcc, 0xdc, 0x17, 0x89, 0x57, 0xfd, 0xbb, 0x37, 0x75,
0x47, 0x5a, 0xec, 0x2c, 0x6e, 0x3c, 0x15, 0x92, 0x54, 0x64, 0x2c, 0xab, 0x9e, 0xab, 0x2b, 0xdd, 0x3c, 0x66, 0xa0,
0x8f, 0x47, 0x5e, 0x93, 0x1a, 0x37, 0x16, 0xf4, 0x89, 0x23, 0x00,
0x8f, 0x47, 0x5e, 0x93, 0x1a, 0x37, 0x16, 0xf4, 0x88, 0xe3, 0x00,
];

const CB_DATA_ENCODED: [u8; 975] = [
Expand Down
Loading