use crate::{
constants, errors::UZ2LibErrors, helper::get_sha1_hasher, types::InputArguments,
types::ProcessingResult,
};
use flate2::{Compression, write::ZlibEncoder};
use sha1_smol::Sha1;
use std::{
fs::File,
io::{BufReader, BufWriter, Read, Write},
time::Instant,
};
pub fn compress(
input_stream: &mut BufReader<File>,
output_stream: &mut BufWriter<File>,
input_arguments: &InputArguments,
) -> Result<ProcessingResult, UZ2LibErrors> {
let mut chunk_count: u32 = 0;
let mut buffer: Vec<u8> = vec![0u8; constants::UNCOMPRESSED_CHUNK_SIZE];
let mut encoder: ZlibEncoder<Vec<u8>> = ZlibEncoder::new(Vec::new(), Compression::default());
let mut hasher: Option<Sha1> = get_sha1_hasher(&input_arguments.log_level);
let start: Instant = Instant::now();
loop {
let bytes_read: usize = input_stream.read(&mut buffer)?;
if bytes_read == 0 {
break;
}
let chunk_size_original: &[u8] = &buffer[..bytes_read].len().to_le_bytes()[..4];
let compressed_bytes: Vec<u8> = compress_single_chunk(&buffer[..bytes_read], &mut encoder)?;
let chunk_size_compressed: &[u8] = &compressed_bytes.len().to_le_bytes()[..4];
output_stream.write_all(chunk_size_compressed)?;
output_stream.write_all(chunk_size_original)?;
output_stream.write_all(&compressed_bytes)?;
if let Some(ref mut sha1) = hasher {
sha1.update(chunk_size_compressed);
sha1.update(chunk_size_original);
sha1.update(&compressed_bytes);
}
chunk_count += 1;
}
let input_size: u64 = input_stream.get_mut().metadata()?.len();
let output_size: u64 = output_stream.get_mut().metadata()?.len();
Ok(ProcessingResult {
time: start.elapsed(),
chunk_count,
hasher,
input_file_size: input_size,
output_file_size: output_size,
})
}
fn compress_single_chunk(
buffer: &[u8],
encoder: &mut ZlibEncoder<Vec<u8>>,
) -> Result<Vec<u8>, UZ2LibErrors> {
encoder.write_all(buffer)?;
let compressed_chunk: Vec<u8> = encoder.reset(Vec::new())?;
Ok(compressed_chunk)
}