zrle encoding

This commit is contained in:
Jovi Hsu 2022-10-10 00:23:33 +00:00
parent ce95686417
commit b55a58ff38
5 changed files with 449 additions and 69 deletions

View File

@ -13,6 +13,8 @@ default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.83"
js-sys = "0.3"
flate2 = "1"
byteorder = "1"
# bytes="1"
# The `console_error_panic_hook` crate provides better debugging of panics by

View File

@ -1,6 +1,9 @@
use std::rc::Rc;
use crate::vnc::{ImageData, MouseEventType, Vnc};
use crate::{
console_log, log,
vnc::{ImageData, MouseEventType, Vnc},
};
use wasm_bindgen::prelude::*;
use wasm_bindgen::{Clamped, JsCast};
use web_sys::{
@ -183,12 +186,18 @@ impl Canvas {
Clamped(&ri.data),
ri.width as u32,
ri.height as u32,
)
.unwrap();
// ConsoleService::log(&format!(
// "renderring at ({}, {}), width {}, height {}",
// cr.x, cr.y, cr.width, cr.height
// ));
);
if data.is_err() {
console_log!(
"renderring failed at ({}, {}), width {}, height {}, len {}",
ri.x,
ri.y,
ri.width,
ri.height,
ri.data.len(),
);
}
let data = data.unwrap();
let _ = self.ctx.put_image_data(&data, ri.x as f64, ri.y as f64);
}
}

View File

@ -2,6 +2,7 @@ mod des;
mod vnc_impl;
mod x11cursor;
mod x11keyboard;
mod zlib;
pub enum MouseEventType {
Down,
@ -92,10 +93,10 @@ pub struct StreamReader {
#[allow(dead_code)]
impl StreamReader {
pub fn new(bufs: Vec<Vec<u8>>) -> Self {
pub fn new(bufs: Vec<Vec<u8>>, len: usize) -> Self {
Self {
inner: bufs,
remain: 0,
remain: len,
}
}

View File

@ -1,5 +1,5 @@
use super::*;
use super::{des, x11cursor::MouseUtils, x11keyboard, MouseEventType};
use super::{des, x11cursor::MouseUtils, x11keyboard, zlib, MouseEventType};
use crate::{console_log, log};
const VNC_RFB33: &[u8; 12] = b"RFB 003.003\n";
@ -25,6 +25,7 @@ pub enum SecurityType {
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
#[allow(clippy::upper_case_acronyms)]
pub enum VncEncoding {
Raw = 0,
CopyRect = 1,
@ -71,6 +72,7 @@ pub struct Vnc {
padding_rect: Option<VncRect>,
outbuf: Vec<u8>,
outs: Vec<VncOutput>,
zlib_decoder: zlib::Decoder,
}
impl Vnc {
@ -78,18 +80,18 @@ impl Vnc {
Self {
state: VncState::Init,
supported_encodings: vec![
VncEncoding::Raw,
// VncEncoding::Raw,
VncEncoding::CopyRect,
// VncEncoding::RRE,
// VncEncoding::Hextile,
// VncEncoding::TRLE,
// VncEncoding::ZRLE,
VncEncoding::ZRLE,
// VncEncoding::CursorPseudo,
// VncEncoding::DesktopSizePseudo,
],
security_type: SecurityType::Invalid,
challenge: [0; 16],
reader: StreamReader::new(Vec::with_capacity(10)),
reader: StreamReader::new(Vec::with_capacity(10), 0),
mouse: MouseUtils::new(),
require: 12, // the handleshake message length
width: 0,
@ -101,24 +103,21 @@ impl Vnc {
padding_rect: None,
outbuf: Vec::with_capacity(128),
outs: Vec::with_capacity(10),
zlib_decoder: zlib::Decoder::new(),
}
}
pub fn do_input(&mut self, input: Vec<u8>) {
// ConsoleService::info(&format!(
// console_log!(
// "VNC input {}, left {}, require {}",
// input.len(),
// self.reader.remain(),
// self.require
// ));
// );
self.reader.append(input);
while self.reader.remain() >= self.require {
self.handle_input();
// ConsoleService::info(&format!(
// "left {}, require {}",
// self.reader.remain(),
// self.require
// ));
// console_log!("left {}, require {}", self.reader.remain(), self.require);
}
}
@ -471,7 +470,12 @@ impl Vnc {
self.read_exact(&mut pfb, 16);
// This pixel format will be used unless the client requests a different format using the SetPixelFormat message
self.pf = (&pfb).into();
console_log!("VNC: {}x{}", self.width, self.height);
console_log!(
"VNC: {}x{}\nPixel Format {:#?}",
self.width,
self.height,
self.pf
);
self.name = self.read_string_l32();
self.state = VncState::Connected;
self.require = 1; // any message from sever will be handled
@ -506,7 +510,7 @@ impl Vnc {
fn handle_framebuffer_update(&mut self) {
let _padding = self.read_u8();
self.num_rect_left = self.read_u16();
// console_log!("VNC: {} rects", self.num_rects_left);
// console_log!("VNC: {} rects", self.num_rect_left);
self.require = 12; // the length of the first rectangle hdr
self.msg_handling = ServerMessage::FramebufferUpdate;
}
@ -546,32 +550,25 @@ impl Vnc {
}
}
} else {
match self.padding_rect.as_ref().unwrap().encoding_type {
16 => {
if self.require == 4 {
self.require = self.read_u32() as usize;
return;
}
}
_ => (),
}
// we now have an entire rectangle
let rect = self.padding_rect.take().unwrap();
let mut image_data: Vec<u8> = Vec::with_capacity(self.require);
self.read_exact_vec(&mut image_data, self.require);
match rect.encoding_type {
0 => {
// for _ in 0..rect.height {
// for _ in 0..rect.width {
// let mut pixel = [0u8; 4];
// self.read_exact(&mut pixel, 4);
// let b = pixel[0];
// let g = pixel[1];
// let r = pixel[2];
// let a = pixel[3];
// image_data.extend_from_slice(&[r, g, b, a]);
// }
// }
self.read_exact_vec(&mut image_data, self.require);
// raw
let mut y = 0;
let mut x = 0;
// for y in 0..rect.height {
// for x in 0..rect.width {
// let idx = (y as usize * rect.width as usize + x as usize) * 4;
// image_data.swap(idx, idx + 2)
// }
// }
while y < rect.height {
while x < rect.width {
let idx = (y as usize * rect.width as usize + x as usize) * 4;
@ -581,21 +578,41 @@ impl Vnc {
x = 0;
y += 1;
}
self.outs.push(VncOutput::RenderImage(ImageData {
type_: rect.encoding_type,
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
data: image_data,
}));
}
1 => {
// copy rectangle
self.read_exact_vec(&mut image_data, 4);
self.outs.push(VncOutput::RenderImage(ImageData {
type_: rect.encoding_type,
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
data: image_data,
}));
}
_ => unimplemented!(),
16 => {
// ZRLE
match self.zlib_decoder.decode(&self.pf, &rect, &image_data) {
Ok(images) => {
for i in images {
self.outs.push(VncOutput::RenderImage(i));
}
}
Err(e) => {
self.outs.push(VncOutput::Err(format!("{:?}", e)));
}
}
}
_ => unimplemented!("Unknow encoding {}", rect.encoding_type),
}
self.outs.push(VncOutput::RenderImage(ImageData {
type_: rect.encoding_type,
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
data: image_data,
}));
self.num_rect_left -= 1;
if 0 == self.num_rect_left {
self.msg_handling = ServerMessage::None;
@ -713,8 +730,15 @@ impl Vnc {
unimplemented!()
}
fn handle_zrle_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) {
unimplemented!()
fn handle_zrle_encoding(&mut self, x: u16, y: u16, width: u16, height: u16) {
self.require = 4;
self.padding_rect = Some(VncRect {
x,
y,
width,
height,
encoding_type: 16,
})
}
fn handle_cursor_pseudo_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) {
@ -739,24 +763,24 @@ impl Vnc {
// 1 CARD8 blue-shift
// 1 CARD8 padding
#[derive(Debug, Clone, Copy, Default)]
struct PixelFormat {
pub struct PixelFormat {
// the number of bits used for each pixel value on the wire
// 8, 16, 32(usually) only
bits_per_pixel: u8,
depth: u8,
pub bits_per_pixel: u8,
pub depth: u8,
// true if multi-byte pixels are interpreted as big endian
big_endian_flag: u8,
pub big_endian_flag: u8,
// true then the last six items specify how to extract the red, green and blue intensities from the pixel value
true_color_flag: u8,
pub true_color_flag: u8,
// the next three always in big-endian order
// no matter how the `big_endian_flag` is set
red_max: u16,
green_max: u16,
blue_max: u16,
pub red_max: u16,
pub green_max: u16,
pub blue_max: u16,
// the number of shifts needed to get the red value in a pixel to the least significant bit
red_shift: u8,
green_shift: u8,
blue_shift: u8,
pub red_shift: u8,
pub green_shift: u8,
pub blue_shift: u8,
padding_1: u8,
padding_2: u8,
padding_3: u8,
@ -818,10 +842,11 @@ impl From<&[u8; 16]> for PixelFormat {
}
}
struct VncRect {
x: u16,
y: u16,
width: u16,
height: u16,
encoding_type: u32,
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VncRect {
pub x: u16,
pub y: u16,
pub width: u16,
pub height: u16,
pub encoding_type: u32,
}

343
webvnc/src/vnc/zlib.rs Normal file
View File

@ -0,0 +1,343 @@
/*
Copyright (c) 2016 whitequark <whitequark@whitequark.org>
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
use super::vnc_impl::*;
use super::ImageData;
use byteorder::ReadBytesExt;
use std::io::{Read, Result};
struct ZlibReader<'a> {
decompressor: flate2::Decompress,
input: &'a [u8],
}
impl<'a> ZlibReader<'a> {
fn new(decompressor: flate2::Decompress, input: &'a [u8]) -> ZlibReader<'a> {
ZlibReader {
decompressor,
input,
}
}
fn into_inner(self) -> Result<flate2::Decompress> {
if self.input.is_empty() {
Ok(self.decompressor)
} else {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"leftover ZRLE byte data",
))
}
}
}
impl<'a> Read for ZlibReader<'a> {
fn read(&mut self, output: &mut [u8]) -> std::io::Result<usize> {
let in_before = self.decompressor.total_in();
let out_before = self.decompressor.total_out();
let result =
self.decompressor
.decompress(self.input, output, flate2::FlushDecompress::None);
let consumed = (self.decompressor.total_in() - in_before) as usize;
let produced = (self.decompressor.total_out() - out_before) as usize;
self.input = &self.input[consumed..];
match result {
Ok(flate2::Status::Ok) => Ok(produced),
Ok(flate2::Status::BufError) => Ok(0),
Err(error) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, error)),
Ok(flate2::Status::StreamEnd) => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"ZRLE stream end",
)),
}
}
}
struct BitReader<T: Read> {
reader: T,
buffer: u8,
position: usize,
}
impl<T: Read> BitReader<T> {
fn new(reader: T) -> BitReader<T> {
BitReader {
reader,
buffer: 0,
position: 8,
}
}
fn into_inner(self) -> Result<T> {
if self.position == 8 {
Ok(self.reader)
} else {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"leftover ZRLE bit data",
))
}
}
fn read_bits(&mut self, count: usize) -> std::io::Result<u8> {
assert!(count > 0 && count <= 8);
if self.position == 8 {
self.buffer = self.reader.read_u8()?;
self.position = 0;
}
if self.position + count <= 8 {
let shift = 8 - (count + self.position);
let mask = (1 << count) - 1;
let result = (self.buffer >> shift) & mask;
self.position += count;
Ok(result)
} else {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"unaligned ZRLE bit read",
))
}
}
fn read_bit(&mut self) -> std::io::Result<bool> {
Ok(self.read_bits(1)? != 0)
}
fn align(&mut self) {
self.position = 8;
}
}
impl<T: Read> Read for BitReader<T> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if self.position == 8 {
self.reader.read(buf)
} else {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"unaligned ZRLE byte read",
))
}
}
}
pub struct Decoder {
decompressor: Option<flate2::Decompress>,
}
impl Decoder {
pub fn new() -> Decoder {
Decoder {
decompressor: Some(flate2::Decompress::new(/*zlib_header*/ true)),
}
}
pub fn decode(
&mut self,
format: &PixelFormat,
rect: &VncRect,
input: &[u8],
) -> Result<Vec<ImageData>> {
fn read_run_length(reader: &mut dyn Read) -> Result<usize> {
let mut run_length_part;
let mut run_length = 1;
loop {
run_length_part = reader.read_u8()?;
run_length += run_length_part as usize;
if 255 != run_length_part {
break;
}
}
Ok(run_length)
}
fn copy_true_color(
reader: &mut dyn Read,
pixels: &mut Vec<u8>,
pad: bool,
compressed_bpp: usize,
bpp: usize,
) -> Result<()> {
let mut buf = [255; 4];
reader.read_exact(&mut buf[pad as usize..pad as usize + compressed_bpp])?;
buf.swap(0, 2);
pixels.extend_from_slice(&buf[..bpp]);
Ok(())
}
fn copy_indexed(palette: &[u8], pixels: &mut Vec<u8>, bpp: usize, index: u8) {
let start = index as usize * bpp;
pixels.extend_from_slice(&palette[start..start + bpp])
}
let mut ret = Vec::new();
let bpp = format.bits_per_pixel as usize / 8;
let pixel_mask = (format.red_max as u32) << format.red_shift
| (format.green_max as u32) << format.green_shift
| (format.blue_max as u32) << format.blue_shift;
let (compressed_bpp, pad_pixel) =
if format.bits_per_pixel == 32 && format.true_color_flag > 0 && format.depth <= 24 {
if pixel_mask & 0x000000ff == 0 {
(3, format.big_endian_flag > 0)
} else if pixel_mask & 0xff000000 == 0 {
(3, format.big_endian_flag == 0)
} else {
(4, false)
}
} else {
(bpp, false)
};
let mut palette = Vec::with_capacity(128 * bpp);
let mut reader = BitReader::new(ZlibReader::new(self.decompressor.take().unwrap(), input));
let mut y = 0;
while y < rect.height {
let height = if y + 64 > rect.height {
rect.height - y
} else {
64
};
let mut x = 0;
while x < rect.width {
let width = if x + 64 > rect.width {
rect.width - x
} else {
64
};
let pixel_count = height as usize * width as usize;
let is_rle = reader.read_bit()?;
let palette_size = reader.read_bits(7)?;
palette.truncate(0);
for _ in 0..palette_size {
copy_true_color(&mut reader, &mut palette, pad_pixel, compressed_bpp, bpp)?
}
let mut pixels = Vec::with_capacity(pixel_count * bpp);
match (is_rle, palette_size) {
(false, 0) => {
// True Color pixels
for _ in 0..pixel_count {
copy_true_color(
&mut reader,
&mut pixels,
pad_pixel,
compressed_bpp,
bpp,
)?
}
}
(false, 1) => {
// Color fill
for _ in 0..pixel_count {
copy_indexed(&palette, &mut pixels, bpp, 0)
}
}
(false, 2) | (false, 3..=4) | (false, 5..=16) => {
// Indexed pixels
let bits_per_index = match palette_size {
2 => 1,
3..=4 => 2,
5..=16 => 4,
_ => unreachable!(),
};
for _ in 0..height {
for _ in 0..width {
let index = reader.read_bits(bits_per_index)?;
copy_indexed(&palette, &mut pixels, bpp, index)
}
reader.align();
}
}
(true, 0) => {
// True Color RLE
let mut count = 0;
let mut pixel = Vec::new();
while count < pixel_count {
pixel.truncate(0);
copy_true_color(
&mut reader,
&mut pixel,
pad_pixel,
compressed_bpp,
bpp,
)?;
let run_length = read_run_length(&mut reader)?;
for _ in 0..run_length {
pixels.extend(&pixel)
}
count += run_length;
}
}
(true, 2..=127) => {
// Indexed RLE
let mut count = 0;
while count < pixel_count {
let longer_than_one = reader.read_bit()?;
let index = reader.read_bits(7)?;
let run_length = if longer_than_one {
read_run_length(&mut reader)?
} else {
1
};
for _ in 0..run_length {
copy_indexed(&palette, &mut pixels, bpp, index);
}
count += run_length;
}
}
_ => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"ZRLE subencoding",
))
}
}
ret.push(ImageData {
data: pixels,
height,
width,
x: rect.x + x,
y: rect.y + y,
type_: 0,
});
x += width;
}
y += height;
}
self.decompressor = Some(reader.into_inner()?.into_inner()?);
Ok(ret)
}
}