sevenz_rust2/
archive.rs

1#![allow(unused)]
2use crate::{folder::*, method_options::MethodOptions};
3use bit_set::BitSet;
4use nt_time::FileTime;
5
6pub(crate) const SIGNATURE_HEADER_SIZE: u64 = 32;
7pub(crate) const SEVEN_Z_SIGNATURE: &[u8] = &[b'7', b'z', 0xBC, 0xAF, 0x27, 0x1C];
8
9pub(crate) const K_END: u8 = 0x00;
10pub(crate) const K_HEADER: u8 = 0x01;
11pub(crate) const K_ARCHIVE_PROPERTIES: u8 = 0x02;
12pub(crate) const K_ADDITIONAL_STREAMS_INFO: u8 = 0x03;
13pub(crate) const K_MAIN_STREAMS_INFO: u8 = 0x04;
14pub(crate) const K_FILES_INFO: u8 = 0x05;
15pub(crate) const K_PACK_INFO: u8 = 0x06;
16pub(crate) const K_UNPACK_INFO: u8 = 0x07;
17pub(crate) const K_SUB_STREAMS_INFO: u8 = 0x08;
18pub(crate) const K_SIZE: u8 = 0x09;
19pub(crate) const K_CRC: u8 = 0x0A;
20pub(crate) const K_FOLDER: u8 = 0x0B;
21pub(crate) const K_CODERS_UNPACK_SIZE: u8 = 0x0C;
22pub(crate) const K_NUM_UNPACK_STREAM: u8 = 0x0D;
23pub(crate) const K_EMPTY_STREAM: u8 = 0x0E;
24pub(crate) const K_EMPTY_FILE: u8 = 0x0F;
25pub(crate) const K_ANTI: u8 = 0x10;
26pub(crate) const K_NAME: u8 = 0x11;
27pub(crate) const K_C_TIME: u8 = 0x12;
28pub(crate) const K_A_TIME: u8 = 0x13;
29pub(crate) const K_M_TIME: u8 = 0x14;
30pub(crate) const K_WIN_ATTRIBUTES: u8 = 0x15;
31pub(crate) const K_COMMENT: u8 = 0x16;
32pub(crate) const K_ENCODED_HEADER: u8 = 0x17;
33pub(crate) const K_START_POS: u8 = 0x18;
34pub(crate) const K_DUMMY: u8 = 0x19;
35
36#[derive(Debug, Default, Clone)]
37pub struct Archive {
38    /// Offset from beginning of file + SIGNATURE_HEADER_SIZE to packed streams.
39    pub pack_pos: u64,
40    pub pack_sizes: Vec<u64>,
41    pub pack_crcs_defined: BitSet,
42    pub pack_crcs: Vec<u64>,
43    pub folders: Vec<Folder>,
44    pub sub_streams_info: Option<SubStreamsInfo>,
45    pub files: Vec<SevenZArchiveEntry>,
46    pub stream_map: StreamMap,
47    pub is_solid: bool,
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}
77
78impl SevenZArchiveEntry {
79    pub fn new() -> Self {
80        Self::default()
81    }
82
83    pub fn new_file(entry_name: &str) -> Self {
84        Self {
85            name: entry_name.to_string(),
86            has_stream: true,
87            is_directory: false,
88            ..Default::default()
89        }
90    }
91
92    pub fn new_folder(entry_name: &str) -> Self {
93        Self {
94            name: entry_name.to_string(),
95            has_stream: false,
96            is_directory: true,
97            ..Default::default()
98        }
99    }
100
101    pub fn from_path(path: impl AsRef<std::path::Path>, entry_name: String) -> Self {
102        let path = path.as_ref();
103        #[cfg(target_os = "windows")]
104        let entry_name = {
105            let mut name_bytes = entry_name.into_bytes();
106            for b in &mut name_bytes {
107                if *b == b'\\' {
108                    *b = b'/';
109                }
110            }
111            String::from_utf8(name_bytes).unwrap()
112        };
113        let mut entry = SevenZArchiveEntry {
114            name: entry_name,
115            has_stream: path.is_file(),
116            is_directory: path.is_dir(),
117            ..Default::default()
118        };
119
120        if let Ok(meta) = path.metadata() {
121            if let Ok(modified) = meta.modified() {
122                if let Ok(date) = modified.try_into() {
123                    entry.last_modified_date = date;
124                    entry.has_last_modified_date = entry.last_modified_date.to_raw() > 0;
125                }
126            }
127            if let Ok(date) = meta.created() {
128                if let Ok(date) = date.try_into() {
129                    entry.creation_date = date;
130                    entry.has_creation_date = entry.creation_date.to_raw() > 0;
131                }
132            }
133            if let Ok(date) = meta.accessed() {
134                if let Ok(date) = date.try_into() {
135                    entry.access_date = date;
136                    entry.has_access_date = entry.access_date.to_raw() > 0;
137                }
138            }
139        }
140        entry
141    }
142
143    pub fn name(&self) -> &str {
144        self.name.as_ref()
145    }
146
147    pub fn is_directory(&self) -> bool {
148        self.is_directory
149    }
150
151    pub fn has_stream(&self) -> bool {
152        self.has_stream
153    }
154
155    pub fn creation_date(&self) -> FileTime {
156        self.creation_date
157    }
158
159    pub fn last_modified_date(&self) -> FileTime {
160        self.last_modified_date
161    }
162
163    pub fn size(&self) -> u64 {
164        self.size
165    }
166
167    pub fn windows_attributes(&self) -> u32 {
168        self.windows_attributes
169    }
170
171    pub fn access_date(&self) -> FileTime {
172        self.access_date
173    }
174
175    pub fn is_anti_item(&self) -> bool {
176        self.is_anti_item
177    }
178}
179
180#[derive(Debug, Default)]
181pub struct SevenZMethodConfiguration {
182    pub method: SevenZMethod,
183    pub options: Option<MethodOptions>,
184}
185
186impl From<SevenZMethod> for SevenZMethodConfiguration {
187    fn from(value: SevenZMethod) -> Self {
188        Self::new(value)
189    }
190}
191
192impl Clone for SevenZMethodConfiguration {
193    fn clone(&self) -> Self {
194        Self {
195            method: self.method,
196            options: self.options.clone(),
197        }
198    }
199}
200
201impl SevenZMethodConfiguration {
202    pub fn new(method: SevenZMethod) -> Self {
203        Self {
204            method,
205            options: None,
206        }
207    }
208
209    pub fn with_options(mut self, options: MethodOptions) -> Self {
210        self.options = Some(options);
211        self
212    }
213}
214
215#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Hash)]
216pub struct SevenZMethod(&'static str, &'static [u8]);
217
218impl SevenZMethod {
219    pub const ID_COPY: &'static [u8] = &[0x00];
220    pub const ID_DELTA: &'static [u8] = &[0x03];
221    pub const ID_BCJ: &'static [u8] = &[0x04];
222
223    pub const ID_LZMA: &'static [u8] = &[0x03, 0x01, 0x01];
224    pub const ID_BCJ_X86: &'static [u8] = &[0x03, 0x03, 0x01, 0x03];
225    pub const ID_BCJ2: &'static [u8] = &[0x03, 0x03, 0x01, 0x1B];
226    pub const ID_BCJ_PPC: &'static [u8] = &[0x03, 0x03, 0x02, 0x05];
227    pub const ID_BCJ_IA64: &'static [u8] = &[0x03, 0x03, 0x04, 0x01];
228    pub const ID_BCJ_ARM: &'static [u8] = &[0x03, 0x03, 0x05, 0x01];
229    pub const ID_BCJ_ARM64: &'static [u8] = &[0xa];
230    pub const ID_BCJ_ARM_THUMB: &'static [u8] = &[0x03, 0x03, 0x07, 0x01];
231    pub const ID_BCJ_SPARC: &'static [u8] = &[0x03, 0x03, 0x08, 0x05];
232    pub const ID_PPMD: &'static [u8] = &[0x03, 0x04, 0x01];
233
234    pub const ID_LZMA2: &'static [u8] = &[0x21];
235    pub const ID_BZIP2: &'static [u8] = &[0x04, 0x02, 0x02];
236    pub const ID_ZSTD: &'static [u8] = &[0x04, 0xf7, 0x11, 0x01];
237    pub const ID_BROTLI: &'static [u8] = &[0x04, 0xf7, 0x11, 0x02];
238    pub const ID_LZ4: &'static [u8] = &[0x04, 0xf7, 0x11, 0x04];
239    pub const ID_LZS: &'static [u8] = &[0x04, 0xf7, 0x11, 0x05];
240    pub const ID_LIZARD: &'static [u8] = &[0x04, 0xf7, 0x11, 0x06];
241    pub const ID_DEFLATE: &'static [u8] = &[0x04, 0x01, 0x08];
242    pub const ID_DEFLATE64: &'static [u8] = &[0x04, 0x01, 0x09];
243    pub const ID_AES256SHA256: &'static [u8] = &[0x06, 0xf1, 0x07, 0x01];
244
245    pub const COPY: Self = Self("COPY", Self::ID_COPY);
246    pub const LZMA: Self = Self("LZMA", Self::ID_LZMA);
247    pub const LZMA2: Self = Self("LZMA2", Self::ID_LZMA2);
248    pub const PPMD: Self = Self("PPMD", Self::ID_PPMD);
249    pub const BZIP2: Self = Self("BZIP2", Self::ID_BZIP2);
250    pub const ZSTD: Self = Self("ZSTD", Self::ID_ZSTD);
251    pub const BROTLI: Self = Self("BROTLI", Self::ID_BROTLI);
252    pub const LZ4: Self = Self("LZ4", Self::ID_LZ4);
253    pub const LZS: Self = Self("LZS", Self::ID_LZS);
254    pub const LIZARD: Self = Self("LIZARD", Self::ID_LIZARD);
255    pub const DEFLATE: Self = Self("DEFLATE", Self::ID_DEFLATE);
256    pub const DEFLATE64: Self = Self("DEFLATE64", Self::ID_DEFLATE64);
257    pub const AES256SHA256: Self = Self("AES256SHA256", Self::ID_AES256SHA256);
258
259    pub const BCJ_X86_FILTER: Self = Self("BCJ_X86", Self::ID_BCJ_X86);
260    pub const BCJ_PPC_FILTER: Self = Self("BCJ_PPC", Self::ID_BCJ_PPC);
261    pub const BCJ_IA64_FILTER: Self = Self("BCJ_IA64", Self::ID_BCJ_IA64);
262    pub const BCJ_ARM_FILTER: Self = Self("BCJ_ARM", Self::ID_BCJ_ARM);
263    pub const BCJ_ARM64_FILTER: Self = Self("BCJ_ARM64", Self::ID_BCJ_ARM64);
264    pub const BCJ_ARM_THUMB_FILTER: Self = Self("BCJ_ARM_THUMB", Self::ID_BCJ_ARM_THUMB);
265    pub const BCJ_SPARC_FILTER: Self = Self("BCJ_SPARC", Self::ID_BCJ_SPARC);
266    pub const DELTA_FILTER: Self = Self("DELTA", Self::ID_DELTA);
267    pub const BCJ2_FILTER: Self = Self("BCJ2", Self::ID_BCJ2);
268
269    const METHODS: &'static [&'static SevenZMethod] = &[
270        &Self::COPY,
271        &Self::LZMA,
272        &Self::LZMA2,
273        &Self::PPMD,
274        &Self::BZIP2,
275        &Self::ZSTD,
276        &Self::BROTLI,
277        &Self::LZ4,
278        &Self::LZS,
279        &Self::LIZARD,
280        &Self::DEFLATE,
281        &Self::DEFLATE64,
282        &Self::AES256SHA256,
283        &Self::BCJ_X86_FILTER,
284        &Self::BCJ_PPC_FILTER,
285        &Self::BCJ_IA64_FILTER,
286        &Self::BCJ_ARM_FILTER,
287        &Self::BCJ_ARM64_FILTER,
288        &Self::BCJ_ARM_THUMB_FILTER,
289        &Self::BCJ_SPARC_FILTER,
290        &Self::DELTA_FILTER,
291        &Self::BCJ2_FILTER,
292    ];
293
294    #[inline]
295    pub const fn name(&self) -> &'static str {
296        self.0
297    }
298
299    #[inline]
300    pub const fn id(&self) -> &'static [u8] {
301        self.1
302    }
303
304    #[inline]
305    pub fn by_id(id: &[u8]) -> Option<Self> {
306        Self::METHODS
307            .iter()
308            .find(|item| item.id() == id)
309            .cloned()
310            .cloned()
311    }
312}
313
314#[derive(Debug, Default, Clone)]
315pub struct StreamMap {
316    pub folder_first_pack_stream_index: Vec<usize>,
317    pub pack_stream_offsets: Vec<u64>,
318    pub folder_first_file_index: Vec<usize>,
319    pub file_folder_index: Vec<Option<usize>>,
320}
321
322#[derive(Debug, Clone, Copy)]
323pub(crate) struct StartHeader {
324    pub(crate) next_header_offset: u64,
325    pub(crate) next_header_size: u64,
326    pub(crate) next_header_crc: u64,
327}