sevenz_rust/
archive.rs

1#![allow(unused)]
2use crate::{folder::*, method_options::MethodOptions};
3use bit_set::BitSet;
4use nt_time::FileTime;
5use std::{any::Any, collections::LinkedList, sync::Arc, time::SystemTime};
6
7pub(crate) 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;
32pub(crate) const K_COMMENT: u8 = 0x16;
33pub(crate) const K_ENCODED_HEADER: u8 = 0x17;
34pub(crate) const K_START_POS: u8 = 0x18;
35pub(crate) const K_DUMMY: u8 = 0x19;
36
37#[derive(Debug, Default, Clone)]
38pub struct Archive {
39    /// Offset from beginning of file + SIGNATURE_HEADER_SIZE to packed streams.
40    pub pack_pos: u64,
41    pub pack_sizes: Vec<u64>,
42    pub pack_crcs_defined: bit_set::BitSet,
43    pub pack_crcs: Vec<u64>,
44    pub folders: Vec<Folder>,
45    pub sub_streams_info: Option<SubStreamsInfo>,
46    pub files: Vec<SevenZArchiveEntry>,
47    pub stream_map: StreamMap,
48}
49
50#[derive(Debug, Default, Clone)]
51pub struct SubStreamsInfo {
52    pub unpack_sizes: Vec<u64>,
53    pub has_crc: BitSet,
54    pub crcs: Vec<u64>,
55}
56
57#[derive(Debug, Default, Clone)]
58pub struct SevenZArchiveEntry {
59    pub name: String,
60    pub has_stream: bool,
61    pub is_directory: bool,
62    pub is_anti_item: bool,
63    pub has_creation_date: bool,
64    pub has_last_modified_date: bool,
65    pub has_access_date: bool,
66    pub creation_date: FileTime,
67    pub last_modified_date: FileTime,
68    pub access_date: FileTime,
69    pub has_windows_attributes: bool,
70    pub windows_attributes: u32,
71    pub has_crc: bool,
72    pub crc: u64,
73    pub compressed_crc: u64,
74    pub size: u64,
75    pub compressed_size: u64,
76    // pub(crate) content_methods: LinkedList<SevenZMethodConfiguration>,
77    pub(crate) content_methods: Arc<Vec<SevenZMethodConfiguration>>,
78}
79
80impl SevenZArchiveEntry {
81    pub fn new() -> Self {
82        Default::default()
83    }
84
85    pub fn name(&self) -> &str {
86        self.name.as_ref()
87    }
88
89    pub fn is_directory(&self) -> bool {
90        self.is_directory
91    }
92
93    pub fn has_stream(&self) -> bool {
94        self.has_stream
95    }
96
97    pub fn creation_date(&self) -> FileTime {
98        self.creation_date
99    }
100
101    pub fn last_modified_date(&self) -> FileTime {
102        self.last_modified_date
103    }
104
105    pub fn size(&self) -> u64 {
106        self.size
107    }
108
109    pub fn windows_attributes(&self) -> u32 {
110        self.windows_attributes
111    }
112
113    pub fn access_date(&self) -> FileTime {
114        self.access_date
115    }
116
117    pub fn is_anti_item(&self) -> bool {
118        self.is_anti_item
119    }
120
121    pub fn from_path(path: impl AsRef<std::path::Path>, entry_name: String) -> SevenZArchiveEntry {
122        let path = path.as_ref();
123        #[cfg(target_os = "windows")]
124        let entry_name = {
125            let mut name_bytes = entry_name.into_bytes();
126            for b in &mut name_bytes {
127                if *b == b'\\' {
128                    *b = b'/';
129                }
130            }
131            String::from_utf8(name_bytes).unwrap()
132        };
133        let mut entry = SevenZArchiveEntry {
134            name: entry_name,
135            has_stream: path.is_file(),
136            is_directory: path.is_dir(),
137            ..Default::default()
138        };
139
140        if let Ok(meta) = path.metadata() {
141            if let Ok(modified) = meta.modified() {
142                if let Ok(date) = modified.try_into() {
143                    entry.last_modified_date = date;
144                    entry.has_last_modified_date = entry.last_modified_date.to_raw() > 0;
145                }
146            }
147            if let Ok(date) = meta.created() {
148                if let Ok(date) = date.try_into() {
149                    entry.creation_date = date;
150                    entry.has_creation_date = entry.creation_date.to_raw() > 0;
151                }
152            }
153            if let Ok(date) = meta.accessed() {
154                if let Ok(date) = date.try_into() {
155                    entry.access_date = date;
156                    entry.has_access_date = entry.access_date.to_raw() > 0;
157                }
158            }
159        }
160        entry
161    }
162}
163
164#[derive(Debug, Default)]
165pub struct SevenZMethodConfiguration {
166    pub method: SevenZMethod,
167    pub options: Option<MethodOptions>,
168}
169
170impl From<SevenZMethod> for SevenZMethodConfiguration {
171    fn from(value: SevenZMethod) -> Self {
172        Self::new(value)
173    }
174}
175
176impl Clone for SevenZMethodConfiguration {
177    fn clone(&self) -> Self {
178        Self {
179            method: self.method,
180            options: self.options.clone(),
181        }
182    }
183}
184
185impl SevenZMethodConfiguration {
186    pub fn new(method: SevenZMethod) -> Self {
187        Self {
188            method,
189            options: None,
190        }
191    }
192
193    pub fn with_options(mut self, options: MethodOptions) -> Self {
194        self.options = Some(options);
195        self
196    }
197}
198
199#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Hash)]
200pub struct SevenZMethod(&'static str, &'static [u8]);
201
202impl SevenZMethod {
203    pub const ID_COPY: &'static [u8] = &[0x00];
204
205    pub const ID_LZMA: &'static [u8] = &[0x03, 0x01, 0x01];
206    pub const ID_LZMA2: &'static [u8] = &[0x21];
207    pub const ID_ZSTD: &'static [u8] = &[4, 247, 17, 1];
208    pub const ID_DEFLATE: &'static [u8] = &[0x04, 0x01, 0x08];
209    pub const ID_DEFLATE64: &'static [u8] = &[0x04, 0x01, 0x09];
210
211    pub const ID_BCJ_X86: &'static [u8] = &[0x03, 0x03, 0x01, 0x03];
212    pub const ID_BCJ_PPC: &'static [u8] = &[0x03, 0x03, 0x02, 0x05];
213    pub const ID_BCJ_IA64: &'static [u8] = &[0x03, 0x03, 0x04, 0x01];
214    pub const ID_BCJ_ARM: &'static [u8] = &[0x03, 0x03, 0x05, 0x01];
215    pub const ID_BCJ_ARM_THUMB: &'static [u8] = &[0x03, 0x03, 0x07, 0x01];
216    pub const ID_BCJ_SPARC: &'static [u8] = &[0x03, 0x03, 0x08, 0x05];
217    pub const ID_DELTA: &'static [u8] = &[0x03];
218    pub const ID_BZIP2: &'static [u8] = &[0x04, 0x02, 0x02];
219    pub const ID_AES256SHA256: &'static [u8] = &[0x06, 0xf1, 0x07, 0x01];
220    pub const ID_BCJ2: &'static [u8] = &[0x03, 0x03, 0x01, 0x1B];
221    /// no compression
222    pub const COPY: SevenZMethod = Self("COPY", Self::ID_COPY);
223
224    pub const LZMA: Self = Self("LZMA", Self::ID_LZMA);
225    pub const LZMA2: Self = Self("LZMA2", Self::ID_LZMA2);
226    pub const ZSTD: Self = Self("ZSTD", Self::ID_ZSTD);
227
228    pub const DEFLATE: Self = Self("DEFLATE", Self::ID_DEFLATE);
229    pub const DEFLATE64: Self = Self("DEFLATE64", Self::ID_DEFLATE64);
230
231    pub const BZIP2: Self = Self("BZIP2", Self::ID_BZIP2);
232    pub const AES256SHA256: Self = Self("AES256SHA256", Self::ID_AES256SHA256);
233
234    pub const BCJ_X86_FILTER: Self = Self("BCJ_X86", Self::ID_BCJ_X86);
235    pub const BCJ_PPC_FILTER: Self = Self("BCJ_PPC", Self::ID_BCJ_PPC);
236    pub const BCJ_IA64_FILTER: Self = Self("BCJ_IA64", Self::ID_BCJ_IA64);
237    pub const BCJ_ARM_FILTER: Self = Self("BCJ_ARM", Self::ID_BCJ_ARM);
238    pub const BCJ_ARM_THUMB_FILTER: Self = Self("BCJ_ARM_THUMB", Self::ID_BCJ_ARM_THUMB);
239    pub const BCJ_SPARC_FILTER: Self = Self("BCJ_SPARC", Self::ID_BCJ_SPARC);
240    pub const DELTA_FILTER: Self = Self("DELTA", Self::ID_DELTA);
241    pub const BCJ2_FILTER: Self = Self("BCJ2", Self::ID_BCJ2);
242
243    const METHODS: &'static [&'static SevenZMethod] = &[
244        &Self::COPY,
245        &Self::ZSTD,
246        &Self::LZMA,
247        &Self::LZMA2,
248        &Self::DEFLATE,
249        &Self::DEFLATE64,
250        &Self::BZIP2,
251        &Self::AES256SHA256,
252        &Self::BCJ_X86_FILTER,
253        &Self::BCJ_PPC_FILTER,
254        &Self::BCJ_IA64_FILTER,
255        &Self::BCJ_ARM_FILTER,
256        &Self::BCJ_ARM_THUMB_FILTER,
257        &Self::BCJ_SPARC_FILTER,
258        &Self::DELTA_FILTER,
259        &Self::BCJ2_FILTER,
260    ];
261
262    #[inline]
263    pub const fn name(&self) -> &'static str {
264        self.0
265    }
266
267    #[inline]
268    pub const fn id(&self) -> &'static [u8] {
269        self.1
270    }
271
272    #[inline]
273    pub fn by_id(id: &[u8]) -> Option<Self> {
274        Self::METHODS
275            .iter()
276            .find(|item| item.id() == id)
277            .cloned()
278            .cloned()
279    }
280}
281
282#[derive(Debug, Default, Clone)]
283pub struct StreamMap {
284    pub folder_first_pack_stream_index: Vec<usize>,
285    pub pack_stream_offsets: Vec<u64>,
286    pub folder_first_file_index: Vec<usize>,
287    pub file_folder_index: Vec<Option<usize>>,
288}
289
290#[derive(Debug, Clone, Copy)]
291pub(crate) struct StartHeader {
292    pub(crate) next_header_offset: u64,
293    pub(crate) next_header_size: u64,
294    pub(crate) next_header_crc: u64,
295}