1use quick_xml::Reader;
2use quick_xml::events::Event;
3use std::{
4 fs::File,
5 io,
6 io::BufReader,
7 io::prelude::*,
8 path::Path
9};
10
11pub trait IsImage {
12 fn is_png(&self) -> Result<bool, io::Error>;
13 fn is_jpg(&self) -> Result<bool, io::Error>;
14 fn is_gif(&self) -> Result<bool, io::Error>;
15 fn is_bmp(&self) -> Result<bool, io::Error>;
16 fn is_tif(&self) -> Result<bool, io::Error>;
17 fn is_xcf(&self) -> Result<bool, io::Error>;
18 fn is_ppm(&self) -> Result<bool, io::Error>;
19 fn is_pgm(&self) -> Result<bool, io::Error>;
20 fn is_pbm(&self) -> Result<bool, io::Error>;
21 fn is_svg(&self) -> Result<bool, quick_xml::Error>;
22}
23
24pub trait IsExecutable {
25 fn is_elf(&self) -> Result<bool, io::Error>;
26}
27
28macro_rules! impl_isexecutable {
29 ($head:ident) => {
30 impl IsExecutable for $head {
31 fn is_elf(&self) -> Result<bool, io::Error> {
32 let mut file = File::open(self)?;
33 let mut bytes: [u8; 24] = [0; 24];
34 file.read_exact(&mut bytes)?;
35 let magic = vec![
36 0x7F,
37 0x45,
38 0x4C,
39 0x46
40 ];
41 let format: Vec<u8> = (0x01..=0x02).collect();
42 let os: Vec<u8> = (0x00..=0x12).collect();
43 let filetype: Vec<u16> = vec![
44 0x0000,
45 0x0100,
46 0x0200,
47 0x0300,
48 0x0400,
49 0xFE00,
50 0xFEFF,
51 0xFF00,
52 0xFFFF
53 ];
54 let architecture: Vec<u16> = vec![
55 0x0000,
56 0x0100,
57 0x0200,
58 0x0300,
59 0x0400,
60 0x0500,
61 0x0600,
62 0x0700,
63 0x0800,
64 0x0900,
65 0x0A00,
66 0x0B00,
67 0x0C00,
68 0x0D00,
69 0x0E00,
70 0x0F00,
71 0x1300,
72 0x1400,
73 0x1500,
74 0x1600,
75 0x2800,
76 0x2A00,
77 0x3200,
78 0x3E00,
79 0x8C00,
80 0xB700,
81 0xF300,
82 0x1010
83 ];
84 let pad: Vec<u8> = vec![
85 0x00,
86 0x00,
87 0x00,
88 0x00,
89 0x00,
90 0x00,
91 0x00
92 ];
93 if bytes[0..=3] != magic {
94 return Ok(false);
95 }
96 if let None = format.iter().position(|b| *b == bytes[4]) {
98 return Ok(false);
99 }
100 if let None = format.iter().position(|b| *b == bytes[5]) {
102 return Ok(false);
103 }
104 if bytes[6] != 0x01 {
106 return Ok(false);
107 }
108 if let None = os.iter().position(|b| *b == bytes[7]) {
110 return Ok(false);
111 }
112 if &bytes[9..=15] != pad {
114 return Ok(false)
115 }
116 if let None = filetype.iter().position(|b| *b == ((bytes[16] as u16) << 8) | (bytes[17] as u16)) {
118 return Ok(false);
119 }
120 if let None = architecture.iter().position(|b| *b == ((bytes[18] as u16) << 8) | (bytes[19] as u16)) {
122 return Ok(false);
123 }
124 if bytes[20] != 0x01 {
126 return Ok(false);
127 }
128 if &bytes[21..=23] != [0x00, 0x00, 0x00] {
130 return Ok(false);
131 }
132 Ok(true)
133 }
134 }
135 }
136}
137
138macro_rules! impl_isimage {
139 ($head:ident) => {
140 impl IsImage for $head {
141 fn is_png(&self) -> Result<bool, io::Error> {
142 let mut file = File::open(self)?;
143 let mut bytes: [u8; 8] = [0; 8];
144 file.read_exact(&mut bytes)?;
145 let header = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
146 Ok(header == bytes)
147 }
148
149 fn is_jpg(&self) -> Result<bool, io::Error> {
150 let mut file = File::open(self)?;
151 let mut bytes: [u8; 11] = [0; 11];
152 file.read_exact(&mut bytes)?;
153 let candidate = bytes.iter().enumerate().filter(|(i, _)| *i != 4 && *i != 5).map(|(_, b)| *b).collect::<Vec<u8>>();
154 let headerv1 = vec![0xFF, 0xD8, 0xFF, 0xE0, 0x4A, 0x46, 0x49, 0x46, 0x00];
155 let headerv2 = vec![0xFF, 0xD8, 0xFF, 0xFF, 0x4A, 0x46, 0x49, 0x46, 0x00];
156 Ok(headerv1 == candidate || headerv2 == candidate)
157 }
158 fn is_gif(&self) -> Result<bool, io::Error> {
159 let mut file = File::open(self)?;
160 let mut bytes: [u8; 6] = [0; 6];
161 file.read_exact(&mut bytes)?;
162 let headerv89a = vec![0x47, 0x49, 0x46, 0x38, 0x39, 0x61];
163 let headerv87a = vec![0x47, 0x49, 0x46, 0x38, 0x37, 0x61];
164 Ok(headerv89a == bytes || headerv87a == bytes)
165 }
166 fn is_bmp(&self) -> Result<bool, io::Error> {
167 let mut file = File::open(self)?;
168 let mut bytes: [u8; 2] = [0; 2];
169 file.read_exact(&mut bytes)?;
170 let header = vec![0x42, 0x4D];
171 Ok(header == bytes)
172 }
173 fn is_tif(&self) -> Result<bool, io::Error> {
174 let mut file = File::open(self)?;
175 let mut bytes: [u8; 3] = [0; 3];
176 file.read_exact(&mut bytes)?;
177 let headerle = vec![0x49, 0x49, 0x2A];
178 let headerbe = vec![0x4D, 0x4D, 0x2A];
179 Ok(headerle == bytes || headerbe == bytes)
180 }
181 fn is_xcf(&self) -> Result<bool, io::Error> {
182 let mut file = File::open(self)?;
183 let mut bytes: [u8; 9] = [0; 9];
184 file.read_exact(&mut bytes)?;
185 let header = vec![0x67, 0x69, 0x6D, 0x70, 0x20, 0x78, 0x63, 0x66, 0x20];
186 Ok(header == bytes)
187 }
188 fn is_ppm(&self) -> Result<bool, io::Error> {
189 let mut file = File::open(self)?;
190 let mut bytes: [u8; 2] = [0; 2];
191 file.read_exact(&mut bytes)?;
192 let headerp3 = vec![0x50, 0x33];
193 let headerp6 = vec![0x50, 0x36];
194 Ok(headerp3 == bytes || headerp6 == bytes)
195 }
196 fn is_pgm(&self) -> Result<bool, io::Error> {
197 let mut file = File::open(self)?;
198 let mut bytes: [u8; 2] = [0; 2];
199 file.read_exact(&mut bytes)?;
200 let headerp2 = vec![0x50, 0x32];
201 let headerp5 = vec![0x50, 0x35];
202 Ok(headerp2 == bytes || headerp5 == bytes)
203 }
204 fn is_pbm(&self) -> Result<bool, io::Error> {
205 let mut file = File::open(self)?;
206 let mut bytes: [u8; 2] = [0; 2];
207 file.read_exact(&mut bytes)?;
208 let headerp1 = vec![0x50, 0x31];
209 Ok(headerp1 == bytes)
210 }
211 fn is_svg(&self) -> Result<bool, quick_xml::Error> {
212 let mut reader: Reader<BufReader<File>>;
213 reader = Reader::from_file(self)?;
214 let mut buffer = Vec::new();
215 loop {
216 match reader.read_event(&mut buffer) {
217 Ok(Event::Start(ref e)) if e.name() == b"svg" => {
218 return Ok(true);
219 }
220 Ok(Event::Eof) => break,
221 Err(error) => return Err(error),
222 _ => ()
223 }
224 }
225 Ok(false)
226 }
227 }
228 }
229}
230
231macro_rules! for_each_ident {
232 ($callback:ident, $head:ident) => {
233 $callback!($head);
234 };
235 ($callback:ident, $head:ident, $($tail:ident),*) => {
236 $callback!($head);
237 for_each_ident!($callback, $($tail),*);
238 }
239}
240
241for_each_ident!(impl_isimage, Path, String, str);
242for_each_ident!(impl_isexecutable, Path, String, str);