Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/lzma-rs-0.2.0/src/xz/mod.rs
Line
Count
Source
1
//! Logic for handling `.xz` file format.
2
//!
3
//! Format specifications are at [https://tukaani.org/xz/xz-file-format.txt](spec).
4
//!
5
//! [spec]: https://tukaani.org/xz/xz-file-format.txt
6
7
use crate::error;
8
use std::io;
9
10
pub(crate) mod footer;
11
pub(crate) mod header;
12
13
/// Stream flags, see sect. 2.1.1.2.
14
///
15
/// This does not store the leading null byte, which is currently unused.
16
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17
pub(crate) struct StreamFlags {
18
    pub(crate) check_method: CheckMethod,
19
}
20
21
impl StreamFlags {
22
    /// Parse Stream Flags from a 16bits value.
23
0
    pub(crate) fn parse(input: u16) -> error::Result<Self> {
24
0
        let flags_bytes = input.to_be_bytes();
25
26
0
        if flags_bytes[0] != 0x00 {
27
0
            return Err(error::Error::XzError(format!(
28
0
                "Invalid null byte in Stream Flags: {:x}",
29
0
                flags_bytes[0]
30
0
            )));
31
0
        }
32
33
0
        let flags = Self {
34
0
            check_method: CheckMethod::try_from(flags_bytes[1])?,
35
        };
36
0
        Ok(flags)
37
0
    }
38
39
    /// Serialize Stream Flags into a writer.
40
0
    pub(crate) fn serialize<W>(self, writer: &mut W) -> io::Result<usize>
41
0
    where
42
0
        W: io::Write,
43
    {
44
        // First byte is currently unused and hard-coded to null.
45
0
        writer
46
0
            .write(&[0x00, self.check_method as u8])
47
0
            .map_err(Into::into)
48
0
    }
49
}
50
51
/// Stream check type, see sect. 2.1.1.2.
52
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
53
#[repr(u8)]
54
pub enum CheckMethod {
55
    None = 0x00,
56
    Crc32 = 0x01,
57
    Crc64 = 0x04,
58
    Sha256 = 0x0A,
59
}
60
61
impl CheckMethod {
62
    /// Parse Check ID (second byte in Stream Flags).
63
0
    pub fn try_from(id: u8) -> error::Result<CheckMethod> {
64
0
        match id {
65
0
            0x00 => Ok(CheckMethod::None),
66
0
            0x01 => Ok(CheckMethod::Crc32),
67
0
            0x04 => Ok(CheckMethod::Crc64),
68
0
            0x0A => Ok(CheckMethod::Sha256),
69
0
            _ => Err(error::Error::XzError(format!(
70
0
                "Invalid check method {:x}, expected one of [0x00, 0x01, 0x04, 0x0A]",
71
0
                id
72
0
            ))),
73
        }
74
0
    }
75
}
76
77
impl From<CheckMethod> for u8 {
78
0
    fn from(method: CheckMethod) -> u8 {
79
0
        method as u8
80
0
    }
81
}
82
83
#[cfg(test)]
84
mod test {
85
    use super::*;
86
    use byteorder::{BigEndian, ReadBytesExt};
87
    use std::io::{Seek, SeekFrom};
88
89
    #[test]
90
    fn test_checkmethod_roundtrip() {
91
        let mut count_valid = 0;
92
        for input in 0..std::u8::MAX {
93
            if let Ok(check) = CheckMethod::try_from(input) {
94
                let output: u8 = check.into();
95
                assert_eq!(input, output);
96
                count_valid += 1;
97
            }
98
        }
99
        assert_eq!(count_valid, 4);
100
    }
101
102
    #[test]
103
    fn test_streamflags_roundtrip() {
104
        let input = StreamFlags {
105
            check_method: CheckMethod::Crc32,
106
        };
107
108
        let mut cursor = std::io::Cursor::new(vec![0u8; 2]);
109
        let len = input.serialize(&mut cursor).unwrap();
110
        assert_eq!(len, 2);
111
112
        cursor.seek(SeekFrom::Start(0)).unwrap();
113
        let field = cursor.read_u16::<BigEndian>().unwrap();
114
        let output = StreamFlags::parse(field).unwrap();
115
        assert_eq!(input, output);
116
    }
117
}