vncrs 0.1.8

A pure Rust VNC server library for Windows
use super::raw::swap_rb_inplace;
use super::Encoder;
use crate::error::Result;
use flate2::{Compress, Compression, FlushCompress};

pub struct ZlibCompressor {
    compress: Compress,
    raw_buf: Vec<u8>,
}

impl Default for ZlibCompressor {
    fn default() -> Self {
        Self::new()
    }
}

impl ZlibCompressor {
    pub fn new() -> Self {
        Self {
            compress: Compress::new(Compression::fast(), true),
            raw_buf: Vec::with_capacity(64 * 1024),
        }
    }
}

impl Encoder for ZlibCompressor {
    fn encoding_id(&self) -> i32 {
        6
    }

    #[allow(clippy::too_many_arguments)]
    fn encode_rect_into(
        &mut self,
        pixels: &[u8],
        stride: usize,
        x: u16,
        y: u16,
        w: u16,
        h: u16,
        swap_rb: bool,
        out: &mut Vec<u8>,
    ) -> Result<()> {
        let row_bytes = w as usize * 4;
        let total = row_bytes * h as usize;

        self.raw_buf.clear();
        self.raw_buf.reserve(total);

        if x == 0 && row_bytes == stride {
            let start = y as usize * stride;
            self.raw_buf
                .extend_from_slice(&pixels[start..start + total]);
        } else {
            for row in y..y + h {
                let start = row as usize * stride + x as usize * 4;
                self.raw_buf
                    .extend_from_slice(&pixels[start..start + row_bytes]);
            }
        }

        if swap_rb {
            swap_rb_inplace(&mut self.raw_buf);
        }

        let len_pos = out.len();
        out.extend_from_slice(&[0, 0, 0, 0]);

        let before = self.compress.total_out();
        self.compress
            .compress_vec(&self.raw_buf, out, FlushCompress::Partial)
            .map_err(|e| crate::error::VncError::Encoding(e.to_string()))?;
        self.compress
            .compress_vec(&[], out, FlushCompress::Sync)
            .map_err(|e| crate::error::VncError::Encoding(e.to_string()))?;
        let compressed_len = (self.compress.total_out() - before) as usize;

        out.truncate(len_pos + 4 + compressed_len);

        out[len_pos..len_pos + 4].copy_from_slice(&(compressed_len as u32).to_be_bytes());

        Ok(())
    }
}