From 83ad04dd56b00deec0730774127ca4b8f74998af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 23 Jul 2025 16:46:26 +0400 Subject: [PATCH] refactor(cliprdr-format): hand-implement Error trait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau --- Cargo.lock | 1 - crates/ironrdp-cliprdr-format/Cargo.toml | 1 - crates/ironrdp-cliprdr-format/src/bitmap.rs | 60 ++++++++++++++++----- crates/ironrdp-cliprdr-format/src/html.rs | 46 ++++++++++++---- fuzz/Cargo.lock | 1 - 5 files changed, 84 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6ea99e7..b54e3827 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2474,7 +2474,6 @@ version = "0.1.3" dependencies = [ "ironrdp-core", "png", - "thiserror 1.0.69", ] [[package]] diff --git a/crates/ironrdp-cliprdr-format/Cargo.toml b/crates/ironrdp-cliprdr-format/Cargo.toml index 63daf219..f2bdcbf5 100644 --- a/crates/ironrdp-cliprdr-format/Cargo.toml +++ b/crates/ironrdp-cliprdr-format/Cargo.toml @@ -17,7 +17,6 @@ test = false [dependencies] ironrdp-core = { path = "../ironrdp-core", version = "0.1" } # public -thiserror = "1" # FIXME: handwrite the Error trait implementations. png = "0.17" [lints] diff --git a/crates/ironrdp-cliprdr-format/src/bitmap.rs b/crates/ironrdp-cliprdr-format/src/bitmap.rs index 590ed98f..497c6bb2 100644 --- a/crates/ironrdp-cliprdr-format/src/bitmap.rs +++ b/crates/ironrdp-cliprdr-format/src/bitmap.rs @@ -2,31 +2,65 @@ use ironrdp_core::{ cast_int, ensure_fixed_part_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor, }; -use thiserror::Error; /// Maximum size of PNG image that could be placed on the clipboard. const MAX_BUFFER_SIZE: usize = 64 * 1024 * 1024; // 64 MB -#[derive(Debug, Error)] +#[derive(Debug)] pub enum BitmapError { - #[error("decoding error")] Decode(ironrdp_core::DecodeError), - #[error("encoding error")] Encode(ironrdp_core::EncodeError), - #[error("unsupported bitmap: {0}")] Unsupported(&'static str), - #[error("one of bitmap's dimensions is invalid")] InvalidSize, - #[error("buffer size required for allocation is too big")] BufferTooBig, - #[error("image width is too big")] WidthTooBig, - #[error("image height is too big")] HeightTooBig, - #[error("PNG encoding error")] - PngEncode(#[from] png::EncodingError), - #[error("PNG decoding error")] - PngDecode(#[from] png::DecodingError), + PngEncode(png::EncodingError), + PngDecode(png::DecodingError), +} + +impl core::fmt::Display for BitmapError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + BitmapError::Decode(_error) => write!(f, "decoding error"), + BitmapError::Encode(_error) => write!(f, "encoding error"), + BitmapError::Unsupported(s) => write!(f, "unsupported bitmap: {s}"), + BitmapError::InvalidSize => write!(f, "one of bitmap's dimensions is invalid"), + BitmapError::BufferTooBig => write!(f, "buffer size required for allocation is too big"), + BitmapError::WidthTooBig => write!(f, "image width is too big"), + BitmapError::HeightTooBig => write!(f, "image height is too big"), + BitmapError::PngEncode(_error) => write!(f, "PNG encoding error"), + BitmapError::PngDecode(_error) => write!(f, "PNG decoding error"), + } + } +} + +impl core::error::Error for BitmapError { + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + match self { + BitmapError::Decode(error) => Some(error), + BitmapError::Encode(error) => Some(error), + BitmapError::Unsupported(_) => None, + BitmapError::InvalidSize => None, + BitmapError::BufferTooBig => None, + BitmapError::WidthTooBig => None, + BitmapError::HeightTooBig => None, + BitmapError::PngEncode(encoding_error) => Some(encoding_error), + BitmapError::PngDecode(decoding_error) => Some(decoding_error), + } + } +} + +impl From for BitmapError { + fn from(error: png::EncodingError) -> Self { + BitmapError::PngEncode(error) + } +} + +impl From for BitmapError { + fn from(error: png::DecodingError) -> Self { + BitmapError::PngDecode(error) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/ironrdp-cliprdr-format/src/html.rs b/crates/ironrdp-cliprdr-format/src/html.rs index 05c89e3b..ed1e2f54 100644 --- a/crates/ironrdp-cliprdr-format/src/html.rs +++ b/crates/ironrdp-cliprdr-format/src/html.rs @@ -1,17 +1,45 @@ -use thiserror::Error; - -#[derive(Debug, Error)] +#[derive(Debug)] pub enum HtmlError { - #[error("invalid CF_HTML format")] InvalidFormat, - #[error("invalid UTF-8")] - InvalidUtf8(#[from] core::str::Utf8Error), - #[error("failed to parse integer")] - InvalidInteger(#[from] core::num::ParseIntError), - #[error("invalid integer conversion")] + InvalidUtf8(core::str::Utf8Error), + InvalidInteger(core::num::ParseIntError), InvalidConversion, } +impl core::fmt::Display for HtmlError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + HtmlError::InvalidFormat => write!(f, "invalid CF_HTML format"), + HtmlError::InvalidUtf8(_error) => write!(f, "invalid UTF-8"), + HtmlError::InvalidInteger(_error) => write!(f, "failed to parse integer"), + HtmlError::InvalidConversion => write!(f, "invalid integer conversion"), + } + } +} + +impl core::error::Error for HtmlError { + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + match self { + HtmlError::InvalidFormat => None, + HtmlError::InvalidUtf8(utf8_error) => Some(utf8_error), + HtmlError::InvalidInteger(parse_int_error) => Some(parse_int_error), + HtmlError::InvalidConversion => None, + } + } +} + +impl From for HtmlError { + fn from(error: core::str::Utf8Error) -> Self { + HtmlError::InvalidUtf8(error) + } +} + +impl From for HtmlError { + fn from(error: core::num::ParseIntError) -> Self { + HtmlError::InvalidInteger(error) + } +} + /// Converts `CF_HTML` format to plain HTML text. /// /// Note that the `CF_HTML` format is using UTF-8, and the input is expected to be valid UTF-8. diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 3084dcc7..69b8c80e 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -302,7 +302,6 @@ version = "0.1.3" dependencies = [ "ironrdp-core", "png", - "thiserror", ] [[package]]