rar_stream/parsing/
marker_header.rs1use crate::error::{RarError, Result};
8
9pub const RAR4_SIGNATURE: [u8; 7] = [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00];
11
12pub const RAR5_SIGNATURE: [u8; 8] = [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00];
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17pub enum RarVersion {
18 #[default]
20 Rar4,
21 Rar5,
23}
24
25impl RarVersion {
26 pub fn signature_size(&self) -> usize {
28 match self {
29 Self::Rar4 => 7,
30 Self::Rar5 => 8,
31 }
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct MarkerHeader {
37 pub crc: u16,
38 pub header_type: u8,
39 pub flags: u16,
40 pub size: u32,
41 pub version: RarVersion,
42}
43
44pub struct MarkerHeaderParser;
45
46impl MarkerHeaderParser {
47 pub const HEADER_SIZE: usize = 7;
48
49 pub fn detect_version(buffer: &[u8]) -> Result<RarVersion> {
51 if buffer.len() >= 8 && buffer[..8] == RAR5_SIGNATURE {
52 return Ok(RarVersion::Rar5);
53 }
54 if buffer.len() >= 7 && buffer[..7] == RAR4_SIGNATURE {
55 return Ok(RarVersion::Rar4);
56 }
57 Err(RarError::InvalidSignature)
58 }
59
60 pub fn parse(buffer: &[u8]) -> Result<MarkerHeader> {
64 if buffer.len() < Self::HEADER_SIZE {
65 return Err(RarError::BufferTooSmall {
66 needed: Self::HEADER_SIZE,
67 have: buffer.len(),
68 });
69 }
70
71 if buffer.len() >= 8 && buffer[..8] == RAR5_SIGNATURE {
73 return Ok(MarkerHeader {
74 crc: 0,
75 header_type: 0,
76 flags: 0,
77 size: 8,
78 version: RarVersion::Rar5,
79 });
80 }
81
82 if buffer[..7] != RAR4_SIGNATURE {
84 return Err(RarError::InvalidSignature);
85 }
86
87 let crc = u16::from_le_bytes([buffer[0], buffer[1]]);
89 let header_type = buffer[2];
90 let flags = u16::from_le_bytes([buffer[3], buffer[4]]);
91 let size = u16::from_le_bytes([buffer[5], buffer[6]]) as u32;
92
93 Ok(MarkerHeader {
94 crc,
95 header_type,
96 flags,
97 size,
98 version: RarVersion::Rar4,
99 })
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_parse_rar4_marker() {
109 let buffer = [
111 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, ];
114 let header = MarkerHeaderParser::parse(&buffer).unwrap();
115 assert_eq!(header.header_type, b'r'); }
117
118 #[test]
119 fn test_invalid_signature() {
120 let buffer = [0x00; 11];
121 assert!(matches!(
122 MarkerHeaderParser::parse(&buffer),
123 Err(RarError::InvalidSignature)
124 ));
125 }
126
127 #[test]
128 fn test_buffer_too_small() {
129 let buffer = [0x52, 0x61, 0x72];
130 assert!(matches!(
131 MarkerHeaderParser::parse(&buffer),
132 Err(RarError::BufferTooSmall { .. })
133 ));
134 }
135}