mirror of
https://github.com/netbirdio/IronRDP.git
synced 2026-05-22 18:43:12 -07:00
refactor(graphics): hand-implement Error trait
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
committed by
Benoît Cortier
parent
a47a12ce94
commit
cb99c82c7d
Generated
-1
@@ -2590,7 +2590,6 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"thiserror 1.0.69",
|
||||
"yuv",
|
||||
]
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ byteorder = "1.5" # TODO: remove
|
||||
lazy_static.workspace = true # Legacy crate; prefer std::sync::LazyLock or LazyCell
|
||||
num-derive.workspace = true # TODO: remove
|
||||
num-traits.workspace = true # TODO: remove
|
||||
thiserror = "1" # FIXME: handwrite the Error trait implementations.
|
||||
yuv = { version = "0.8", features = ["rdp"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -21,20 +21,55 @@
|
||||
|
||||
use ironrdp_core::ReadCursor;
|
||||
use ironrdp_pdu::pointer::{ColorPointerAttribute, LargePointerAttribute, PointerAttribute};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::color_conversion::rdp_16bit_to_rgb;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug)]
|
||||
pub enum PointerError {
|
||||
#[error("invalid pointer xorMask size. Expected: {expected}, actual: {actual}")]
|
||||
InvalidXorMaskSize { expected: usize, actual: usize },
|
||||
#[error("invalid pointer andMask size. Expected: {expected}, actual: {actual}")]
|
||||
InvalidAndMaskSize { expected: usize, actual: usize },
|
||||
#[error("not supported pointer bpp: {bpp}")]
|
||||
NotSupportedBpp { bpp: u16 },
|
||||
#[error(transparent)]
|
||||
Pdu(#[from] ironrdp_pdu::PduError),
|
||||
Pdu(ironrdp_pdu::PduError),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for PointerError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
PointerError::InvalidXorMaskSize { expected, actual } => {
|
||||
write!(
|
||||
f,
|
||||
"invalid pointer xorMask size. Expected: {expected}, actual: {actual}"
|
||||
)
|
||||
}
|
||||
PointerError::InvalidAndMaskSize { expected, actual } => {
|
||||
write!(
|
||||
f,
|
||||
"invalid pointer andMask size. Expected: {expected}, actual: {actual}"
|
||||
)
|
||||
}
|
||||
PointerError::NotSupportedBpp { bpp } => {
|
||||
write!(f, "not supported pointer bpp: {bpp}")
|
||||
}
|
||||
PointerError::Pdu(err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::error::Error for PointerError {
|
||||
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
|
||||
match self {
|
||||
PointerError::InvalidXorMaskSize { .. } => None,
|
||||
PointerError::InvalidAndMaskSize { .. } => None,
|
||||
PointerError::NotSupportedBpp { .. } => None,
|
||||
PointerError::Pdu(error) => error.source(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ironrdp_pdu::PduError> for PointerError {
|
||||
fn from(error: ironrdp_pdu::PduError) -> Self {
|
||||
PointerError::Pdu(error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents RDP pointer in decoded form (color channels stored as RGBA pre-multiplied values)
|
||||
|
||||
@@ -1,20 +1,53 @@
|
||||
use ironrdp_core::{decode, DecodeError};
|
||||
use ironrdp_pdu::bitmap::rdp6::{BitmapStream as BitmapStreamPdu, ColorPlaneDefinition};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::color_conversion::Rgb;
|
||||
use crate::rdp6::rle::{decompress_8bpp_plane, RleDecodeError};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug)]
|
||||
pub enum BitmapDecodeError {
|
||||
#[error("failed to decode RDP6 bitmap stream PDU: {0}")]
|
||||
Decode(#[from] DecodeError),
|
||||
#[error("failed to perform RLE decompression of RDP6 bitmap stream: {0}")]
|
||||
Rle(#[from] RleDecodeError),
|
||||
#[error("color plane data size provided in PDU is not sufficient to reconstruct the bitmap")]
|
||||
Decode(DecodeError),
|
||||
Rle(RleDecodeError),
|
||||
InvalidUncompressedDataSize,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for BitmapDecodeError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
BitmapDecodeError::Decode(_error) => write!(f, "failed to decode RDP6 bitmap stream PDU"),
|
||||
BitmapDecodeError::Rle(_error) => {
|
||||
write!(f, "failed to perform RLE decompression of RDP6 bitmap stream")
|
||||
}
|
||||
BitmapDecodeError::InvalidUncompressedDataSize => write!(
|
||||
f,
|
||||
"color plane data size provided in PDU is not sufficient to reconstruct the bitmap"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::error::Error for BitmapDecodeError {
|
||||
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
|
||||
match self {
|
||||
BitmapDecodeError::Decode(err) => Some(err),
|
||||
BitmapDecodeError::Rle(err) => Some(err),
|
||||
BitmapDecodeError::InvalidUncompressedDataSize => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DecodeError> for BitmapDecodeError {
|
||||
fn from(err: DecodeError) -> Self {
|
||||
BitmapDecodeError::Decode(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RleDecodeError> for BitmapDecodeError {
|
||||
fn from(err: RleDecodeError) -> Self {
|
||||
BitmapDecodeError::Rle(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements decoding of RDP6 bitmap stream PDU (see [`BitmapStreamPdu`])
|
||||
#[derive(Debug, Default)]
|
||||
pub struct BitmapStreamDecoder {
|
||||
|
||||
@@ -1,17 +1,32 @@
|
||||
use ironrdp_core::{not_enough_bytes_err, EncodeError, WriteCursor};
|
||||
use ironrdp_pdu::bitmap::rdp6::{BitmapStreamHeader, ColorPlaneDefinition};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::rdp6::rle::{compress_8bpp_plane, RleEncodeError};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug)]
|
||||
pub enum BitmapEncodeError {
|
||||
#[error("failed to rle compress")]
|
||||
Rle(RleEncodeError),
|
||||
#[error("failed to encode pdu")]
|
||||
Encode(EncodeError),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for BitmapEncodeError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
BitmapEncodeError::Rle(_error) => write!(f, "failed to rle compress"),
|
||||
BitmapEncodeError::Encode(_error) => write!(f, "failed to encode pdu"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::error::Error for BitmapEncodeError {
|
||||
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
|
||||
match self {
|
||||
BitmapEncodeError::Rle(error) => Some(error),
|
||||
BitmapEncodeError::Encode(error) => Some(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ColorChannels {
|
||||
const STRIDE: usize;
|
||||
const R: usize;
|
||||
|
||||
@@ -3,36 +3,60 @@ use std::io::{Read, Write};
|
||||
|
||||
use byteorder::ReadBytesExt;
|
||||
use ironrdp_core::WriteCursor;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Maximum possible segment size is 47 (run_length = 2, raw_bytes_count = 15), which is treated as
|
||||
/// special mode segment, which repeats last decoded byte in scanline 32 + raw_bytes_count times
|
||||
const MAX_DECODED_SEGMENT_SIZE: usize = 47;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug)]
|
||||
pub enum RleDecodeError {
|
||||
#[error("failed to read RLE-compressed data: {0}")]
|
||||
ReadCompressedData(#[source] std::io::Error),
|
||||
|
||||
#[error("failed to write decompressed data: {0}")]
|
||||
WriteDecompressedData(#[source] std::io::Error),
|
||||
|
||||
#[error("invalid RLE segment header")]
|
||||
ReadCompressedData(std::io::Error),
|
||||
WriteDecompressedData(std::io::Error),
|
||||
InvalidSegmentHeader,
|
||||
|
||||
#[error("decoded scanline segments length exceeds scanline length")]
|
||||
SegmentDoNotFitScanline,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RleEncodeError {
|
||||
#[error("not enough data to compress")]
|
||||
NotEnoughBytes,
|
||||
impl core::fmt::Display for RleDecodeError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
RleDecodeError::ReadCompressedData(_error) => write!(f, "failed to read RLE-compressed data"),
|
||||
RleDecodeError::WriteDecompressedData(_error) => write!(f, "failed to write decompressed data"),
|
||||
RleDecodeError::InvalidSegmentHeader => write!(f, "invalid RLE segment header"),
|
||||
RleDecodeError::SegmentDoNotFitScanline => {
|
||||
write!(f, "decoded scanline segments length exceeds scanline length")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[error("destination buffer is too small")]
|
||||
impl core::error::Error for RleDecodeError {
|
||||
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
|
||||
match self {
|
||||
RleDecodeError::ReadCompressedData(error) => Some(error),
|
||||
RleDecodeError::WriteDecompressedData(error) => Some(error),
|
||||
RleDecodeError::InvalidSegmentHeader => None,
|
||||
RleDecodeError::SegmentDoNotFitScanline => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RleEncodeError {
|
||||
NotEnoughBytes,
|
||||
BufferTooSmall,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for RleEncodeError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
RleEncodeError::NotEnoughBytes => write!(f, "not enough data to compress"),
|
||||
RleEncodeError::BufferTooSmall => write!(f, "destination buffer is too small"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::error::Error for RleEncodeError {}
|
||||
|
||||
/// RLE-encoded color plane decoder implementation for RDP6 bitmap stream
|
||||
#[derive(Debug)]
|
||||
struct RlePlaneDecoder {
|
||||
|
||||
@@ -6,7 +6,6 @@ use bitvec::order::Msb0;
|
||||
use bitvec::prelude::*;
|
||||
use bitvec::slice::BitSlice;
|
||||
use ironrdp_pdu::codecs::rfx::EntropyAlgorithm;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::utils::Bits;
|
||||
|
||||
@@ -355,10 +354,32 @@ impl From<u32> for CompressionMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug)]
|
||||
pub enum RlgrError {
|
||||
#[error("IO error: {0}")]
|
||||
IoError(#[from] io::Error),
|
||||
#[error("the input tile is empty")]
|
||||
IoError(io::Error),
|
||||
EmptyTile,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for RlgrError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::IoError(_error) => write!(f, "IO error"),
|
||||
Self::EmptyTile => write!(f, "the input tile is empty"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::error::Error for RlgrError {
|
||||
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::IoError(error) => Some(error),
|
||||
Self::EmptyTile => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for RlgrError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
Self::IoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ use bitvec::field::BitField as _;
|
||||
use bitvec::order::Msb0;
|
||||
use bitvec::slice::BitSlice;
|
||||
use byteorder::WriteBytesExt;
|
||||
use thiserror::Error;
|
||||
|
||||
use self::circular_buffer::FixedCircularBuffer;
|
||||
use self::control_messages::{BulkEncodedData, CompressionFlags, SegmentedDataPdu};
|
||||
@@ -426,27 +425,54 @@ lazy_static::lazy_static! {
|
||||
];
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug)]
|
||||
pub enum ZgfxError {
|
||||
#[error("IO error")]
|
||||
IOError(#[from] io::Error),
|
||||
#[error("invalid compression type")]
|
||||
IOError(io::Error),
|
||||
InvalidCompressionType,
|
||||
#[error("invalid segmented descriptor")]
|
||||
InvalidSegmentedDescriptor,
|
||||
#[error(
|
||||
"decompressed size of segments ({}) does not equal to uncompressed size ({})",
|
||||
decompressed_size,
|
||||
uncompressed_size
|
||||
)]
|
||||
InvalidDecompressedSize {
|
||||
decompressed_size: usize,
|
||||
uncompressed_size: usize,
|
||||
},
|
||||
#[error("token bits not found")]
|
||||
TokenBitsNotFound,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for ZgfxError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::IOError(_error) => write!(f, "IO error"),
|
||||
Self::InvalidCompressionType => write!(f, "invalid compression type"),
|
||||
Self::InvalidSegmentedDescriptor => write!(f, "invalid segmented descriptor"),
|
||||
Self::InvalidDecompressedSize {
|
||||
decompressed_size,
|
||||
uncompressed_size,
|
||||
} => write!(
|
||||
f,
|
||||
"decompressed size of segments ({decompressed_size}) does not equal to uncompressed size ({uncompressed_size})",
|
||||
),
|
||||
Self::TokenBitsNotFound => write!(f, "token bits not found"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::error::Error for ZgfxError {
|
||||
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::IOError(error) => Some(error),
|
||||
Self::InvalidCompressionType => None,
|
||||
Self::InvalidSegmentedDescriptor => None,
|
||||
Self::InvalidDecompressedSize { .. } => None,
|
||||
Self::TokenBitsNotFound => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for ZgfxError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
Self::IOError(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Generated
-2
@@ -292,7 +292,6 @@ dependencies = [
|
||||
"ironrdp-core",
|
||||
"ironrdp-pdu",
|
||||
"ironrdp-svc",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@@ -374,7 +373,6 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"thiserror",
|
||||
"yuv",
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user