Skip to main content

rar_stream/parsing/
archive_header.rs

1//! Archive header parser.
2//!
3//! The archive header follows the marker header and contains
4//! archive-level flags and metadata.
5
6use crate::error::{RarError, Result};
7
8#[derive(Debug, Clone)]
9pub struct ArchiveHeader {
10    pub crc: u16,
11    pub header_type: u8,
12    pub flags: u16,
13    pub size: u16,
14    pub reserved1: u16,
15    pub reserved2: u32,
16    // Parsed flags
17    pub has_volume_attributes: bool,
18    pub has_comment: bool,
19    pub is_locked: bool,
20    pub has_solid_attributes: bool,
21    pub is_new_name_scheme: bool,
22    pub has_auth_info: bool,
23    pub has_recovery: bool,
24    pub is_block_encoded: bool,
25    pub is_first_volume: bool,
26}
27
28pub struct ArchiveHeaderParser;
29
30impl ArchiveHeaderParser {
31    pub const HEADER_SIZE: usize = 13;
32
33    pub fn parse(buffer: &[u8]) -> Result<ArchiveHeader> {
34        if buffer.len() < Self::HEADER_SIZE {
35            return Err(RarError::BufferTooSmall {
36                needed: Self::HEADER_SIZE,
37                have: buffer.len(),
38            });
39        }
40
41        let crc = u16::from_le_bytes([buffer[0], buffer[1]]);
42        let header_type = buffer[2];
43        let flags = u16::from_le_bytes([buffer[3], buffer[4]]);
44        let size = u16::from_le_bytes([buffer[5], buffer[6]]);
45        let reserved1 = u16::from_le_bytes([buffer[7], buffer[8]]);
46        let reserved2 = u32::from_le_bytes([buffer[9], buffer[10], buffer[11], buffer[12]]);
47
48        Ok(ArchiveHeader {
49            crc,
50            header_type,
51            flags,
52            size,
53            reserved1,
54            reserved2,
55            has_volume_attributes: (flags & 0x0001) != 0,
56            has_comment: (flags & 0x0002) != 0,
57            is_locked: (flags & 0x0004) != 0,
58            has_solid_attributes: (flags & 0x0008) != 0,
59            is_new_name_scheme: (flags & 0x0010) != 0,
60            has_auth_info: (flags & 0x0020) != 0,
61            has_recovery: (flags & 0x0040) != 0,
62            is_block_encoded: (flags & 0x0080) != 0,
63            is_first_volume: (flags & 0x0100) != 0,
64        })
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn test_parse_archive_header() {
74        let buffer = [
75            0x00, 0x00, // crc
76            0x73, // type (ARCHIVE_HEADER = 0x73)
77            0x01, 0x00, // flags (has_volume_attributes)
78            0x0D, 0x00, // size = 13
79            0x00, 0x00, // reserved1
80            0x00, 0x00, 0x00, 0x00, // reserved2
81        ];
82        let header = ArchiveHeaderParser::parse(&buffer).unwrap();
83        assert_eq!(header.header_type, 0x73);
84        assert!(header.has_volume_attributes);
85        assert!(!header.has_comment);
86    }
87}