1#[cfg(feature = "compress")]
2use crate::encoder_options::EncoderOptions;
3use crate::{NtTime, bitset::BitSet, block::*};
4
5pub const SIGNATURE_HEADER_SIZE: u64 = 32;
8pub(crate) const SEVEN_Z_SIGNATURE: &[u8] = &[b'7', b'z', 0xBC, 0xAF, 0x27, 0x1C];
9
10pub(crate) const K_END: u8 = 0x00;
11pub(crate) const K_HEADER: u8 = 0x01;
12pub(crate) const K_ARCHIVE_PROPERTIES: u8 = 0x02;
13pub(crate) const K_ADDITIONAL_STREAMS_INFO: u8 = 0x03;
14pub(crate) const K_MAIN_STREAMS_INFO: u8 = 0x04;
15pub(crate) const K_FILES_INFO: u8 = 0x05;
16pub(crate) const K_PACK_INFO: u8 = 0x06;
17pub(crate) const K_UNPACK_INFO: u8 = 0x07;
18pub(crate) const K_SUB_STREAMS_INFO: u8 = 0x08;
19pub(crate) const K_SIZE: u8 = 0x09;
20pub(crate) const K_CRC: u8 = 0x0A;
21pub(crate) const K_FOLDER: u8 = 0x0B;
22pub(crate) const K_CODERS_UNPACK_SIZE: u8 = 0x0C;
23pub(crate) const K_NUM_UNPACK_STREAM: u8 = 0x0D;
24pub(crate) const K_EMPTY_STREAM: u8 = 0x0E;
25pub(crate) const K_EMPTY_FILE: u8 = 0x0F;
26pub(crate) const K_ANTI: u8 = 0x10;
27pub(crate) const K_NAME: u8 = 0x11;
28pub(crate) const K_C_TIME: u8 = 0x12;
29pub(crate) const K_A_TIME: u8 = 0x13;
30pub(crate) const K_M_TIME: u8 = 0x14;
31pub(crate) const K_WIN_ATTRIBUTES: u8 = 0x15;
32
33#[allow(unused)]
35pub(crate) const K_COMMENT: u8 = 0x16;
36pub(crate) const K_ENCODED_HEADER: u8 = 0x17;
37pub(crate) const K_START_POS: u8 = 0x18;
38pub(crate) const K_DUMMY: u8 = 0x19;
39
40#[derive(Debug, Default, Clone)]
45pub struct Archive {
46 pub(crate) pack_pos: u64,
48 pub(crate) pack_sizes: Vec<u64>,
49 pub(crate) pack_crcs_defined: BitSet,
50 pub(crate) pack_crcs: Vec<u64>,
51 pub(crate) sub_streams_info: Option<SubStreamsInfo>,
52 pub blocks: Vec<Block>,
54 pub files: Vec<ArchiveEntry>,
56 pub stream_map: StreamMap,
58 pub is_solid: bool,
60}
61
62impl Archive {
63 pub fn pack_pos(&self) -> u64 {
66 self.pack_pos
67 }
68
69 pub fn pack_sizes(&self) -> &[u64] {
72 &self.pack_sizes
73 }
74}
75
76#[derive(Debug, Default, Clone)]
77pub(crate) struct SubStreamsInfo {
78 pub(crate) unpack_sizes: Vec<u64>,
79 pub(crate) has_crc: BitSet,
80 pub(crate) crcs: Vec<u64>,
81}
82
83#[derive(Debug, Default, Clone)]
88pub struct ArchiveEntry {
89 pub name: String,
91 pub has_stream: bool,
93 pub is_directory: bool,
95 pub is_anti_item: bool,
97 pub has_creation_date: bool,
99 pub has_last_modified_date: bool,
101 pub has_access_date: bool,
103 pub creation_date: NtTime,
105 pub last_modified_date: NtTime,
107 pub access_date: NtTime,
109 pub has_windows_attributes: bool,
111 pub windows_attributes: u32,
113 pub has_crc: bool,
115 pub crc: u64,
117 pub compressed_crc: u64,
119 pub size: u64,
121 pub compressed_size: u64,
123}
124
125impl ArchiveEntry {
126 pub fn new() -> Self {
128 Self::default()
129 }
130
131 pub fn new_file(entry_name: &str) -> Self {
136 Self {
137 name: entry_name.to_string(),
138 has_stream: true,
139 is_directory: false,
140 ..Default::default()
141 }
142 }
143
144 pub fn new_directory(entry_name: &str) -> Self {
149 Self {
150 name: entry_name.to_string(),
151 has_stream: false,
152 is_directory: true,
153 ..Default::default()
154 }
155 }
156
157 pub fn from_path(path: impl AsRef<std::path::Path>, entry_name: String) -> Self {
166 let path = path.as_ref();
167 #[cfg(target_os = "windows")]
168 let entry_name = {
169 let mut name_bytes = entry_name.into_bytes();
170 for b in &mut name_bytes {
171 if *b == b'\\' {
172 *b = b'/';
173 }
174 }
175 String::from_utf8(name_bytes).unwrap()
176 };
177 let mut entry = ArchiveEntry {
178 name: entry_name,
179 has_stream: path.is_file(),
180 is_directory: path.is_dir(),
181 ..Default::default()
182 };
183
184 if let Ok(meta) = path.metadata() {
185 if let Ok(modified) = meta.modified() {
186 if let Ok(date) = NtTime::try_from(modified) {
187 entry.last_modified_date = date;
188 entry.has_last_modified_date = entry.last_modified_date.0 > 0;
189 }
190 }
191 if let Ok(date) = meta.created() {
192 if let Ok(date) = NtTime::try_from(date) {
193 entry.creation_date = date;
194 entry.has_creation_date = entry.creation_date.0 > 0;
195 }
196 }
197 if let Ok(date) = meta.accessed() {
198 if let Ok(date) = NtTime::try_from(date) {
199 entry.access_date = date;
200 entry.has_access_date = entry.access_date.0 > 0;
201 }
202 }
203 }
204 entry
205 }
206
207 pub fn name(&self) -> &str {
209 self.name.as_ref()
210 }
211
212 pub fn is_directory(&self) -> bool {
214 self.is_directory
215 }
216
217 pub fn has_stream(&self) -> bool {
219 self.has_stream
220 }
221
222 pub fn creation_date(&self) -> NtTime {
224 self.creation_date
225 }
226
227 pub fn last_modified_date(&self) -> NtTime {
229 self.last_modified_date
230 }
231
232 pub fn size(&self) -> u64 {
234 self.size
235 }
236
237 pub fn windows_attributes(&self) -> u32 {
239 self.windows_attributes
240 }
241
242 pub fn access_date(&self) -> NtTime {
244 self.access_date
245 }
246
247 pub fn is_anti_item(&self) -> bool {
249 self.is_anti_item
250 }
251}
252
253#[cfg(feature = "compress")]
257#[derive(Debug, Default)]
258pub struct EncoderConfiguration {
259 pub method: EncoderMethod,
261 pub options: Option<EncoderOptions>,
263}
264
265#[cfg(feature = "compress")]
266impl From<EncoderMethod> for EncoderConfiguration {
267 fn from(value: EncoderMethod) -> Self {
268 Self::new(value)
269 }
270}
271
272#[cfg(feature = "compress")]
273impl Clone for EncoderConfiguration {
274 fn clone(&self) -> Self {
275 Self {
276 method: self.method,
277 options: self.options.clone(),
278 }
279 }
280}
281
282#[cfg(feature = "compress")]
283impl EncoderConfiguration {
284 pub fn new(method: EncoderMethod) -> Self {
289 Self {
290 method,
291 options: None,
292 }
293 }
294
295 pub fn with_options(mut self, options: EncoderOptions) -> Self {
300 self.options = Some(options);
301 self
302 }
303}
304
305#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Hash)]
307pub struct EncoderMethod(&'static str, &'static [u8]);
308
309impl EncoderMethod {
310 pub const ID_COPY: &'static [u8] = &[0x00];
312 pub const ID_DELTA: &'static [u8] = &[0x03];
314
315 pub const ID_LZMA: &'static [u8] = &[0x03, 0x01, 0x01];
317 pub const ID_BCJ_X86: &'static [u8] = &[0x03, 0x03, 0x01, 0x03];
319 pub const ID_BCJ2: &'static [u8] = &[0x03, 0x03, 0x01, 0x1B];
321 pub const ID_BCJ_PPC: &'static [u8] = &[0x03, 0x03, 0x02, 0x05];
323 pub const ID_BCJ_IA64: &'static [u8] = &[0x03, 0x03, 0x04, 0x01];
325 pub const ID_BCJ_ARM: &'static [u8] = &[0x03, 0x03, 0x05, 0x01];
327 pub const ID_BCJ_ARM64: &'static [u8] = &[0xA];
329 pub const ID_BCJ_ARM_THUMB: &'static [u8] = &[0x03, 0x03, 0x07, 0x01];
331 pub const ID_BCJ_SPARC: &'static [u8] = &[0x03, 0x03, 0x08, 0x05];
333 pub const ID_BCJ_RISCV: &'static [u8] = &[0xB];
335 pub const ID_PPMD: &'static [u8] = &[0x03, 0x04, 0x01];
337
338 pub const ID_LZMA2: &'static [u8] = &[0x21];
340 pub const ID_BZIP2: &'static [u8] = &[0x04, 0x02, 0x02];
342 pub const ID_ZSTD: &'static [u8] = &[0x04, 0xF7, 0x11, 0x01];
344 pub const ID_BROTLI: &'static [u8] = &[0x04, 0xF7, 0x11, 0x02];
346 pub const ID_LZ4: &'static [u8] = &[0x04, 0xF7, 0x11, 0x04];
348 pub const ID_LZS: &'static [u8] = &[0x04, 0xF7, 0x11, 0x05];
350 pub const ID_LIZARD: &'static [u8] = &[0x04, 0xF7, 0x11, 0x06];
352 pub const ID_DEFLATE: &'static [u8] = &[0x04, 0x01, 0x08];
354 pub const ID_DEFLATE64: &'static [u8] = &[0x04, 0x01, 0x09];
356 pub const ID_AES256_SHA256: &'static [u8] = &[0x06, 0xF1, 0x07, 0x01];
358
359 pub const COPY: Self = Self("COPY", Self::ID_COPY);
361 pub const LZMA: Self = Self("LZMA", Self::ID_LZMA);
363 pub const LZMA2: Self = Self("LZMA2", Self::ID_LZMA2);
365 pub const PPMD: Self = Self("PPMD", Self::ID_PPMD);
367 pub const BZIP2: Self = Self("BZIP2", Self::ID_BZIP2);
369 pub const ZSTD: Self = Self("ZSTD", Self::ID_ZSTD);
371 pub const BROTLI: Self = Self("BROTLI", Self::ID_BROTLI);
373 pub const LZ4: Self = Self("LZ4", Self::ID_LZ4);
375 pub const LZS: Self = Self("LZS", Self::ID_LZS);
377 pub const LIZARD: Self = Self("LIZARD", Self::ID_LIZARD);
379 pub const DEFLATE: Self = Self("DEFLATE", Self::ID_DEFLATE);
381 pub const DEFLATE64: Self = Self("DEFLATE64", Self::ID_DEFLATE64);
383 pub const AES256_SHA256: Self = Self("AES256_SHA256", Self::ID_AES256_SHA256);
385
386 pub const BCJ_X86_FILTER: Self = Self("BCJ_X86", Self::ID_BCJ_X86);
388 pub const BCJ_PPC_FILTER: Self = Self("BCJ_PPC", Self::ID_BCJ_PPC);
390 pub const BCJ_IA64_FILTER: Self = Self("BCJ_IA64", Self::ID_BCJ_IA64);
392 pub const BCJ_ARM_FILTER: Self = Self("BCJ_ARM", Self::ID_BCJ_ARM);
394 pub const BCJ_ARM64_FILTER: Self = Self("BCJ_ARM64", Self::ID_BCJ_ARM64);
396 pub const BCJ_ARM_THUMB_FILTER: Self = Self("BCJ_ARM_THUMB", Self::ID_BCJ_ARM_THUMB);
398 pub const BCJ_SPARC_FILTER: Self = Self("BCJ_SPARC", Self::ID_BCJ_SPARC);
400 pub const BCJ_RISCV_FILTER: Self = Self("BCJ_RISCV", Self::ID_BCJ_RISCV);
402 pub const DELTA_FILTER: Self = Self("DELTA", Self::ID_DELTA);
404 pub const BCJ2_FILTER: Self = Self("BCJ2", Self::ID_BCJ2);
406
407 const ENCODING_METHODS: &'static [&'static EncoderMethod] = &[
408 &Self::COPY,
409 &Self::LZMA,
410 &Self::LZMA2,
411 &Self::PPMD,
412 &Self::BZIP2,
413 &Self::ZSTD,
414 &Self::BROTLI,
415 &Self::LZ4,
416 &Self::LZS,
417 &Self::LIZARD,
418 &Self::DEFLATE,
419 &Self::DEFLATE64,
420 &Self::AES256_SHA256,
421 &Self::BCJ_X86_FILTER,
422 &Self::BCJ_PPC_FILTER,
423 &Self::BCJ_IA64_FILTER,
424 &Self::BCJ_ARM_FILTER,
425 &Self::BCJ_ARM64_FILTER,
426 &Self::BCJ_ARM_THUMB_FILTER,
427 &Self::BCJ_SPARC_FILTER,
428 &Self::BCJ_RISCV_FILTER,
429 &Self::DELTA_FILTER,
430 &Self::BCJ2_FILTER,
431 ];
432
433 #[inline]
434 pub const fn name(&self) -> &'static str {
436 self.0
437 }
438
439 #[inline]
440 pub const fn id(&self) -> &'static [u8] {
442 self.1
443 }
444
445 #[inline]
446 pub fn by_id(id: &[u8]) -> Option<Self> {
451 Self::ENCODING_METHODS
452 .iter()
453 .find(|item| item.id() == id)
454 .cloned()
455 .cloned()
456 }
457}
458
459#[derive(Debug, Default, Clone)]
464pub struct StreamMap {
465 pub(crate) block_first_pack_stream_index: Vec<usize>,
466 pub(crate) pack_stream_offsets: Vec<u64>,
467 pub block_first_file_index: Vec<usize>,
469 pub file_block_index: Vec<Option<usize>>,
471}
472
473impl StreamMap {
474 pub fn block_first_pack_stream_index(&self) -> &[usize] {
477 &self.block_first_pack_stream_index
478 }
479
480 pub fn pack_stream_offsets(&self) -> &[u64] {
483 &self.pack_stream_offsets
484 }
485}
486
487#[derive(Debug, Clone, Copy)]
488pub(crate) struct StartHeader {
489 pub(crate) next_header_offset: u64,
490 pub(crate) next_header_size: u64,
491 pub(crate) next_header_crc: u64,
492}