1use std::fs::File;
11use std::io::Read;
12use std::path::Path;
13
14pub fn is_zip(path: &Path) -> bool {
21 check_magic_bytes(path, &[0x50, 0x4B, 0x03, 0x04])
22}
23
24pub fn is_gzip(path: &Path) -> bool {
25 check_magic_bytes(path, &[0x1F, 0x8B])
26}
27
28pub fn is_squashfs(path: &Path) -> bool {
36 check_magic_bytes(path, &[0x68, 0x73, 0x71, 0x73])
39 || check_magic_bytes(path, &[0x73, 0x71, 0x73, 0x68])
40}
41
42pub fn is_nsis_installer(path: &Path) -> bool {
50 const SEARCH_SIZE: usize = 8192; const NSIS_SIGNATURE: &[u8] = b"Nullsoft.NSIS.exehead";
52
53 let mut file = match File::open(path) {
54 Ok(f) => f,
55 Err(_) => return false,
56 };
57
58 let mut buffer = vec![0u8; SEARCH_SIZE];
59 let bytes_read = match file.read(&mut buffer) {
60 Ok(n) => n,
61 Err(_) => return false,
62 };
63
64 buffer.truncate(bytes_read);
65
66 buffer
68 .windows(NSIS_SIGNATURE.len())
69 .any(|window| window == NSIS_SIGNATURE)
70}
71
72fn check_magic_bytes(path: &Path, magic: &[u8]) -> bool {
76 let mut file = match File::open(path) {
77 Ok(f) => f,
78 Err(_) => return false,
79 };
80
81 let mut buffer = vec![0u8; magic.len()];
82 match file.read_exact(&mut buffer) {
83 Ok(()) => buffer == magic,
84 Err(_) => false,
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use std::io::Write;
92 use tempfile::NamedTempFile;
93
94 #[test]
95 fn test_is_zip() {
96 let mut file = NamedTempFile::new().unwrap();
98 file.write_all(&[0x50, 0x4B, 0x03, 0x04, 0x00, 0x00])
99 .unwrap();
100 assert!(is_zip(file.path()));
101
102 let mut file2 = NamedTempFile::new().unwrap();
104 file2.write_all(&[0x1F, 0x8B, 0x08, 0x00]).unwrap();
105 assert!(!is_zip(file2.path()));
106
107 assert!(!is_zip(Path::new("/nonexistent/file.zip")));
109 }
110
111 #[test]
112 fn test_is_gzip() {
113 let mut file = NamedTempFile::new().unwrap();
114 file.write_all(&[0x1F, 0x8B, 0x08, 0x00]).unwrap();
115 assert!(is_gzip(file.path()));
116
117 let mut file2 = NamedTempFile::new().unwrap();
118 file2.write_all(&[0x50, 0x4B, 0x03, 0x04]).unwrap();
119 assert!(!is_gzip(file2.path()));
120 }
121
122 #[test]
123 fn test_is_squashfs_little_endian() {
124 let mut file = NamedTempFile::new().unwrap();
126 file.write_all(&[0x68, 0x73, 0x71, 0x73, 0x00, 0x00])
127 .unwrap();
128 assert!(is_squashfs(file.path()));
129 }
130
131 #[test]
132 fn test_is_squashfs_big_endian() {
133 let mut file = NamedTempFile::new().unwrap();
135 file.write_all(&[0x73, 0x71, 0x73, 0x68, 0x00, 0x00])
136 .unwrap();
137 assert!(is_squashfs(file.path()));
138 }
139
140 #[test]
141 fn test_is_squashfs_negative() {
142 let mut file = NamedTempFile::new().unwrap();
144 file.write_all(&[0x50, 0x4B, 0x03, 0x04]).unwrap();
145 assert!(!is_squashfs(file.path()));
146
147 assert!(!is_squashfs(Path::new("/nonexistent/file.squashfs")));
149 }
150
151 #[test]
152 fn test_is_nsis_installer() {
153 let mut file = NamedTempFile::new().unwrap();
155 file.write_all(b"MZ\x90\x00").unwrap(); file.write_all(b"Nullsoft.NSIS.exehead").unwrap();
157 file.write_all(&[0u8; 100]).unwrap();
158 assert!(is_nsis_installer(file.path()));
159
160 let mut file2 = NamedTempFile::new().unwrap();
162 file2.write_all(&vec![0u8; 1000]).unwrap();
163 file2.write_all(b"Nullsoft.NSIS.exehead").unwrap();
164 assert!(is_nsis_installer(file2.path()));
165
166 let mut file3 = NamedTempFile::new().unwrap();
168 file3.write_all(b"This is not an NSIS installer").unwrap();
169 assert!(!is_nsis_installer(file3.path()));
170
171 assert!(!is_nsis_installer(Path::new("/nonexistent/setup.exe")));
173 }
174
175 #[test]
176 fn test_is_nsis_installer_beyond_8kb() {
177 let mut file = NamedTempFile::new().unwrap();
179 file.write_all(&vec![0u8; 8500]).unwrap();
180 file.write_all(b"Nullsoft.NSIS.exehead").unwrap();
181 assert!(!is_nsis_installer(file.path()));
182 }
183
184 #[test]
185 fn test_check_magic_bytes_short_file() {
186 let mut file = NamedTempFile::new().unwrap();
188 file.write_all(&[0x50, 0x4B]).unwrap(); assert!(!check_magic_bytes(file.path(), &[0x50, 0x4B, 0x03, 0x04]));
190 }
191
192 #[test]
193 fn test_check_magic_bytes_empty_file() {
194 let file = NamedTempFile::new().unwrap();
196 assert!(!check_magic_bytes(file.path(), &[0x50, 0x4B]));
197 }
198}