use crate::bytes;
use crate::compress::{max_compress_len, Encoder};
use crate::crc32::CheckSummer;
use crate::error::Error;
use crate::MAX_BLOCK_SIZE;
pub const MAX_COMPRESS_BLOCK_SIZE: usize = 76490;
pub const STREAM_IDENTIFIER: &'static [u8] = b"\xFF\x06\x00\x00sNaPpY";
pub const STREAM_BODY: &'static [u8] = b"sNaPpY";
pub const CHUNK_HEADER_AND_CRC_SIZE: usize = 8;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ChunkType {
Stream = 0xFF,
Compressed = 0x00,
Uncompressed = 0x01,
Padding = 0xFE,
}
impl ChunkType {
pub fn from_u8(b: u8) -> Result<ChunkType, u8> {
match b {
0xFF => Ok(ChunkType::Stream),
0x00 => Ok(ChunkType::Compressed),
0x01 => Ok(ChunkType::Uncompressed),
0xFE => Ok(ChunkType::Padding),
b => Err(b),
}
}
}
pub fn compress_frame<'a>(
enc: &mut Encoder,
checksummer: CheckSummer,
src: &'a [u8],
dst_chunk_header: &mut [u8],
dst: &'a mut [u8],
always_use_dst: bool,
) -> Result<&'a [u8], Error> {
assert!(src.len() <= MAX_BLOCK_SIZE);
assert!(dst.len() >= max_compress_len(MAX_BLOCK_SIZE));
assert_eq!(dst_chunk_header.len(), CHUNK_HEADER_AND_CRC_SIZE);
let checksum = checksummer.crc32c_masked(src);
let compress_len = enc.compress(src, dst)?;
let (chunk_type, chunk_len) =
if compress_len >= src.len() - (src.len() / 8) {
(ChunkType::Uncompressed, 4 + src.len())
} else {
(ChunkType::Compressed, 4 + compress_len)
};
dst_chunk_header[0] = chunk_type as u8;
bytes::write_u24_le(chunk_len as u32, &mut dst_chunk_header[1..]);
bytes::write_u32_le(checksum, &mut dst_chunk_header[4..]);
if chunk_type == ChunkType::Compressed {
Ok(&dst[0..compress_len])
} else if always_use_dst {
dst[..src.len()].copy_from_slice(src);
Ok(&dst[..src.len()])
} else {
Ok(src)
}
}