Skip to main content

futilities/
lib.rs

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                // Bitset
97                if let None = format.iter().position(|b| *b == bytes[4]) {
98                    return Ok(false);
99                }
100                // Endian
101                if let None = format.iter().position(|b| *b == bytes[5]) {
102                    return Ok(false);
103                }
104                // Version
105                if bytes[6] != 0x01 {
106                    return Ok(false);
107                }
108                // Os ABI
109                if let None = os.iter().position(|b| *b == bytes[7]) {
110                    return Ok(false);
111                }
112                // 7 bytes of padding
113                if &bytes[9..=15] != pad {
114                    return Ok(false)
115                }
116                // Object file type
117                if let None = filetype.iter().position(|b| *b == ((bytes[16] as u16) << 8) | (bytes[17] as u16)) {
118                    return Ok(false);
119                }
120                // Architecture
121                if let None = architecture.iter().position(|b| *b == ((bytes[18] as u16) << 8) | (bytes[19] as u16)) {
122                    return Ok(false);
123                }
124                // Version
125                if bytes[20] != 0x01 {
126                    return Ok(false);
127                }
128                // 3 bytes of padding
129                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);