fuel_etk_cli/
io.rs

1//! Tools for reading/writing various formats.
2
3use crate::parse::Hex;
4
5use std::fs::File;
6use std::io;
7use std::path::PathBuf;
8
9use clap::StructOpt;
10
11/// Command-line options describing an input source, either from a file or
12/// directly from the command line.
13#[derive(Debug, StructOpt)]
14pub struct InputSource {
15    #[structopt(
16        long = "bin-file",
17        short = 'b',
18        help = "path to input data, as raw binary data",
19        conflicts_with_all(&["hex-file", "code"]),
20        required_unless_present_any(&["hex-file", "code"]),
21    )]
22    bin_file: Option<PathBuf>,
23
24    #[structopt(
25        long = "hex-file",
26        short = 'x',
27        help = "path to input data, encoded in hexadecimal format",
28        conflicts_with = "code"
29    )]
30    hex_file: Option<PathBuf>,
31
32    #[structopt(
33        long = "code",
34        short = 'c',
35        help = "input data, encoded in hexadecimal format (with 0x prefix)"
36    )]
37    code: Option<Hex<Vec<u8>>>,
38}
39
40impl InputSource {
41    /// Convert `self` into something that implements `std::io::Read`.
42    pub fn open(self) -> Result<impl io::Read, io::Error> {
43        let boxed: Box<dyn io::Read> = match (self.bin_file, self.hex_file, self.code) {
44            (Some(bin), None, None) => Box::new(Self::bin(bin)?),
45            (None, Some(hex), None) => Box::new(Self::hex(hex)?),
46            (None, None, Some(code)) => Box::new(Self::code(code.0)),
47            _ => unreachable!(),
48        };
49
50        Ok(boxed)
51    }
52
53    fn bin(path: PathBuf) -> Result<File, io::Error> {
54        File::open(path)
55    }
56
57    fn hex(path: PathBuf) -> Result<HexRead<File>, io::Error> {
58        Ok(HexRead::new(File::open(path)?))
59    }
60
61    fn code(code: Vec<u8>) -> io::Cursor<Vec<u8>> {
62        io::Cursor::new(code)
63    }
64}
65
66/// An implementation of `std::io::Write` that converts from binary to
67/// hexadecimal.
68#[derive(Debug)]
69pub struct HexWrite<W> {
70    file: W,
71}
72
73impl<W> HexWrite<W> {
74    /// Create a new `HexWrite` wrapping another implementation of
75    /// `std::io::Write`.
76    pub fn new(file: W) -> Self {
77        Self { file }
78    }
79}
80
81impl<W> io::Write for HexWrite<W>
82where
83    W: io::Write,
84{
85    fn flush(&mut self) -> Result<(), io::Error> {
86        self.file.flush()
87    }
88
89    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
90        let encoded = hex::encode(buf);
91        let wrote = self.file.write(encoded.as_bytes())?;
92
93        if wrote % 2 != 0 {
94            // Didn't write an entire byte, so we're screwed.
95            Err(io::Error::from(io::ErrorKind::Other))
96        } else {
97            Ok(wrote / 2)
98        }
99    }
100}
101
102#[derive(Debug)]
103struct HexRead<R> {
104    first_read: bool,
105    file: R,
106    remainder: Option<u8>,
107}
108
109impl<R> HexRead<R> {
110    fn new(file: R) -> Self {
111        Self {
112            first_read: true,
113            remainder: None,
114            file,
115        }
116    }
117}
118
119impl<R> io::Read for HexRead<R>
120where
121    R: io::Read,
122{
123    fn read(&mut self, buffer: &mut [u8]) -> Result<usize, io::Error> {
124        // TODO: It's possible to avoid the allocation (use latter two thirds of
125        //       `buffer` to read from file, then decode into first third) but
126        //       it doesn't seem worth the effort.
127
128        if buffer.is_empty() {
129            return Ok(0);
130        }
131
132        let mut available;
133        let mut hexbuffer;
134
135        if let Some(remainder) = self.remainder {
136            available = 1;
137            hexbuffer = vec![0u8; 1 + (2 * buffer.len())];
138            hexbuffer[0] = remainder;
139        } else {
140            available = 0;
141            hexbuffer = vec![0u8; 2 * buffer.len()];
142        }
143
144        // Shadow the vec so we can manipulate the start index.
145        let mut hexbuffer: &mut [u8] = &mut hexbuffer;
146
147        let mut eof;
148
149        loop {
150            let read = self.file.read(&mut hexbuffer[available..])?;
151            eof = 0 == read;
152            available += read;
153
154            // Check for the 0x prefix, if we have read less than 2 bytes.
155            if self.first_read && available >= 2 {
156                self.first_read = false;
157                if b"0x" == &hexbuffer[..2] {
158                    available -= 2;
159
160                    if hexbuffer.len() > 2 {
161                        hexbuffer = &mut hexbuffer[2..];
162                    }
163                }
164            }
165
166            if eof || available > 1 {
167                break;
168            }
169        }
170
171        if eof && 1 == available {
172            if char::from(hexbuffer[0]).is_whitespace() {
173                available = 0;
174            } else {
175                let kind = io::ErrorKind::InvalidData;
176                let src = hex::FromHexError::OddLength;
177                return Err(io::Error::new(kind, src));
178            }
179        } else if available % 2 == 0 {
180            self.remainder = None;
181        } else {
182            self.remainder = Some(hexbuffer[available - 1]);
183            available -= 1;
184        }
185
186        if 0 == available {
187            return Ok(0);
188        }
189
190        let out_sz = available / 2;
191
192        hex::decode_to_slice(&mut hexbuffer[..available], &mut buffer[..out_sz])
193            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
194
195        Ok(out_sz)
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use hex_literal::hex;
202
203    use std::io::Read;
204
205    use clap::ErrorKind;
206
207    use super::*;
208
209    #[test]
210    fn input_source_at_least_one() {
211        let args: &[&str] = &[];
212        let err = InputSource::try_parse_from(args).unwrap_err();
213        assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
214    }
215
216    #[test]
217    fn input_source_bin_file_conflicts_with_hex_file() {
218        let args = &["exe", "--bin-file", "floop", "--hex-file", "whoop"];
219        let err = InputSource::try_parse_from(args).unwrap_err();
220        assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
221    }
222
223    #[test]
224    fn input_source_bin_file_conflicts_with_code() {
225        let args = &["exe", "--bin-file", "floop", "--code", "0x00"];
226        let err = InputSource::try_parse_from(args).unwrap_err();
227        assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
228    }
229
230    #[test]
231    fn input_source_hex_file_conflicts_with_code() {
232        let args = &["exe", "--hex-file", "floop", "--code", "0x00"];
233        let err = InputSource::try_parse_from(args).unwrap_err();
234        assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
235    }
236
237    #[test]
238    fn hex_read_with_prefix_empty() {
239        let data = b"0x";
240        let mut decoder = HexRead::new(&data[..]);
241
242        let mut buf = [0u8; 10];
243        let sz = decoder.read(&mut buf).unwrap();
244        assert_eq!(sz, 0);
245    }
246
247    #[test]
248    fn hex_read_no_prefix_empty() {
249        let data = b"";
250        let mut decoder = HexRead::new(&data[..]);
251
252        let mut buf = [0u8; 10];
253        let sz = decoder.read(&mut buf).unwrap();
254        assert_eq!(sz, 0);
255    }
256
257    #[test]
258    fn hex_read_with_prefix_odd_length() {
259        let data = b"0xabcdef012345678";
260        let mut decoder = HexRead::new(&data[..]);
261        let err = decoder.read_to_end(&mut vec![]).unwrap_err();
262        assert_eq!(err.kind(), io::ErrorKind::InvalidData);
263    }
264
265    #[test]
266    fn hex_read_no_prefix_odd_length() {
267        let data = b"abcdef012345678";
268        let mut decoder = HexRead::new(&data[..]);
269        let err = decoder.read_to_end(&mut vec![]).unwrap_err();
270        assert_eq!(err.kind(), io::ErrorKind::InvalidData);
271    }
272
273    #[test]
274    fn hex_read_with_prefix_big_buffer() {
275        let data = b"0xabcdef0123456789";
276        let mut decoder = HexRead::new(&data[..]);
277
278        let mut buf = vec![0u8; data.len()];
279        let sz = decoder.read(&mut buf).unwrap();
280        assert_eq!(sz, 8);
281
282        let actual = &buf[..sz];
283        assert_eq!(actual, hex!("abcdef0123456789"));
284
285        let sz = decoder.read(&mut buf).unwrap();
286        assert_eq!(sz, 0);
287    }
288
289    #[test]
290    fn hex_read_no_prefix_big_buffer() {
291        let data = b"abcdef0123456789";
292        let mut decoder = HexRead::new(&data[..]);
293
294        let mut buf = vec![0u8; data.len()];
295        let sz = decoder.read(&mut buf).unwrap();
296        assert_eq!(sz, 8);
297
298        let actual = &buf[..sz];
299        assert_eq!(actual, hex!("abcdef0123456789"));
300
301        let sz = decoder.read(&mut buf).unwrap();
302        assert_eq!(sz, 0);
303    }
304
305    #[test]
306    fn hex_read_with_prefix_tiny_buffer() {
307        let data = b"0xabcdef0123456789";
308        let mut decoder = HexRead::new(&data[..]);
309
310        let mut buf = [0u8];
311
312        let sz = decoder.read(&mut buf).unwrap();
313        assert_eq!(sz, 1);
314        assert_eq!(buf[0], 0xab);
315
316        let sz = decoder.read(&mut buf).unwrap();
317        assert_eq!(sz, 1);
318        assert_eq!(buf[0], 0xcd);
319
320        let sz = decoder.read(&mut buf).unwrap();
321        assert_eq!(sz, 1);
322        assert_eq!(buf[0], 0xef);
323
324        let sz = decoder.read(&mut buf).unwrap();
325        assert_eq!(sz, 1);
326        assert_eq!(buf[0], 0x01);
327
328        let sz = decoder.read(&mut buf).unwrap();
329        assert_eq!(sz, 1);
330        assert_eq!(buf[0], 0x23);
331
332        let sz = decoder.read(&mut buf).unwrap();
333        assert_eq!(sz, 1);
334        assert_eq!(buf[0], 0x45);
335
336        let sz = decoder.read(&mut buf).unwrap();
337        assert_eq!(sz, 1);
338        assert_eq!(buf[0], 0x67);
339
340        let sz = decoder.read(&mut buf).unwrap();
341        assert_eq!(sz, 1);
342        assert_eq!(buf[0], 0x89);
343    }
344
345    #[test]
346    fn hex_read_no_prefix_tiny_buffer() {
347        let data = b"abcdef0123456789";
348        let mut decoder = HexRead::new(&data[..]);
349
350        let mut buf = [0u8];
351
352        let sz = decoder.read(&mut buf).unwrap();
353        assert_eq!(sz, 1);
354        assert_eq!(buf[0], 0xab);
355
356        let sz = decoder.read(&mut buf).unwrap();
357        assert_eq!(sz, 1);
358        assert_eq!(buf[0], 0xcd);
359
360        let sz = decoder.read(&mut buf).unwrap();
361        assert_eq!(sz, 1);
362        assert_eq!(buf[0], 0xef);
363
364        let sz = decoder.read(&mut buf).unwrap();
365        assert_eq!(sz, 1);
366        assert_eq!(buf[0], 0x01);
367
368        let sz = decoder.read(&mut buf).unwrap();
369        assert_eq!(sz, 1);
370        assert_eq!(buf[0], 0x23);
371
372        let sz = decoder.read(&mut buf).unwrap();
373        assert_eq!(sz, 1);
374        assert_eq!(buf[0], 0x45);
375
376        let sz = decoder.read(&mut buf).unwrap();
377        assert_eq!(sz, 1);
378        assert_eq!(buf[0], 0x67);
379
380        let sz = decoder.read(&mut buf).unwrap();
381        assert_eq!(sz, 1);
382        assert_eq!(buf[0], 0x89);
383
384        let sz = decoder.read(&mut buf).unwrap();
385        assert_eq!(sz, 0);
386    }
387}