Skip to main content

magic_pack/modules/
mod.rs

1mod compression;
2
3use std::fs::File;
4use std::io::{Error, ErrorKind, Read, Seek};
5
6use crate::contents::enums;
7
8fn find_subsequence(source: &[u8], target: &[u8]) -> Option<usize> {
9    source
10        .windows(target.len())
11        .position(|window| window == target)
12}
13
14pub fn get_file_type(file_path: &std::path::PathBuf) -> Result<enums::FileType, std::io::Error> {
15    struct CompressMagic {
16        magic_number: &'static [u8],
17        length: usize,
18        file_type: enums::FileType,
19    }
20
21    let compress_magic_startswith_list = [
22        CompressMagic {
23            magic_number: b"BZh",
24            length: 3,
25            file_type: enums::FileType::Bz2,
26        },
27        CompressMagic {
28            magic_number: &[0x1f, 0x8b],
29            length: 2,
30            file_type: enums::FileType::Gz,
31        },
32        CompressMagic {
33            magic_number: &[0x50, 0x4b, 0x03, 0x04],
34            length: 4,
35            file_type: enums::FileType::Zip,
36        },
37        CompressMagic {
38            magic_number: &[0x37, 0x7a, 0xbc, 0xaf],
39            length: 4,
40            file_type: enums::FileType::SevenZ,
41        },
42        CompressMagic {
43            magic_number: &[0xfd, 0x37, 0x7a, 0x58],
44            length: 4,
45            file_type: enums::FileType::Xz,
46        },
47        CompressMagic {
48            magic_number: &[0x28, 0xb5, 0x2f, 0xfd],
49            length: 4,
50            file_type: enums::FileType::Zst,
51        },
52        CompressMagic {
53            magic_number: &[0x04, 0x22, 0x4d, 0x18],
54            length: 4,
55            file_type: enums::FileType::Lz4,
56        },
57    ];
58
59    let compress_magic_include_list = [CompressMagic {
60        magic_number: &[0x75, 0x73, 0x74, 0x61, 0x72],
61        length: 5,
62        file_type: enums::FileType::Tar,
63    }];
64
65    let mut startswith_buffer = [0u8; 4];
66    let mut file = File::open(file_path).expect("File open failed");
67    match file.read_exact(&mut startswith_buffer) {
68        Ok(_) => (),
69        Err(_) => return Err(Error::from(ErrorKind::Unsupported)),
70    };
71
72    for compress_magic in compress_magic_startswith_list.iter() {
73        if startswith_buffer.get(..compress_magic.length).unwrap() == compress_magic.magic_number {
74            return Ok(compress_magic.file_type);
75        }
76    }
77
78    file.rewind().expect("Seek 0 failed");
79    let mut include_vec = Vec::new();
80    file.read_to_end(&mut include_vec)
81        .expect("Read file failed");
82
83    for compress_magic in compress_magic_include_list.iter() {
84        if find_subsequence(&include_vec, compress_magic.magic_number).is_some() {
85            return Ok(compress_magic.file_type);
86        }
87    }
88
89    if compression::upx::detect(&include_vec) {
90        return Ok(enums::FileType::Upx);
91    }
92
93    Err(Error::from(ErrorKind::Unsupported))
94}
95
96/// Backward-compatible entry point (no encryption). Equivalent to
97/// `compress_with_password(.., None)`.
98pub fn compress(
99    file_type: enums::FileType,
100    src_path: &std::path::Path,
101    dst_path: &std::path::Path,
102) {
103    compress_with_password(file_type, src_path, dst_path, None);
104}
105
106pub fn compress_with_password(
107    file_type: enums::FileType,
108    src_path: &std::path::Path,
109    dst_path: &std::path::Path,
110    password: Option<&str>,
111) {
112    match file_type {
113        enums::FileType::Zip => {
114            compression::zip::compress(src_path, dst_path);
115        }
116        enums::FileType::Tar => {
117            compression::tar::compress(src_path, dst_path);
118        }
119        enums::FileType::Bz2 => {
120            compression::bz2::compress(src_path, dst_path);
121        }
122        enums::FileType::Gz => {
123            compression::gz::compress(src_path, dst_path);
124        }
125        enums::FileType::Tarbz2 => {
126            compression::tar_bz2::compress(src_path, dst_path);
127        }
128        enums::FileType::Targz => {
129            compression::tar_gz::compress(src_path, dst_path);
130        }
131        enums::FileType::SevenZ => {
132            compression::sevenz::compress(src_path, dst_path, password);
133        }
134        enums::FileType::Xz => {
135            compression::xz::compress(src_path, dst_path);
136        }
137        enums::FileType::Tarxz => {
138            compression::tar_xz::compress(src_path, dst_path);
139        }
140        enums::FileType::Zst => {
141            compression::zst::compress(src_path, dst_path);
142        }
143        enums::FileType::Tarzst => {
144            compression::tar_zst::compress(src_path, dst_path);
145        }
146        enums::FileType::Lz4 => {
147            compression::lz4::compress(src_path, dst_path);
148        }
149        enums::FileType::Tarlz4 => {
150            compression::tar_lz4::compress(src_path, dst_path);
151        }
152        enums::FileType::Upx => {
153            compression::upx::compress(src_path, dst_path);
154        }
155    }
156}
157
158/// Backward-compatible entry point (no encryption). Equivalent to
159/// `decompress_with_password(.., None)`.
160pub fn decompress(
161    file_type: enums::FileType,
162    src_path: &std::path::Path,
163    dst_path: &std::path::Path,
164) {
165    decompress_with_password(file_type, src_path, dst_path, None);
166}
167
168pub fn decompress_with_password(
169    file_type: enums::FileType,
170    src_path: &std::path::Path,
171    dst_path: &std::path::Path,
172    password: Option<&str>,
173) {
174    match file_type {
175        enums::FileType::Zip => {
176            compression::zip::decompress(src_path, dst_path);
177        }
178        enums::FileType::Tar => {
179            compression::tar::decompress(src_path, dst_path);
180        }
181        enums::FileType::Tarbz2 => {
182            compression::tar_bz2::decompress(src_path, dst_path);
183        }
184        enums::FileType::Targz => {
185            compression::tar_gz::decompress(src_path, dst_path);
186        }
187        enums::FileType::Bz2 => {
188            compression::bz2::decompress(src_path, dst_path);
189        }
190        enums::FileType::Gz => {
191            compression::gz::decompress(src_path, dst_path);
192        }
193        enums::FileType::SevenZ => {
194            compression::sevenz::decompress(src_path, dst_path, password);
195        }
196        enums::FileType::Xz => {
197            compression::xz::decompress(src_path, dst_path);
198        }
199        enums::FileType::Tarxz => {
200            compression::tar_xz::decompress(src_path, dst_path);
201        }
202        enums::FileType::Zst => {
203            compression::zst::decompress(src_path, dst_path);
204        }
205        enums::FileType::Tarzst => {
206            compression::tar_zst::decompress(src_path, dst_path);
207        }
208        enums::FileType::Lz4 => {
209            compression::lz4::decompress(src_path, dst_path);
210        }
211        enums::FileType::Tarlz4 => {
212            compression::tar_lz4::decompress(src_path, dst_path);
213        }
214        enums::FileType::Upx => {
215            compression::upx::decompress(src_path, dst_path);
216        }
217    }
218}