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]
53pub fn decompress_file_with_password(
54 src_path: impl AsRef<Path>,
55 dest: impl AsRef<Path>,
56 password: Password,
57) -> Result<(), Error> {
58 let file = std::fs::File::open(src_path.as_ref())
59 .map_err(|e| Error::file_open(e, src_path.as_ref().to_string_lossy().to_string()))?;
60 decompress_with_password(file, dest, password)
61}
62
63#[cfg(all(feature = "aes256", not(target_arch = "wasm32")))]
64#[inline]
65pub fn decompress_with_password<R: Read + Seek>(
66 src_reader: R,
67 dest: impl AsRef<Path>,
68 password: Password,
69) -> Result<(), Error> {
70 decompress_impl(src_reader, dest, password, default_entry_extract_fn)
71}
72
73#[cfg(all(feature = "aes256", not(target_arch = "wasm32")))]
74pub fn decompress_with_extract_fn_and_password<R: Read + Seek>(
75 src_reader: R,
76 dest: impl AsRef<Path>,
77 password: Password,
78 extract_fn: impl FnMut(&SevenZArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
79) -> Result<(), Error> {
80 decompress_impl(src_reader, dest, password, extract_fn)
81}
82
83#[cfg(not(target_arch = "wasm32"))]
84fn decompress_impl<R: Read + Seek>(
85 mut src_reader: R,
86 dest: impl AsRef<Path>,
87 password: Password,
88 mut extract_fn: impl FnMut(&SevenZArchiveEntry, &mut dyn Read, &PathBuf) -> Result<bool, Error>,
89) -> Result<(), Error> {
90 use std::io::SeekFrom;
91
92 let pos = src_reader.stream_position().map_err(Error::io)?;
93 src_reader.seek(SeekFrom::Start(pos)).map_err(Error::io)?;
94 let mut seven = SevenZReader::new(src_reader, 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}