use std::io::Write; use std::io; use std::u16; use bitstream::LsbWriter; use byteorder::{LittleEndian, WriteBytesExt}; #[cfg(test)] const BLOCK_SIZE: u16 = 32000; const STORED_FIRST_BYTE: u8 = 0b0000_0000; pub const STORED_FIRST_BYTE_FINAL: u8 = 0b0000_0001; pub const MAX_STORED_BLOCK_LENGTH: usize = (u16::MAX as usize) / 2; pub fn write_stored_header(writer: &mut LsbWriter, final_block: bool) { let header = if final_block { STORED_FIRST_BYTE_FINAL } else { STORED_FIRST_BYTE }; // Write the block header writer.write_bits(header.into(), 3); // Flush the writer to make sure we are aligned to the byte boundary. writer.flush_raw(); } // Compress one stored block (excluding the header) pub fn compress_block_stored(input: &[u8], writer: &mut W) -> io::Result { if input.len() > u16::max_value() as usize { return Err(io::Error::new( io::ErrorKind::InvalidInput, "Stored block too long!", )); }; // The header is written before this function. // The next two bytes indicates the length writer.write_u16::(input.len() as u16)?; // the next two after the length is the ones complement of the length writer.write_u16::(!input.len() as u16)?; // After this the data is written directly with no compression writer.write(input) } #[cfg(test)] pub fn compress_data_stored(input: &[u8]) -> Vec { let block_length = BLOCK_SIZE as usize; let mut output = Vec::with_capacity(input.len() + 2); let mut i = input.chunks(block_length).peekable(); while let Some(chunk) = i.next() { let last_chunk = i.peek().is_none(); // First bit tells us if this is the final chunk // the next two details compression type (none in this case) let first_byte = if last_chunk { STORED_FIRST_BYTE_FINAL } else { STORED_FIRST_BYTE }; output.write(&[first_byte]).unwrap(); compress_block_stored(chunk, &mut output).unwrap(); } output } #[cfg(test)] mod test { use super::*; use test_utils::decompress_to_end; #[test] fn no_compression_one_chunk() { let test_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8]; let compressed = compress_data_stored(&test_data); let result = decompress_to_end(&compressed); assert_eq!(test_data, result); } #[test] fn no_compression_multiple_chunks() { let test_data = vec![32u8; 40000]; let compressed = compress_data_stored(&test_data); let result = decompress_to_end(&compressed); assert_eq!(test_data, result); } #[test] fn no_compression_string() { let test_data = String::from( "This is some text, this is some more text, this is even \ more text, lots of text here.", ).into_bytes(); let compressed = compress_data_stored(&test_data); let result = decompress_to_end(&compressed); assert_eq!(test_data, result); } }