sevenz_rust2/util/
decompress.rs1#[cfg(target_os = "macos")]
2use std::os::macos::fs::FileTimesExt;
3#[cfg(windows)]
4use std::os::windows::fs::FileTimesExt;
5use std::{
6 fs::FileTimes,
7 io::{Read, Seek},
8 path::{Path, PathBuf},
9};
10
11use crate::{Error, Password, *};
12
13pub fn decompress_file(src_path: impl AsRef<Path>, dest: impl AsRef<Path>) -> Result<(), Error> {
21 let file = std::fs::File::open(src_path.as_ref())
22 .map_err(|e| Error::file_open(e, src_path.as_ref().to_string_lossy().to_string()))?;
23 decompress(file, dest)
24}
25
26pub fn decompress_file_with_extract_fn(
36 src_path: impl AsRef<Path>,
37 dest: impl AsRef<Path>,
38 extract_fn: impl FnMut(&ArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
39) -> Result<(), Error> {
40 let file = std::fs::File::open(src_path.as_ref())
41 .map_err(|e| Error::file_open(e, src_path.as_ref().to_string_lossy().to_string()))?;
42 decompress_with_extract_fn(file, dest, extract_fn)
43}
44
45pub fn decompress<R: Read + Seek>(src_reader: R, dest: impl AsRef<Path>) -> Result<(), Error> {
51 decompress_with_extract_fn(src_reader, dest, default_entry_extract_fn)
52}
53
54#[cfg(not(target_arch = "wasm32"))]
63pub fn decompress_with_extract_fn<R: Read + Seek>(
64 src_reader: R,
65 dest: impl AsRef<Path>,
66 extract_fn: impl FnMut(&ArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
67) -> Result<(), Error> {
68 decompress_impl(src_reader, dest, Password::empty(), extract_fn)
69}
70
71#[cfg(all(feature = "aes256", not(target_arch = "wasm32")))]
78pub fn decompress_file_with_password(
79 src_path: impl AsRef<Path>,
80 dest: impl AsRef<Path>,
81 password: Password,
82) -> Result<(), Error> {
83 let file = std::fs::File::open(src_path.as_ref())
84 .map_err(|e| Error::file_open(e, src_path.as_ref().to_string_lossy().to_string()))?;
85 decompress_with_password(file, dest, password)
86}
87
88#[cfg(all(feature = "aes256", not(target_arch = "wasm32")))]
95pub fn decompress_with_password<R: Read + Seek>(
96 src_reader: R,
97 dest: impl AsRef<Path>,
98 password: Password,
99) -> Result<(), Error> {
100 decompress_impl(src_reader, dest, password, default_entry_extract_fn)
101}
102
103#[cfg(all(feature = "aes256", not(target_arch = "wasm32")))]
114pub fn decompress_with_extract_fn_and_password<R: Read + Seek>(
115 src_reader: R,
116 dest: impl AsRef<Path>,
117 password: Password,
118 extract_fn: impl FnMut(&ArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
119) -> Result<(), Error> {
120 decompress_impl(src_reader, dest, password, extract_fn)
121}
122
123#[cfg(not(target_arch = "wasm32"))]
124fn decompress_impl<R: Read + Seek>(
125 mut src_reader: R,
126 dest: impl AsRef<Path>,
127 password: Password,
128 mut extract_fn: impl FnMut(&ArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
129) -> Result<(), Error> {
130 use std::io::SeekFrom;
131
132 let pos = src_reader.stream_position()?;
133 src_reader.seek(SeekFrom::Start(pos))?;
134 let mut seven = ArchiveReader::new(src_reader, password)?;
135 let dest = PathBuf::from(dest.as_ref());
136 if !dest.exists() {
137 std::fs::create_dir_all(&dest)?;
138 }
139 seven.for_each_entries(|entry, reader| {
140 let dest_path = dest.join(entry.name());
141 extract_fn(entry, reader, &dest_path)
142 })?;
143
144 Ok(())
145}
146
147#[cfg(not(target_arch = "wasm32"))]
154pub fn default_entry_extract_fn(
155 entry: &ArchiveEntry,
156 reader: &mut dyn Read,
157 dest: &PathBuf,
158) -> Result<bool, Error> {
159 use std::{fs::File, io::BufWriter};
160
161 if entry.is_directory() {
162 let dir = dest;
163 if !dir.exists() {
164 std::fs::create_dir_all(dir)?;
165 }
166 } else {
167 let path = dest;
168 path.parent().and_then(|p| {
169 if !p.exists() {
170 std::fs::create_dir_all(p).ok()
171 } else {
172 None
173 }
174 });
175 let file = File::create(path)
176 .map_err(|e| Error::file_open(e, path.to_string_lossy().to_string()))?;
177 if entry.size() > 0 {
178 let mut writer = BufWriter::new(file);
179 std::io::copy(reader, &mut writer)?;
180
181 let file = writer.get_mut();
182 let file_times = FileTimes::new()
183 .set_accessed(entry.access_date().into())
184 .set_modified(entry.last_modified_date().into());
185
186 #[cfg(any(windows, target_os = "macos"))]
187 let file_times = file_times.set_created(entry.creation_date().into());
188
189 let _ = file.set_times(file_times);
190 }
191 }
192
193 Ok(true)
194}