use super::deflate::deflate;
use super::ZopfliOptions;
pub fn gzip_compress(options: &ZopfliOptions, in_: &[u8], out: &mut Vec<u8>) {
let crcvalue = crc32fast::hash(in_);
out.push(31); out.push(139); out.push(8); out.push(0); out.push(0); out.push(0); out.push(0); out.push(0); out.push(2); out.push(3);
deflate(options, 2, true, in_, 0, out);
out.push((crcvalue & 0xff) as u8);
out.push(((crcvalue >> 8) & 0xff) as u8);
out.push(((crcvalue >> 16) & 0xff) as u8);
out.push(((crcvalue >> 24) & 0xff) as u8);
let isize_lo = (in_.len() & 0xffff_ffff) as u32;
out.push((isize_lo & 0xff) as u8);
out.push(((isize_lo >> 8) & 0xff) as u8);
out.push(((isize_lo >> 16) & 0xff) as u8);
out.push(((isize_lo >> 24) & 0xff) as u8);
if options.verbose != 0 {
let removed = if !in_.is_empty() {
100.0 * (in_.len() as f64 - out.len() as f64) / in_.len() as f64
} else {
0.0
};
eprintln!(
"Original Size: {}, Gzip: {}, Compression: {}% Removed",
in_.len(),
out.len(),
removed
);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn header_is_well_formed_and_trailer_records_isize() {
let opts = ZopfliOptions::default();
let mut out = Vec::new();
let data = b"hello, world!\n";
gzip_compress(&opts, data, &mut out);
assert_eq!(out[0], 0x1f);
assert_eq!(out[1], 0x8b);
assert_eq!(out[2], 8);
assert_eq!(out[3], 0);
assert_eq!(&out[4..8], &[0u8, 0, 0, 0]); assert_eq!(out[8], 2); assert_eq!(out[9], 3);
let n = out.len();
let isize_le = u32::from_le_bytes(out[n - 4..n].try_into().unwrap());
assert_eq!(isize_le as usize, data.len());
let crc_le = u32::from_le_bytes(out[n - 8..n - 4].try_into().unwrap());
assert_eq!(crc_le, crc32fast::hash(data));
}
}