use std::convert::TryInto;
use crate::errors::ParseError;
use crate::protocol::{request_name, ErrorKind};
use crate::utils::RawFdContainer;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct X11Error {
pub error_kind: ErrorKind,
pub error_code: u8,
pub sequence: u16,
pub bad_value: u32,
pub minor_opcode: u16,
pub major_opcode: u8,
pub extension_name: Option<String>,
pub request_name: Option<&'static str>,
}
impl X11Error {
pub fn try_parse(
data: &[u8],
ext_info_provider: &dyn ExtInfoProvider,
) -> Result<Self, ParseError> {
let (response_type, remaining) = u8::try_parse(data)?;
let (error_code, remaining) = u8::try_parse(remaining)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
let (bad_value, remaining) = u32::try_parse(remaining)?;
let (minor_opcode, remaining) = u16::try_parse(remaining)?;
let (major_opcode, _) = u8::try_parse(remaining)?;
if response_type != 0 {
Err(ParseError::InvalidValue)
} else {
let error_kind = ErrorKind::from_wire_error_code(error_code, ext_info_provider);
let extension_name = ext_info_provider
.get_from_major_opcode(major_opcode)
.map(|(name, _)| name.to_string());
let request_name = request_name(extension_name.as_deref(), major_opcode, minor_opcode);
Ok(X11Error {
error_kind,
error_code,
sequence,
bad_value,
minor_opcode,
major_opcode,
extension_name,
request_name,
})
}
}
}
impl From<&X11Error> for [u8; 32] {
fn from(input: &X11Error) -> Self {
let sequence_bytes = input.sequence.serialize();
let bad_value_bytes = input.bad_value.serialize();
let minor_opcode_bytes = input.minor_opcode.serialize();
[
0,
input.error_code,
sequence_bytes[0],
sequence_bytes[1],
bad_value_bytes[0],
bad_value_bytes[1],
bad_value_bytes[2],
bad_value_bytes[3],
minor_opcode_bytes[0],
minor_opcode_bytes[1],
input.major_opcode,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
]
}
}
impl From<X11Error> for [u8; 32] {
fn from(input: X11Error) -> Self {
Self::from(&input)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ExtensionInformation {
pub major_opcode: u8,
pub first_event: u8,
pub first_error: u8,
}
pub trait ExtInfoProvider {
fn get_from_major_opcode(&self, major_opcode: u8) -> Option<(&str, ExtensionInformation)>;
fn get_from_event_code(&self, event_code: u8) -> Option<(&str, ExtensionInformation)>;
fn get_from_error_code(&self, error_code: u8) -> Option<(&str, ExtensionInformation)>;
}
pub trait TryParse: Sized {
fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError>;
}
pub trait TryParseFd: Sized {
fn try_parse_fd<'a>(
value: &'a [u8],
fds: &mut Vec<RawFdContainer>,
) -> Result<(Self, &'a [u8]), ParseError>;
}
impl<T: TryParse> TryParseFd for T {
fn try_parse_fd<'a>(
value: &'a [u8],
_: &mut Vec<RawFdContainer>,
) -> Result<(Self, &'a [u8]), ParseError> {
T::try_parse(value)
}
}
#[derive(Debug, Clone, Copy)]
pub struct RequestHeader {
pub major_opcode: u8,
pub minor_opcode: u8,
pub remaining_length: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BigRequests {
Enabled,
NotEnabled,
}
pub fn parse_request_header(
input: &[u8],
big_requests_enabled: BigRequests,
) -> Result<(RequestHeader, &[u8]), ParseError> {
let (major_opcode, remaining) = u8::try_parse(input)?;
let (minor_opcode, remaining) = u8::try_parse(remaining)?;
let (length, remaining) = u16::try_parse(remaining)?;
let (remaining_length, finally_remaining) = if length == 0 {
if big_requests_enabled == BigRequests::NotEnabled {
return Err(ParseError::InvalidValue);
}
let (length, remaining) = u32::try_parse(remaining)?;
if length < 2 {
return Err(ParseError::InvalidValue);
}
(length - 2, remaining)
} else {
(u32::from(length) - 1, remaining)
};
Ok((
RequestHeader {
major_opcode,
minor_opcode,
remaining_length,
},
finally_remaining,
))
}
pub trait Request {
type Reply: Into<crate::protocol::Reply> + TryParseFd;
fn parse_reply<'a>(
bytes: &'a [u8],
fds: &mut Vec<RawFdContainer>,
) -> Result<(crate::protocol::Reply, &'a [u8]), ParseError> {
let (reply, remaining) = Self::Reply::try_parse_fd(bytes, fds)?;
Ok((reply.into(), remaining))
}
}
pub type ReplyParsingFunction =
for<'a> fn(
&'a [u8],
&mut Vec<RawFdContainer>,
) -> Result<(crate::protocol::Reply, &'a [u8]), ParseError>;
pub trait Serialize {
type Bytes;
fn serialize(&self) -> Self::Bytes;
fn serialize_into(&self, bytes: &mut Vec<u8>);
}
macro_rules! implement_try_parse {
($t:ty) => {
impl TryParse for $t {
fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let len = std::mem::size_of::<$t>();
let bytes = value
.get(..len)
.ok_or(ParseError::InsufficientData)?
.try_into() .unwrap();
Ok((<$t>::from_ne_bytes(bytes), &value[len..]))
}
}
};
}
macro_rules! implement_serialize {
($t:ty: $size:expr) => {
impl Serialize for $t {
type Bytes = [u8; $size];
fn serialize(&self) -> Self::Bytes {
self.to_ne_bytes()
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
bytes.extend_from_slice(&self.to_ne_bytes());
}
}
};
}
macro_rules! forward_float {
($from:ty: $to:ty) => {
impl TryParse for $from {
fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let (data, remaining) = <$to>::try_parse(value)?;
Ok((<$from>::from_bits(data), remaining))
}
}
impl Serialize for $from {
type Bytes = <$to as Serialize>::Bytes;
fn serialize(&self) -> Self::Bytes {
self.to_bits().serialize()
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
self.to_bits().serialize_into(bytes);
}
}
};
}
implement_try_parse!(u8);
implement_try_parse!(i8);
implement_try_parse!(u16);
implement_try_parse!(i16);
implement_try_parse!(u32);
implement_try_parse!(i32);
implement_try_parse!(u64);
implement_try_parse!(i64);
implement_serialize!(u8: 1);
implement_serialize!(i8: 1);
implement_serialize!(u16: 2);
implement_serialize!(i16: 2);
implement_serialize!(u32: 4);
implement_serialize!(i32: 4);
implement_serialize!(u64: 8);
implement_serialize!(i64: 8);
forward_float!(f32: u32);
forward_float!(f64: u64);
impl TryParse for bool {
fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let (data, remaining) = u8::try_parse(value)?;
Ok((data != 0, remaining))
}
}
impl Serialize for bool {
type Bytes = [u8; 1];
fn serialize(&self) -> Self::Bytes {
[u8::from(*self)]
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
bytes.push(u8::from(*self));
}
}
macro_rules! tuple_try_parse {
($($name:ident)*) => {
impl<$($name,)*> TryParse for ($($name,)*)
where $($name: TryParse,)*
{
#[allow(non_snake_case)]
fn try_parse(remaining: &[u8]) -> Result<(($($name,)*), &[u8]), ParseError> {
$(let ($name, remaining) = $name::try_parse(remaining)?;)*
Ok((($($name,)*), remaining))
}
}
}
}
macro_rules! tuple_serialize {
($($name:ident:$idx:tt)*) => {
impl<$($name,)*> Serialize for ($($name,)*)
where $($name: Serialize,)*
{
type Bytes = Vec<u8>;
fn serialize(&self) -> Self::Bytes {
let mut result = Vec::new();
self.serialize_into(&mut result);
result
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
$(self.$idx.serialize_into(bytes);)*
}
}
}
}
macro_rules! tuple_impls {
($($name:ident:$idx:tt)*) => {
tuple_try_parse!($($name)*);
tuple_serialize!($($name:$idx)*);
}
}
impl Serialize for () {
type Bytes = [u8; 0];
fn serialize(&self) -> Self::Bytes {
[]
}
fn serialize_into(&self, _bytes: &mut Vec<u8>) {}
}
impl<T: Serialize> Serialize for (T,) {
type Bytes = T::Bytes;
fn serialize(&self) -> Self::Bytes {
self.0.serialize()
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
self.0.serialize_into(bytes)
}
}
tuple_try_parse!();
tuple_try_parse!(A);
tuple_impls!(A:0 B:1);
tuple_impls!(A:0 B:1 C:2);
tuple_impls!(A:0 B:1 C:2 D:3);
tuple_impls!(A:0 B:1 C:2 D:3 E:4);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12 N:13);
tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12 N:13 O:14);
pub fn parse_list<T>(data: &[u8], list_length: usize) -> Result<(Vec<T>, &[u8]), ParseError>
where
T: TryParse,
{
let mut remaining = data;
let mut result = Vec::with_capacity(list_length);
for _ in 0..list_length {
let (entry, new_remaining) = T::try_parse(remaining)?;
result.push(entry);
remaining = new_remaining;
}
Ok((result, remaining))
}
pub fn parse_u8_list(data: &[u8], list_length: usize) -> Result<(&[u8], &[u8]), ParseError> {
if data.len() < list_length {
Err(ParseError::InsufficientData)
} else {
Ok(data.split_at(list_length))
}
}
impl<T: Serialize> Serialize for [T] {
type Bytes = Vec<u8>;
fn serialize(&self) -> Self::Bytes {
let mut result = Vec::new();
self.serialize_into(&mut result);
result
}
fn serialize_into(&self, bytes: &mut Vec<u8>) {
for item in self {
item.serialize_into(bytes);
}
}
}
macro_rules! bitmask_binop {
($t:ty, $u:ty) => {
impl std::ops::BitOr for $t {
type Output = $t;
fn bitor(self, other: Self) -> Self::Output {
Self::from(<$u>::from(self) | <$u>::from(other))
}
}
impl std::ops::BitOr<$u> for $t {
type Output = $t;
fn bitor(self, other: $u) -> Self::Output {
self | Self::from(other)
}
}
impl std::ops::BitOr<$t> for $u {
type Output = $t;
fn bitor(self, other: $t) -> Self::Output {
<$t>::from(self) | other
}
}
impl std::ops::BitOrAssign<$t> for $u {
fn bitor_assign(&mut self, other: $t) {
*self |= Self::from(other)
}
}
impl std::ops::BitOrAssign<$u> for $t {
fn bitor_assign(&mut self, other: $u) {
*self = *self | Self::from(other)
}
}
};
}
pub(crate) trait TryIntoUSize: TryInto<usize> {
fn try_to_usize(self) -> Result<usize, ParseError> {
self.try_into().or(Err(ParseError::ConversionFailed))
}
}
impl TryIntoUSize for u8 {}
impl TryIntoUSize for u16 {}
impl TryIntoUSize for u32 {}
impl TryIntoUSize for u64 {}
impl TryIntoUSize for i8 {}
impl TryIntoUSize for i16 {}
impl TryIntoUSize for i32 {}
impl TryIntoUSize for i64 {}
#[macro_export]
macro_rules! atom_manager {
{
$vis:vis $struct_name:ident: $cookie_name:ident {
$($field_name:ident$(: $atom_value:expr)?,)*
}
} => {
#[allow(non_snake_case)]
#[derive(Debug)]
$vis struct $cookie_name<'a, C: $crate::protocol::xproto::ConnectionExt> {
phantom: std::marker::PhantomData<&'a C>,
$(
$field_name: $crate::cookie::Cookie<'a, C, $crate::protocol::xproto::InternAtomReply>,
)*
}
#[allow(non_snake_case)]
#[derive(Debug, Clone, Copy)]
$vis struct $struct_name {
$(
$vis $field_name: $crate::protocol::xproto::Atom,
)*
}
impl $struct_name {
$vis fn new<C: $crate::protocol::xproto::ConnectionExt>(
_conn: &C,
) -> ::std::result::Result<$cookie_name<'_, C>, $crate::errors::ConnectionError> {
Ok($cookie_name {
phantom: std::marker::PhantomData,
$(
$field_name: _conn.intern_atom(
false,
$crate::__atom_manager_atom_value!($field_name$(: $atom_value)?),
)?,
)*
})
}
}
impl<'a, C: $crate::protocol::xproto::ConnectionExt> $cookie_name<'a, C> {
$vis fn reply(self) -> ::std::result::Result<$struct_name, $crate::errors::ReplyError> {
Ok($struct_name {
$(
$field_name: self.$field_name.reply()?.atom,
)*
})
}
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __atom_manager_atom_value {
($field_name:ident) => {
stringify!($field_name).as_bytes()
};
($field_name:ident: $atom_value:expr) => {
$atom_value
};
}