1use crate::date_time::DosDateTime;
4
5pub const ACE_MAGIC: &[u8; 7] = b"**ACE**";
7
8#[allow(dead_code)]
10pub mod header_type {
11 pub const MAIN: u8 = 0;
12 pub const FILE: u8 = 1;
13 pub const RECOVERY32: u8 = 2;
14 pub const RECOVERY64A: u8 = 3;
15 pub const RECOVERY64B: u8 = 4;
16}
17
18#[allow(dead_code)]
20pub mod header_flags {
21 pub const ADDSIZE: u16 = 0x0001;
22 pub const COMMENT: u16 = 0x0002;
23 pub const MEMORY_64BIT: u16 = 0x0004;
24 pub const AV_STRING: u16 = 0x0008;
25 pub const SOLID: u16 = 0x0010;
26 pub const LOCKED: u16 = 0x0020;
27 pub const PROTECTED: u16 = 0x0040;
28 pub const PASSWORD: u16 = 0x0080;
29 pub const V20FORMAT: u16 = 0x0100;
31 pub const SFX: u16 = 0x0200;
32 pub const LIMITSFXJR: u16 = 0x0400;
33 pub const MULTIVOLUME: u16 = 0x0800;
34 pub const ADVERT: u16 = 0x1000;
35 pub const RECOVERY: u16 = 0x2000;
36 pub const LOCKED_MAIN: u16 = 0x4000;
37 pub const SOLID_MAIN: u16 = 0x8000;
38 pub const NTSECURITY: u16 = 0x0400;
40 pub const CONTINUED_PREV: u16 = 0x1000;
41 pub const CONTINUED_NEXT: u16 = 0x2000;
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum CompressionType {
47 Stored,
49 Lz77,
51 Blocked,
53 Unknown(u8),
55}
56
57impl From<u8> for CompressionType {
58 fn from(value: u8) -> Self {
59 match value {
60 0 => CompressionType::Stored,
61 1 => CompressionType::Lz77,
62 2 => CompressionType::Blocked,
63 n => CompressionType::Unknown(n),
64 }
65 }
66}
67
68impl std::fmt::Display for CompressionType {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 match self {
71 CompressionType::Stored => write!(f, "Stored"),
72 CompressionType::Lz77 => write!(f, "LZ77"),
73 CompressionType::Blocked => write!(f, "Blocked"),
74 CompressionType::Unknown(n) => write!(f, "Unknown({})", n),
75 }
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub enum CompressionQuality {
82 None,
83 Fastest,
84 Fast,
85 Normal,
86 Good,
87 Best,
88 Unknown(u8),
89}
90
91impl From<u8> for CompressionQuality {
92 fn from(value: u8) -> Self {
93 match value {
94 0 => CompressionQuality::None,
95 1 => CompressionQuality::Fastest,
96 2 => CompressionQuality::Fast,
97 3 => CompressionQuality::Normal,
98 4 => CompressionQuality::Good,
99 5 => CompressionQuality::Best,
100 n => CompressionQuality::Unknown(n),
101 }
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum HostOs {
108 MsDos,
109 Os2,
110 Windows,
111 Unix,
112 MacOs,
113 WinNt,
114 Primos,
115 AppleGs,
116 Atari,
117 Vax,
118 Amiga,
119 Next,
120 Unknown(u8),
121}
122
123impl From<u8> for HostOs {
124 fn from(value: u8) -> Self {
125 match value {
126 0 => HostOs::MsDos,
127 1 => HostOs::Os2,
128 2 => HostOs::Windows,
129 3 => HostOs::Unix,
130 4 => HostOs::MacOs,
131 5 => HostOs::WinNt,
132 6 => HostOs::Primos,
133 7 => HostOs::AppleGs,
134 8 => HostOs::Atari,
135 9 => HostOs::Vax,
136 10 => HostOs::Amiga,
137 11 => HostOs::Next,
138 n => HostOs::Unknown(n),
139 }
140 }
141}
142
143#[derive(Debug)]
145pub struct MainHeader {
146 pub header_crc: u16,
147 pub header_size: u16,
148 pub header_type: u8,
149 pub header_flags: u16,
150 pub extract_version: u8,
151 pub creator_version: u8,
152 pub host_os: HostOs,
153 pub volume_number: u8,
154 pub datetime: DosDateTime,
155 pub advert: String,
156 pub comment: Vec<u8>,
157}
158
159impl MainHeader {
160 pub fn is_64bit(&self) -> bool {
162 self.header_flags & header_flags::MEMORY_64BIT != 0
163 }
164
165 pub fn is_solid(&self) -> bool {
167 self.header_flags & header_flags::SOLID != 0
168 }
169
170 pub fn is_encrypted(&self) -> bool {
172 self.header_flags & header_flags::PASSWORD != 0
173 }
174
175 pub fn is_multivolume(&self) -> bool {
177 self.header_flags & header_flags::MULTIVOLUME != 0
178 }
179}
180
181#[derive(Debug, Clone)]
183pub struct FileHeader {
184 pub header_crc: u16,
185 pub header_size: u16,
186 pub header_type: u8,
187 pub header_flags: u16,
188 pub packed_size: u64,
189 pub original_size: u64,
190 pub datetime: DosDateTime,
191 pub attributes: u32,
192 pub crc32: u32,
193 pub compression_type: CompressionType,
194 pub compression_quality: CompressionQuality,
195 pub parameters: u16,
196 pub filename: String,
197 pub comment: Vec<u8>,
198 pub data_offset: u64,
200}
201
202impl FileHeader {
203 pub fn is_directory(&self) -> bool {
205 self.attributes & 0x10 != 0
206 }
207
208 pub fn is_encrypted(&self) -> bool {
210 self.header_flags & header_flags::PASSWORD != 0
211 }
212
213 pub fn is_continued_from_prev(&self) -> bool {
215 self.header_flags & header_flags::CONTINUED_PREV != 0
216 }
217
218 pub fn is_continued_to_next(&self) -> bool {
220 self.header_flags & header_flags::CONTINUED_NEXT != 0
221 }
222
223 pub fn dictionary_size(&self) -> usize {
225 let bits = (self.parameters & 0x0F) as usize;
226 if bits < 10 {
227 1024 } else {
229 1 << bits
230 }
231 }
232}