mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-12-23 12:26:46 +00:00
refactor: add as_conversions clippy correctness lint (#1021)
Some checks failed
CI / Check formatting (push) Has been cancelled
CI / Check typos (push) Has been cancelled
Coverage / Coverage Report (push) Has been cancelled
Release crates / Open release PR (push) Has been cancelled
Release crates / Release crates (push) Has been cancelled
CI / Checks [linux] (push) Has been cancelled
CI / Checks [macos] (push) Has been cancelled
CI / Checks [windows] (push) Has been cancelled
CI / Fuzzing (push) Has been cancelled
CI / Web Client (push) Has been cancelled
CI / FFI (push) Has been cancelled
CI / Success (push) Has been cancelled
Some checks failed
CI / Check formatting (push) Has been cancelled
CI / Check typos (push) Has been cancelled
Coverage / Coverage Report (push) Has been cancelled
Release crates / Open release PR (push) Has been cancelled
Release crates / Release crates (push) Has been cancelled
CI / Checks [linux] (push) Has been cancelled
CI / Checks [macos] (push) Has been cancelled
CI / Checks [windows] (push) Has been cancelled
CI / Fuzzing (push) Has been cancelled
CI / Web Client (push) Has been cancelled
CI / FFI (push) Has been cancelled
CI / Success (push) Has been cancelled
Co-authored-by: Benoît CORTIER <git.divisible626@passmail.com>
This commit is contained in:
parent
d3e0cb17e1
commit
9622619e8c
52 changed files with 526 additions and 264 deletions
|
|
@ -92,7 +92,7 @@ fn_to_numeric_cast_any = "warn"
|
|||
ptr_cast_constness = "warn"
|
||||
|
||||
# == Correctness == #
|
||||
#as_conversions = "warn"
|
||||
as_conversions = "warn"
|
||||
cast_lossless = "warn"
|
||||
cast_possible_truncation = "warn"
|
||||
cast_possible_wrap = "warn"
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
let mut updates = DisplayUpdates::new(file, DesktopSize { width, height }, fps);
|
||||
while let Some(up) = updates.next_update().await? {
|
||||
if let DisplayUpdate::Bitmap(ref up) = up {
|
||||
total_raw += up.data.len() as u64;
|
||||
total_raw += u64::try_from(up.data.len())?;
|
||||
} else {
|
||||
eprintln!("Invalid update");
|
||||
break;
|
||||
|
|
@ -78,7 +78,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
let Some(frag) = iter.next().await else {
|
||||
break;
|
||||
};
|
||||
let len = frag?.data.len() as u64;
|
||||
let len = u64::try_from(frag?.data.len())?;
|
||||
total_enc += len;
|
||||
}
|
||||
n_updates += 1;
|
||||
|
|
@ -87,6 +87,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||
}
|
||||
println!();
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "casting u64 to f64")]
|
||||
let ratio = total_enc as f64 / total_raw as f64;
|
||||
let percent = 100.0 - ratio * 100.0;
|
||||
println!("Encoder: {encoder:?}");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
msrv = "1.84"
|
||||
msrv = "1.87"
|
||||
semicolon-outside-block-ignore-multiline = true
|
||||
accept-comment-above-statement = true
|
||||
accept-comment-above-attributes = true
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ impl App {
|
|||
let Some((window, _)) = self.window.as_mut() else {
|
||||
return;
|
||||
};
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to u32")]
|
||||
let scale_factor = (window.scale_factor() * 100.0) as u32;
|
||||
|
||||
let width = u16::try_from(size.width).expect("reasonable width");
|
||||
|
|
@ -222,8 +223,10 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
}
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let win_size = window.inner_size();
|
||||
let x = (position.x / win_size.width as f64 * self.buffer_size.0 as f64) as u16;
|
||||
let y = (position.y / win_size.height as f64 * self.buffer_size.1 as f64) as u16;
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to u16")]
|
||||
let x = (position.x / f64::from(win_size.width) * f64::from(self.buffer_size.0)) as u16;
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to u16")]
|
||||
let y = (position.y / f64::from(win_size.height) * f64::from(self.buffer_size.1)) as u16;
|
||||
let operation = ironrdp::input::Operation::MouseMove(ironrdp::input::MousePosition { x, y });
|
||||
|
||||
let input_events = self.input_database.apply(core::iter::once(operation));
|
||||
|
|
@ -239,6 +242,7 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
operations.push(ironrdp::input::Operation::WheelRotations(
|
||||
ironrdp::input::WheelRotations {
|
||||
is_vertical: false,
|
||||
#[expect(clippy::as_conversions, reason = "casting f32 to i16")]
|
||||
rotation_units: (delta_x * 100.) as i16,
|
||||
},
|
||||
));
|
||||
|
|
@ -248,6 +252,7 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
operations.push(ironrdp::input::Operation::WheelRotations(
|
||||
ironrdp::input::WheelRotations {
|
||||
is_vertical: true,
|
||||
#[expect(clippy::as_conversions, reason = "casting f32 to i16")]
|
||||
rotation_units: (delta_y * 100.) as i16,
|
||||
},
|
||||
));
|
||||
|
|
@ -258,6 +263,7 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
operations.push(ironrdp::input::Operation::WheelRotations(
|
||||
ironrdp::input::WheelRotations {
|
||||
is_vertical: false,
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to i16")]
|
||||
rotation_units: delta.x as i16,
|
||||
},
|
||||
));
|
||||
|
|
@ -267,6 +273,7 @@ impl ApplicationHandler<RdpOutputEvent> for App {
|
|||
operations.push(ironrdp::input::Operation::WheelRotations(
|
||||
ironrdp::input::WheelRotations {
|
||||
is_vertical: true,
|
||||
#[expect(clippy::as_conversions, reason = "casting f64 to i16")]
|
||||
rotation_units: delta.y as i16,
|
||||
},
|
||||
));
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ async fn connect(
|
|||
|
||||
let upgraded = ironrdp_tokio::mark_as_upgraded(should_upgrade, &mut connector);
|
||||
|
||||
let erased_stream = Box::new(upgraded_stream) as Box<dyn AsyncReadWrite + Unpin + Send + Sync>;
|
||||
let erased_stream: Box<dyn AsyncReadWrite + Unpin + Send + Sync> = Box::new(upgraded_stream);
|
||||
let mut upgraded_framed = ironrdp_tokio::TokioFramed::new_with_leftover(erased_stream, leftover_bytes);
|
||||
|
||||
let connection_result = ironrdp_tokio::connect_finalize(
|
||||
|
|
@ -336,7 +336,7 @@ async fn connect_ws(
|
|||
.await?;
|
||||
|
||||
let (ws, leftover_bytes) = framed.into_inner();
|
||||
let erased_stream = Box::new(ws) as Box<dyn AsyncReadWrite + Unpin + Send + Sync>;
|
||||
let erased_stream: Box<dyn AsyncReadWrite + Unpin + Send + Sync> = Box::new(ws);
|
||||
let upgraded_framed = ironrdp_tokio::TokioFramed::new_with_leftover(erased_stream, leftover_bytes);
|
||||
|
||||
Ok((connection_result, upgraded_framed))
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl<'a> ClipboardDataRef<'a> {
|
|||
};
|
||||
|
||||
// SAFETY: It is safe to call `GlobalLock` on the valid handle.
|
||||
let data = unsafe { GlobalLock(handle) } as *const u8;
|
||||
let data = unsafe { GlobalLock(handle) }.cast::<u8>().cast_const();
|
||||
|
||||
if data.is_null() {
|
||||
// Can't lock data handle, handle is not valid anymore (e.g. clipboard has changed)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use core::ptr::with_exposed_provenance_mut;
|
||||
use core::time::Duration;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::mpsc;
|
||||
|
|
@ -320,17 +321,19 @@ pub(crate) unsafe extern "system" fn clipboard_subproc(
|
|||
|
||||
// SAFETY: `data` is a valid pointer, returned by `Box::into_raw`, transferred to OS earlier
|
||||
// via `SetWindowSubclass` call.
|
||||
let _ = unsafe { Box::from_raw(data as *mut WinClipboardImpl) };
|
||||
let _ = unsafe { Box::from_raw(with_exposed_provenance_mut::<WinClipboardImpl>(data)) };
|
||||
return LRESULT(0);
|
||||
}
|
||||
|
||||
// SAFETY: `data` is a valid pointer, returned by `Box::into_raw`, transferred to OS earlier
|
||||
// via `SetWindowSubclass` call.
|
||||
let ctx = unsafe { &mut *(data as *mut WinClipboardImpl) };
|
||||
let ctx = unsafe { &mut *(with_exposed_provenance_mut::<WinClipboardImpl>(data)) };
|
||||
|
||||
match msg {
|
||||
// We need to keep track of window state to distinguish between local and remote copy
|
||||
WM_ACTIVATE | WM_ACTIVATEAPP => ctx.window_is_active = wparam.0 != WA_INACTIVE as usize, // `as` conversion is fine for constants
|
||||
WM_ACTIVATE | WM_ACTIVATEAPP => {
|
||||
ctx.window_is_active = wparam.0 != usize::try_from(WA_INACTIVE).expect("WA_INACTIVE fits into usize")
|
||||
}
|
||||
// Sent by the OS when OS clipboard content is changed
|
||||
WM_CLIPBOARDUPDATE => {
|
||||
// SAFETY: `GetClipboardOwner` is always safe to call.
|
||||
|
|
@ -347,8 +350,9 @@ pub(crate) unsafe extern "system" fn clipboard_subproc(
|
|||
}
|
||||
// Sent by the OS when delay-rendered data is requested for rendering.
|
||||
WM_RENDERFORMAT => {
|
||||
#[expect(clippy::cast_possible_truncation)] // should never truncate in practice
|
||||
ctx.handle_event(BackendEvent::RenderFormat(ClipboardFormatId::new(wparam.0 as u32)));
|
||||
ctx.handle_event(BackendEvent::RenderFormat(ClipboardFormatId::new(
|
||||
u32::try_from(wparam.0).expect("should never truncate in practice"),
|
||||
)));
|
||||
}
|
||||
// Sent by the OS when all delay-rendered data is requested for rendering.
|
||||
WM_RENDERALLFORMATS => {
|
||||
|
|
|
|||
|
|
@ -200,8 +200,14 @@ impl WinClipboard {
|
|||
//
|
||||
// SAFETY: `window` is a valid window handle, `clipboard_subproc` is in the static memory,
|
||||
// `ctx` is valid and its ownership is transferred to the subclass via `into_raw`.
|
||||
let winapi_result =
|
||||
unsafe { SetWindowSubclass(window, Some(clipboard_subproc), 0, Box::into_raw(ctx) as usize) };
|
||||
let winapi_result = unsafe {
|
||||
SetWindowSubclass(
|
||||
window,
|
||||
Some(clipboard_subproc),
|
||||
0,
|
||||
Box::into_raw(ctx).expose_provenance(),
|
||||
)
|
||||
};
|
||||
|
||||
if winapi_result == FALSE {
|
||||
return Err(WinCliprdrError::WindowSubclass);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ impl GlobalMemoryBuffer {
|
|||
// - `dst` is valid for writes of `data.len()` bytes, we allocated enough above.
|
||||
// - Both `data` and `dst` are properly aligned: u8 alignment is 1
|
||||
// - Memory regions are not overlapping, `dst` was allocated by us just above.
|
||||
unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), dst as *mut u8, data.len()) };
|
||||
unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), dst.cast::<u8>(), data.len()) };
|
||||
|
||||
// SAFETY: We called `GlobalLock` on this handle just above.
|
||||
if let Err(error) = unsafe { GlobalUnlock(handle) } {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
#![cfg_attr(doc, doc = include_str!("../README.md"))]
|
||||
#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
|
||||
#![allow(clippy::arithmetic_side_effects)] // FIXME: remove
|
||||
#![allow(clippy::cast_lossless)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_truncation)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_wrap)] // FIXME: remove
|
||||
#![allow(clippy::cast_sign_loss)] // FIXME: remove
|
||||
|
||||
pub mod backend;
|
||||
pub mod pdu;
|
||||
|
|
|
|||
|
|
@ -699,9 +699,9 @@ fn create_gcc_blocks<'a>(
|
|||
desktop_physical_width: Some(0), // 0 per FreeRDP
|
||||
desktop_physical_height: Some(0), // 0 per FreeRDP
|
||||
desktop_orientation: if config.desktop_size.width > config.desktop_size.height {
|
||||
Some(MonitorOrientation::Landscape as u16)
|
||||
Some(MonitorOrientation::Landscape.as_u16())
|
||||
} else {
|
||||
Some(MonitorOrientation::Portrait as u16)
|
||||
Some(MonitorOrientation::Portrait.as_u16())
|
||||
},
|
||||
desktop_scale_factor: Some(config.desktop_scale_factor),
|
||||
device_scale_factor: if config.desktop_scale_factor >= 100 && config.desktop_scale_factor <= 500 {
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ impl Header {
|
|||
|
||||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_fixed_part_size!(in: dst);
|
||||
dst.write_u8(((self.cmd as u8) << 4) | (Into::<u8>::into(self.sp) << 2) | Into::<u8>::into(self.cb_id));
|
||||
dst.write_u8(((self.cmd.as_u8()) << 4) | (Into::<u8>::into(self.sp) << 2) | Into::<u8>::into(self.cb_id));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -235,6 +235,16 @@ enum Cmd {
|
|||
SoftSyncResponse = 0x09,
|
||||
}
|
||||
|
||||
impl Cmd {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Cmd {
|
||||
type Error = DecodeError;
|
||||
|
||||
|
|
@ -702,7 +712,7 @@ impl CapsVersion {
|
|||
|
||||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: Self::size());
|
||||
dst.write_u16(*self as u16);
|
||||
dst.write_u16(u16::from(*self));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -725,6 +735,10 @@ impl TryFrom<u16> for CapsVersion {
|
|||
}
|
||||
|
||||
impl From<CapsVersion> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(version: CapsVersion) -> Self {
|
||||
version as u16
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,8 +114,8 @@ pub fn rdp6_decode_bitmap_stream_to_rgb24(input: &BitmapInput<'_>) {
|
|||
let _ = BitmapStreamDecoder::default().decode_bitmap_stream_to_rgb24(
|
||||
input.src,
|
||||
&mut out,
|
||||
input.width as usize,
|
||||
input.height as usize,
|
||||
usize::from(input.width),
|
||||
usize::from(input.height),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,10 +83,15 @@ pub fn to_64x64_ycbcr_tile(
|
|||
/// Convert a 16-bit RDP color to RGB representation. Input value should be represented in
|
||||
/// little-endian format.
|
||||
pub fn rdp_16bit_to_rgb(color: u16) -> [u8; 3] {
|
||||
let r = (((((color >> 11) & 0x1f) * 527) + 23) >> 6) as u8;
|
||||
let g = (((((color >> 5) & 0x3f) * 259) + 33) >> 6) as u8;
|
||||
let b = ((((color & 0x1f) * 527) + 23) >> 6) as u8;
|
||||
[r, g, b]
|
||||
#[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer underflow)")]
|
||||
let out = {
|
||||
let r = u8::try_from(((((color >> 11) & 0x1f) * 527) + 23) >> 6).expect("max possible value is 255");
|
||||
let g = u8::try_from(((((color >> 5) & 0x3f) * 259) + 33) >> 6).expect("max possible value is 255");
|
||||
let b = u8::try_from((((color & 0x1f) * 527) + 23) >> 6).expect("max possible value is 255");
|
||||
[r, g, b]
|
||||
};
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -22,17 +22,21 @@ fn dwt_vertical<const SUBBAND_WIDTH: usize>(buffer: &[i16], dwt: &mut [i16]) {
|
|||
let h_index = l_index + SUBBAND_WIDTH * total_width;
|
||||
let src_index = y * total_width + x;
|
||||
|
||||
dwt[h_index] = ((i32::from(buffer[src_index + total_width])
|
||||
- ((i32::from(buffer[src_index])
|
||||
+ i32::from(buffer[src_index + if n < SUBBAND_WIDTH - 1 { 2 * total_width } else { 0 }]))
|
||||
>> 1))
|
||||
>> 1) as i16;
|
||||
dwt[l_index] = (i32::from(buffer[src_index])
|
||||
+ if n == 0 {
|
||||
i32::from(dwt[h_index])
|
||||
} else {
|
||||
(i32::from(dwt[h_index - total_width]) + i32::from(dwt[h_index])) >> 1
|
||||
}) as i16;
|
||||
dwt[h_index] = i32_to_i16_possible_truncation(
|
||||
(i32::from(buffer[src_index + total_width])
|
||||
- ((i32::from(buffer[src_index])
|
||||
+ i32::from(buffer[src_index + if n < SUBBAND_WIDTH - 1 { 2 * total_width } else { 0 }]))
|
||||
>> 1))
|
||||
>> 1,
|
||||
);
|
||||
dwt[l_index] = i32_to_i16_possible_truncation(
|
||||
i32::from(buffer[src_index])
|
||||
+ if n == 0 {
|
||||
i32::from(dwt[h_index])
|
||||
} else {
|
||||
(i32::from(dwt[h_index - total_width]) + i32::from(dwt[h_index])) >> 1
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -57,16 +61,20 @@ fn dwt_horizontal<const SUBBAND_WIDTH: usize>(mut buffer: &mut [i16], dwt: &[i16
|
|||
let x = n * 2;
|
||||
|
||||
// HL
|
||||
hl[n] = ((i32::from(l_src[x + 1])
|
||||
- ((i32::from(l_src[x]) + i32::from(l_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1))
|
||||
>> 1) as i16;
|
||||
hl[n] = i32_to_i16_possible_truncation(
|
||||
(i32::from(l_src[x + 1])
|
||||
- ((i32::from(l_src[x]) + i32::from(l_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1))
|
||||
>> 1,
|
||||
);
|
||||
// LL
|
||||
ll[n] = (i32::from(l_src[x])
|
||||
+ if n == 0 {
|
||||
i32::from(hl[n])
|
||||
} else {
|
||||
(i32::from(hl[n - 1]) + i32::from(hl[n])) >> 1
|
||||
}) as i16;
|
||||
ll[n] = i32_to_i16_possible_truncation(
|
||||
i32::from(l_src[x])
|
||||
+ if n == 0 {
|
||||
i32::from(hl[n])
|
||||
} else {
|
||||
(i32::from(hl[n - 1]) + i32::from(hl[n])) >> 1
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// H
|
||||
|
|
@ -74,16 +82,20 @@ fn dwt_horizontal<const SUBBAND_WIDTH: usize>(mut buffer: &mut [i16], dwt: &[i16
|
|||
let x = n * 2;
|
||||
|
||||
// HH
|
||||
hh[n] = ((i32::from(h_src[x + 1])
|
||||
- ((i32::from(h_src[x]) + i32::from(h_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1))
|
||||
>> 1) as i16;
|
||||
hh[n] = i32_to_i16_possible_truncation(
|
||||
(i32::from(h_src[x + 1])
|
||||
- ((i32::from(h_src[x]) + i32::from(h_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1))
|
||||
>> 1,
|
||||
);
|
||||
// LH
|
||||
lh[n] = (i32::from(h_src[x])
|
||||
+ if n == 0 {
|
||||
i32::from(hh[n])
|
||||
} else {
|
||||
(i32::from(hh[n - 1]) + i32::from(hh[n])) >> 1
|
||||
}) as i16;
|
||||
lh[n] = i32_to_i16_possible_truncation(
|
||||
i32::from(h_src[x])
|
||||
+ if n == 0 {
|
||||
i32::from(hh[n])
|
||||
} else {
|
||||
(i32::from(hh[n - 1]) + i32::from(hh[n])) >> 1
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
hl = &mut hl[SUBBAND_WIDTH..];
|
||||
|
|
@ -124,24 +136,30 @@ fn inverse_horizontal(mut buffer: &[i16], temp_buffer: &mut [i16], subband_width
|
|||
|
||||
for _ in 0..subband_width {
|
||||
// Even coefficients
|
||||
l_dst[0] = (i32::from(ll[0]) - ((i32::from(hl[0]) + i32::from(hl[0]) + 1) >> 1)) as i16;
|
||||
h_dst[0] = (i32::from(lh[0]) - ((i32::from(hh[0]) + i32::from(hh[0]) + 1) >> 1)) as i16;
|
||||
l_dst[0] = i32_to_i16_possible_truncation(i32::from(ll[0]) - ((i32::from(hl[0]) + i32::from(hl[0]) + 1) >> 1));
|
||||
h_dst[0] = i32_to_i16_possible_truncation(i32::from(lh[0]) - ((i32::from(hh[0]) + i32::from(hh[0]) + 1) >> 1));
|
||||
for n in 1..subband_width {
|
||||
let x = n * 2;
|
||||
l_dst[x] = (i32::from(ll[n]) - ((i32::from(hl[n - 1]) + i32::from(hl[n]) + 1) >> 1)) as i16;
|
||||
h_dst[x] = (i32::from(lh[n]) - ((i32::from(hh[n - 1]) + i32::from(hh[n]) + 1) >> 1)) as i16;
|
||||
l_dst[x] =
|
||||
i32_to_i16_possible_truncation(i32::from(ll[n]) - ((i32::from(hl[n - 1]) + i32::from(hl[n]) + 1) >> 1));
|
||||
h_dst[x] =
|
||||
i32_to_i16_possible_truncation(i32::from(lh[n]) - ((i32::from(hh[n - 1]) + i32::from(hh[n]) + 1) >> 1));
|
||||
}
|
||||
|
||||
// Odd coefficients
|
||||
for n in 0..subband_width - 1 {
|
||||
let x = n * 2;
|
||||
l_dst[x + 1] = (i32::from(hl[n] << 1) + ((i32::from(l_dst[x]) + i32::from(l_dst[x + 2])) >> 1)) as i16;
|
||||
h_dst[x + 1] = (i32::from(hh[n] << 1) + ((i32::from(h_dst[x]) + i32::from(h_dst[x + 2])) >> 1)) as i16;
|
||||
l_dst[x + 1] = i32_to_i16_possible_truncation(
|
||||
i32::from(hl[n] << 1) + ((i32::from(l_dst[x]) + i32::from(l_dst[x + 2])) >> 1),
|
||||
);
|
||||
h_dst[x + 1] = i32_to_i16_possible_truncation(
|
||||
i32::from(hh[n] << 1) + ((i32::from(h_dst[x]) + i32::from(h_dst[x + 2])) >> 1),
|
||||
);
|
||||
}
|
||||
let n = subband_width - 1;
|
||||
let x = n * 2;
|
||||
l_dst[x + 1] = (i32::from(hl[n] << 1) + i32::from(l_dst[x])) as i16;
|
||||
h_dst[x + 1] = (i32::from(hh[n] << 1) + i32::from(h_dst[x])) as i16;
|
||||
l_dst[x + 1] = i32_to_i16_possible_truncation(i32::from(hl[n] << 1) + i32::from(l_dst[x]));
|
||||
h_dst[x + 1] = i32_to_i16_possible_truncation(i32::from(hh[n] << 1) + i32::from(h_dst[x]));
|
||||
|
||||
hl = &hl[subband_width..];
|
||||
lh = &lh[subband_width..];
|
||||
|
|
@ -157,8 +175,9 @@ fn inverse_vertical(mut buffer: &mut [i16], mut temp_buffer: &[i16], subband_wid
|
|||
let total_width = subband_width * 2;
|
||||
|
||||
for _ in 0..total_width {
|
||||
buffer[0] =
|
||||
(i32::from(temp_buffer[0]) - ((i32::from(temp_buffer[subband_width * total_width]) * 2 + 1) >> 1)) as i16;
|
||||
buffer[0] = i32_to_i16_possible_truncation(
|
||||
i32::from(temp_buffer[0]) - ((i32::from(temp_buffer[subband_width * total_width]) * 2 + 1) >> 1),
|
||||
);
|
||||
|
||||
let mut l = temp_buffer;
|
||||
let mut lh = &temp_buffer[(subband_width - 1) * total_width..];
|
||||
|
|
@ -171,18 +190,28 @@ fn inverse_vertical(mut buffer: &mut [i16], mut temp_buffer: &[i16], subband_wid
|
|||
h = &h[total_width..];
|
||||
|
||||
// Even coefficients
|
||||
dst[2 * total_width] = (i32::from(l[0]) - ((i32::from(lh[0]) + i32::from(h[0]) + 1) >> 1)) as i16;
|
||||
dst[2 * total_width] =
|
||||
i32_to_i16_possible_truncation(i32::from(l[0]) - ((i32::from(lh[0]) + i32::from(h[0]) + 1) >> 1));
|
||||
|
||||
// Odd coefficients
|
||||
dst[total_width] =
|
||||
(i32::from(lh[0] << 1) + ((i32::from(dst[0]) + i32::from(dst[2 * total_width])) >> 1)) as i16;
|
||||
dst[total_width] = i32_to_i16_possible_truncation(
|
||||
i32::from(lh[0] << 1) + ((i32::from(dst[0]) + i32::from(dst[2 * total_width])) >> 1),
|
||||
);
|
||||
|
||||
dst = &mut dst[2 * total_width..];
|
||||
}
|
||||
|
||||
dst[total_width] = (i32::from(lh[total_width] << 1) + ((i32::from(dst[0]) + i32::from(dst[0])) >> 1)) as i16;
|
||||
dst[total_width] = i32_to_i16_possible_truncation(
|
||||
i32::from(lh[total_width] << 1) + ((i32::from(dst[0]) + i32::from(dst[0])) >> 1),
|
||||
);
|
||||
|
||||
temp_buffer = &temp_buffer[1..];
|
||||
buffer = &mut buffer[1..];
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::as_conversions)]
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
fn i32_to_i16_possible_truncation(value: i32) -> i16 {
|
||||
value as i16
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
#![cfg_attr(doc, doc = include_str!("../README.md"))]
|
||||
#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
|
||||
#![allow(clippy::arithmetic_side_effects)] // FIXME: remove
|
||||
#![allow(clippy::cast_lossless)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_truncation)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_wrap)] // FIXME: remove
|
||||
#![allow(clippy::cast_sign_loss)] // FIXME: remove
|
||||
|
||||
pub mod color_conversion;
|
||||
pub mod diff;
|
||||
|
|
|
|||
|
|
@ -260,9 +260,12 @@ impl DecodedPointer {
|
|||
} else if target.should_premultiply_alpha() {
|
||||
// Calculate premultiplied alpha via integer arithmetic
|
||||
let with_premultiplied_alpha = [
|
||||
((color[0] as u16 * color[0] as u16) >> 8) as u8,
|
||||
((color[1] as u16 * color[1] as u16) >> 8) as u8,
|
||||
((color[2] as u16 * color[2] as u16) >> 8) as u8,
|
||||
u8::try_from((u16::from(color[0]) * u16::from(color[0])) >> 8)
|
||||
.expect("(u16 >> 8) fits into u8"),
|
||||
u8::try_from((u16::from(color[1]) * u16::from(color[1])) >> 8)
|
||||
.expect("(u16 >> 8) fits into u8"),
|
||||
u8::try_from((u16::from(color[2]) * u16::from(color[2])) >> 8)
|
||||
.expect("(u16 >> 8) fits into u8"),
|
||||
color[3],
|
||||
];
|
||||
bitmap_data.extend_from_slice(&with_premultiplied_alpha);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub fn decode(buffer: &mut [i16], quant: &Quant) {
|
|||
let (first_level, buffer) = buffer.split_at_mut(FIRST_LEVEL_SUBBANDS_COUNT * FIRST_LEVEL_SIZE);
|
||||
let (second_level, third_level) = buffer.split_at_mut(SECOND_LEVEL_SUBBANDS_COUNT * SECOND_LEVEL_SIZE);
|
||||
|
||||
let decode_chunk = |a: (&mut [i16], u8)| decode_block(a.0, a.1 as i16 - 1);
|
||||
let decode_chunk = |a: (&mut [i16], u8)| decode_block(a.0, i16::from(a.1) - 1);
|
||||
|
||||
first_level
|
||||
.chunks_mut(FIRST_LEVEL_SIZE)
|
||||
|
|
@ -49,7 +49,7 @@ pub fn encode(buffer: &mut [i16], quant: &Quant) {
|
|||
let (first_level, buffer) = buffer.split_at_mut(FIRST_LEVEL_SUBBANDS_COUNT * FIRST_LEVEL_SIZE);
|
||||
let (second_level, third_level) = buffer.split_at_mut(SECOND_LEVEL_SUBBANDS_COUNT * SECOND_LEVEL_SIZE);
|
||||
|
||||
let encode_chunk = |a: (&mut [i16], u8)| encode_block(a.0, a.1 as i16 - 1);
|
||||
let encode_chunk = |a: (&mut [i16], u8)| encode_block(a.0, i16::from(a.1) - 1);
|
||||
|
||||
first_level
|
||||
.chunks_mut(FIRST_LEVEL_SIZE)
|
||||
|
|
|
|||
|
|
@ -195,8 +195,9 @@ impl<'a> BitmapStreamDecoderImpl<'a> {
|
|||
}
|
||||
|
||||
fn write_aycocg_planes_to_rgb24(&self, params: AYCoCgParams, planes: &[u8], dst: &mut Vec<u8>) {
|
||||
#![allow(clippy::similar_names)] // It’s hard to find better names for co, cg, etc.
|
||||
let sample_shift = params.chroma_subsampling as usize;
|
||||
#![allow(clippy::similar_names, reason = "it’s hard to find better names for co, cg, etc")]
|
||||
|
||||
let sample_shift = usize::from(params.chroma_subsampling);
|
||||
|
||||
let (y_offset, co_offset, cg_offset) = (
|
||||
self.color_plane_offsets[0],
|
||||
|
|
@ -265,12 +266,13 @@ fn ycocg_with_cll_to_rgb(cll: u8, y: u8, co: u8, cg: u8) -> Rgb {
|
|||
// |R| |1 1/2 -1/2| |Y |
|
||||
// |G| = |1 0 1/2| * |Co|
|
||||
// |B| |1 -1/2 -1/2| |Cg|
|
||||
let chroma_shift = (cll - 1) as usize;
|
||||
let chroma_shift = cll - 1;
|
||||
|
||||
let clip_i16 = |v: i16| v.clamp(0, 255) as u8;
|
||||
let clip_i16 =
|
||||
|v: i16| u8::try_from(v.clamp(0, 255)).expect("fits into u8 because the value is clamped to [0..256]");
|
||||
|
||||
let co_signed = (co << chroma_shift) as i8;
|
||||
let cg_signed = (cg << chroma_shift) as i8;
|
||||
let co_signed = (co << chroma_shift).cast_signed();
|
||||
let cg_signed = (cg << chroma_shift).cast_signed();
|
||||
|
||||
let y = i16::from(y);
|
||||
let co = i16::from(co_signed);
|
||||
|
|
|
|||
|
|
@ -93,9 +93,9 @@ impl RlePlaneDecoder {
|
|||
let raw_bytes_field = (control_byte >> 4) & 0x0F;
|
||||
|
||||
let (run_length, raw_bytes_count) = match rle_bytes_field {
|
||||
1 => (16 + raw_bytes_field as usize, 0),
|
||||
2 => (32 + raw_bytes_field as usize, 0),
|
||||
rle_control => (rle_control as usize, raw_bytes_field as usize),
|
||||
1 => (16 + usize::from(raw_bytes_field), 0),
|
||||
2 => (32 + usize::from(raw_bytes_field), 0),
|
||||
rle_control => (usize::from(rle_control), usize::from(raw_bytes_field)),
|
||||
};
|
||||
|
||||
self.decoded_data_len = raw_bytes_count + run_length;
|
||||
|
|
@ -207,7 +207,8 @@ impl<I: Iterator> RleEncoderScanlineIterator<I> {
|
|||
}
|
||||
|
||||
fn delta_value(prev: u8, next: u8) -> u8 {
|
||||
let mut result = (next as i16 - prev as i16) as u8;
|
||||
let mut result = u8::try_from((i16::from(next) - i16::from(prev)) & 0xFF)
|
||||
.expect("masking with 0xFF ensures that the value fits into u8");
|
||||
|
||||
// bit magic from 3.1.9.2.1 of [MS-RDPEGDI].
|
||||
if result < 128 {
|
||||
|
|
@ -326,7 +327,10 @@ impl RlePlaneEncoder {
|
|||
raw = &raw[15..];
|
||||
}
|
||||
|
||||
let control = ((raw.len() as u8) << 4) + cmp::min(run, 15) as u8;
|
||||
let raw_len = u8::try_from(raw.len()).expect("max value is guaranteed to be 15 due to the prior while loop");
|
||||
let run_capped = u8::try_from(cmp::min(run, 15)).expect("max value is guaranteed to be 15");
|
||||
|
||||
let control = (raw_len << 4) + run_capped;
|
||||
|
||||
ensure_size!(dst: dst, size: raw.len() + 1);
|
||||
|
||||
|
|
@ -352,7 +356,8 @@ impl RlePlaneEncoder {
|
|||
while run >= 16 {
|
||||
ensure_size!(dst: dst, size: 1);
|
||||
|
||||
let current = cmp::min(run, MAX_DECODED_SEGMENT_SIZE) as u8;
|
||||
let current = u8::try_from(cmp::min(run, MAX_DECODED_SEGMENT_SIZE))
|
||||
.expect("max value is guaranteed to be MAX_DECODED_SEGMENT_SIZE (47)");
|
||||
|
||||
let c_raw_bytes = cmp::min(current / 16, 2);
|
||||
let n_run_length = current - c_raw_bytes * 16;
|
||||
|
|
@ -361,7 +366,7 @@ impl RlePlaneEncoder {
|
|||
dst.write_u8(control);
|
||||
written += 1;
|
||||
|
||||
run -= current as usize;
|
||||
run -= usize::from(current);
|
||||
}
|
||||
|
||||
if run > 0 {
|
||||
|
|
|
|||
|
|
@ -63,17 +63,23 @@ impl<'a> BitStream<'a> {
|
|||
}
|
||||
|
||||
pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<usize, RlgrError> {
|
||||
let mut k: u32 = 1;
|
||||
let kr: u32 = 1;
|
||||
let mut kp: u32 = k << LS_GR;
|
||||
let mut krp: u32 = kr << LS_GR;
|
||||
#![expect(
|
||||
clippy::as_conversions,
|
||||
reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop"
|
||||
)]
|
||||
|
||||
if input.is_empty() {
|
||||
return Err(RlgrError::EmptyTile);
|
||||
}
|
||||
|
||||
let mut k: u32 = 1;
|
||||
let kr: u32 = 1;
|
||||
let mut kp: u32 = k << LS_GR;
|
||||
let mut krp: u32 = kr << LS_GR;
|
||||
let mut bits = BitStream::new(tile);
|
||||
|
||||
let mut input = input.iter().peekable();
|
||||
|
||||
while input.peek().is_some() {
|
||||
match CompressionMode::from(k) {
|
||||
CompressionMode::RunLength => {
|
||||
|
|
@ -98,7 +104,7 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<
|
|||
bits.output_bits(k as usize, nz);
|
||||
|
||||
if let Some(val) = input.next() {
|
||||
let mag = val.unsigned_abs() as u32;
|
||||
let mag = u32::from(val.unsigned_abs());
|
||||
bits.output_bit(1, *val < 0);
|
||||
code_gr(&mut bits, &mut krp, mag - 1);
|
||||
}
|
||||
|
|
@ -152,37 +158,53 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result<
|
|||
fn get_2magsign(val: i16) -> u32 {
|
||||
let sign = if val < 0 { 1 } else { 0 };
|
||||
|
||||
(val.unsigned_abs() as u32) * 2 - sign
|
||||
(u32::from(val.unsigned_abs())) * 2 - sign
|
||||
}
|
||||
|
||||
fn code_gr(bits: &mut BitStream<'_>, krp: &mut u32, val: u32) {
|
||||
let kr = (*krp >> LS_GR) as usize;
|
||||
let vk = (val >> kr) as usize;
|
||||
#![expect(
|
||||
clippy::as_conversions,
|
||||
reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop"
|
||||
)]
|
||||
|
||||
bits.output_bit(vk, true);
|
||||
let kr = (*krp >> LS_GR) as usize;
|
||||
|
||||
let vk = val >> kr;
|
||||
let vk_usize = vk as usize;
|
||||
|
||||
bits.output_bit(vk_usize, true);
|
||||
bits.output_bit(1, false);
|
||||
|
||||
if kr != 0 {
|
||||
let remainder = val & ((1 << kr) - 1);
|
||||
bits.output_bits(kr, remainder);
|
||||
}
|
||||
|
||||
if vk == 0 {
|
||||
*krp = krp.saturating_sub(2);
|
||||
} else if vk > 1 {
|
||||
*krp = min(*krp + vk as u32, KP_MAX);
|
||||
*krp = min(*krp + vk, KP_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Result<(), RlgrError> {
|
||||
let mut k: u32 = 1;
|
||||
let mut kr: u32 = 1;
|
||||
let mut kp: u32 = k << LS_GR;
|
||||
let mut krp: u32 = kr << LS_GR;
|
||||
#![expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop"
|
||||
)]
|
||||
|
||||
if tile.is_empty() {
|
||||
return Err(RlgrError::EmptyTile);
|
||||
}
|
||||
|
||||
let mut k: u32 = 1;
|
||||
let mut kr: u32 = 1;
|
||||
let mut kp: u32 = k << LS_GR;
|
||||
let mut krp: u32 = kr << LS_GR;
|
||||
|
||||
let mut bits = Bits::new(BitSlice::from_slice(tile));
|
||||
|
||||
while !bits.is_empty() && !output.is_empty() {
|
||||
match CompressionMode::from(k) {
|
||||
CompressionMode::RunLength => {
|
||||
|
|
@ -201,7 +223,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re
|
|||
kp = kp.saturating_sub(DN_GR);
|
||||
k = kp >> LS_GR;
|
||||
|
||||
let magnitude = compute_rl_magnitude(sign_bit, code_remainder);
|
||||
let magnitude = compute_rl_magnitude(sign_bit, code_remainder)?;
|
||||
|
||||
let size = min(run as usize, output.len());
|
||||
fill(&mut output[..size], 0);
|
||||
|
|
@ -218,7 +240,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re
|
|||
|
||||
match mode {
|
||||
EntropyAlgorithm::Rlgr1 => {
|
||||
let magnitude = compute_rlgr1_magnitude(code_remainder, &mut k, &mut kp);
|
||||
let magnitude = compute_rlgr1_magnitude(code_remainder, &mut k, &mut kp)?;
|
||||
write_byte!(output, magnitude);
|
||||
}
|
||||
EntropyAlgorithm::Rlgr3 => {
|
||||
|
|
@ -234,10 +256,10 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re
|
|||
k = kp >> LS_GR;
|
||||
}
|
||||
|
||||
let magnitude = compute_rlgr3_magnitude(val1);
|
||||
let magnitude = compute_rlgr3_magnitude(val1)?;
|
||||
write_byte!(output, magnitude);
|
||||
|
||||
let magnitude = compute_rlgr3_magnitude(val2);
|
||||
let magnitude = compute_rlgr3_magnitude(val2)?;
|
||||
write_byte!(output, magnitude);
|
||||
}
|
||||
}
|
||||
|
|
@ -245,7 +267,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re
|
|||
}
|
||||
}
|
||||
|
||||
// fill remaining buffer with zeros
|
||||
// Fill remaining buffer with zeros.
|
||||
fill(output, 0);
|
||||
|
||||
Ok(())
|
||||
|
|
@ -288,37 +310,41 @@ fn count_run(number_of_zeros: usize, k: &mut u32, kp: &mut u32) -> u32 {
|
|||
.sum()
|
||||
}
|
||||
|
||||
fn compute_rl_magnitude(sign_bit: u8, code_remainder: u32) -> i16 {
|
||||
fn compute_rl_magnitude(sign_bit: u8, code_remainder: u32) -> Result<i16, RlgrError> {
|
||||
let rl_magnitude =
|
||||
i16::try_from(code_remainder + 1).map_err(|_| RlgrError::InvalidIntegralConversion("code remainder + 1"))?;
|
||||
|
||||
if sign_bit != 0 {
|
||||
-((code_remainder + 1) as i16)
|
||||
Ok(-rl_magnitude)
|
||||
} else {
|
||||
(code_remainder + 1) as i16
|
||||
Ok(rl_magnitude)
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_rlgr1_magnitude(code_remainder: u32, k: &mut u32, kp: &mut u32) -> i16 {
|
||||
fn compute_rlgr1_magnitude(code_remainder: u32, k: &mut u32, kp: &mut u32) -> Result<i16, RlgrError> {
|
||||
if code_remainder == 0 {
|
||||
*kp = min(*kp + UQ_GR, KP_MAX);
|
||||
*k = *kp >> LS_GR;
|
||||
|
||||
0
|
||||
Ok(0)
|
||||
} else {
|
||||
*kp = kp.saturating_sub(DQ_GR);
|
||||
*k = *kp >> LS_GR;
|
||||
|
||||
if code_remainder % 2 != 0 {
|
||||
-(((code_remainder + 1) >> 1) as i16)
|
||||
Ok(-i16::try_from((code_remainder + 1) >> 1)
|
||||
.map_err(|_| RlgrError::InvalidIntegralConversion("(code remainder + 1) >> 1"))?)
|
||||
} else {
|
||||
(code_remainder >> 1) as i16
|
||||
i16::try_from(code_remainder >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("code remainder >> 1"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_rlgr3_magnitude(val: u32) -> i16 {
|
||||
fn compute_rlgr3_magnitude(val: u32) -> Result<i16, RlgrError> {
|
||||
if val % 2 != 0 {
|
||||
-(((val + 1) >> 1) as i16)
|
||||
Ok(-i16::try_from((val + 1) >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("(val + 1) >> 1"))?)
|
||||
} else {
|
||||
(val >> 1) as i16
|
||||
i16::try_from(val >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("val >> 1"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,11 +361,17 @@ fn compute_n_index(code_remainder: u32) -> usize {
|
|||
}
|
||||
|
||||
fn update_parameters_according_to_number_of_ones(number_of_ones: usize, kr: &mut u32, krp: &mut u32) {
|
||||
#![expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "usize-to-u32 conversions, hot loop"
|
||||
)]
|
||||
|
||||
if number_of_ones == 0 {
|
||||
*krp = (*krp).saturating_sub(2);
|
||||
*kr = *krp >> LS_GR;
|
||||
} else if number_of_ones > 1 {
|
||||
*krp = min(*krp + number_of_ones as u32, KP_MAX);
|
||||
*krp = min(*krp + (number_of_ones as u32), KP_MAX);
|
||||
*kr = *krp >> LS_GR;
|
||||
}
|
||||
}
|
||||
|
|
@ -365,6 +397,7 @@ pub enum RlgrError {
|
|||
Io(io::Error),
|
||||
Yuv(YuvError),
|
||||
EmptyTile,
|
||||
InvalidIntegralConversion(&'static str),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for RlgrError {
|
||||
|
|
@ -373,6 +406,7 @@ impl core::fmt::Display for RlgrError {
|
|||
Self::Io(_) => write!(f, "IO error"),
|
||||
Self::Yuv(_) => write!(f, "YUV error"),
|
||||
Self::EmptyTile => write!(f, "the input tile is empty"),
|
||||
Self::InvalidIntegralConversion(s) => write!(f, "invalid `{s}`: out of range integral type conversion"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -383,6 +417,7 @@ impl core::error::Error for RlgrError {
|
|||
Self::Io(error) => Some(error),
|
||||
Self::Yuv(error) => Some(error),
|
||||
Self::EmptyTile => None,
|
||||
Self::InvalidIntegralConversion(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,14 @@ impl<'a> SegmentedDataPdu<'a> {
|
|||
match descriptor {
|
||||
SegmentedDescriptor::Single => Ok(SegmentedDataPdu::Single(BulkEncodedData::from_buffer(buffer)?)),
|
||||
SegmentedDescriptor::Multipart => {
|
||||
let segment_count = buffer.read_u16::<LittleEndian>()? as usize;
|
||||
let uncompressed_size = buffer.read_u32::<LittleEndian>()? as usize;
|
||||
let segment_count = usize::from(buffer.read_u16::<LittleEndian>()?);
|
||||
let uncompressed_size = usize::try_from(buffer.read_u32::<LittleEndian>()?)
|
||||
.map_err(|_| ZgfxError::InvalidIntegralConversion("segments uncompressed size"))?;
|
||||
|
||||
let mut segments = Vec::with_capacity(segment_count);
|
||||
for _ in 0..segment_count {
|
||||
let size = buffer.read_u32::<LittleEndian>()? as usize;
|
||||
let size = usize::try_from(buffer.read_u32::<LittleEndian>()?)
|
||||
.map_err(|_| ZgfxError::InvalidIntegralConversion("segment data size"))?;
|
||||
let (segment_data, new_buffer) = buffer.split_at(size);
|
||||
buffer = new_buffer;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ impl Decompressor {
|
|||
let mut bits = BitSlice::from_slice(encoded_data);
|
||||
|
||||
// The value of the last byte indicates the number of unused bits in the final byte
|
||||
bits =
|
||||
&bits[..8 * (encoded_data.len() - 1) - *encoded_data.last().expect("encoded_data is not empty") as usize];
|
||||
bits = &bits
|
||||
[..8 * (encoded_data.len() - 1) - usize::from(*encoded_data.last().expect("encoded_data is not empty"))];
|
||||
let mut bits = Bits::new(bits);
|
||||
let mut bytes_written = 0;
|
||||
|
||||
|
|
@ -135,14 +135,15 @@ fn handle_match(
|
|||
distance_base: u32,
|
||||
history: &mut FixedCircularBuffer,
|
||||
output: &mut Vec<u8>,
|
||||
) -> io::Result<usize> {
|
||||
) -> Result<usize, ZgfxError> {
|
||||
// Each token has been assigned a different base distance
|
||||
// and number of additional value bits to be added to compute the full distance.
|
||||
|
||||
let distance = (distance_base + bits.split_to(distance_value_size).load_be::<u32>()) as usize;
|
||||
let distance = usize::try_from(distance_base + bits.split_to(distance_value_size).load_be::<u32>())
|
||||
.map_err(|_| ZgfxError::InvalidIntegralConversion("token's full distance"))?;
|
||||
|
||||
if distance == 0 {
|
||||
read_unencoded_bytes(bits, history, output)
|
||||
read_unencoded_bytes(bits, history, output).map_err(ZgfxError::from)
|
||||
} else {
|
||||
read_encoded_bytes(bits, distance, history, output)
|
||||
}
|
||||
|
|
@ -156,7 +157,7 @@ fn read_unencoded_bytes(
|
|||
// A match distance of zero is a special case,
|
||||
// which indicates that an unencoded run of bytes follows.
|
||||
// The count of bytes is encoded as a 15-bit value
|
||||
let length = bits.split_to(15).load_be::<u32>() as usize;
|
||||
let length = bits.split_to(15).load_be::<usize>();
|
||||
|
||||
if bits.remaining_bits_of_last_byte() > 0 {
|
||||
let pad_to_byte_boundary = 8 - bits.remaining_bits_of_last_byte();
|
||||
|
|
@ -179,7 +180,7 @@ fn read_encoded_bytes(
|
|||
distance: usize,
|
||||
history: &mut FixedCircularBuffer,
|
||||
output: &mut Vec<u8>,
|
||||
) -> io::Result<usize> {
|
||||
) -> Result<usize, ZgfxError> {
|
||||
// A match length prefix follows the token and indicates
|
||||
// how many additional bits will be needed to get the full length
|
||||
// (the number of bytes to be copied).
|
||||
|
|
@ -192,9 +193,12 @@ fn read_encoded_bytes(
|
|||
|
||||
3
|
||||
} else {
|
||||
let length = bits.split_to(length_token_size + 1).load_be::<u32>() as usize;
|
||||
let length = bits.split_to(length_token_size + 1).load_be::<usize>();
|
||||
|
||||
let base = 2u32.pow(length_token_size as u32 + 1) as usize;
|
||||
let length_token_size = u32::try_from(length_token_size)
|
||||
.map_err(|_| ZgfxError::InvalidIntegralConversion("length of the token size"))?;
|
||||
|
||||
let base = 2usize.pow(length_token_size + 1);
|
||||
|
||||
base + length
|
||||
};
|
||||
|
|
@ -441,6 +445,7 @@ pub enum ZgfxError {
|
|||
uncompressed_size: usize,
|
||||
},
|
||||
TokenBitsNotFound,
|
||||
InvalidIntegralConversion(&'static str),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for ZgfxError {
|
||||
|
|
@ -457,6 +462,7 @@ impl core::fmt::Display for ZgfxError {
|
|||
"decompressed size of segments ({decompressed_size}) does not equal to uncompressed size ({uncompressed_size})",
|
||||
),
|
||||
Self::TokenBitsNotFound => write!(f, "token bits not found"),
|
||||
Self::InvalidIntegralConversion(type_name) => write!(f, "invalid `{type_name}`: out of range integral type conversion"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -469,6 +475,7 @@ impl core::error::Error for ZgfxError {
|
|||
Self::InvalidSegmentedDescriptor => None,
|
||||
Self::InvalidDecompressedSize { .. } => None,
|
||||
Self::TokenBitsNotFound => None,
|
||||
Self::InvalidIntegralConversion(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ pub enum MouseButton {
|
|||
}
|
||||
|
||||
impl MouseButton {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
pub fn as_idx(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
|
@ -78,7 +82,11 @@ impl Scancode {
|
|||
pub const fn from_u16(scancode: u16) -> Self {
|
||||
let extended = scancode & 0xE000 == 0xE000;
|
||||
|
||||
#[expect(clippy::cast_possible_truncation)] // truncating on purpose
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "truncating on purpose"
|
||||
)]
|
||||
let code = scancode as u8;
|
||||
|
||||
Self { code, extended }
|
||||
|
|
|
|||
|
|
@ -221,7 +221,8 @@ impl GwClient {
|
|||
let mut cur = ReadCursor::new(&msg);
|
||||
let hdr = PktHdr::decode(&mut cur).map_err(|e| custom_err!("Header Decode", e))?;
|
||||
|
||||
assert!(cur.len() >= hdr.length as usize - hdr.size());
|
||||
let header_length = usize::try_from(hdr.length).map_err(|_| Error::new("PktHdr too big", GwErrorKind::Decode))?;
|
||||
assert!(cur.len() >= header_length - hdr.size());
|
||||
match hdr.ty {
|
||||
PktTy::Keepalive => {
|
||||
continue;
|
||||
|
|
@ -287,7 +288,10 @@ impl GwConn {
|
|||
let mut cur = ReadCursor::new(&msg);
|
||||
|
||||
let hdr = PktHdr::decode(&mut cur).map_err(|_| Error::new("PktHdr", GwErrorKind::Decode))?;
|
||||
if cur.len() != hdr.length as usize - hdr.size() {
|
||||
|
||||
let header_length =
|
||||
usize::try_from(hdr.length).map_err(|_| Error::new("PktHdr too big", GwErrorKind::Decode))?;
|
||||
if cur.len() != header_length - hdr.size() {
|
||||
return Err(Error::new("read_packet", GwErrorKind::PacketEof));
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +319,7 @@ impl GwConn {
|
|||
async fn tunnel(&mut self) -> Result<(), Error> {
|
||||
let req = TunnelReqPkt {
|
||||
// Havent seen any server working without this.
|
||||
caps: HttpCapsTy::MessagingConsentSign as u32,
|
||||
caps: HttpCapsTy::MessagingConsentSign.as_u32(),
|
||||
fields_present: 0,
|
||||
..TunnelReqPkt::default()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,6 +37,16 @@ pub(crate) enum PktTy {
|
|||
Keepalive = 0x0D,
|
||||
}
|
||||
|
||||
impl PktTy {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u16(self) -> u16 {
|
||||
self as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u16> for PktTy {
|
||||
type Error = ();
|
||||
|
||||
|
|
@ -78,7 +88,7 @@ impl Encode for PktHdr {
|
|||
fn encode(&self, dst: &mut WriteCursor<'_>) -> ironrdp_core::EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: self.size());
|
||||
|
||||
dst.write_u16(self.ty as u16);
|
||||
dst.write_u16(self.ty.as_u16());
|
||||
dst.write_u16(self._reserved);
|
||||
dst.write_u32(self.length);
|
||||
|
||||
|
|
@ -215,6 +225,7 @@ impl Encode for TunnelReqPkt {
|
|||
/// 2.2.5.3.9 HTTP_CAPABILITY_TYPE Enumeration
|
||||
#[repr(u32)]
|
||||
#[expect(dead_code)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum HttpCapsTy {
|
||||
QuarSOH = 1,
|
||||
IdleTimeout = 2,
|
||||
|
|
@ -224,8 +235,19 @@ pub(crate) enum HttpCapsTy {
|
|||
UdpTransport = 0x20,
|
||||
}
|
||||
|
||||
impl HttpCapsTy {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
pub(crate) fn as_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// 2.2.5.3.8 HTTP_TUNNEL_RESPONSE_FIELDS_PRESENT_FLAGS
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum HttpTunnelResponseFields {
|
||||
TunnelID = 1,
|
||||
Caps = 2,
|
||||
|
|
@ -234,6 +256,16 @@ enum HttpTunnelResponseFields {
|
|||
Consent = 0x10,
|
||||
}
|
||||
|
||||
impl HttpTunnelResponseFields {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u16(self) -> u16 {
|
||||
self as u16
|
||||
}
|
||||
}
|
||||
|
||||
/// 2.2.10.20 HTTP_TUNNEL_RESPONSE Structure
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct TunnelRespPkt {
|
||||
|
|
@ -266,26 +298,26 @@ impl Decode<'_> for TunnelRespPkt {
|
|||
..TunnelRespPkt::default()
|
||||
};
|
||||
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::TunnelID as u16) != 0 {
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::TunnelID.as_u16()) != 0 {
|
||||
ensure_size!(in: src, size: 4);
|
||||
pkt.tunnel_id = Some(src.read_u32());
|
||||
}
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Caps as u16) != 0 {
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Caps.as_u16()) != 0 {
|
||||
ensure_size!(in: src, size: 4);
|
||||
pkt.caps_flags = Some(src.read_u32());
|
||||
}
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Soh as u16) != 0 {
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Soh.as_u16()) != 0 {
|
||||
ensure_size!(in: src, size: 2 + 2);
|
||||
pkt.nonce = Some(src.read_u16());
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
pkt.server_cert = src.read_slice(len as usize).to_vec();
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
pkt.server_cert = src.read_slice(len).to_vec();
|
||||
}
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Consent as u16) != 0 {
|
||||
if pkt.fields_present & (HttpTunnelResponseFields::Consent.as_u16()) != 0 {
|
||||
ensure_size!(in: src, size: 2);
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
pkt.consent_msg = src.read_slice(len as usize).to_vec();
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
pkt.consent_msg = src.read_slice(len).to_vec();
|
||||
}
|
||||
|
||||
Ok(pkt)
|
||||
|
|
@ -330,12 +362,12 @@ impl Decode<'_> for ExtendedAuthPkt {
|
|||
fn decode(src: &mut ReadCursor<'_>) -> ironrdp_core::DecodeResult<Self> {
|
||||
ensure_size!(in: src, size: 4 + 2);
|
||||
let error_code = src.read_u32();
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
|
||||
Ok(ExtendedAuthPkt {
|
||||
error_code,
|
||||
blob: src.read_slice(len as usize).to_vec(),
|
||||
blob: src.read_slice(len).to_vec(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -497,9 +529,9 @@ impl Decode<'_> for ChannelResp {
|
|||
}
|
||||
if resp.fields_present & 4 != 0 {
|
||||
ensure_size!(in: src, size: 2);
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
resp.authn_cookie = src.read_slice(len as usize).to_vec();
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
resp.authn_cookie = src.read_slice(len).to_vec();
|
||||
}
|
||||
Ok(resp)
|
||||
}
|
||||
|
|
@ -538,10 +570,10 @@ impl Encode for DataPkt<'_> {
|
|||
impl<'a> Decode<'a> for DataPkt<'a> {
|
||||
fn decode(src: &mut ReadCursor<'a>) -> ironrdp_core::DecodeResult<Self> {
|
||||
ensure_size!(in: src, size: 2);
|
||||
let len = src.read_u16();
|
||||
ensure_size!(in: src, size: len as usize);
|
||||
let len = usize::from(src.read_u16());
|
||||
ensure_size!(in: src, size: len);
|
||||
Ok(DataPkt {
|
||||
data: src.read_slice(len as usize),
|
||||
data: src.read_slice(len),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ impl Encode for ExtendedMonitorInfo {
|
|||
|
||||
dst.write_u32(self.physical_width);
|
||||
dst.write_u32(self.physical_height);
|
||||
dst.write_u32(self.orientation.as_u32());
|
||||
dst.write_u32(u32::from(self.orientation.as_u16()));
|
||||
dst.write_u32(self.desktop_scale_factor);
|
||||
dst.write_u32(self.device_scale_factor);
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ impl<'de> Decode<'de> for ExtendedMonitorInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[repr(u16)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive)]
|
||||
pub enum MonitorOrientation {
|
||||
Landscape = 0,
|
||||
|
|
@ -146,7 +146,7 @@ impl MonitorOrientation {
|
|||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u32(self) -> u32 {
|
||||
self as u32
|
||||
pub fn as_u16(self) -> u16 {
|
||||
self as u16
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -637,6 +637,10 @@ pub enum EntropyBits {
|
|||
}
|
||||
|
||||
impl EntropyBits {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -412,6 +412,10 @@ impl RdpSpecificCode {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -976,6 +976,10 @@ pub enum PixelFormat {
|
|||
}
|
||||
|
||||
impl PixelFormat {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
#![cfg_attr(doc, doc = include_str!("../README.md"))]
|
||||
#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
|
||||
#![allow(clippy::arithmetic_side_effects)] // FIXME: remove
|
||||
#![allow(clippy::cast_lossless)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_truncation)] // FIXME: remove
|
||||
#![allow(clippy::cast_possible_wrap)] // FIXME: remove
|
||||
#![allow(clippy::cast_sign_loss)] // FIXME: remove
|
||||
|
||||
use ironrdp_core::{decode_cursor, impl_as_any, ReadCursor};
|
||||
use ironrdp_pdu::gcc::ChannelName;
|
||||
|
|
|
|||
|
|
@ -154,9 +154,15 @@ impl ClientNameRequest {
|
|||
|
||||
pub fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: self.size());
|
||||
|
||||
let encoded_computer_name_length = cast_length!(
|
||||
"encoded computer name length",
|
||||
encoded_str_len(self.computer_name(), self.unicode_flag().into(), true)
|
||||
)?;
|
||||
|
||||
dst.write_u32(self.unicode_flag().into());
|
||||
dst.write_u32(0); // // CodePage (4 bytes): it MUST be set to 0
|
||||
dst.write_u32(encoded_str_len(self.computer_name(), self.unicode_flag().into(), true) as u32);
|
||||
dst.write_u32(encoded_computer_name_length);
|
||||
write_string_to_cursor(dst, self.computer_name(), self.unicode_flag().into(), true)
|
||||
}
|
||||
|
||||
|
|
@ -186,6 +192,10 @@ impl From<ClientNameRequestUnicodeFlag> for CharacterSet {
|
|||
}
|
||||
|
||||
impl From<ClientNameRequestUnicodeFlag> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(val: ClientNameRequestUnicodeFlag) -> Self {
|
||||
val as u32
|
||||
}
|
||||
|
|
@ -431,7 +441,7 @@ impl CapabilityHeader {
|
|||
fn new_general() -> Self {
|
||||
Self {
|
||||
cap_type: CapabilityType::General,
|
||||
length: (Self::SIZE + GeneralCapabilitySet::SIZE) as u16,
|
||||
length: u16::try_from(Self::SIZE + GeneralCapabilitySet::SIZE).expect("value fits into u16"),
|
||||
version: GENERAL_CAPABILITY_VERSION_02,
|
||||
}
|
||||
}
|
||||
|
|
@ -439,7 +449,7 @@ impl CapabilityHeader {
|
|||
fn new_smartcard() -> Self {
|
||||
Self {
|
||||
cap_type: CapabilityType::Smartcard,
|
||||
length: Self::SIZE as u16,
|
||||
length: u16::try_from(Self::SIZE).expect("value fits into u16"),
|
||||
version: SMARTCARD_CAPABILITY_VERSION_01,
|
||||
}
|
||||
}
|
||||
|
|
@ -447,7 +457,7 @@ impl CapabilityHeader {
|
|||
fn new_drive() -> Self {
|
||||
Self {
|
||||
cap_type: CapabilityType::Drive,
|
||||
length: Self::SIZE as u16,
|
||||
length: u16::try_from(Self::SIZE).expect("value fits into u16"),
|
||||
version: DRIVE_CAPABILITY_VERSION_02,
|
||||
}
|
||||
}
|
||||
|
|
@ -490,6 +500,10 @@ enum CapabilityType {
|
|||
}
|
||||
|
||||
impl From<CapabilityType> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(cap_type: CapabilityType) -> Self {
|
||||
cap_type as u16
|
||||
}
|
||||
|
|
@ -990,6 +1004,10 @@ pub enum DeviceType {
|
|||
}
|
||||
|
||||
impl From<DeviceType> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(device_type: DeviceType) -> Self {
|
||||
device_type as u32
|
||||
}
|
||||
|
|
@ -1211,6 +1229,10 @@ impl TryFrom<u32> for MajorFunction {
|
|||
}
|
||||
|
||||
impl From<MajorFunction> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(major_function: MajorFunction) -> Self {
|
||||
major_function as u32
|
||||
}
|
||||
|
|
@ -1253,12 +1275,6 @@ impl From<MinorFunction> for u32 {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<MinorFunction> for u8 {
|
||||
fn from(minor_function: MinorFunction) -> Self {
|
||||
minor_function.0 as u8
|
||||
}
|
||||
}
|
||||
|
||||
/// [2.2.1.4.5] Device Control Request (DR_CONTROL_REQ)
|
||||
///
|
||||
/// [2.2.1.4.5]: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/30662c80-ec6e-4ed1-9004-2e6e367bb59f
|
||||
|
|
|
|||
|
|
@ -574,6 +574,10 @@ impl ReturnCode {
|
|||
}
|
||||
|
||||
impl From<ReturnCode> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(val: ReturnCode) -> Self {
|
||||
val as u32
|
||||
}
|
||||
|
|
@ -1244,7 +1248,7 @@ impl rpce::HeaderlessDecode for TransmitCall {
|
|||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct SCardIORequest {
|
||||
pub protocol: CardProtocol,
|
||||
pub extra_bytes_length: u32,
|
||||
pub extra_bytes_length: usize,
|
||||
pub extra_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
|
|
@ -1255,7 +1259,7 @@ impl ndr::Decode for SCardIORequest {
|
|||
{
|
||||
ensure_size!(in: src, size: size_of::<u32>() * 2);
|
||||
let protocol = CardProtocol::from_bits_retain(src.read_u32());
|
||||
let extra_bytes_length = src.read_u32();
|
||||
let extra_bytes_length = cast_length!("SCardIORequest", "extra_bytes_length", src.read_u32())?;
|
||||
let _extra_bytes_ptr = ndr::decode_ptr(src, index)?;
|
||||
let extra_bytes = Vec::new();
|
||||
Ok(Self {
|
||||
|
|
@ -1267,9 +1271,8 @@ impl ndr::Decode for SCardIORequest {
|
|||
|
||||
fn decode_value(&mut self, src: &mut ReadCursor<'_>, charset: Option<CharacterSet>) -> DecodeResult<()> {
|
||||
expect_no_charset(charset)?;
|
||||
let extra_bytes_length: usize = cast_length!("TransmitCall", "extra_bytes_length", self.extra_bytes_length)?;
|
||||
ensure_size!(in: src, size: extra_bytes_length);
|
||||
self.extra_bytes = src.read_slice(extra_bytes_length).to_vec();
|
||||
ensure_size!(in: src, size: self.extra_bytes_length);
|
||||
self.extra_bytes = src.read_slice(self.extra_bytes_length).to_vec();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1277,8 +1280,11 @@ impl ndr::Decode for SCardIORequest {
|
|||
impl ndr::Encode for SCardIORequest {
|
||||
fn encode_ptr(&self, index: &mut u32, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
ensure_size!(in: dst, size: self.size_ptr());
|
||||
|
||||
let extra_bytes_length = cast_length!("SCardIORequest", "extra_bytes_length", self.extra_bytes_length)?;
|
||||
|
||||
dst.write_u32(self.protocol.bits());
|
||||
ndr::encode_ptr(Some(self.extra_bytes_length), index, dst)
|
||||
ndr::encode_ptr(Some(extra_bytes_length), index, dst)
|
||||
}
|
||||
|
||||
fn encode_value(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
|
||||
|
|
@ -1292,7 +1298,7 @@ impl ndr::Encode for SCardIORequest {
|
|||
}
|
||||
|
||||
fn size_value(&self) -> usize {
|
||||
self.extra_bytes_length as usize
|
||||
self.extra_bytes_length
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1485,6 +1491,10 @@ pub enum CardState {
|
|||
}
|
||||
|
||||
impl From<CardState> for u32 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(val: CardState) -> Self {
|
||||
val as u32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,6 +244,10 @@ impl TryFrom<u8> for Endianness {
|
|||
}
|
||||
|
||||
impl From<Endianness> for u8 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(endianness: Endianness) -> Self {
|
||||
endianness as u8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,6 +374,10 @@ impl TryFrom<u16> for Component {
|
|||
}
|
||||
|
||||
impl From<Component> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(component: Component) -> Self {
|
||||
component as u16
|
||||
}
|
||||
|
|
@ -454,6 +458,10 @@ impl Display for PacketId {
|
|||
}
|
||||
|
||||
impl From<PacketId> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(packet_id: PacketId) -> Self {
|
||||
packet_id as u16
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,10 @@ impl DecodeStream {
|
|||
}
|
||||
};
|
||||
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "opus::Channels has no conversions to usize implemented"
|
||||
)]
|
||||
let mut pcm = vec![0u8; nb_samples * chan as usize * size_of::<i16>()];
|
||||
if let Err(error) = dec.decode(&pkt, bytemuck::cast_slice_mut(pcm.as_mut_slice()), false) {
|
||||
error!(?error, "Failed to decode an Opus packet");
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ impl Rdpsnd {
|
|||
|
||||
server_format
|
||||
.formats
|
||||
.get(format_no as usize)
|
||||
.get(usize::from(format_no))
|
||||
.ok_or_else(|| pdu_other_err!("invalid format"))
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ impl SvcProcessor for Rdpsnd {
|
|||
match pdu {
|
||||
// TODO: handle WaveInfo for < v8
|
||||
pdu::ServerAudioOutputPdu::Wave2(pdu) => {
|
||||
let format_no = pdu.format_no as usize;
|
||||
let format_no = usize::from(pdu.format_no);
|
||||
let ts = pdu.audio_timestamp;
|
||||
self.handler.wave(format_no, ts, pdu.data);
|
||||
return Ok(self.wave_confirm(pdu.timestamp, pdu.block_no)?.into());
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ impl TryFrom<u16> for Version {
|
|||
}
|
||||
|
||||
impl From<Version> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(version: Version) -> Self {
|
||||
version as u16
|
||||
}
|
||||
|
|
@ -442,9 +446,8 @@ impl<'de> Decode<'de> for ClientAudioFormatPdu {
|
|||
ensure_fixed_part_size!(in: src);
|
||||
|
||||
let flags = AudioFormatFlags::from_bits_truncate(src.read_u32());
|
||||
let volume = src.read_u32();
|
||||
let volume_left = (volume & 0xFFFF) as u16;
|
||||
let volume_right = (volume >> 16) as u16;
|
||||
let volume_left = src.read_u16();
|
||||
let volume_right = src.read_u16();
|
||||
let pitch = src.read_u32();
|
||||
let dgram_port = src.read_u16_be();
|
||||
let n_formats = usize::from(src.read_u16());
|
||||
|
|
@ -489,6 +492,10 @@ impl TryFrom<u16> for QualityMode {
|
|||
}
|
||||
|
||||
impl From<QualityMode> for u16 {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn from(mode: QualityMode) -> Self {
|
||||
mode as u16
|
||||
}
|
||||
|
|
@ -626,7 +633,7 @@ impl<'de> Decode<'de> for TrainingPdu {
|
|||
ensure_fixed_part_size!(in: src);
|
||||
|
||||
let timestamp = src.read_u16();
|
||||
let len = src.read_u16() as usize;
|
||||
let len = usize::from(src.read_u16());
|
||||
let data = if len != 0 {
|
||||
if len < Self::FIXED_PART_SIZE + ServerAudioOutputPdu::FIXED_PART_SIZE {
|
||||
return Err(invalid_field_err!("TrainingPdu::wPackSize", "too small"));
|
||||
|
|
@ -839,7 +846,7 @@ impl Encode for WavePdu<'_> {
|
|||
impl WavePdu<'_> {
|
||||
fn decode(src: &mut ReadCursor<'_>, body_size: u16) -> DecodeResult<Self> {
|
||||
let info = WaveInfoPdu::decode(src)?;
|
||||
let body_size = body_size as usize;
|
||||
let body_size = usize::from(body_size);
|
||||
let data_len = body_size
|
||||
.checked_sub(info.size())
|
||||
.ok_or_else(|| invalid_field_err!("Length", "WaveInfo body_size is too small"))?;
|
||||
|
|
@ -1090,9 +1097,8 @@ impl<'de> Decode<'de> for VolumePdu {
|
|||
fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
|
||||
ensure_fixed_part_size!(in: src);
|
||||
|
||||
let volume = src.read_u32();
|
||||
let volume_left = (volume & 0xFFFF) as u16;
|
||||
let volume_right = (volume >> 16) as u16;
|
||||
let volume_left = src.read_u16();
|
||||
let volume_right = src.read_u16();
|
||||
|
||||
Ok(Self {
|
||||
volume_left,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub(crate) struct BitmapEncoder {
|
|||
impl BitmapEncoder {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
buffer: vec![0; u16::MAX as usize],
|
||||
buffer: vec![0; usize::from(u16::MAX)],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,16 @@ enum CodecId {
|
|||
None = 0x0,
|
||||
}
|
||||
|
||||
impl CodecId {
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
|
||||
)]
|
||||
fn as_u8(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "__bench", visibility::make(pub))]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UpdateEncoderCodecs {
|
||||
|
|
@ -389,7 +399,7 @@ impl BitmapUpdateHandler for NoneHandler {
|
|||
for row in bitmap.data.chunks(bitmap.stride.get()).rev() {
|
||||
data.extend_from_slice(&row[..stride]);
|
||||
}
|
||||
set_surface(bitmap, CodecId::None as u8, &data)
|
||||
set_surface(bitmap, CodecId::None.as_u8(), &data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,9 +97,14 @@ impl From<(u16, fast_path::KeyboardFlags)> for KeyboardEvent {
|
|||
}
|
||||
|
||||
impl From<(u16, scan_code::KeyboardFlags)> for KeyboardEvent {
|
||||
#[expect(clippy::cast_possible_truncation)] // we are actually truncating the value
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "we are truncating the value on purpose"
|
||||
)]
|
||||
fn from((key, flags): (u16, scan_code::KeyboardFlags)) -> Self {
|
||||
let extended = flags.contains(scan_code::KeyboardFlags::EXTENDED);
|
||||
|
||||
if flags.contains(scan_code::KeyboardFlags::RELEASE) {
|
||||
KeyboardEvent::Released {
|
||||
code: key as u8,
|
||||
|
|
@ -131,7 +136,11 @@ impl From<SynchronizeFlags> for KeyboardEvent {
|
|||
}
|
||||
|
||||
impl From<SyncToggleFlags> for KeyboardEvent {
|
||||
#[expect(clippy::cast_possible_truncation)] // we are actually truncating the value
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "we are truncating the value on purpose"
|
||||
)]
|
||||
fn from(value: SyncToggleFlags) -> Self {
|
||||
KeyboardEvent::Synchronize(SynchronizeFlags::from_bits_truncate(value.bits() as u8))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ struct PointerRenderingState {
|
|||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
#[expect(clippy::cast_lossless)] // FIXME
|
||||
fn copy_cursor_data(
|
||||
from: &[u8],
|
||||
from_pos: (usize, usize),
|
||||
|
|
@ -124,11 +123,17 @@ fn copy_cursor_data(
|
|||
continue;
|
||||
}
|
||||
|
||||
// Integer alpha blending, source represented as premultiplied alpha color, calculation in floating point
|
||||
to[to_start + pixel * PIXEL_SIZE] = src_r + (((dest_r as u16) * (255 - src_a) as u16) >> 8) as u8;
|
||||
to[to_start + pixel * PIXEL_SIZE + 1] = src_g + (((dest_g as u16) * (255 - src_a) as u16) >> 8) as u8;
|
||||
to[to_start + pixel * PIXEL_SIZE + 2] = src_b + (((dest_b as u16) * (255 - src_a) as u16) >> 8) as u8;
|
||||
// Framebuffer is always opaque, so we can skip alpha channel change
|
||||
#[expect(clippy::as_conversions, reason = "(u16 >> 8) fits into u8 + hot loop")]
|
||||
{
|
||||
// Integer alpha blending, source represented as premultiplied alpha color, calculation in floating point
|
||||
to[to_start + pixel * PIXEL_SIZE] =
|
||||
src_r + ((u16::from(dest_r) * u16::from(255 - src_a)) >> 8) as u8;
|
||||
to[to_start + pixel * PIXEL_SIZE + 1] =
|
||||
src_g + ((u16::from(dest_g) * u16::from(255 - src_a)) >> 8) as u8;
|
||||
to[to_start + pixel * PIXEL_SIZE + 2] =
|
||||
src_b + ((u16::from(dest_b) * u16::from(255 - src_a)) >> 8) as u8;
|
||||
// Framebuffer is always opaque, so we can skip alpha channel change
|
||||
}
|
||||
}
|
||||
} else {
|
||||
to[to_start..to_start + width * PIXEL_SIZE]
|
||||
|
|
@ -227,6 +232,13 @@ impl DecodedImage {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let pointer_src_rect_width = usize::from(self.pointer_src_rect.width());
|
||||
let pointer_src_rect_height = usize::from(self.pointer_src_rect.height());
|
||||
let pointer_draw_x = usize::from(self.pointer_draw_x);
|
||||
let pointer_draw_y = usize::from(self.pointer_draw_y);
|
||||
let width = usize::from(self.width);
|
||||
let height = usize::from(self.height);
|
||||
|
||||
match &layer {
|
||||
PointerLayer::Background => {
|
||||
if self.pointer_backbuffer.is_empty() {
|
||||
|
|
@ -237,15 +249,12 @@ impl DecodedImage {
|
|||
copy_cursor_data(
|
||||
&self.pointer_backbuffer,
|
||||
(0, 0),
|
||||
self.pointer_src_rect.width() as usize * 4,
|
||||
pointer_src_rect_width * 4,
|
||||
&mut self.data,
|
||||
self.width as usize * 4,
|
||||
(self.pointer_draw_x as usize, self.pointer_draw_y as usize),
|
||||
(
|
||||
self.pointer_src_rect.width() as usize,
|
||||
self.pointer_src_rect.height() as usize,
|
||||
),
|
||||
(self.width as usize, self.height as usize),
|
||||
width * 4,
|
||||
(pointer_draw_x, pointer_draw_y),
|
||||
(pointer_src_rect_width, pointer_src_rect_height),
|
||||
(width, height),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
|
@ -254,37 +263,34 @@ impl DecodedImage {
|
|||
let buffer_size = self
|
||||
.pointer_backbuffer
|
||||
.len()
|
||||
.max(self.pointer_src_rect.width() as usize * self.pointer_src_rect.height() as usize * 4);
|
||||
.max(pointer_src_rect_width * pointer_src_rect_height * 4);
|
||||
self.pointer_backbuffer.resize(buffer_size, 0);
|
||||
|
||||
copy_cursor_data(
|
||||
&self.data,
|
||||
(self.pointer_draw_x as usize, self.pointer_draw_y as usize),
|
||||
self.width as usize * 4,
|
||||
(pointer_draw_x, pointer_draw_y),
|
||||
width * 4,
|
||||
&mut self.pointer_backbuffer,
|
||||
self.pointer_src_rect.width() as usize * 4,
|
||||
pointer_src_rect_width * 4,
|
||||
(0, 0),
|
||||
(
|
||||
self.pointer_src_rect.width() as usize,
|
||||
self.pointer_src_rect.height() as usize,
|
||||
),
|
||||
(self.width as usize, self.height as usize),
|
||||
(pointer_src_rect_width, pointer_src_rect_height),
|
||||
(width, height),
|
||||
false,
|
||||
);
|
||||
|
||||
// Draw pointer (with compositing)
|
||||
copy_cursor_data(
|
||||
pointer.bitmap_data.as_slice(),
|
||||
(self.pointer_src_rect.left as usize, self.pointer_src_rect.top as usize),
|
||||
(
|
||||
usize::from(self.pointer_src_rect.left),
|
||||
usize::from(self.pointer_src_rect.top),
|
||||
),
|
||||
usize::from(pointer.width) * 4,
|
||||
&mut self.data,
|
||||
self.width as usize * 4,
|
||||
(self.pointer_draw_x as usize, self.pointer_draw_y as usize),
|
||||
(
|
||||
self.pointer_src_rect.width() as usize,
|
||||
self.pointer_src_rect.height() as usize,
|
||||
),
|
||||
(self.width as usize, self.height as usize),
|
||||
width * 4,
|
||||
(pointer_draw_x, pointer_draw_y),
|
||||
(pointer_src_rect_width, pointer_src_rect_height),
|
||||
(width, height),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
|
@ -312,7 +318,6 @@ impl DecodedImage {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::cast_possible_wrap)] // FIXME
|
||||
fn recalculate_pointer_geometry(&mut self) {
|
||||
let x = self.pointer_x;
|
||||
let y = self.pointer_y;
|
||||
|
|
@ -322,10 +327,10 @@ impl DecodedImage {
|
|||
_ => return,
|
||||
};
|
||||
|
||||
let left_virtual = x as i16 - pointer.hotspot_x as i16;
|
||||
let top_virtual = y as i16 - pointer.hotspot_y as i16;
|
||||
let right_virtual = left_virtual + pointer.width as i16 - 1;
|
||||
let bottom_virtual = top_virtual + pointer.height as i16 - 1;
|
||||
let left_virtual = i32::from(x) - i32::from(pointer.hotspot_x);
|
||||
let top_virtual = i32::from(y) - i32::from(pointer.hotspot_y);
|
||||
let right_virtual = left_virtual + i32::from(pointer.width) - 1;
|
||||
let bottom_virtual = top_virtual + i32::from(pointer.height) - 1;
|
||||
|
||||
let (left, draw_x) = if left_virtual < 0 {
|
||||
// Cut left side if required
|
||||
|
|
@ -342,7 +347,7 @@ impl DecodedImage {
|
|||
};
|
||||
|
||||
// Cut right side if required
|
||||
let right = if right_virtual >= (self.width - 1) as i16 {
|
||||
let right = if right_virtual >= i32::from(self.width - 1) {
|
||||
if draw_x + 1 >= self.width {
|
||||
// Pointer is completely out of bounds horizontally
|
||||
self.pointer_visible_on_screen = false;
|
||||
|
|
@ -355,7 +360,7 @@ impl DecodedImage {
|
|||
};
|
||||
|
||||
// Cut bottom side if required
|
||||
let bottom = if bottom_virtual >= (self.height - 1) as i16 {
|
||||
let bottom = if bottom_virtual >= i32::from(self.height - 1) {
|
||||
if (draw_y + 1) >= self.height {
|
||||
// Pointer is completely out of bounds vertically
|
||||
self.pointer_visible_on_screen = false;
|
||||
|
|
@ -539,7 +544,7 @@ impl DecodedImage {
|
|||
const SRC_COLOR_DEPTH: usize = 2;
|
||||
const DST_COLOR_DEPTH: usize = 4;
|
||||
|
||||
let image_width = self.width as usize;
|
||||
let image_width = usize::from(self.width);
|
||||
let rectangle_width = usize::from(update_rectangle.width());
|
||||
let top = usize::from(update_rectangle.top);
|
||||
let left = usize::from(update_rectangle.left);
|
||||
|
|
@ -586,7 +591,7 @@ impl DecodedImage {
|
|||
const SRC_COLOR_DEPTH: usize = 3;
|
||||
const DST_COLOR_DEPTH: usize = 4;
|
||||
|
||||
let image_width = self.width as usize;
|
||||
let image_width = usize::from(self.width);
|
||||
let top = usize::from(update_rectangle.top);
|
||||
let left = usize::from(update_rectangle.left);
|
||||
|
||||
|
|
@ -636,7 +641,7 @@ impl DecodedImage {
|
|||
const SRC_COLOR_DEPTH: usize = 4;
|
||||
const DST_COLOR_DEPTH: usize = 4;
|
||||
|
||||
let image_width = self.width as usize;
|
||||
let image_width = usize::from(self.width);
|
||||
let rectangle_width = usize::from(update_rectangle.width());
|
||||
let top = usize::from(update_rectangle.top);
|
||||
let left = usize::from(update_rectangle.left);
|
||||
|
|
|
|||
|
|
@ -187,10 +187,11 @@ struct DecodingTileContext {
|
|||
|
||||
impl DecodingTileContext {
|
||||
fn new() -> Self {
|
||||
let tile_size = usize::from(TILE_SIZE);
|
||||
Self {
|
||||
tile_output: vec![0; TILE_SIZE as usize * TILE_SIZE as usize * 4],
|
||||
ycbcr_buffer: vec![vec![0; TILE_SIZE as usize * TILE_SIZE as usize]; 3],
|
||||
ycbcr_temp_buffer: vec![0; TILE_SIZE as usize * TILE_SIZE as usize],
|
||||
tile_output: vec![0; tile_size * tile_size * 4],
|
||||
ycbcr_buffer: vec![vec![0; tile_size * tile_size]; 3],
|
||||
ycbcr_temp_buffer: vec![0; tile_size * tile_size],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ const fn make_gcc_block_buffer<const N: usize>(data_type: u16, buffer: &[u8]) ->
|
|||
|
||||
let array = copy_slice(&data_type.to_le_bytes(), [0; N], 0);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
let length = (buffer.len() + USER_HEADER_LEN) as u16;
|
||||
let array = copy_slice(&length.to_le_bytes(), array, 2);
|
||||
|
||||
|
|
@ -161,6 +162,7 @@ pub static SERVER_GCC_WITH_OPTIONAL_FIELDS: LazyLock<ServerGccBlocks> = LazyLock
|
|||
data
|
||||
});
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const CLIENT_GCC_CORE_BLOCK_BUFFER: [u8; gcc_block_size(
|
||||
CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL_BUFFER,
|
||||
)] = make_gcc_block_buffer(
|
||||
|
|
@ -168,18 +170,22 @@ pub const CLIENT_GCC_CORE_BLOCK_BUFFER: [u8; gcc_block_size(
|
|||
&CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL_BUFFER,
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const CLIENT_GCC_SECURITY_BLOCK_BUFFER: [u8; gcc_block_size(CLIENT_SECURITY_DATA_BUFFER)] =
|
||||
make_gcc_block_buffer(ClientGccType::SecurityData as u16, &CLIENT_SECURITY_DATA_BUFFER);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const CLIENT_GCC_NETWORK_BLOCK_BUFFER: [u8; gcc_block_size(CLIENT_NETWORK_DATA_WITH_CHANNELS_BUFFER)] =
|
||||
make_gcc_block_buffer(
|
||||
ClientGccType::NetworkData as u16,
|
||||
&CLIENT_NETWORK_DATA_WITH_CHANNELS_BUFFER,
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const CLIENT_GCC_CLUSTER_BLOCK_BUFFER: [u8; gcc_block_size(CLUSTER_DATA_BUFFER)] =
|
||||
make_gcc_block_buffer(ClientGccType::ClusterData as u16, &CLUSTER_DATA_BUFFER);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const CLIENT_GCC_MONITOR_BLOCK_BUFFER: [u8; gcc_block_size(
|
||||
crate::monitor_data::MONITOR_DATA_WITH_MONITORS_BUFFER,
|
||||
)] = make_gcc_block_buffer(
|
||||
|
|
@ -187,6 +193,7 @@ pub const CLIENT_GCC_MONITOR_BLOCK_BUFFER: [u8; gcc_block_size(
|
|||
&crate::monitor_data::MONITOR_DATA_WITH_MONITORS_BUFFER,
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const CLIENT_GCC_MONITOR_EXTENDED_BLOCK_BUFFER: [u8; gcc_block_size(
|
||||
crate::monitor_extended_data::MONITOR_DATA_WITH_MONITORS_BUFFER,
|
||||
)] = make_gcc_block_buffer(
|
||||
|
|
@ -194,24 +201,28 @@ pub const CLIENT_GCC_MONITOR_EXTENDED_BLOCK_BUFFER: [u8; gcc_block_size(
|
|||
&crate::monitor_extended_data::MONITOR_DATA_WITH_MONITORS_BUFFER,
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const SERVER_GCC_CORE_BLOCK_BUFFER: [u8; gcc_block_size(SERVER_CORE_DATA_TO_REQUESTED_PROTOCOL_BUFFER)] =
|
||||
make_gcc_block_buffer(
|
||||
ServerGccType::CoreData as u16,
|
||||
&SERVER_CORE_DATA_TO_REQUESTED_PROTOCOL_BUFFER,
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const SERVER_GCC_NETWORK_BLOCK_BUFFER: [u8; gcc_block_size(SERVER_NETWORK_DATA_WITH_CHANNELS_ID_BUFFER)] =
|
||||
make_gcc_block_buffer(
|
||||
ServerGccType::NetworkData as u16,
|
||||
&SERVER_NETWORK_DATA_WITH_CHANNELS_ID_BUFFER,
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const SERVER_GCC_SECURITY_BLOCK_BUFFER: [u8; gcc_block_size(SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_BUFFER)] =
|
||||
make_gcc_block_buffer(
|
||||
ServerGccType::SecurityData as u16,
|
||||
&SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_BUFFER,
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const SERVER_GCC_MESSAGE_CHANNEL_BLOCK_BUFFER: [u8; gcc_block_size(
|
||||
crate::message_channel_data::SERVER_GCC_MESSAGE_CHANNEL_BLOCK_BUFFER,
|
||||
)] = make_gcc_block_buffer(
|
||||
|
|
@ -219,6 +230,7 @@ pub const SERVER_GCC_MESSAGE_CHANNEL_BLOCK_BUFFER: [u8; gcc_block_size(
|
|||
&crate::message_channel_data::SERVER_GCC_MESSAGE_CHANNEL_BLOCK_BUFFER,
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK_BUFFER: [u8; gcc_block_size(
|
||||
crate::multi_transport_channel_data::SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK_BUFFER,
|
||||
)] = make_gcc_block_buffer(
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ pub static SERVER_LICENSE_PDU: LazyLock<LicensePdu> = LazyLock::new(|| {
|
|||
state_transition: LicensingStateTransition::NoTransition,
|
||||
error_info: Vec::new(),
|
||||
};
|
||||
pdu.license_header.preamble_message_size = pdu.size() as u16;
|
||||
pdu.license_header.preamble_message_size = u16::try_from(pdu.size()).unwrap();
|
||||
pdu.into()
|
||||
});
|
||||
pub static SERVER_DEMAND_ACTIVE_PDU: LazyLock<ShareControlHeader> = LazyLock::new(|| ShareControlHeader {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ pub static SERVER_SECURITY_DATA_WITH_MISMATCH_OF_REQUIRED_AND_OPTIONAL_FIELDS: L
|
|||
server_cert: SERVER_CERT_BUFFER.to_vec(),
|
||||
});
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_BUFFER: [u8; 232] = concat_arrays!(
|
||||
SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_PREFIX_BUFFER,
|
||||
(SERVER_RANDOM_BUFFER.len() as u32).to_le_bytes(),
|
||||
|
|
@ -73,6 +74,7 @@ pub const SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_BUFFER: [u8; 232] = concat_a
|
|||
SERVER_CERT_BUFFER
|
||||
);
|
||||
|
||||
#[expect(clippy::as_conversions, reason = "must be const casts")]
|
||||
pub const SERVER_SECURITY_DATA_WITH_INVALID_SERVER_RANDOM_BUFFER: [u8; 233] = concat_arrays!(
|
||||
SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_PREFIX_BUFFER,
|
||||
(SERVER_RANDOM_BUFFER.len() as u32 + 1).to_le_bytes(),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const DATA: [u8; 12] = [0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x
|
|||
const EDGE_CASE_LENGTH: u32 = 0x639;
|
||||
const EDGE_CASE_CHANNEL_ID: u32 = 0x07;
|
||||
const EDGE_CASE_PREFIX: [u8; 4] = [0x24, 0x7, 0x39, 0x6];
|
||||
#[expect(clippy::as_conversions)]
|
||||
const EDGE_CASE_DATA: [u8; EDGE_CASE_LENGTH as usize] = [
|
||||
0xe0, 0x24, 0xa9, 0xba, 0xe0, 0x68, 0xa9, 0xba, 0x8a, 0x73, 0x41, 0x25, 0x12, 0x12, 0x1c, 0x28, 0x3b, 0xa6, 0x34,
|
||||
0x8, 0x8, 0x7a, 0x38, 0x34, 0x2c, 0xe8, 0xf8, 0xd0, 0xef, 0x18, 0xc2, 0xc, 0x27, 0x1f, 0xb1, 0x83, 0x3c, 0x58,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use core::future::Future;
|
|||
use core::net::{IpAddr, Ipv4Addr};
|
||||
use core::pin::Pin;
|
||||
|
||||
use ironrdp_connector::{custom_err, ConnectorResult};
|
||||
use ironrdp_connector::{custom_err, general_err, ConnectorResult};
|
||||
use reqwest::Client;
|
||||
use sspi::{Error, ErrorKind};
|
||||
use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
|
||||
|
|
@ -62,7 +62,10 @@ impl ReqwestNetworkClient {
|
|||
.map_err(|e| Error::new(ErrorKind::NoAuthenticatingAuthority, format!("{e:?}")))
|
||||
.map_err(|e| custom_err!("failed to send KDC request over TCP", e))?;
|
||||
|
||||
let mut buf = vec![0; len as usize + 4];
|
||||
let len = usize::try_from(len)
|
||||
.map_err(|_| general_err!("invalid buffer length: out of range integral type conversion"))?;
|
||||
|
||||
let mut buf = vec![0; len + 4];
|
||||
buf[0..4].copy_from_slice(&(len.to_be_bytes()));
|
||||
|
||||
stream
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use core::num::NonZeroU32;
|
||||
|
||||
use anyhow::Context as _;
|
||||
use ironrdp::pdu::geometry::{InclusiveRectangle, Rectangle as _};
|
||||
use softbuffer::{NoDisplayHandle, NoWindowHandle};
|
||||
use web_sys::HtmlCanvasElement;
|
||||
|
|
@ -61,7 +62,7 @@ impl Canvas {
|
|||
let region_width_usize = usize::from(region_width);
|
||||
|
||||
for dst_row in dst
|
||||
.chunks_exact_mut(self.width.get() as usize)
|
||||
.chunks_exact_mut(usize::try_from(self.width.get()).context("canvas width")?)
|
||||
.skip(region_top_usize)
|
||||
.take(region_height_usize)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ struct SessionBuilderInner {
|
|||
|
||||
use_display_control: bool,
|
||||
enable_credssp: bool,
|
||||
outbound_message_size_limit: Option<u32>,
|
||||
outbound_message_size_limit: Option<usize>,
|
||||
}
|
||||
|
||||
impl Default for SessionBuilderInner {
|
||||
|
|
@ -216,8 +216,8 @@ impl iron_remote_desktop::SessionBuilder for SessionBuilder {
|
|||
|enable_credssp: bool| { self.0.borrow_mut().enable_credssp = enable_credssp };
|
||||
|outbound_message_size_limit: f64| {
|
||||
let limit = if outbound_message_size_limit >= 0.0 && outbound_message_size_limit <= f64::from(u32::MAX) {
|
||||
#[expect(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||
{ outbound_message_size_limit as u32 }
|
||||
#[expect(clippy::as_conversions, clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||
{ outbound_message_size_limit as usize }
|
||||
} else {
|
||||
warn!(outbound_message_size_limit, "Invalid outbound message size limit; fallback to unlimited");
|
||||
0 // Fallback to no limit for invalid values.
|
||||
|
|
@ -899,20 +899,20 @@ fn build_config(
|
|||
async fn writer_task(
|
||||
rx: mpsc::UnboundedReceiver<Vec<u8>>,
|
||||
rdp_writer: WriteHalf<WebSocket>,
|
||||
outbound_limit: Option<u32>,
|
||||
outbound_limit: Option<usize>,
|
||||
) {
|
||||
debug!("writer task started");
|
||||
|
||||
async fn inner(
|
||||
mut rx: mpsc::UnboundedReceiver<Vec<u8>>,
|
||||
mut rdp_writer: WriteHalf<WebSocket>,
|
||||
outbound_limit: Option<u32>,
|
||||
outbound_limit: Option<usize>,
|
||||
) -> anyhow::Result<()> {
|
||||
while let Some(frame) = rx.next().await {
|
||||
match outbound_limit {
|
||||
Some(max_size) if frame.len() > max_size as usize => {
|
||||
Some(max_size) if frame.len() > max_size => {
|
||||
// Send in chunks.
|
||||
for chunk in frame.chunks(max_size as usize) {
|
||||
for chunk in frame.chunks(max_size) {
|
||||
rdp_writer.write_all(chunk).await.context("couldn't write chunk")?;
|
||||
rdp_writer.flush().await.context("couldn't flush chunk")?;
|
||||
}
|
||||
|
|
@ -1153,8 +1153,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::cast_sign_loss)]
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
#[expect(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
||||
fn f64_to_u16_saturating_cast(value: f64) -> u16 {
|
||||
value as u16
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,19 +364,23 @@ fn generate_sine_wave(sample_rate: u32, frequency: f32, duration_ms: u64, phase:
|
|||
use core::f32::consts::PI;
|
||||
|
||||
let total_samples = (u64::from(sample_rate) * duration_ms) / 1000;
|
||||
|
||||
#[expect(clippy::as_conversions)]
|
||||
let delta_phase = 2.0 * PI * frequency / sample_rate as f32;
|
||||
|
||||
let amplitude = 32767.0; // Max amplitude for 16-bit audio
|
||||
|
||||
let capacity = (total_samples as usize) * 2; // 2 channels
|
||||
let capacity = usize::try_from(total_samples).expect("u64-to-usize") * 2; // 2 channels
|
||||
let mut samples = Vec::with_capacity(capacity);
|
||||
|
||||
for _ in 0..total_samples {
|
||||
let sample = (*phase).sin();
|
||||
*phase += delta_phase;
|
||||
// Wrap phase to maintain precision and avoid overflow
|
||||
|
||||
// Wrap phase to maintain precision and avoid overflow.
|
||||
*phase %= 2.0 * PI;
|
||||
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
#[expect(clippy::as_conversions, clippy::cast_possible_truncation)]
|
||||
let sample_i16 = (sample * amplitude) as i16;
|
||||
|
||||
// Write same sample to both channels (stereo)
|
||||
|
|
|
|||
|
|
@ -328,8 +328,11 @@ fn get_json_float(value: &tinyjson::JsonValue, key: &str) -> anyhow::Result<f64>
|
|||
}
|
||||
|
||||
fn get_json_int(value: &tinyjson::JsonValue, key: &str) -> anyhow::Result<u64> {
|
||||
// tinyjson does not expose any integers at all, so we need the f64 to u64 as casting
|
||||
#[expect(clippy::cast_sign_loss)]
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
#[expect(
|
||||
clippy::as_conversions,
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_possible_truncation,
|
||||
reason = "tinyjson does not expose any integers at all, so we need the f64 to u64 as casting"
|
||||
)]
|
||||
get_json_float(value, key).map(|value| value as u64)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue