1use std::fs::File;
8use std::io::Read;
9use std::path::Path;
10
11pub fn is_zip(path: &Path) -> bool {
18 check_magic_bytes(path, &[0x50, 0x4B, 0x03, 0x04])
19}
20
21pub fn is_gzip(path: &Path) -> bool {
22 check_magic_bytes(path, &[0x1F, 0x8B])
23}
24
25pub fn is_squashfs(path: &Path) -> bool {
33 check_magic_bytes(path, &[0x68, 0x73, 0x71, 0x73])
36 || check_magic_bytes(path, &[0x73, 0x71, 0x73, 0x68])
37}
38
39pub fn is_nsis_installer(path: &Path) -> bool {
47 const SEARCH_SIZE: usize = 8192; const NSIS_SIGNATURE: &[u8] = b"Nullsoft.NSIS.exehead";
49
50 let mut file = match File::open(path) {
51 Ok(f) => f,
52 Err(_) => return false,
53 };
54
55 let mut buffer = vec![0u8; SEARCH_SIZE];
56 let bytes_read = match file.read(&mut buffer) {
57 Ok(n) => n,
58 Err(_) => return false,
59 };
60
61 buffer.truncate(bytes_read);
62
63 buffer
65 .windows(NSIS_SIGNATURE.len())
66 .any(|window| window == NSIS_SIGNATURE)
67}
68
69fn check_magic_bytes(path: &Path, magic: &[u8]) -> bool {
73 let mut file = match File::open(path) {
74 Ok(f) => f,
75 Err(_) => return false,
76 };
77
78 let mut buffer = vec![0u8; magic.len()];
79 match file.read_exact(&mut buffer) {
80 Ok(()) => buffer == magic,
81 Err(_) => false,
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use std::io::Write;
89 use tempfile::NamedTempFile;
90
91 #[test]
92 fn test_is_zip() {
93 let mut file = NamedTempFile::new().unwrap();
95 file.write_all(&[0x50, 0x4B, 0x03, 0x04, 0x00, 0x00])
96 .unwrap();
97 assert!(is_zip(file.path()));
98
99 let mut file2 = NamedTempFile::new().unwrap();
101 file2.write_all(&[0x1F, 0x8B, 0x08, 0x00]).unwrap();
102 assert!(!is_zip(file2.path()));
103
104 assert!(!is_zip(Path::new("/nonexistent/file.zip")));
106 }
107
108 #[test]
109 fn test_is_gzip() {
110 let mut file = NamedTempFile::new().unwrap();
111 file.write_all(&[0x1F, 0x8B, 0x08, 0x00]).unwrap();
112 assert!(is_gzip(file.path()));
113
114 let mut file2 = NamedTempFile::new().unwrap();
115 file2.write_all(&[0x50, 0x4B, 0x03, 0x04]).unwrap();
116 assert!(!is_gzip(file2.path()));
117 }
118
119 #[test]
120 fn test_is_squashfs_little_endian() {
121 let mut file = NamedTempFile::new().unwrap();
123 file.write_all(&[0x68, 0x73, 0x71, 0x73, 0x00, 0x00])
124 .unwrap();
125 assert!(is_squashfs(file.path()));
126 }
127
128 #[test]
129 fn test_is_squashfs_big_endian() {
130 let mut file = NamedTempFile::new().unwrap();
132 file.write_all(&[0x73, 0x71, 0x73, 0x68, 0x00, 0x00])
133 .unwrap();
134 assert!(is_squashfs(file.path()));
135 }
136
137 #[test]
138 fn test_is_squashfs_negative() {
139 let mut file = NamedTempFile::new().unwrap();
141 file.write_all(&[0x50, 0x4B, 0x03, 0x04]).unwrap();
142 assert!(!is_squashfs(file.path()));
143
144 assert!(!is_squashfs(Path::new("/nonexistent/file.squashfs")));
146 }
147
148 #[test]
149 fn test_is_nsis_installer() {
150 let mut file = NamedTempFile::new().unwrap();
152 file.write_all(b"MZ\x90\x00").unwrap(); file.write_all(b"Nullsoft.NSIS.exehead").unwrap();
154 file.write_all(&[0u8; 100]).unwrap();
155 assert!(is_nsis_installer(file.path()));
156
157 let mut file2 = NamedTempFile::new().unwrap();
159 file2.write_all(&vec![0u8; 1000]).unwrap();
160 file2.write_all(b"Nullsoft.NSIS.exehead").unwrap();
161 assert!(is_nsis_installer(file2.path()));
162
163 let mut file3 = NamedTempFile::new().unwrap();
165 file3.write_all(b"This is not an NSIS installer").unwrap();
166 assert!(!is_nsis_installer(file3.path()));
167
168 assert!(!is_nsis_installer(Path::new("/nonexistent/setup.exe")));
170 }
171
172 #[test]
173 fn test_is_nsis_installer_beyond_8kb() {
174 let mut file = NamedTempFile::new().unwrap();
176 file.write_all(&vec![0u8; 8500]).unwrap();
177 file.write_all(b"Nullsoft.NSIS.exehead").unwrap();
178 assert!(!is_nsis_installer(file.path()));
179 }
180
181 #[test]
182 fn test_check_magic_bytes_short_file() {
183 let mut file = NamedTempFile::new().unwrap();
185 file.write_all(&[0x50, 0x4B]).unwrap(); assert!(!check_magic_bytes(file.path(), &[0x50, 0x4B, 0x03, 0x04]));
187 }
188
189 #[test]
190 fn test_check_magic_bytes_empty_file() {
191 let file = NamedTempFile::new().unwrap();
193 assert!(!check_magic_bytes(file.path(), &[0x50, 0x4B]));
194 }
195}