Skip to main content

xz_rs/stream/
footer.rs

1use crate::checksum::{Checksum, Crc32};
2use crate::decode::{Decode, DecodeError};
3use crate::encode::Encode;
4
5use super::{StreamDecodeError, StreamFlags};
6
7const MAGIC_BYTES_LEN: usize = 2;
8const MAGIC_BYTES: [u8; MAGIC_BYTES_LEN] = [0x59, 0x5A];
9
10#[derive(Debug, Clone)]
11pub struct StreamFooter {
12    pub backward_size: u32,
13    pub flags: StreamFlags,
14}
15
16impl Encode for StreamFooter {
17    fn encoding(&self) -> Vec<u8> {
18        let mut crc_32 = Crc32::new();
19
20        let backward_size = self.backward_size.to_le_bytes();
21        crc_32.process_words(&backward_size);
22
23        let flags = self.flags.encoding();
24        crc_32.process_words(&flags);
25
26        let crc_32 = crc_32.result().to_le_bytes();
27
28        crc_32
29            .into_iter()
30            .chain(backward_size)
31            .chain(flags)
32            .chain(MAGIC_BYTES)
33            .collect()
34    }
35}
36
37impl Decode for StreamFooter {
38    fn decode<R: std::io::Read>(src: &mut R) -> Result<Self, DecodeError> {
39        let err = |e| Err(DecodeError::from(e));
40        use StreamDecodeError::*;
41
42        let mut bytes = [0u8; 12];
43        src.read_exact(&mut bytes)?;
44        if bytes[10..] != MAGIC_BYTES {
45            return err(InvalidFooter);
46        }
47
48        let backward_size = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
49
50        let flags = StreamFlags::try_from(&[bytes[8], bytes[9]])?;
51
52        let mut crc_32 = Crc32::new();
53        crc_32.process_words(&bytes[4..10]);
54        if bytes[..4] != crc_32.result().to_le_bytes() {
55            return err(InvalidFooter);
56        }
57
58        Ok(Self {
59            backward_size,
60            flags,
61        })
62    }
63}