diff --git a/src/od/inputdecoder.rs b/src/od/inputdecoder.rs new file mode 100644 index 000000000..01143d24b --- /dev/null +++ b/src/od/inputdecoder.rs @@ -0,0 +1,182 @@ +use std::io; +use byteorder_io::ByteOrder; +use multifilereader::HasError; +use peekreader::PeekRead; + +/// Processes an input and provides access to the data read in various formats +/// +/// Currently only useful if the input implements `PeekRead`. +pub struct InputDecoder<'a, I> where I: 'a { + /// The input from which data is read + input: &'a mut I, + + /// A memory buffer, it's size is set in `new`. + data: Vec, + /// The numer of bytes in the buffer reserved for the peek data from `PeekRead`. + reserved_peek_length: usize, + + /// The number of (valid) bytes in the buffer. + used_normal_length: usize, + /// The number of peek bytes in the buffer. + used_peek_length: usize, + + /// Byte order used to read data from the buffer. + byte_order: ByteOrder, +} + +impl<'a, I> InputDecoder<'a, I> { + /// Creates a new `InputDecoder` with an allocated buffer of `normal_length`+`peek_length` bytes. + /// `byte_order` determines how to read multibyte formats from the buffer. + pub fn new(input: &mut I, normal_length: usize, peek_length: usize, byte_order: ByteOrder) -> InputDecoder { + + let mut bytes: Vec = Vec::with_capacity(normal_length+peek_length); + unsafe { bytes.set_len(normal_length+peek_length); } // fast but uninitialized + + InputDecoder { + input: input, + data: bytes, + reserved_peek_length: peek_length, + used_normal_length: 0, + used_peek_length: 0, + byte_order: byte_order, + } + } +} + + +impl<'a, I> InputDecoder<'a, I> where I : PeekRead { + /// calls `peek_read` on the internal stream to (re)fill the buffer. Returns a + /// MemoryDecoder providing access to the result or returns an i/o error. + pub fn peek_read(&mut self) -> io::Result { + match self.input.peek_read(self.data.as_mut_slice(), self.reserved_peek_length) { + Ok((n, p)) => { + self.used_normal_length = n; + self.used_peek_length = p; + Ok(MemoryDecoder { + data: &mut self.data, + used_normal_length: self.used_normal_length, + used_peek_length: self.used_peek_length, + byte_order: self.byte_order, + }) + }, + Err(e) => Err(e), + } + + } +} + +impl<'a, I> HasError for InputDecoder<'a, I> where I : HasError { + /// calls has_error on the internal stream. + fn has_error(&self) -> bool { + self.input.has_error() + } +} + +/// Provides access to the internal data in various formats +pub struct MemoryDecoder<'a> { + /// A reference to the parents' data + data: &'a mut Vec, + /// The number of (valid) bytes in the buffer. + used_normal_length: usize, + /// The number of peek bytes in the buffer. + used_peek_length: usize, + /// Byte order used to read data from the buffer. + byte_order: ByteOrder, +} + +impl<'a> MemoryDecoder<'a> { + /// Set a part of the internal buffer to zero. + /// access to the whole buffer is possible, not just to the valid data. + pub fn zero_out_buffer(&mut self, start:usize, end:usize) { + for i in start..end { + self.data[i] = 0; + } + } + + /// Returns the current length of the buffer. (ie. how much valid data it contains.) + pub fn length(&self) -> usize { + self.used_normal_length + } + + /// Creates a clone of the internal buffer. The clone only contain the valid data. + pub fn clone_buffer(&self, other: &mut Vec) { + other.clone_from(&self.data); + other.resize(self.used_normal_length, 0); + } + + /// Returns a slice to the internal buffer starting at `start`. + pub fn get_buffer(&self, start: usize) -> &[u8] { + &self.data[start..self.used_normal_length] + } + + /// Returns a slice to the internal buffer including the peek data starting at `start`. + pub fn get_full_buffer(&self, start: usize) -> &[u8] { + &self.data[start..self.used_normal_length+self.used_peek_length] + } + + /// Returns a u8/u16/u32/u64 from the internal buffer at position `start`. + pub fn read_uint(&self, start: usize, byte_size: usize) -> u64 { + match byte_size { + 1 => self.data[start] as u64, + 2 => self.byte_order.read_u16(&self.data[start..start + 2]) as u64, + 4 => self.byte_order.read_u32(&self.data[start..start + 4]) as u64, + 8 => self.byte_order.read_u64(&self.data[start..start + 8]), + _ => panic!("Invalid byte_size: {}", byte_size), + } + } + + /// Returns a f32/f64 from the internal buffer at position `start`. + pub fn read_float(&self, start: usize, byte_size: usize) -> f64 { + match byte_size { + 4 => self.byte_order.read_f32(&self.data[start..start + 4]) as f64, + 8 => self.byte_order.read_f64(&self.data[start..start + 8]), + _ => panic!("Invalid byte_size: {}", byte_size), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Cursor; + use peekreader::PeekReader; + use byteorder_io::ByteOrder; + + #[test] + fn smoke_test() { + let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xff, 0xff]; + let mut input=PeekReader::new(Cursor::new(&data)); + let mut sut=InputDecoder::new(&mut input, 8, 2, ByteOrder::Little); + + match sut.peek_read() { + Ok(mut mem) => { + assert_eq!(8, mem.length()); + + assert_eq!(-2.0, mem.read_float(0, 8)); + assert_eq!(-2.0, mem.read_float(4, 4)); + assert_eq!(0xc000000000000000, mem.read_uint(0, 8)); + assert_eq!(0xc0000000, mem.read_uint(4, 4)); + assert_eq!(0xc000, mem.read_uint(6, 2)); + assert_eq!(0xc0, mem.read_uint(7, 1)); + assert_eq!(&[0, 0xc0], mem.get_buffer(6)); + assert_eq!(&[0, 0xc0, 0xff, 0xff], mem.get_full_buffer(6)); + + let mut copy: Vec = Vec::new(); + mem.clone_buffer(&mut copy); + assert_eq!(vec!{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0}, copy); + + mem.zero_out_buffer(7, 8); + assert_eq!(&[0, 0, 0xff, 0xff], mem.get_full_buffer(6)); + } + Err(e) => { assert!(false, e); } + } + + match sut.peek_read() { + Ok(mem) => { + assert_eq!(2, mem.length()); + assert_eq!(0xffff, mem.read_uint(0, 2)); + } + Err(e) => { assert!(false, e); } + } + } +} diff --git a/src/od/od.rs b/src/od/od.rs index 0b32b48cb..8270e74a3 100644 --- a/src/od/od.rs +++ b/src/od/od.rs @@ -27,6 +27,7 @@ mod parse_nrofbytes; mod parse_formats; mod parse_inputs; mod inputoffset; +mod inputdecoder; #[cfg(test)] mod mockstream; @@ -42,6 +43,7 @@ use parse_formats::{parse_format_flags, ParsedFormatterItemInfo}; use prn_char::format_ascii_dump; use parse_inputs::{parse_inputs, CommandLineInputs}; use inputoffset::{InputOffset, Radix}; +use inputdecoder::{InputDecoder,MemoryDecoder}; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); const MAX_BYTES_PER_UNIT: usize = 8; @@ -233,25 +235,25 @@ pub fn uumain(args: Vec) -> i32 { let mut input = open_input_peek_reader(&input_strings, skip_bytes, read_bytes); + let mut input_decoder = InputDecoder::new(&mut input, line_bytes, PEEK_BUFFER_SIZE, byte_order); + let mut input_offset = InputOffset::new(Radix::Octal, skip_bytes, label); if let Err(e) = input_offset.parse_radix_from_commandline(matches.opt_str("A")) { disp_err!("Invalid -A/--address-radix\n{}", e); return 1; } - odfunc(&mut input, &mut input_offset, line_bytes, byte_order, &formats[..], + odfunc(&mut input_decoder, &mut input_offset, line_bytes, &formats[..], output_duplicates) } // TODO: refactor, too many arguments -fn odfunc(input: &mut I, input_offset: &mut InputOffset, line_bytes: usize, byte_order: ByteOrder, +fn odfunc(input_decoder: &mut InputDecoder, input_offset: &mut InputOffset, line_bytes: usize, formats: &[ParsedFormatterItemInfo], output_duplicates: bool) -> i32 where I : PeekRead+HasError { let mut duplicate_line = false; let mut previous_bytes: Vec = Vec::new(); - let mut bytes: Vec = Vec::with_capacity(line_bytes + PEEK_BUFFER_SIZE); - unsafe { bytes.set_len(line_bytes + PEEK_BUFFER_SIZE); } // fast but uninitialized let byte_size_block = formats.iter().fold(1, |max, next| cmp::max(max, next.formatter_item_info.byte_size)); let print_width_block = formats @@ -294,29 +296,29 @@ fn odfunc(input: &mut I, input_offset: &mut InputOffset, line_bytes: usize, b loop { // print each line data (or multi-format raster of several lines describing the same data). - match input.peek_read(bytes.as_mut_slice(), PEEK_BUFFER_SIZE) { - Ok((0, _)) => { - input_offset.print_final_offset(); - break; - } - Ok((n, peekbytes)) => { + match input_decoder.peek_read() { + Ok(mut memory_decoder) => { + let length=memory_decoder.length(); + + if length == 0 { + input_offset.print_final_offset(); + break; + } + // not enough byte for a whole element, this should only happen on the last line. - if n != line_bytes { + if length != line_bytes { // set zero bytes in the part of the buffer that will be used, but is not filled. - let mut max_used = n + MAX_BYTES_PER_UNIT; + let mut max_used = length + MAX_BYTES_PER_UNIT; if max_used > line_bytes { max_used = line_bytes; } - for i in n..max_used { - bytes[i] = 0; - } + memory_decoder.zero_out_buffer(length, max_used); } if !output_duplicates - && n == line_bytes - && !previous_bytes.is_empty() - && previous_bytes[..line_bytes] == bytes[..line_bytes] { + && length == line_bytes + && memory_decoder.get_buffer(0) == &previous_bytes[..] { if !duplicate_line { duplicate_line = true; println!("*"); @@ -324,17 +326,16 @@ fn odfunc(input: &mut I, input_offset: &mut InputOffset, line_bytes: usize, b } else { duplicate_line = false; - if n == line_bytes { + if length == line_bytes { // save a copy of the input unless it is the last line - previous_bytes.clone_from(&bytes); + memory_decoder.clone_buffer(&mut previous_bytes); } - print_bytes(byte_order, &bytes, n, peekbytes, - &input_offset.format_byte_offset(), + print_bytes(&input_offset.format_byte_offset(), &memory_decoder, &spaced_formatters, byte_size_block, print_width_line); } - input_offset.increase_position(n); + input_offset.increase_position(length); } Err(e) => { show_error!("{}", e); @@ -344,70 +345,47 @@ fn odfunc(input: &mut I, input_offset: &mut InputOffset, line_bytes: usize, b }; } - if input.has_error() { + if input_decoder.has_error() { 1 } else { 0 } } -fn print_bytes(byte_order: ByteOrder, bytes: &[u8], length: usize, peekbytes: usize, prefix: &str, +fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, formats: &[SpacedFormatterItemInfo], byte_size_block: usize, print_width_line: usize) { let mut first = true; // First line of a multi-format raster. for f in formats { let mut output_text = String::new(); let mut b = 0; - while b < length { - let nextb = b + f.frm.formatter_item_info.byte_size; - + while b < input_decoder.length() { output_text.push_str(&format!("{:>width$}", "", width = f.spacing[b % byte_size_block])); match f.frm.formatter_item_info.formatter { FormatWriter::IntWriter(func) => { - let p: u64 = match f.frm.formatter_item_info.byte_size { - 1 => { - bytes[b] as u64 - } - 2 => { - byte_order.read_u16(&bytes[b..nextb]) as u64 - } - 4 => { - byte_order.read_u32(&bytes[b..nextb]) as u64 - } - 8 => { - byte_order.read_u64(&bytes[b..nextb]) - } - _ => { panic!("Invalid byte_size: {}", f.frm.formatter_item_info.byte_size); } - }; + let p = input_decoder.read_uint(b, f.frm.formatter_item_info.byte_size); output_text.push_str(&func(p)); } FormatWriter::FloatWriter(func) => { - let p: f64 = match f.frm.formatter_item_info.byte_size { - 4 => { - byte_order.read_f32(&bytes[b..nextb]) as f64 - } - 8 => { - byte_order.read_f64(&bytes[b..nextb]) - } - _ => { panic!("Invalid byte_size: {}", f.frm.formatter_item_info.byte_size); } - }; + let p = input_decoder.read_float(b, f.frm.formatter_item_info.byte_size); output_text.push_str(&func(p)); } FormatWriter::MultibyteWriter(func) => { - output_text.push_str(&func(&bytes[b..length+peekbytes])); + output_text.push_str(&func(input_decoder.get_full_buffer(b))); } } - b = nextb; + + b += f.frm.formatter_item_info.byte_size; } if f.frm.add_ascii_dump { let missing_spacing = print_width_line.saturating_sub(output_text.chars().count()); output_text.push_str(&format!("{:>width$} {}", "", - format_ascii_dump(&bytes[..length]), + format_ascii_dump(input_decoder.get_buffer(0)), width=missing_spacing)); }