mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2026-01-16 02:01:05 +00:00
183 lines
6.5 KiB
Rust
183 lines
6.5 KiB
Rust
use std::io;
|
|
use byteorder_io::ByteOrder;
|
|
use multifilereader::HasError;
|
|
use peekreader::PeekRead;
|
|
use half::f16;
|
|
|
|
/// 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<u8>,
|
|
/// The number 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<I> {
|
|
let mut bytes: Vec<u8> = 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<MemoryDecoder> {
|
|
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<u8>,
|
|
/// 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<u8>) {
|
|
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 {
|
|
2 => f64::from(f16::from_bits(self.byte_order.read_u16(&self.data[start..start + 2]))),
|
|
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<u8> = 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); }
|
|
}
|
|
}
|
|
}
|