use crate::VncError;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum VncEncoding {
Raw = 0,
CopyRect = 1,
Tight = 7,
Trle = 15,
Zrle = 16,
CursorPseudo = -239,
DesktopSizePseudo = -223,
LastRectPseudo = -224,
}
impl From<u32> for VncEncoding {
fn from(num: u32) -> Self {
match num as i32 {
0 => VncEncoding::Raw,
1 => VncEncoding::CopyRect,
7 => VncEncoding::Tight,
15 => VncEncoding::Trle,
16 => VncEncoding::Zrle,
-239 => VncEncoding::CursorPseudo,
-223 => VncEncoding::DesktopSizePseudo,
-224 => VncEncoding::LastRectPseudo,
_ => VncEncoding::Raw,
}
}
}
impl From<VncEncoding> for u32 {
fn from(e: VncEncoding) -> Self {
e as u32
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq)]
#[repr(u8)]
pub enum VncVersion {
RFB33,
RFB37,
RFB38,
}
impl From<[u8; 12]> for VncVersion {
fn from(version: [u8; 12]) -> Self {
match &version {
b"RFB 003.003\n" => VncVersion::RFB33,
b"RFB 003.007\n" => VncVersion::RFB37,
b"RFB 003.008\n" => VncVersion::RFB38,
_ => VncVersion::RFB33,
}
}
}
impl From<VncVersion> for &[u8; 12] {
fn from(version: VncVersion) -> Self {
match version {
VncVersion::RFB33 => b"RFB 003.003\n",
VncVersion::RFB37 => b"RFB 003.007\n",
VncVersion::RFB38 => b"RFB 003.008\n",
}
}
}
impl VncVersion {
pub(crate) async fn read<S>(reader: &mut S) -> Result<Self, VncError>
where
S: AsyncRead + Unpin,
{
let mut buffer = [0_u8; 12];
reader.read_exact(&mut buffer).await?;
Ok(buffer.into())
}
pub(crate) async fn write<S>(self, writer: &mut S) -> Result<(), VncError>
where
S: AsyncWrite + Unpin,
{
writer
.write_all(&<VncVersion as Into<&[u8; 12]>>::into(self)[..])
.await?;
Ok(())
}
}
#[derive(Debug, Clone, Copy)]
pub struct PixelFormat {
pub bits_per_pixel: u8,
pub depth: u8,
pub big_endian_flag: u8,
pub true_color_flag: u8,
pub red_max: u16,
pub green_max: u16,
pub blue_max: u16,
pub red_shift: u8,
pub green_shift: u8,
pub blue_shift: u8,
_padding_1: u8,
_padding_2: u8,
_padding_3: u8,
}
impl From<PixelFormat> for Vec<u8> {
fn from(pf: PixelFormat) -> Vec<u8> {
vec![
pf.bits_per_pixel,
pf.depth,
pf.big_endian_flag,
pf.true_color_flag,
(pf.red_max >> 8) as u8,
pf.red_max as u8,
(pf.green_max >> 8) as u8,
pf.green_max as u8,
(pf.blue_max >> 8) as u8,
pf.blue_max as u8,
pf.red_shift,
pf.green_shift,
pf.blue_shift,
pf._padding_1,
pf._padding_2,
pf._padding_3,
]
}
}
impl TryFrom<[u8; 16]> for PixelFormat {
type Error = VncError;
fn try_from(pf: [u8; 16]) -> Result<Self, Self::Error> {
let bits_per_pixel = pf[0];
if bits_per_pixel != 8 && bits_per_pixel != 16 && bits_per_pixel != 32 {
return Err(VncError::WrongPixelFormat);
}
let depth = pf[1];
let big_endian_flag = pf[2];
let true_color_flag = pf[3];
let red_max = u16::from_be_bytes(pf[4..6].try_into().unwrap());
let green_max = u16::from_be_bytes(pf[6..8].try_into().unwrap());
let blue_max = u16::from_be_bytes(pf[8..10].try_into().unwrap());
let red_shift = pf[10];
let green_shift = pf[11];
let blue_shift = pf[12];
let _padding_1 = pf[13];
let _padding_2 = pf[14];
let _padding_3 = pf[15];
Ok(PixelFormat {
bits_per_pixel,
depth,
big_endian_flag,
true_color_flag,
red_max,
green_max,
blue_max,
red_shift,
green_shift,
blue_shift,
_padding_1,
_padding_2,
_padding_3,
})
}
}
impl Default for PixelFormat {
fn default() -> Self {
Self {
bits_per_pixel: 32,
depth: 24,
big_endian_flag: 0,
true_color_flag: 1,
red_max: 255,
green_max: 255,
blue_max: 255,
red_shift: 16,
green_shift: 8,
blue_shift: 0,
_padding_1: 0,
_padding_2: 0,
_padding_3: 0,
}
}
}
impl PixelFormat {
pub fn bgra() -> PixelFormat {
PixelFormat::default()
}
pub fn rgba() -> PixelFormat {
Self {
red_shift: 0,
blue_shift: 16,
..Default::default()
}
}
pub(crate) async fn read<S>(reader: &mut S) -> Result<Self, VncError>
where
S: AsyncRead + Unpin,
{
let mut pixel_buffer = [0_u8; 16];
reader.read_exact(&mut pixel_buffer).await?;
pixel_buffer.try_into()
}
}