zrle encoding
This commit is contained in:
parent
ce95686417
commit
b55a58ff38
@ -13,6 +13,8 @@ default = ["console_error_panic_hook"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen = "0.2.83"
|
wasm-bindgen = "0.2.83"
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
|
flate2 = "1"
|
||||||
|
byteorder = "1"
|
||||||
# bytes="1"
|
# bytes="1"
|
||||||
|
|
||||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use std::rc::Rc;
|
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::prelude::*;
|
||||||
use wasm_bindgen::{Clamped, JsCast};
|
use wasm_bindgen::{Clamped, JsCast};
|
||||||
use web_sys::{
|
use web_sys::{
|
||||||
@ -183,12 +186,18 @@ impl Canvas {
|
|||||||
Clamped(&ri.data),
|
Clamped(&ri.data),
|
||||||
ri.width as u32,
|
ri.width as u32,
|
||||||
ri.height as u32,
|
ri.height as u32,
|
||||||
)
|
);
|
||||||
.unwrap();
|
if data.is_err() {
|
||||||
// ConsoleService::log(&format!(
|
console_log!(
|
||||||
// "renderring at ({}, {}), width {}, height {}",
|
"renderring failed at ({}, {}), width {}, height {}, len {}",
|
||||||
// cr.x, cr.y, cr.width, cr.height
|
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);
|
let _ = self.ctx.put_image_data(&data, ri.x as f64, ri.y as f64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ mod des;
|
|||||||
mod vnc_impl;
|
mod vnc_impl;
|
||||||
mod x11cursor;
|
mod x11cursor;
|
||||||
mod x11keyboard;
|
mod x11keyboard;
|
||||||
|
mod zlib;
|
||||||
|
|
||||||
pub enum MouseEventType {
|
pub enum MouseEventType {
|
||||||
Down,
|
Down,
|
||||||
@ -92,10 +93,10 @@ pub struct StreamReader {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl StreamReader {
|
impl StreamReader {
|
||||||
pub fn new(bufs: Vec<Vec<u8>>) -> Self {
|
pub fn new(bufs: Vec<Vec<u8>>, len: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: bufs,
|
inner: bufs,
|
||||||
remain: 0,
|
remain: len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use super::{des, x11cursor::MouseUtils, x11keyboard, MouseEventType};
|
use super::{des, x11cursor::MouseUtils, x11keyboard, zlib, MouseEventType};
|
||||||
use crate::{console_log, log};
|
use crate::{console_log, log};
|
||||||
|
|
||||||
const VNC_RFB33: &[u8; 12] = b"RFB 003.003\n";
|
const VNC_RFB33: &[u8; 12] = b"RFB 003.003\n";
|
||||||
@ -25,6 +25,7 @@ pub enum SecurityType {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub enum VncEncoding {
|
pub enum VncEncoding {
|
||||||
Raw = 0,
|
Raw = 0,
|
||||||
CopyRect = 1,
|
CopyRect = 1,
|
||||||
@ -71,6 +72,7 @@ pub struct Vnc {
|
|||||||
padding_rect: Option<VncRect>,
|
padding_rect: Option<VncRect>,
|
||||||
outbuf: Vec<u8>,
|
outbuf: Vec<u8>,
|
||||||
outs: Vec<VncOutput>,
|
outs: Vec<VncOutput>,
|
||||||
|
zlib_decoder: zlib::Decoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vnc {
|
impl Vnc {
|
||||||
@ -78,18 +80,18 @@ impl Vnc {
|
|||||||
Self {
|
Self {
|
||||||
state: VncState::Init,
|
state: VncState::Init,
|
||||||
supported_encodings: vec![
|
supported_encodings: vec![
|
||||||
VncEncoding::Raw,
|
// VncEncoding::Raw,
|
||||||
VncEncoding::CopyRect,
|
VncEncoding::CopyRect,
|
||||||
// VncEncoding::RRE,
|
// VncEncoding::RRE,
|
||||||
// VncEncoding::Hextile,
|
// VncEncoding::Hextile,
|
||||||
// VncEncoding::TRLE,
|
// VncEncoding::TRLE,
|
||||||
// VncEncoding::ZRLE,
|
VncEncoding::ZRLE,
|
||||||
// VncEncoding::CursorPseudo,
|
// VncEncoding::CursorPseudo,
|
||||||
// VncEncoding::DesktopSizePseudo,
|
// VncEncoding::DesktopSizePseudo,
|
||||||
],
|
],
|
||||||
security_type: SecurityType::Invalid,
|
security_type: SecurityType::Invalid,
|
||||||
challenge: [0; 16],
|
challenge: [0; 16],
|
||||||
reader: StreamReader::new(Vec::with_capacity(10)),
|
reader: StreamReader::new(Vec::with_capacity(10), 0),
|
||||||
mouse: MouseUtils::new(),
|
mouse: MouseUtils::new(),
|
||||||
require: 12, // the handleshake message length
|
require: 12, // the handleshake message length
|
||||||
width: 0,
|
width: 0,
|
||||||
@ -101,24 +103,21 @@ impl Vnc {
|
|||||||
padding_rect: None,
|
padding_rect: None,
|
||||||
outbuf: Vec::with_capacity(128),
|
outbuf: Vec::with_capacity(128),
|
||||||
outs: Vec::with_capacity(10),
|
outs: Vec::with_capacity(10),
|
||||||
|
zlib_decoder: zlib::Decoder::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_input(&mut self, input: Vec<u8>) {
|
pub fn do_input(&mut self, input: Vec<u8>) {
|
||||||
// ConsoleService::info(&format!(
|
// console_log!(
|
||||||
// "VNC input {}, left {}, require {}",
|
// "VNC input {}, left {}, require {}",
|
||||||
// input.len(),
|
// input.len(),
|
||||||
// self.reader.remain(),
|
// self.reader.remain(),
|
||||||
// self.require
|
// self.require
|
||||||
// ));
|
// );
|
||||||
self.reader.append(input);
|
self.reader.append(input);
|
||||||
while self.reader.remain() >= self.require {
|
while self.reader.remain() >= self.require {
|
||||||
self.handle_input();
|
self.handle_input();
|
||||||
// ConsoleService::info(&format!(
|
// console_log!("left {}, require {}", self.reader.remain(), self.require);
|
||||||
// "left {}, require {}",
|
|
||||||
// self.reader.remain(),
|
|
||||||
// self.require
|
|
||||||
// ));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,7 +470,12 @@ impl Vnc {
|
|||||||
self.read_exact(&mut pfb, 16);
|
self.read_exact(&mut pfb, 16);
|
||||||
// This pixel format will be used unless the client requests a different format using the SetPixelFormat message
|
// This pixel format will be used unless the client requests a different format using the SetPixelFormat message
|
||||||
self.pf = (&pfb).into();
|
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.name = self.read_string_l32();
|
||||||
self.state = VncState::Connected;
|
self.state = VncState::Connected;
|
||||||
self.require = 1; // any message from sever will be handled
|
self.require = 1; // any message from sever will be handled
|
||||||
@ -506,7 +510,7 @@ impl Vnc {
|
|||||||
fn handle_framebuffer_update(&mut self) {
|
fn handle_framebuffer_update(&mut self) {
|
||||||
let _padding = self.read_u8();
|
let _padding = self.read_u8();
|
||||||
self.num_rect_left = self.read_u16();
|
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.require = 12; // the length of the first rectangle hdr
|
||||||
self.msg_handling = ServerMessage::FramebufferUpdate;
|
self.msg_handling = ServerMessage::FramebufferUpdate;
|
||||||
}
|
}
|
||||||
@ -546,32 +550,25 @@ impl Vnc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
// we now have an entire rectangle
|
||||||
let rect = self.padding_rect.take().unwrap();
|
let rect = self.padding_rect.take().unwrap();
|
||||||
let mut image_data: Vec<u8> = Vec::with_capacity(self.require);
|
let mut image_data: Vec<u8> = Vec::with_capacity(self.require);
|
||||||
|
self.read_exact_vec(&mut image_data, self.require);
|
||||||
match rect.encoding_type {
|
match rect.encoding_type {
|
||||||
0 => {
|
0 => {
|
||||||
// for _ in 0..rect.height {
|
// raw
|
||||||
// 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);
|
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
let mut x = 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 y < rect.height {
|
||||||
while x < rect.width {
|
while x < rect.width {
|
||||||
let idx = (y as usize * rect.width as usize + x as usize) * 4;
|
let idx = (y as usize * rect.width as usize + x as usize) * 4;
|
||||||
@ -581,21 +578,41 @@ impl Vnc {
|
|||||||
x = 0;
|
x = 0;
|
||||||
y += 1;
|
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 => {
|
1 => {
|
||||||
// copy rectangle
|
// 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;
|
self.num_rect_left -= 1;
|
||||||
if 0 == self.num_rect_left {
|
if 0 == self.num_rect_left {
|
||||||
self.msg_handling = ServerMessage::None;
|
self.msg_handling = ServerMessage::None;
|
||||||
@ -713,8 +730,15 @@ impl Vnc {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_zrle_encoding(&mut self, _x: u16, _y: u16, _width: u16, _height: u16) {
|
fn handle_zrle_encoding(&mut self, x: u16, y: u16, width: u16, height: u16) {
|
||||||
unimplemented!()
|
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) {
|
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 blue-shift
|
||||||
// 1 CARD8 padding
|
// 1 CARD8 padding
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
struct PixelFormat {
|
pub struct PixelFormat {
|
||||||
// the number of bits used for each pixel value on the wire
|
// the number of bits used for each pixel value on the wire
|
||||||
// 8, 16, 32(usually) only
|
// 8, 16, 32(usually) only
|
||||||
bits_per_pixel: u8,
|
pub bits_per_pixel: u8,
|
||||||
depth: u8,
|
pub depth: u8,
|
||||||
// true if multi-byte pixels are interpreted as big endian
|
// 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 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
|
// the next three always in big-endian order
|
||||||
// no matter how the `big_endian_flag` is set
|
// no matter how the `big_endian_flag` is set
|
||||||
red_max: u16,
|
pub red_max: u16,
|
||||||
green_max: u16,
|
pub green_max: u16,
|
||||||
blue_max: u16,
|
pub blue_max: u16,
|
||||||
// the number of shifts needed to get the red value in a pixel to the least significant bit
|
// the number of shifts needed to get the red value in a pixel to the least significant bit
|
||||||
red_shift: u8,
|
pub red_shift: u8,
|
||||||
green_shift: u8,
|
pub green_shift: u8,
|
||||||
blue_shift: u8,
|
pub blue_shift: u8,
|
||||||
padding_1: u8,
|
padding_1: u8,
|
||||||
padding_2: u8,
|
padding_2: u8,
|
||||||
padding_3: u8,
|
padding_3: u8,
|
||||||
@ -818,10 +842,11 @@ impl From<&[u8; 16]> for PixelFormat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VncRect {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
x: u16,
|
pub struct VncRect {
|
||||||
y: u16,
|
pub x: u16,
|
||||||
width: u16,
|
pub y: u16,
|
||||||
height: u16,
|
pub width: u16,
|
||||||
encoding_type: u32,
|
pub height: u16,
|
||||||
|
pub encoding_type: u32,
|
||||||
}
|
}
|
||||||
|
343
webvnc/src/vnc/zlib.rs
Normal file
343
webvnc/src/vnc/zlib.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user