file_endec 1.0.1

Secure file encryption and decryption from the command line.
Documentation
use ::std::io::Read;

use ::brotli::enc::BrotliEncoderParams;
use ::lazy_static::lazy_static;

use crate::header::CompressionAlg;
use crate::util::FedResult;

lazy_static! {
    static ref BROTLI_CONFIG: BrotliEncoderParams = BrotliEncoderParams {
        quality: 6,
        ..Default::default()
    };
}

pub fn compress_file(
    data: Vec<u8>,
    alg: &Option<CompressionAlg>,
    start_progress: &mut impl FnMut(&CompressionAlg),
) -> FedResult<Vec<u8>> {
    match alg {
        Some(alg) => {
            start_progress(&alg);
            match alg {
                CompressionAlg::Brotli => brotli_compress(&data),
            }
        }
        None => Ok(data),
    }
}

pub fn brotli_compress(data: &[u8]) -> FedResult<Vec<u8>> {
    let mut compress = brotli::CompressorReader::new(data, 4096, 6, 22);
    let mut output = Vec::with_capacity(data.len());
    match compress.read_to_end(&mut output) {
        Ok(len) => {
            if len > 0 {
                Ok(output)
            } else {
                Err("No data was read during compression".to_owned())
            }
        }
        Err(err) => Err(format!("Brotli compress error: {}", err)),
    }
}

pub fn decompress_file(
    data: Vec<u8>,
    alg: &Option<CompressionAlg>,
    start_progress: &mut impl FnMut(&CompressionAlg),
) -> FedResult<Vec<u8>> {
    match alg {
        Some(alg) => {
            start_progress(alg);
            match alg {
                CompressionAlg::Brotli => brotli_decompress(&data),
            }
        }
        None => Ok(data),
    }
}

pub fn brotli_decompress(data: &[u8]) -> FedResult<Vec<u8>> {
    let mut decompress = brotli::Decompressor::new(data, 4096);
    let mut output = Vec::with_capacity(data.len());
    match decompress.read_to_end(&mut output) {
        Ok(_) => Ok(output),
        Err(err) => Err(format!("Brotli decompress error: {}", err)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn brotli_compression_empty() {
        let input = vec![];
        let actual = brotli_compress(&input).unwrap();
        let expected = vec![59u8];
        assert_eq!(expected, actual);
    }

    #[test]
    fn brotli_compression() {
        let input = vec![
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
            24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
        ];
        let expected = vec![
            27, 63, 0, 0, 196, 3, 224, 120, 26, 226, 75, 49, 9, 126, 86, 64, 57, 221, 231, 199, 0,
            16, 86, 3,
        ];
        let actual = brotli_compress(&input).unwrap();
        assert_eq!(expected, actual);
    }

    #[test]
    fn brotli_decompression_empty() {
        let input = vec![59];
        let actual = brotli_decompress(&input).unwrap();
        let expected: Vec<u8> = vec![];
        assert_eq!(expected, actual);
    }

    #[test]
    fn brotli_decompression() {
        let expected = vec![
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
            24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
        ];
        let input = vec![
            27, 63, 0, 0, 196, 3, 224, 120, 26, 226, 75, 49, 9, 126, 86, 64, 57, 221, 231, 199, 0,
            16, 86, 3,
        ];
        let actual = brotli_decompress(&input).unwrap();
        assert_eq!(expected, actual);
    }
}