1use crate::{password::Password, Error, *};
2use std::io::{Read, Seek};
3use std::path::{Path, PathBuf};
4
5#[inline]
12pub fn decompress_file(src_path: impl AsRef<Path>, dest: impl AsRef<Path>) -> Result<(), Error> {
13 let file = std::fs::File::open(src_path.as_ref())
14 .map_err(|e| Error::file_open(e, src_path.as_ref().to_string_lossy().to_string()))?;
15 decompress(file, dest)
16}
17
18#[inline]
19pub fn decompress_file_with_extract_fn(
20 src_path: impl AsRef<Path>,
21 dest: impl AsRef<Path>,
22 extract_fn: impl FnMut(&SevenZArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
23) -> Result<(), Error> {
24 let file = std::fs::File::open(src_path.as_ref())
25 .map_err(|e| Error::file_open(e, src_path.as_ref().to_string_lossy().to_string()))?;
26 decompress_with_extract_fn(file, dest, extract_fn)
27}
28
29#[inline]
31pub fn decompress<R: Read + Seek>(src_reader: R, dest: impl AsRef<Path>) -> Result<(), Error> {
32 decompress_with_extract_fn(src_reader, dest, default_entry_extract_fn)
33}
34
35#[cfg(not(target_arch = "wasm32"))]
36#[inline]
37pub fn decompress_with_extract_fn<R: Read + Seek>(
38 src_reader: R,
39 dest: impl AsRef<Path>,
40 extract_fn: impl FnMut(&SevenZArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
41) -> Result<(), Error> {
42 decompress_impl(src_reader, dest, Password::empty(), extract_fn)
43}
44
45#[cfg(all(feature = "aes256", not(target_arch = "wasm32")))]
46#[inline]
52pub fn decompress_file_with_password(
53 src_path: impl AsRef<Path>,
54 dest: impl AsRef<Path>,
55 password: Password,
56) -> Result<(), Error> {
57 let file = std::fs::File::open(src_path.as_ref())
58 .map_err(|e| Error::file_open(e, src_path.as_ref().to_string_lossy().to_string()))?;
59 decompress_with_password(file, dest, password)
60}
61
62#[cfg(all(feature = "aes256", not(target_arch = "wasm32")))]
63#[inline]
64pub fn decompress_with_password<R: Read + Seek>(
65 src_reader: R,
66 dest: impl AsRef<Path>,
67 password: Password,
68) -> Result<(), Error> {
69 decompress_impl(src_reader, dest, password, default_entry_extract_fn)
70}
71
72#[cfg(all(feature = "aes256", not(target_arch = "wasm32")))]
73pub fn decompress_with_extract_fn_and_password<R: Read + Seek>(
74 src_reader: R,
75 dest: impl AsRef<Path>,
76 password: Password,
77 extract_fn: impl FnMut(&SevenZArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
78) -> Result<(), Error> {
79 decompress_impl(src_reader, dest, password, extract_fn)
80}
81
82#[cfg(not(target_arch = "wasm32"))]
83fn decompress_impl<R: Read + Seek>(
84 mut src_reader: R,
85 dest: impl AsRef<Path>,
86 password: Password,
87 mut extract_fn: impl FnMut(&SevenZArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
88) -> Result<(), Error> {
89 use std::io::SeekFrom;
90
91 let pos = src_reader.stream_position().map_err(Error::io)?;
92 let len = src_reader.seek(SeekFrom::End(0)).map_err(Error::io)?;
93 src_reader.seek(SeekFrom::Start(pos)).map_err(Error::io)?;
94 let mut seven = SevenZReader::new(src_reader, len, password)?;
95 let dest = PathBuf::from(dest.as_ref());
96 if !dest.exists() {
97 std::fs::create_dir_all(&dest).map_err(Error::io)?;
98 }
99 seven.for_each_entries(|entry, reader| {
100 let dest_path = dest.join(entry.name());
101 extract_fn(entry, reader, &dest_path)
102 })?;
103
104 Ok(())
105}
106
107#[cfg(not(target_arch = "wasm32"))]
108pub fn default_entry_extract_fn(
109 entry: &SevenZArchiveEntry,
110 reader: &mut dyn Read,
111 dest: &PathBuf,
112) -> Result<bool, Error> {
113 use std::{fs::File, io::BufWriter};
114
115 if entry.is_directory() {
116 let dir = dest;
117 if !dir.exists() {
118 std::fs::create_dir_all(dir).map_err(Error::io)?;
119 }
120 } else {
121 let path = dest;
122 path.parent().and_then(|p| {
123 if !p.exists() {
124 std::fs::create_dir_all(p).ok()
125 } else {
126 None
127 }
128 });
129 let file = File::create(path)
130 .map_err(|e| Error::file_open(e, path.to_string_lossy().to_string()))?;
131 if entry.size() > 0 {
132 let mut writer = BufWriter::new(file);
133 std::io::copy(reader, &mut writer).map_err(Error::io)?;
134 ft::set_file_handle_times(
135 writer.get_ref(),
136 Some(ft::FileTime::from_system_time(entry.access_date().into())),
137 Some(ft::FileTime::from_system_time(
138 entry.last_modified_date().into(),
139 )),
140 Some(ft::FileTime::from_system_time(entry.creation_date().into())),
141 )
142 .unwrap_or_default();
143 }
144 }
145 Ok(true)
146}