Skip to main content

rar_stream/formats/
mod.rs

1//! RAR format detection and signatures.
2//!
3//! Zero dependencies.
4
5/// RAR file signature detection.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Signature {
8    /// RAR 1.5 to 4.x
9    Rar15,
10    /// RAR 5.0+
11    Rar50,
12}
13
14impl Signature {
15    pub const RAR15: &[u8; 7] = b"Rar!\x1a\x07\x00";
16    pub const RAR50: &[u8; 8] = b"Rar!\x1a\x07\x01\x00";
17
18    pub fn size(&self) -> u64 {
19        match self {
20            Self::Rar15 => 7,
21            Self::Rar50 => 8,
22        }
23    }
24
25    pub fn from_bytes(data: &[u8]) -> Option<Self> {
26        if data.len() >= 8 && data.starts_with(Self::RAR50) {
27            Some(Self::Rar50)
28        } else if data.len() >= 7 && data.starts_with(Self::RAR15) {
29            Some(Self::Rar15)
30        } else {
31            None
32        }
33    }
34}
35
36/// Raw timestamp value (Unix nanoseconds).
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
38pub struct RawTimestamp {
39    pub nanos: i64,
40}
41
42impl RawTimestamp {
43    pub fn from_unix_nanos(nanos: i64) -> Self {
44        Self { nanos }
45    }
46
47    pub fn from_dos(dos_time: u32) -> Self {
48        let second = ((dos_time & 0x1f) * 2) as i64;
49        let minute = ((dos_time >> 5) & 0x3f) as i64;
50        let hour = ((dos_time >> 11) & 0x1f) as i64;
51        let day = ((dos_time >> 16) & 0x1f) as i64;
52        let month = ((dos_time >> 21) & 0x0f) as i64;
53        let year = ((dos_time >> 25) + 1980) as i64;
54        
55        let days = (year - 1970) * 365 + (month - 1) * 30 + day;
56        let secs = days * 86400 + hour * 3600 + minute * 60 + second;
57        Self { nanos: secs * 1_000_000_000 }
58    }
59
60    pub fn saturating_add(self, add_nanos: i64) -> Self {
61        Self { nanos: self.nanos.saturating_add(add_nanos) }
62    }
63}
64
65pub fn parse_dos_datetime(dos_time: u32) -> RawTimestamp {
66    RawTimestamp::from_dos(dos_time)
67}
68
69pub fn parse_windows_filetime(filetime: u64) -> RawTimestamp {
70    const WINDOWS_TICK_NS: i128 = 100;
71    const EPOCH_DIFF: i128 = 11_644_473_600_000_000_000;
72    let unix_ns = (filetime as i128) * WINDOWS_TICK_NS - EPOCH_DIFF;
73    RawTimestamp::from_unix_nanos(unix_ns as i64)
74}