Skip to main content

unarc_rs/arc/
local_file_header.rs

1use crate::date_time::DosDateTime;
2
3#[repr(u8)]
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum FileType {
6    Binary = 0,
7    Text7Bit = 1,
8    CommentHeader = 2,
9    Directory = 3,
10    VolumeLabel = 4,
11    ChapterLabel = 5,
12    Unknown(u8),
13}
14
15impl From<u8> for FileType {
16    fn from(value: u8) -> Self {
17        match value {
18            0 => FileType::Binary,
19            1 => FileType::Text7Bit,
20            2 => FileType::CommentHeader,
21            3 => FileType::Directory,
22            4 => FileType::VolumeLabel,
23            5 => FileType::ChapterLabel,
24            _ => FileType::Unknown(value),
25        }
26    }
27}
28
29#[repr(u8)]
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum CompressionMethod {
32    Unpacked(u8),
33    /// Run Length Encoding
34    RLE90,
35    /// RLE + Huffman
36    Squeezed,
37    /// Lempel-Zev compression
38    Crunched(u8),
39    Squashed,
40    Crushed,
41    Distilled,
42    Unknown(u8),
43}
44
45impl From<u8> for CompressionMethod {
46    fn from(value: u8) -> Self {
47        match value {
48            1 => CompressionMethod::Unpacked(1),
49            2 => CompressionMethod::Unpacked(2),
50            3 => CompressionMethod::RLE90,
51            4 => CompressionMethod::Squeezed,
52            5 => CompressionMethod::Crunched(5),
53            6 => CompressionMethod::Crunched(6),
54            7 => CompressionMethod::Crunched(7),
55            8 => CompressionMethod::Crunched(8),
56            9 => CompressionMethod::Squashed,
57            10 => CompressionMethod::Crushed,
58            11 => CompressionMethod::Distilled,
59            _ => CompressionMethod::Unknown(value),
60        }
61    }
62}
63
64#[derive(Debug, Clone)]
65pub struct LocalFileHeader {
66    pub compression_method: CompressionMethod,
67    pub name: String,
68    pub compressed_size: u32,
69    pub date_time: DosDateTime,
70    pub crc16: u16,
71    pub original_size: u32,
72}
73
74impl LocalFileHeader {
75    pub fn load_from(mut header_bytes: &[u8]) -> Option<Self> {
76        convert_u8!(compression_method, header_bytes);
77        if compression_method == 0 {
78            return None;
79        }
80        let idx = header_bytes.iter().position(|&x| x == 0).unwrap_or(13);
81        let name = String::from_utf8_lossy(&header_bytes[0..idx]).to_string();
82        header_bytes = &header_bytes[13..];
83        convert_u32!(compressed_size, header_bytes);
84        convert_u32!(date_time, header_bytes);
85        convert_u16!(crc16, header_bytes);
86        convert_u32!(original_size, header_bytes);
87
88        Some(LocalFileHeader {
89            compression_method: compression_method.into(),
90            name,
91            compressed_size,
92            date_time: DosDateTime::new(date_time),
93            crc16,
94            original_size,
95        })
96    }
97}