X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-core%2Fsrc%2Fio%2Fbyteio.rs;h=3fbee946a8989872a784adda451e6940582e7519;hp=966169cdefa00756767c79a500cd64ef70499064;hb=dee2d2f1b9a9b17593db0e9affdbb588ac72aa4e;hpb=5641dccfbf2a70d589cf094a0d4ed5a10f919f00 diff --git a/nihav-core/src/io/byteio.rs b/nihav-core/src/io/byteio.rs index 966169c..3fbee94 100644 --- a/nihav-core/src/io/byteio.rs +++ b/nihav-core/src/io/byteio.rs @@ -1,165 +1,426 @@ -use std::io::SeekFrom; -use std::fs::File; +//! Bytestream reading/writing functionality. +pub use std::io::SeekFrom; use std::io::prelude::*; +use std::ptr; +/// A list specifying general bytestream reading and writing errors. #[derive(Debug)] pub enum ByteIOError { + /// End of stream. EOF, + /// Wrong seek position was provided. WrongRange, + /// Tried to call read() on bytestream writer or write() on bytestream reader. WrongIOMode, + /// Functionality is not implemented. NotImplemented, + /// Read error. ReadError, + /// Write error. WriteError, + /// Seeking failed. SeekError, } +/// A specialised `Result` type for bytestream operations. pub type ByteIOResult = Result; +/// Common trait for bytestream operations. pub trait ByteIO { + /// Reads data into provided buffer. Fails if it cannot fill whole buffer. fn read_buf(&mut self, buf: &mut [u8]) -> ByteIOResult; + /// Reads data into provided buffer. Partial read is treated as success. fn read_buf_some(&mut self, buf: &mut [u8]) -> ByteIOResult; + /// Reads data into provided buffer but does not advance read position. fn peek_buf(&mut self, buf: &mut [u8]) -> ByteIOResult; + /// Reads single byte from the stream. fn read_byte(&mut self) -> ByteIOResult; + /// Returns the next byte value in the stream without advancing read position. fn peek_byte(&mut self) -> ByteIOResult; + /// Writes buffer to the stream. fn write_buf(&mut self, buf: &[u8]) -> ByteIOResult<()>; + /// Returns current read or write position. fn tell(&mut self) -> u64; + /// Seeks to the provided position. fn seek(&mut self, pos: SeekFrom) -> ByteIOResult; - fn is_eof(&mut self) -> bool; + /// Tells whether this is end of stream. + fn is_eof(&self) -> bool; + /// Reports whether stream is seekable or not. fn is_seekable(&mut self) -> bool; + /// Returns stream size or -1 if it is not known. fn size(&mut self) -> i64; + /// Flushes output if possible. + fn flush(&mut self) -> ByteIOResult<()>; } +/// High-level bytestream reader. +/// +/// User is supposed to create some reader implementing [`ByteIO`] trait e.g. [`MemoryReader`] and use it to create `ByteReader` which can be used for reading e.g. various integer types. +/// +/// # Examples +/// +/// ```` +/// use nihav_core::io::byteio::{MemoryReader,ByteReader}; +/// # use nihav_core::io::byteio::ByteIOResult; +/// +/// # fn foo() -> ByteIOResult<()> { +/// let memory: [u8; 4] = [ 0, 42, 42, 0 ]; +/// let mut mr = MemoryReader::new_read(&memory); +/// let mut br = ByteReader::new(&mut mr); +/// let val = br.read_u16be()?; // read 16-bit big-endian integer, should be 42 +/// let val = br.read_u16le()?; // read 16-bit little-endian integer, should be 42 as well +/// # Ok(()) +/// # } +/// ```` +/// +/// [`ByteIO`]: ./trait.ByteIO.html +/// [`MemoryReader`]: ./struct.MemoryReader.html #[allow(dead_code)] pub struct ByteReader<'a> { - io: &'a mut ByteIO, + io: &'a mut dyn ByteIO, } +/// Bytestream reader from memory. pub struct MemoryReader<'a> { buf: &'a [u8], - size: usize, pos: usize, } -pub struct FileReader<'a> { - file: &'a File, +/// Bytestream reader from anything implementing `std::io::Read` and `std::io::Seek`. +pub struct FileReader { + file: Box, + eof: bool, +} + +/// Bytestream reader from anything implementing `std::io::Read` and `std::io::Seek` that operates only on a part of the input. +pub struct BoundedFileReader { + file: Box, + start: u64, + end: Option, eof: bool, } macro_rules! read_int { ($s: ident, $inttype: ty, $size: expr, $which: ident) => ({ - let mut buf = [0; $size]; - $s.read_buf(&mut buf)?; unsafe { - Ok((*(buf.as_ptr() as *const $inttype)).$which()) + let mut buf: $inttype = 0; + $s.read_buf(&mut *(&mut buf as *mut $inttype as *mut [u8; $size]))?; + Ok(buf.$which()) } }) } macro_rules! peek_int { ($s: ident, $inttype: ty, $size: expr, $which: ident) => ({ - let mut buf = [0; $size]; - $s.peek_buf(&mut buf)?; unsafe { - Ok((*(buf.as_ptr() as *const $inttype)).$which()) + let mut buf: $inttype = 0; + $s.peek_buf(&mut *(&mut buf as *mut $inttype as *mut [u8; $size]))?; + Ok(buf.$which()) } }) } -impl<'a> ByteReader<'a> { - pub fn new(io: &'a mut ByteIO) -> Self { ByteReader { io: io } } +macro_rules! read_int_func { + ($s: ident, $inttype: ty, $size: expr, $which: ident) => { +/// Reads integer of certain size and endianness. + pub fn $s(src: &[u8]) -> ByteIOResult<$inttype> { + if src.len() < $size { return Err(ByteIOError::ReadError); } + unsafe { + let mut buf: $inttype = 0; + ptr::copy_nonoverlapping(src.as_ptr(), &mut buf as *mut $inttype as *mut u8, std::mem::size_of::<$inttype>()); + Ok(buf.$which()) + } + } + } +} + +read_int_func!(read_u16be, u16, 2, to_be); +read_int_func!(read_u16le, u16, 2, to_le); +read_int_func!(read_u32be, u32, 4, to_be); +read_int_func!(read_u32le, u32, 4, to_le); +read_int_func!(read_u64be, u64, 8, to_be); +read_int_func!(read_u64le, u64, 8, to_le); + +/// Reads 24-bit big-endian integer. +/// +/// # Example +/// +/// ```` +/// use nihav_core::io::byteio::read_u24be; +/// # use nihav_core::io::byteio::ByteIOResult; +/// +/// # fn foo() -> ByteIOResult<()> { +/// let src: [u8; 3] = [ 1, 2, 3]; +/// let value = read_u24be(&src)?; // should return 0x010203 +/// # Ok(()) +/// # } +/// ```` +pub fn read_u24be(src: &[u8]) -> ByteIOResult { + if src.len() < 3 { return Err(ByteIOError::ReadError); } + Ok((u32::from(src[0]) << 16) | (u32::from(src[1]) << 8) | u32::from(src[2])) +} +/// Reads 24-bit little-endian integer. +pub fn read_u24le(src: &[u8]) -> ByteIOResult { + if src.len() < 3 { return Err(ByteIOError::ReadError); } + Ok((u32::from(src[2]) << 16) | (u32::from(src[1]) << 8) | u32::from(src[0])) +} +/// Reads 32-bit big-endian floating point number. +pub fn read_f32be(src: &[u8]) -> ByteIOResult { Ok(f32::from_bits(read_u32be(src)?)) } +/// Reads 32-bit little-endian floating point number. +pub fn read_f32le(src: &[u8]) -> ByteIOResult { Ok(f32::from_bits(read_u32le(src)?)) } +/// Reads 64-bit big-endian floating point number. +pub fn read_f64be(src: &[u8]) -> ByteIOResult { Ok(f64::from_bits(read_u64be(src)?)) } +/// Reads 64-bit little-endian floating point number. +pub fn read_f64le(src: &[u8]) -> ByteIOResult { Ok(f64::from_bits(read_u64le(src)?)) } + +macro_rules! write_int_func { + ($s: ident, $inttype: ty, $size: expr, $which: ident) => { +/// Writes integer of certain size and endianness into byte buffer. + pub fn $s(dst: &mut [u8], val: $inttype) -> ByteIOResult<()> { + if dst.len() < $size { return Err(ByteIOError::WriteError); } + unsafe { + let val = val.$which(); + ptr::copy_nonoverlapping(&val as *const $inttype as *const u8, dst.as_mut_ptr(), std::mem::size_of::<$inttype>()); + } + Ok(()) + } + } +} +write_int_func!(write_u16be, u16, 2, to_be); +write_int_func!(write_u16le, u16, 2, to_le); +write_int_func!(write_u32be, u32, 4, to_be); +write_int_func!(write_u32le, u32, 4, to_le); +write_int_func!(write_u64be, u64, 8, to_be); +write_int_func!(write_u64le, u64, 8, to_le); + +/// Writes 24-bit big-endian integer to the provided buffer. +/// +/// # Example +/// +/// ```` +/// use nihav_core::io::byteio::write_u24be; +/// # use nihav_core::io::byteio::ByteIOResult; +/// +/// # fn foo() -> ByteIOResult<()> { +/// let mut dst = [0u8; 3]; +/// write_u24be(&mut dst, 0x010203)?; +/// // dst should contain [ 1, 2, 3] now +/// # Ok(()) +/// # } +/// ```` +#[allow(clippy::identity_op)] +pub fn write_u24be(dst: &mut [u8], val: u32) -> ByteIOResult<()> { + if dst.len() < 3 { return Err(ByteIOError::WriteError); } + dst[0] = (val >> 16) as u8; + dst[1] = (val >> 8) as u8; + dst[2] = (val >> 0) as u8; + Ok(()) +} +/// Writes 24-bit little-endian integer to the provided buffer. +#[allow(clippy::identity_op)] +pub fn write_u24le(dst: &mut [u8], val: u32) -> ByteIOResult<()> { + if dst.len() < 3 { return Err(ByteIOError::WriteError); } + dst[0] = (val >> 0) as u8; + dst[1] = (val >> 8) as u8; + dst[2] = (val >> 16) as u8; + Ok(()) +} +/// Writes 32-bit big-endian floating point number to the provided buffer. +pub fn write_f32be(dst: &mut [u8], val: f32) -> ByteIOResult<()> { write_u32be(dst, val.to_bits()) } +/// Writes 32-bit little-endian floating point number to the provided buffer. +pub fn write_f32le(dst: &mut [u8], val: f32) -> ByteIOResult<()> { write_u32le(dst, val.to_bits()) } +/// Writes 64-bit big-endian floating point number to the provided buffer. +pub fn write_f64be(dst: &mut [u8], val: f64) -> ByteIOResult<()> { write_u64be(dst, val.to_bits()) } +/// Writes 64-bit little-endian floating point number to the provided buffer. +pub fn write_f64le(dst: &mut [u8], val: f64) -> ByteIOResult<()> { write_u64le(dst, val.to_bits()) } + +impl<'a> ByteReader<'a> { + /// Constructs a new instance of bytestream reader. + /// + /// # Examples + /// + /// ```` + /// use nihav_core::io::byteio::{MemoryReader,ByteReader}; + /// # use nihav_core::io::byteio::ByteIOResult; + /// + /// # fn foo() -> ByteIOResult<()> { + /// let memory: [u8; 4] = [ 0, 42, 42, 0 ]; + /// let mut mr = MemoryReader::new_read(&memory); + /// let mut br = ByteReader::new(&mut mr); + /// # Ok(()) + /// # } + /// ```` + pub fn new(io: &'a mut dyn ByteIO) -> Self { ByteReader { io } } + + /// Reads data into provided buffer. Partial read is treated as success. pub fn read_buf(&mut self, buf: &mut [u8]) -> ByteIOResult { self.io.read_buf(buf) } + /// Reads data into provided buffer. Partial read is treated as success. pub fn read_buf_some(&mut self, buf: &mut [u8]) -> ByteIOResult { self.io.read_buf_some(buf) } + /// Reads data into provided buffer but does not advance read position. pub fn peek_buf(&mut self, buf: &mut [u8]) -> ByteIOResult { self.io.peek_buf(buf) } + /// Reads single byte from the stream. pub fn read_byte(&mut self) -> ByteIOResult { self.io.read_byte() } + /// Returns the next byte value in the stream without advancing read position. pub fn peek_byte(&mut self) -> ByteIOResult { self.io.peek_byte() } + /// Reads four-byte array from the stream. + pub fn read_tag(&mut self) -> ByteIOResult<[u8; 4]> { + let mut buf = [0u8; 4]; + self.io.read_buf(&mut buf)?; + Ok(buf) + } + + /// Reads four-byte array from the stream without advancing read position. + pub fn peek_tag(&mut self) -> ByteIOResult<[u8; 4]> { + let mut buf = [0u8; 4]; + self.io.peek_buf(&mut buf)?; + Ok(buf) + } + + /// Reads 16-bit big-endian integer from the stream. pub fn read_u16be(&mut self) -> ByteIOResult { read_int!(self, u16, 2, to_be) } + /// Reads 16-bit big-endian integer from the stream without advancing read position. pub fn peek_u16be(&mut self) -> ByteIOResult { peek_int!(self, u16, 2, to_be) } + /// Reads 24-bit big-endian integer from the stream. pub fn read_u24be(&mut self) -> ByteIOResult { let p16 = self.read_u16be()?; let p8 = self.read_byte()?; - Ok(((p16 as u32) << 8) | (p8 as u32)) + Ok((u32::from(p16) << 8) | u32::from(p8)) } + /// Reads 24-bit big-endian integer from the stream without advancing read position. pub fn peek_u24be(&mut self) -> ByteIOResult { let mut src: [u8; 3] = [0; 3]; self.peek_buf(&mut src)?; - Ok(((src[0] as u32) << 16) | ((src[1] as u32) << 8) | (src[2] as u32)) + Ok((u32::from(src[0]) << 16) | (u32::from(src[1]) << 8) | u32::from(src[2])) } + /// Reads 32-bit big-endian integer from the stream. pub fn read_u32be(&mut self) -> ByteIOResult { read_int!(self, u32, 4, to_be) } + /// Reads 32-bit big-endian integer from the stream without advancing read position. pub fn peek_u32be(&mut self) -> ByteIOResult { peek_int!(self, u32, 4, to_be) } + /// Reads 64-bit big-endian integer from the stream. pub fn read_u64be(&mut self) -> ByteIOResult { read_int!(self, u64, 8, to_be) } + /// Reads 64-bit big-endian integer from the stream without advancing read position. pub fn peek_u64be(&mut self) -> ByteIOResult { peek_int!(self, u64, 8, to_be) } + /// Reads 32-bit big-endian floating point number from the stream. + pub fn read_f32be(&mut self) -> ByteIOResult { + Ok(f32::from_bits(self.read_u32be()?)) + } + + /// Reads 32-bit big-endian floating point number from the stream without advancing read position. + pub fn peek_f32be(&mut self) -> ByteIOResult { + Ok(f32::from_bits(self.peek_u32be()?)) + } + + /// Reads 64-bit big-endian floating point number from the stream. + pub fn read_f64be(&mut self) -> ByteIOResult { + Ok(f64::from_bits(self.read_u64be()?)) + } + + /// Reads 64-bit big-endian floating point number from the stream without advancing read position. + pub fn peek_f64be(&mut self) -> ByteIOResult { + Ok(f64::from_bits(self.peek_u64be()?)) + } + + /// Reads 16-bit little-endian integer from the stream. pub fn read_u16le(&mut self) -> ByteIOResult { read_int!(self, u16, 2, to_le) } + /// Reads 16-bit little-endian integer from the stream without advancing read position. pub fn peek_u16le(&mut self) -> ByteIOResult { peek_int!(self, u16, 2, to_le) } + /// Reads 24-bit little-endian integer from the stream. pub fn read_u24le(&mut self) -> ByteIOResult { let p8 = self.read_byte()?; let p16 = self.read_u16le()?; - Ok(((p16 as u32) << 8) | (p8 as u32)) + Ok((u32::from(p16) << 8) | u32::from(p8)) } + /// Reads 24-bit little-endian integer from the stream without advancing read position. pub fn peek_u24le(&mut self) -> ByteIOResult { let mut src: [u8; 3] = [0; 3]; self.peek_buf(&mut src)?; - Ok((src[0] as u32) | ((src[1] as u32) << 8) | ((src[2] as u32) << 16)) + Ok(u32::from(src[0]) | (u32::from(src[1]) << 8) | (u32::from(src[2]) << 16)) } + /// Reads 32-bit little-endian integer from the stream. pub fn read_u32le(&mut self) -> ByteIOResult { read_int!(self, u32, 4, to_le) } + /// Reads 32-bit little-endian integer from the stream without advancing read position. pub fn peek_u32le(&mut self) -> ByteIOResult { peek_int!(self, u32, 4, to_le) } + /// Reads 64-bit little-endian integer from the stream. pub fn read_u64le(&mut self) -> ByteIOResult { read_int!(self, u64, 8, to_le) } + /// Reads 64-bit little-endian integer from the stream without advancing read position. pub fn peek_u64le(&mut self) -> ByteIOResult { peek_int!(self, u64, 8, to_le) } + /// Reads 32-bit little-endian floating point number from the stream. + pub fn read_f32le(&mut self) -> ByteIOResult { + Ok(f32::from_bits(self.read_u32le()?)) + } + + /// Reads 32-bit little-endian floating point number from the stream without advancing read position. + pub fn peek_f32le(&mut self) -> ByteIOResult { + Ok(f32::from_bits(self.peek_u32le()?)) + } + + /// Reads 64-bit little-endian floating point number from the stream. + pub fn read_f64le(&mut self) -> ByteIOResult { + Ok(f64::from_bits(self.read_u64le()?)) + } + + /// Reads 64-bit little-endian floating point number from the stream without advancing read position. + pub fn peek_f64le(&mut self) -> ByteIOResult { + Ok(f64::from_bits(self.peek_u64le()?)) + } + + /// Skips requested number of bytes. pub fn read_skip(&mut self, len: usize) -> ByteIOResult<()> { if self.io.is_seekable() { self.io.seek(SeekFrom::Current(len as i64))?; @@ -173,44 +434,49 @@ impl<'a> ByteReader<'a> { } while ssize > 0 { self.io.read_byte()?; - ssize = ssize - 1; + ssize -= 1; } } Ok(()) } + /// Returns current read position. pub fn tell(&mut self) -> u64 { self.io.tell() } + /// Seeks to the provided position. pub fn seek(&mut self, pos: SeekFrom) -> ByteIOResult { self.io.seek(pos) } - pub fn is_eof(&mut self) -> bool { + /// Tells whether this is end of stream. + pub fn is_eof(&self) -> bool { self.io.is_eof() } + /// Returns stream size or -1 if it is not known. pub fn size(&mut self) -> i64 { self.io.size() } + /// Reports number of bytes left in the stream. pub fn left(&mut self) -> i64 { let size = self.io.size(); if size == -1 { return -1; } - return size - (self.io.tell() as i64) + size - (self.io.tell() as i64) } } impl<'a> MemoryReader<'a> { - + /// Constructs a new instance of `MemoryReader`. pub fn new_read(buf: &'a [u8]) -> Self { - MemoryReader { buf: buf, size: buf.len(), pos: 0 } + MemoryReader { buf, pos: 0 } } fn real_seek(&mut self, pos: i64) -> ByteIOResult { - if pos < 0 || (pos as usize) > self.size { - return Err(ByteIOError::WrongRange) + if pos < 0 || (pos as usize) > self.buf.len() { + return Err(ByteIOError::WrongRange); } self.pos = pos as usize; Ok(pos as u64) @@ -221,7 +487,7 @@ impl<'a> ByteIO for MemoryReader<'a> { fn read_byte(&mut self) -> ByteIOResult { if self.is_eof() { return Err(ByteIOError::EOF); } let res = self.buf[self.pos]; - self.pos = self.pos + 1; + self.pos += 1; Ok(res) } @@ -231,11 +497,10 @@ impl<'a> ByteIO for MemoryReader<'a> { } fn peek_buf(&mut self, buf: &mut [u8]) -> ByteIOResult { - let copy_size = if self.size - self.pos < buf.len() { self.size } else { buf.len() }; + let copy_size = if self.buf.len() - self.pos < buf.len() { self.buf.len() - self.pos } else { buf.len() }; if copy_size == 0 { return Err(ByteIOError::EOF); } - for i in 0..copy_size { - buf[i] = self.buf[self.pos + i]; - } + let dst = &mut buf[0..copy_size]; + dst.copy_from_slice(&self.buf[self.pos..][..copy_size]); Ok(copy_size) } @@ -262,8 +527,8 @@ impl<'a> ByteIO for MemoryReader<'a> { } fn seek(&mut self, pos: SeekFrom) -> ByteIOResult { - let cur_pos = self.pos as i64; - let cur_size = self.size as i64; + let cur_pos = self.pos as i64; + let cur_size = self.buf.len() as i64; match pos { SeekFrom::Start(x) => self.real_seek(x as i64), SeekFrom::Current(x) => self.real_seek(cur_pos + x), @@ -271,8 +536,8 @@ impl<'a> ByteIO for MemoryReader<'a> { } } - fn is_eof(&mut self) -> bool { - self.pos >= self.size + fn is_eof(&self) -> bool { + self.pos >= self.buf.len() } fn is_seekable(&mut self) -> bool { @@ -282,21 +547,30 @@ impl<'a> ByteIO for MemoryReader<'a> { fn size(&mut self) -> i64 { self.buf.len() as i64 } + + fn flush(&mut self) -> ByteIOResult<()> { Ok(()) } } -impl<'a> FileReader<'a> { +impl FileReader { - pub fn new_read(file: &'a mut File) -> Self { - FileReader { file: file, eof : false } + /// Constructs a new instance of `FileReader`. + pub fn new_read(file: T) -> Self { + FileReader { file: Box::new(file), eof : false } } + /// Constructs a new instance of `FileReader` using a boxed resource. + pub fn new_read_boxed(file: Box) -> Self { + FileReader { file, eof : false } + } + /// Destroys the reader and releases the reader resource for a further use. + pub fn finish(self) -> Box { self.file } } -impl<'a> ByteIO for FileReader<'a> { +impl ByteIO for FileReader { fn read_byte(&mut self) -> ByteIOResult { let mut byte : [u8; 1] = [0]; - let err = self.file.read(&mut byte); - if let Err(_) = err { return Err(ByteIOError::ReadError); } - let sz = err.unwrap(); + let ret = self.file.read(&mut byte); + if ret.is_err() { return Err(ByteIOError::ReadError); } + let sz = ret.unwrap(); if sz == 0 { self.eof = true; return Err(ByteIOError::EOF); } Ok (byte[0]) } @@ -308,18 +582,30 @@ impl<'a> ByteIO for FileReader<'a> { } fn read_buf(&mut self, buf: &mut [u8]) -> ByteIOResult { - let res = self.file.read(buf); - if let Err(_) = res { return Err(ByteIOError::ReadError); } - let sz = res.unwrap(); - if sz < buf.len() { self.eof = true; return Err(ByteIOError::EOF); } - Ok(sz) + match self.file.read_exact(buf) { + Ok(()) => Ok(buf.len()), + Err(err) => { + if err.kind() == std::io::ErrorKind::UnexpectedEof { + self.eof = true; + Err(ByteIOError::EOF) + } else { + Err(ByteIOError::ReadError) + } + }, + } } fn read_buf_some(&mut self, buf: &mut [u8]) -> ByteIOResult { - let res = self.file.read(buf); - if let Err(_) = res { return Err(ByteIOError::ReadError); } - let sz = res.unwrap(); - if sz < buf.len() { self.eof = true; } + let ret = self.file.read(buf); + if ret.is_err() { return Err(ByteIOError::ReadError); } + let sz = ret.unwrap(); + if sz < buf.len() { + if let Err(_err) = self.file.read(&mut buf[sz..][..1]) { + self.eof = true; + } else { + return Ok(sz + 1); + } + } Ok(sz) } @@ -346,7 +632,7 @@ impl<'a> ByteIO for FileReader<'a> { } } - fn is_eof(&mut self) -> bool { + fn is_eof(&self) -> bool { self.eof } @@ -357,99 +643,344 @@ impl<'a> ByteIO for FileReader<'a> { fn size(&mut self) -> i64 { -1 } + + fn flush(&mut self) -> ByteIOResult<()> { Ok(()) } +} + + +impl BoundedFileReader { + + /// Constructs a new instance of `BoundedFileReader`. The reader pretends that data before `start` and after `end` (if set) does not exist. + pub fn new_read(file: T, start: u64, end: Option) -> ByteIOResult { + let mut file = Box::new(file); + if let Some(epos) = end { + if start > epos { + return Err(ByteIOError::WrongRange); + } + } + if start > 0 && file.seek(SeekFrom::Start(start)).is_err() { + return Err(ByteIOError::SeekError); + } + Ok(Self { file, start, end, eof : false }) + } + /// Constructs a new instance of `BoundedFileReader` using a boxed resource. The reader pretends that data before `start` and after `end` (if set) does not exist. + pub fn new_read_boxed(mut file: Box, start: u64, end: Option) -> ByteIOResult { + if let Some(epos) = end { + if start > epos { + return Err(ByteIOError::WrongRange); + } + } + if start > 0 && file.seek(SeekFrom::Start(start)).is_err() { + return Err(ByteIOError::SeekError); + } + Ok(Self { file, start, end, eof : false }) + } + /// Destroys the reader and releases the reader resource for a further use. + pub fn finish(self) -> Box { self.file } + fn real_tell(&mut self) -> u64 { + self.file.seek(SeekFrom::Current(0)).unwrap() + } + fn max_read_len(&mut self, len: usize) -> usize { + if let Some(epos) = self.end { + (len as u64).min(epos - self.real_tell()) as usize + } else { + len + } + } } +impl ByteIO for BoundedFileReader { + fn read_byte(&mut self) -> ByteIOResult { + if let Some(epos) = self.end { + if self.real_tell() >= epos { + self.eof = true; + return Err(ByteIOError::EOF); + } + } + let mut byte : [u8; 1] = [0]; + let ret = self.file.read(&mut byte); + if ret.is_err() { return Err(ByteIOError::ReadError); } + let sz = ret.unwrap(); + if sz == 0 { self.eof = true; return Err(ByteIOError::EOF); } + Ok (byte[0]) + } + + fn peek_byte(&mut self) -> ByteIOResult { + let b = self.read_byte()?; + if self.file.seek(SeekFrom::Current(-1)).is_err() { + return Err(ByteIOError::SeekError); + } + Ok(b) + } + + fn read_buf(&mut self, buf: &mut [u8]) -> ByteIOResult { + let len = self.max_read_len(buf.len()); + match self.file.read_exact(&mut buf[..len]) { + Ok(()) if len == buf.len() => Ok(buf.len()), + Ok(()) => { + self.eof = true; + Err(ByteIOError::EOF) + }, + Err(err) => { + if err.kind() == std::io::ErrorKind::UnexpectedEof { + self.eof = true; + Err(ByteIOError::EOF) + } else { + Err(ByteIOError::ReadError) + } + }, + } + } + + fn read_buf_some(&mut self, buf: &mut [u8]) -> ByteIOResult { + let len = self.max_read_len(buf.len()); + let ret = self.file.read(&mut buf[..len]); + if ret.is_err() { return Err(ByteIOError::ReadError); } + let sz = ret.unwrap(); + if sz < len { + if let Err(_err) = self.file.read(&mut buf[sz..][..1]) { + self.eof = true; + } else { + return Ok(sz + 1); + } + } + Ok(sz) + } + + fn peek_buf(&mut self, buf: &mut [u8]) -> ByteIOResult { + let len = self.max_read_len(buf.len()); + let size = self.read_buf(&mut buf[..len])?; + if self.file.seek(SeekFrom::Current(-(size as i64))).is_err() { + return Err(ByteIOError::SeekError); + } + Ok(size) + } + + #[allow(unused_variables)] + fn write_buf(&mut self, buf: &[u8]) -> ByteIOResult<()> { + Err(ByteIOError::NotImplemented) + } + + fn tell(&mut self) -> u64 { + self.file.seek(SeekFrom::Current(0)).unwrap() - self.start + } + + fn seek(&mut self, pos: SeekFrom) -> ByteIOResult { + let res = match pos { + SeekFrom::Start(off) => { + let dpos = self.start + off; + if let Some(epos) = self.end { + if dpos > epos { + return Err(ByteIOError::WrongRange); + } + } + self.file.seek(SeekFrom::Start(dpos)) + }, + SeekFrom::Current(off) => { + let dpos = (self.real_tell() as i64) + off; + let end = self.end.unwrap_or(dpos as u64); + if dpos < 0 || ((dpos as u64) < self.start) || ((dpos as u64) > end) { + return Err(ByteIOError::WrongRange); + } + self.file.seek(pos) + }, + SeekFrom::End(off) => { + if let Some(epos) = self.end { + let dpos = (epos as i64) + off; + if dpos < (self.start as i64) || ((dpos as u64) > epos) { + return Err(ByteIOError::WrongRange); + } + self.file.seek(SeekFrom::Start(dpos as u64)) + } else { + self.file.seek(pos) + } + }, + }; + match res { + Ok(r) => Ok(r), + Err(_) => Err(ByteIOError::SeekError), + } + } + + fn is_eof(&self) -> bool { + self.eof + } + + fn is_seekable(&mut self) -> bool { + true + } + + fn size(&mut self) -> i64 { + -1 + } + + fn flush(&mut self) -> ByteIOResult<()> { Ok(()) } +} + + +/// High-level bytestream writer. +/// +/// User is supposed to create some writer implementing [`ByteIO`] trait e.g. [`MemoryWriter`] and use it to create `ByteWriter` which can be used for writing e.g. various integer types. +/// +/// # Examples +/// +/// ```` +/// use nihav_core::io::byteio::{MemoryWriter,ByteWriter}; +/// # use nihav_core::io::byteio::ByteIOResult; +/// +/// # fn foo() -> ByteIOResult<()> { +/// let mut memory = [0u8; 4]; +/// let mut mw = MemoryWriter::new_write(&mut memory); +/// let mut bw = ByteWriter::new(&mut mw); +/// let val = bw.write_u16be(42)?; // memory should be [ 0, 42, 0, 0 ] +/// let val = bw.write_u16le(42)?; // memory should be [ 0, 42, 42, 0 ] +/// # Ok(()) +/// # } +/// ```` +/// +/// [`ByteIO`]: ./trait.ByteIO.html +/// [`MemoryWriter`]: ./struct.MemoryWriter.html #[allow(dead_code)] pub struct ByteWriter<'a> { - io: &'a mut ByteIO, + io: &'a mut dyn ByteIO, } +/// Bytestream writer to memory. pub struct MemoryWriter<'a> { buf: &'a mut [u8], - size: usize, pos: usize, } -pub struct FileWriter { - file: File, +/// Bytestream writer to anything implementing `std::io::Write` and `std::io::Seek`. +pub struct FileWriter { + file: Box, +} + +/// Bytestream writer to memory. +/// +/// Unlike [`MemoryWriter`] which writes to an array of fixed size, `GrowableMemoryWriter` grows output size when output size exceeds capacity. +/// +/// [`MemoryWriter`]: ./struct.MemoryWriter.html +pub struct GrowableMemoryWriter<'a> { + buf: &'a mut Vec, + pos: usize, } impl<'a> ByteWriter<'a> { - pub fn new(io: &'a mut ByteIO) -> Self { ByteWriter { io: io } } + /// Constructs a new instance of `ByteWriter`. + pub fn new(io: &'a mut dyn ByteIO) -> Self { ByteWriter { io } } + /// Writes byte array to the output. pub fn write_buf(&mut self, buf: &[u8]) -> ByteIOResult<()> { self.io.write_buf(buf) } + /// Writes single byte to the output. pub fn write_byte(&mut self, val: u8) -> ByteIOResult<()> { let buf: [u8; 1] = [val]; self.io.write_buf(&buf) } + /// Writes 16-bit big-endian integer to the output. pub fn write_u16be(&mut self, val: u16) -> ByteIOResult<()> { let buf: [u8; 2] = [((val >> 8) & 0xFF) as u8, (val & 0xFF) as u8]; self.io.write_buf(&buf) } + /// Writes 16-bit little-endian integer to the output. pub fn write_u16le(&mut self, val: u16) -> ByteIOResult<()> { let buf: [u8; 2] = [(val & 0xFF) as u8, ((val >> 8) & 0xFF) as u8]; self.io.write_buf(&buf) } + /// Writes 24-bit big-endian integer to the output. pub fn write_u24be(&mut self, val: u32) -> ByteIOResult<()> { let buf: [u8; 3] = [((val >> 16) & 0xFF) as u8, ((val >> 8) & 0xFF) as u8, (val & 0xFF) as u8]; self.write_buf(&buf) } + /// Writes 24-bit little-endian integer to the output. pub fn write_u24le(&mut self, val: u32) -> ByteIOResult<()> { let buf: [u8; 3] = [(val & 0xFF) as u8, ((val >> 8) & 0xFF) as u8, ((val >> 16) & 0xFF) as u8]; self.write_buf(&buf) } + /// Writes 32-bit big-endian integer to the output. pub fn write_u32be(&mut self, val: u32) -> ByteIOResult<()> { self.write_u16be(((val >> 16) & 0xFFFF) as u16)?; self.write_u16be((val & 0xFFFF) as u16) } + /// Writes 32-bit little-endian integer to the output. pub fn write_u32le(&mut self, val: u32) -> ByteIOResult<()> { self.write_u16le((val & 0xFFFF) as u16)?; self.write_u16le(((val >> 16) & 0xFFFF) as u16) } + /// Writes 64-bit big-endian integer to the output. pub fn write_u64be(&mut self, val: u64) -> ByteIOResult<()> { - self.write_u32be(((val >> 32) & 0xFFFFFFFF) as u32)?; - self.write_u32be((val & 0xFFFFFFFF) as u32) + self.write_u32be((val >> 32) as u32)?; + self.write_u32be(val as u32) } + /// Writes 64-bit little-endian integer to the output. pub fn write_u64le(&mut self, val: u64) -> ByteIOResult<()> { - self.write_u32le((val & 0xFFFFFFFF) as u32)?; - self.write_u32le(((val >> 32) & 0xFFFFFFFF) as u32) + self.write_u32le(val as u32)?; + self.write_u32le((val >> 32) as u32) + } + + /// Writes 32-bit big-endian floating point number to the output. + pub fn write_f32be(&mut self, val: f32) -> ByteIOResult<()> { + self.write_u32be(val.to_bits()) + } + + /// Writes 32-bit little-endian floating point number to the output. + pub fn write_f32le(&mut self, val: f32) -> ByteIOResult<()> { + self.write_u32le(val.to_bits()) } + /// Writes 64-bit big-endian floating point number to the output. + pub fn write_f64be(&mut self, val: f64) -> ByteIOResult<()> { + self.write_u64be(val.to_bits()) + } + + /// Writes 64-bit little-endian floating point number to the output. + pub fn write_f64le(&mut self, val: f64) -> ByteIOResult<()> { + self.write_u64le(val.to_bits()) + } + + /// Reports the current write position. pub fn tell(&mut self) -> u64 { self.io.tell() } + /// Seeks to the requested position. pub fn seek(&mut self, pos: SeekFrom) -> ByteIOResult { self.io.seek(pos) } + /// Reports the amount of bytes the writer can still write (-1 if unknown). pub fn size_left(&mut self) -> i64 { let sz = self.io.size(); if sz == -1 { return -1; } sz - (self.tell() as i64) } + + /// Flushes output stream if possible. + pub fn flush(&mut self) -> ByteIOResult<()> { + self.io.flush() + } } impl<'a> MemoryWriter<'a> { + /// Constructs a new instance of `MemoryWriter`. pub fn new_write(buf: &'a mut [u8]) -> Self { - let len = buf.len(); - MemoryWriter { buf: buf, size: len, pos: 0 } + MemoryWriter { buf, pos: 0 } } fn real_seek(&mut self, pos: i64) -> ByteIOResult { - if pos < 0 || (pos as usize) > self.size { + if pos < 0 || (pos as usize) > self.buf.len() { return Err(ByteIOError::WrongRange) } self.pos = pos as usize; @@ -484,10 +1015,88 @@ impl<'a> ByteIO for MemoryWriter<'a> { } fn write_buf(&mut self, buf: &[u8]) -> ByteIOResult<()> { - if self.pos + buf.len() > self.size { return Err(ByteIOError::WriteError); } - for i in 0..buf.len() { - self.buf[self.pos + i] = buf[i]; + if self.pos + buf.len() > self.buf.len() { return Err(ByteIOError::WriteError); } + self.buf[self.pos..][..buf.len()].copy_from_slice(buf); + self.pos += buf.len(); + Ok(()) + } + + fn tell(&mut self) -> u64 { + self.pos as u64 + } + + fn seek(&mut self, pos: SeekFrom) -> ByteIOResult { + let cur_pos = self.pos as i64; + let cur_size = self.buf.len() as i64; + match pos { + SeekFrom::Start(x) => self.real_seek(x as i64), + SeekFrom::Current(x) => self.real_seek(cur_pos + x), + SeekFrom::End(x) => self.real_seek(cur_size + x), } + } + + fn is_eof(&self) -> bool { + self.pos >= self.buf.len() + } + + fn is_seekable(&mut self) -> bool { + true + } + + fn size(&mut self) -> i64 { + self.buf.len() as i64 + } + + fn flush(&mut self) -> ByteIOResult<()> { Ok(()) } +} + +impl<'a> GrowableMemoryWriter<'a> { + + /// Constructs a new instance of `GrowableMemoryWriter`. + pub fn new_write(buf: &'a mut Vec) -> Self { + GrowableMemoryWriter { buf, pos: 0 } + } + + fn real_seek(&mut self, pos: i64) -> ByteIOResult { + if pos < 0 || (pos as usize) > self.buf.len() { + return Err(ByteIOError::WrongRange) + } + self.pos = pos as usize; + Ok(pos as u64) + } +} + +impl<'a> ByteIO for GrowableMemoryWriter<'a> { + #[allow(unused_variables)] + fn read_byte(&mut self) -> ByteIOResult { + Err(ByteIOError::NotImplemented) + } + + #[allow(unused_variables)] + fn peek_byte(&mut self) -> ByteIOResult { + Err(ByteIOError::NotImplemented) + } + + #[allow(unused_variables)] + fn read_buf(&mut self, buf: &mut [u8]) -> ByteIOResult { + Err(ByteIOError::NotImplemented) + } + + #[allow(unused_variables)] + fn read_buf_some(&mut self, buf: &mut [u8]) -> ByteIOResult { + Err(ByteIOError::NotImplemented) + } + + #[allow(unused_variables)] + fn peek_buf(&mut self, buf: &mut [u8]) -> ByteIOResult { + Err(ByteIOError::NotImplemented) + } + + fn write_buf(&mut self, buf: &[u8]) -> ByteIOResult<()> { + if self.pos + buf.len() > self.buf.len() { + self.buf.resize(self.pos + buf.len(), 0); + } + self.buf[self.pos..][..buf.len()].copy_from_slice(buf); self.pos += buf.len(); Ok(()) } @@ -497,8 +1106,8 @@ impl<'a> ByteIO for MemoryWriter<'a> { } fn seek(&mut self, pos: SeekFrom) -> ByteIOResult { - let cur_pos = self.pos as i64; - let cur_size = self.size as i64; + let cur_pos = self.pos as i64; + let cur_size = self.buf.len() as i64; match pos { SeekFrom::Start(x) => self.real_seek(x as i64), SeekFrom::Current(x) => self.real_seek(cur_pos + x), @@ -506,8 +1115,8 @@ impl<'a> ByteIO for MemoryWriter<'a> { } } - fn is_eof(&mut self) -> bool { - self.pos >= self.size + fn is_eof(&self) -> bool { + self.pos >= self.buf.len() } fn is_seekable(&mut self) -> bool { @@ -517,15 +1126,18 @@ impl<'a> ByteIO for MemoryWriter<'a> { fn size(&mut self) -> i64 { self.buf.len() as i64 } + + fn flush(&mut self) -> ByteIOResult<()> { Ok(()) } } -impl FileWriter { - pub fn new_write(file: File) -> Self { - FileWriter { file: file } +impl FileWriter { + /// Constructs a new instance of `FileWriter`. + pub fn new_write(file: T) -> Self { + FileWriter { file: Box::new(file) } } } -impl ByteIO for FileWriter { +impl ByteIO for FileWriter { #[allow(unused_variables)] fn read_byte(&mut self) -> ByteIOResult { Err(ByteIOError::NotImplemented) @@ -570,7 +1182,7 @@ impl ByteIO for FileWriter { } } - fn is_eof(&mut self) -> bool { + fn is_eof(&self) -> bool { false } @@ -581,6 +1193,13 @@ impl ByteIO for FileWriter { fn size(&mut self) -> i64 { -1 } + + fn flush(&mut self) -> ByteIOResult<()> { + match self.file.flush() { + Ok(()) => Ok(()), + Err(_) => Err(ByteIOError::WriteError), + } + } } #[cfg(test)] @@ -599,7 +1218,7 @@ mod test { assert_eq!(reader.read_u24le().unwrap(), 0x010101u32); assert_eq!(reader.read_u32le().unwrap(), 0x01010101u32); assert_eq!(reader.read_u64le().unwrap(), 0x0101010101010101u64); - let mut file = File::open("assets/MaoMacha.asx").unwrap(); + let mut file = File::open("assets/Misc/MaoMacha.asx").unwrap(); let mut fr = FileReader::new_read(&mut file); let mut br2 = ByteReader::new(&mut fr); assert_eq!(br2.read_byte().unwrap(), 0x30);