From 6c5e4d71cf4bc552fa3d324603746121b54c1377 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Sun, 17 Aug 2025 17:59:34 +0200 Subject: [PATCH] nihav_core/io: merge ByteReader/ByteWriter functionality into ByteIO --- nihav-core/src/compr/deflate.rs | 5 +- nihav-core/src/demuxers/mod.rs | 20 +- nihav-core/src/io/byteio.rs | 702 ++++++++++++++------------------ nihav-core/src/muxers/mod.rs | 6 +- 4 files changed, 311 insertions(+), 422 deletions(-) diff --git a/nihav-core/src/compr/deflate.rs b/nihav-core/src/compr/deflate.rs index 80a84d8..72c583b 100644 --- a/nihav-core/src/compr/deflate.rs +++ b/nihav-core/src/compr/deflate.rs @@ -1066,7 +1066,7 @@ impl GzipCRC32 { } /// Decodes input data in gzip file format (RFC 1952) returning a vector containing decoded data. -pub fn gzip_decode(br: &mut ByteReader, skip_crc: bool) -> DecompressResult> { +pub fn gzip_decode(br: &mut dyn ByteIO, skip_crc: bool) -> DecompressResult> { const FLAG_HCRC: u8 = 0x02; const FLAG_EXTRA: u8 = 0x04; const FLAG_NAME: u8 = 0x08; @@ -2212,8 +2212,7 @@ mod test { 0x8B, 0x65, 0x00, 0xB7, 0x36, 0xBD, 0x77, 0xA8, 0xBD, 0x5A, 0xAA, 0x1A, 0x09, 0x00, 0x00 ]; - let mut mr = MemoryReader::new_read(TEST_DATA); - let mut br = ByteReader::new(&mut mr); + let mut br = MemoryReader::new_read(TEST_DATA); let _dst_buf = gzip_decode(&mut br, false).unwrap(); // println!("{}", String::from_utf8_lossy(_dst_buf.as_slice())); diff --git a/nihav-core/src/demuxers/mod.rs b/nihav-core/src/demuxers/mod.rs index 08bf8f7..12ebdd0 100644 --- a/nihav-core/src/demuxers/mod.rs +++ b/nihav-core/src/demuxers/mod.rs @@ -50,7 +50,7 @@ pub trait NAPacketReader { fn fill_packet(&mut self, pkt: &mut NAPacket) -> DemuxerResult<()>; } -impl<'a> NAPacketReader for ByteReader<'a> { +impl NAPacketReader for T { fn read_packet(&mut self, strm: NAStreamRef, ts: NATimeInfo, kf: bool, size: usize) -> DemuxerResult { let mut buf: Vec = Vec::with_capacity(size); if buf.capacity() < size { return Err(DemuxerError::MemoryError); } @@ -448,14 +448,14 @@ impl From for DemuxerError { /// The trait for creating demuxers. pub trait DemuxerCreator { - /// Creates new demuxer instance that will use `ByteReader` source as an input. - fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box + 'a>; + /// Creates new demuxer instance that will use source with `ByteIO` trait as an input. + fn new_demuxer<'a>(&self, br: &'a mut dyn ByteIO) -> Box + 'a>; /// Returns the name of current demuxer creator (equal to the container name it can demux). fn get_name(&self) -> &'static str; } /// Creates demuxer for a provided bytestream. -pub fn create_demuxer<'a>(dmxcr: &dyn DemuxerCreator, br: &'a mut ByteReader<'a>) -> DemuxerResult> { +pub fn create_demuxer<'a>(dmxcr: &dyn DemuxerCreator, br: &'a mut dyn ByteIO) -> DemuxerResult> { let mut dmx = dmxcr.new_demuxer(br); let mut strmgr = StreamManager::new(); let mut seek_idx = SeekIndex::new(); @@ -464,7 +464,7 @@ pub fn create_demuxer<'a>(dmxcr: &dyn DemuxerCreator, br: &'a mut ByteReader<'a> } /// Creates demuxer for a provided bytestream with options applied right after its creation. -pub fn create_demuxer_with_options<'a>(dmxcr: &dyn DemuxerCreator, br: &'a mut ByteReader<'a>, opts: &[NAOption]) -> DemuxerResult> { +pub fn create_demuxer_with_options<'a>(dmxcr: &dyn DemuxerCreator, br: &'a mut dyn ByteIO, opts: &[NAOption]) -> DemuxerResult> { let mut dmx = dmxcr.new_demuxer(br); dmx.set_options(opts); let mut strmgr = StreamManager::new(); @@ -617,16 +617,16 @@ impl<'a> NAOptionHandler for RawDemuxer<'a> { /// The trait for creating raw data demuxers. pub trait RawDemuxerCreator { - /// Creates new raw demuxer instance that will use `ByteReader` source as an input. - fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box + 'a>; + /// Creates new raw demuxer instance that will use source with `ByteIO` trait as an input. + fn new_demuxer<'a>(&self, br: &'a mut dyn ByteIO) -> Box + 'a>; /// Tries to check whether the input can be demuxed with the demuxer. - fn check_format(&self, br: &mut ByteReader) -> bool; + fn check_format(&self, br: &mut dyn ByteIO) -> bool; /// Returns the name of current raw data demuxer creator (equal to the container name it can demux). fn get_name(&self) -> &'static str; } /// Creates raw data demuxer for a provided bytestream. -pub fn create_raw_demuxer<'a>(dmxcr: &dyn RawDemuxerCreator, br: &'a mut ByteReader<'a>) -> DemuxerResult> { +pub fn create_raw_demuxer<'a>(dmxcr: &dyn RawDemuxerCreator, br: &'a mut dyn ByteIO) -> DemuxerResult> { let mut dmx = dmxcr.new_demuxer(br); let mut strmgr = StreamManager::new(); let mut seek_idx = SeekIndex::new(); @@ -635,7 +635,7 @@ pub fn create_raw_demuxer<'a>(dmxcr: &dyn RawDemuxerCreator, br: &'a mut ByteRea } /// Creates raw data demuxer for a provided bytestream with options applied right after its creation. -pub fn create_raw_demuxer_with_options<'a>(dmxcr: &dyn RawDemuxerCreator, br: &'a mut ByteReader<'a>, opts: &[NAOption]) -> DemuxerResult> { +pub fn create_raw_demuxer_with_options<'a>(dmxcr: &dyn RawDemuxerCreator, br: &'a mut dyn ByteIO, opts: &[NAOption]) -> DemuxerResult> { let mut dmx = dmxcr.new_demuxer(br); dmx.set_options(opts); let mut strmgr = StreamManager::new(); diff --git a/nihav-core/src/io/byteio.rs b/nihav-core/src/io/byteio.rs index ec62e9f..e127a0f 100644 --- a/nihav-core/src/io/byteio.rs +++ b/nihav-core/src/io/byteio.rs @@ -25,81 +25,6 @@ pub enum ByteIOError { /// 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; - /// 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 dyn ByteIO, -} - -/// Bytestream reader from memory. -pub struct MemoryReader<'a> { - buf: &'a [u8], - pos: usize, -} - -/// 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) => ({ unsafe { @@ -120,361 +45,462 @@ macro_rules! peek_int { }) } -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. +/// Common trait for bytestream operations. /// -/// # Example +/// User is supposed to create some reader/writer implementing this trait e.g. [`MemoryReader`] or [`MemoryWriter`] and use extended functions for reading or writing e.g. various integer types. +/// +/// # Examples /// +/// Read two 16-bit integers of different endianness: /// ```` -/// use nihav_core::io::byteio::read_u24be; +/// use nihav_core::io::byteio::{ByteIO,MemoryReader}; /// # use nihav_core::io::byteio::ByteIOResult; /// /// # fn foo() -> ByteIOResult<()> { -/// let src: [u8; 3] = [ 1, 2, 3]; -/// let value = read_u24be(&src)?; // should return 0x010203 +/// let memory: [u8; 4] = [ 0, 42, 42, 0 ]; +/// let mut br = MemoryReader::new_read(&memory); +/// 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(()) /// # } /// ```` -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 /// +/// Write two 16-bit integers of different endianness: /// ```` -/// use nihav_core::io::byteio::write_u24be; +/// use nihav_core::io::byteio::{ByteIO,MemoryWriter}; /// # 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 +/// let mut memory = [0u8; 4]; +/// let mut bw = MemoryWriter::new_write(&mut memory); +/// 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(()) /// # } /// ```` -#[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 failure. - pub fn read_buf(&mut self, buf: &mut [u8]) -> ByteIOResult<()> { - self.io.read_buf(buf) - } - - /// Allocates additional space in vector and reads data there. Partial read is treated as failure. - pub fn read_extend(&mut self, buf: &mut Vec, add_size: usize) -> ByteIOResult<()> { - let cur_size = buf.len(); - buf.resize(cur_size + add_size, 0); - self.io.read_buf(&mut buf[cur_size..]) - } - +/// +/// [`ByteIO`]: ./trait.ByteIO.html +/// [`MemoryReader`]: ./struct.MemoryReader.html +/// [`MemoryWriter`]: ./struct.MemoryWriter.html +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. - pub fn read_buf_some(&mut self, buf: &mut [u8]) -> ByteIOResult { - self.io.read_buf_some(buf) - } - + fn read_buf_some(&mut self, buf: &mut [u8]) -> ByteIOResult; /// 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) - } - + fn peek_buf(&mut self, buf: &mut [u8]) -> ByteIOResult; /// Reads single byte from the stream. - pub fn read_byte(&mut self) -> ByteIOResult { - self.io.read_byte() - } - + fn read_byte(&mut self) -> ByteIOResult; /// Returns the next byte value in the stream without advancing read position. - pub fn peek_byte(&mut self) -> ByteIOResult { - self.io.peek_byte() + 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; + /// 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<()>; + + /// Allocates additional space in vector and reads data there. Partial read is treated as failure. + fn read_extend(&mut self, buf: &mut Vec, add_size: usize) -> ByteIOResult<()> { + let cur_size = buf.len(); + buf.resize(cur_size + add_size, 0); + self.read_buf(&mut buf[cur_size..]) } /// Reads four-byte array from the stream. - pub fn read_tag(&mut self) -> ByteIOResult<[u8; 4]> { + fn read_tag(&mut self) -> ByteIOResult<[u8; 4]> { let mut buf = [0u8; 4]; - self.io.read_buf(&mut buf)?; + self.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]> { + fn peek_tag(&mut self) -> ByteIOResult<[u8; 4]> { let mut buf = [0u8; 4]; - self.io.peek_buf(&mut buf)?; + self.peek_buf(&mut buf)?; Ok(buf) } /// Reads 16-bit big-endian integer from the stream. - pub fn read_u16be(&mut self) -> ByteIOResult { + 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 { + 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 { + fn read_u24be(&mut self) -> ByteIOResult { let p16 = self.read_u16be()?; let p8 = self.read_byte()?; 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 { + fn peek_u24be(&mut self) -> ByteIOResult { let mut src: [u8; 3] = [0; 3]; self.peek_buf(&mut src)?; 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + fn read_u24le(&mut self) -> ByteIOResult { let p8 = self.read_byte()?; let p16 = self.read_u16le()?; 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 { + fn peek_u24le(&mut self) -> ByteIOResult { let mut src: [u8; 3] = [0; 3]; self.peek_buf(&mut src)?; 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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))?; + fn read_skip(&mut self, len: usize) -> ByteIOResult<()> { + if self.is_seekable() { + self.seek(SeekFrom::Current(len as i64))?; } else { let mut ssize = len; let mut buf : [u8; 16] = [0; 16]; let bref = &mut buf; while ssize > bref.len() { - self.io.read_buf(bref)?; + self.read_buf(bref)?; ssize -= bref.len(); } while ssize > 0 { - self.io.read_byte()?; + self.read_byte()?; ssize -= 1; } } Ok(()) } - /// Returns current read position. - pub fn tell(&mut self) -> u64 { - self.io.tell() + /// Reports number of bytes left in the stream. + fn left(&mut self) -> i64 { + let size = self.size(); + if size == -1 { return -1; } + size - (self.tell() as i64) } - /// Seeks to the provided position. - pub fn seek(&mut self, pos: SeekFrom) -> ByteIOResult { - self.io.seek(pos) + /// Writes single byte to the output. + fn write_byte(&mut self, val: u8) -> ByteIOResult<()> { + let buf: [u8; 1] = [val]; + self.write_buf(&buf) } - /// Tells whether this is end of stream. - pub fn is_eof(&self) -> bool { - self.io.is_eof() + /// Writes 16-bit big-endian integer to the output. + fn write_u16be(&mut self, val: u16) -> ByteIOResult<()> { + let buf: [u8; 2] = [((val >> 8) & 0xFF) as u8, (val & 0xFF) as u8]; + self.write_buf(&buf) } - /// Returns stream size or -1 if it is not known. - pub fn size(&mut self) -> i64 { - self.io.size() + /// Writes 16-bit little-endian integer to the output. + fn write_u16le(&mut self, val: u16) -> ByteIOResult<()> { + let buf: [u8; 2] = [(val & 0xFF) as u8, ((val >> 8) & 0xFF) as u8]; + self.write_buf(&buf) } - /// Reports number of bytes left in the stream. - pub fn left(&mut self) -> i64 { - let size = self.io.size(); - if size == -1 { return -1; } - size - (self.io.tell() as i64) + /// Writes 24-bit big-endian integer to the output. + 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. + 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. + 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. + 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. + fn write_u64be(&mut self, val: u64) -> ByteIOResult<()> { + self.write_u32be((val >> 32) as u32)?; + self.write_u32be(val as u32) + } + + /// Writes 64-bit little-endian integer to the output. + fn write_u64le(&mut self, val: u64) -> ByteIOResult<()> { + self.write_u32le(val as u32)?; + self.write_u32le((val >> 32) as u32) + } + + /// Writes 32-bit big-endian floating point number to the output. + 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. + 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. + 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. + fn write_f64le(&mut self, val: f64) -> ByteIOResult<()> { + self.write_u64le(val.to_bits()) + } + + /// Reports the amount of bytes the writer can still write (-1 if unknown). + fn size_left(&mut self) -> i64 { + let sz = self.size(); + if sz == -1 { return -1; } + sz - (self.tell() as i64) + } +} + +/// Bytestream reader from memory. +pub struct MemoryReader<'a> { + buf: &'a [u8], + pos: usize, +} + +/// 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_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> MemoryReader<'a> { /// Constructs a new instance of `MemoryReader`. pub fn new_read(buf: &'a [u8]) -> Self { @@ -840,33 +866,6 @@ impl ByteIO for BoundedFileReader { } -/// 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 dyn ByteIO, -} - /// Bytestream writer to memory. pub struct MemoryWriter<'a> { buf: &'a mut [u8], @@ -888,112 +887,6 @@ pub struct GrowableMemoryWriter<'a> { pos: usize, } -impl<'a> ByteWriter<'a> { - /// 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) 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 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`. @@ -1218,16 +1111,14 @@ mod test { fn test_read() { //const DATA : &'static [u8] = include_bytes!("../../assets/file"); let buf: [u8; 64] = [1; 64]; - let mut mr = MemoryReader::new_read(&buf); - let mut reader = ByteReader::new(&mut mr); + let mut reader = MemoryReader::new_read(&buf); assert_eq!(reader.read_byte().unwrap(), 0x01u8); assert_eq!(reader.read_u16le().unwrap(), 0x0101u16); 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/Misc/MaoMacha.asx").unwrap(); - let mut fr = FileReader::new_read(&mut file); - let mut br2 = ByteReader::new(&mut fr); + let mut br2 = FileReader::new_read(&mut file); assert_eq!(br2.read_byte().unwrap(), 0x30); assert_eq!(br2.read_u24be().unwrap(), 0x26B275); assert_eq!(br2.read_u24le().unwrap(), 0xCF668E); @@ -1238,8 +1129,7 @@ mod test { fn test_write() { let mut buf: [u8; 64] = [0; 64]; { - let mut mw = MemoryWriter::new_write(&mut buf); - let mut bw = ByteWriter::new(&mut mw); + let mut bw = MemoryWriter::new_write(&mut buf); bw.write_byte(0x00).unwrap(); bw.write_u16be(0x0102).unwrap(); bw.write_u24be(0x030405).unwrap(); diff --git a/nihav-core/src/muxers/mod.rs b/nihav-core/src/muxers/mod.rs index 4df7c4a..6ea01d8 100644 --- a/nihav-core/src/muxers/mod.rs +++ b/nihav-core/src/muxers/mod.rs @@ -164,8 +164,8 @@ impl<'a> NAOptionHandler for Muxer<'a> { /// The trait for creating muxers. pub trait MuxerCreator { - /// Creates new muxer instance that will use `ByteWriter` for output. - fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box + 'a>; + /// Creates new muxer instance that will use an object with `ByteIO` trait for output. + fn new_muxer<'a>(&self, bw: &'a mut dyn ByteIO) -> Box + 'a>; /// Returns the name of current muxer creator (equal to the container name it can create). fn get_name(&self) -> &'static str; /// Returns muxer capabilities for the current muxer. @@ -175,7 +175,7 @@ pub trait MuxerCreator { } /// Creates muxer for a provided bytestream writer. -pub fn create_muxer<'a>(mxcr: &dyn MuxerCreator, strmgr: StreamManager, bw: &'a mut ByteWriter<'a>) -> MuxerResult> { +pub fn create_muxer<'a>(mxcr: &dyn MuxerCreator, strmgr: StreamManager, bw: &'a mut dyn ByteIO) -> MuxerResult> { let mut mux = mxcr.new_muxer(bw); mux.create(&strmgr)?; Ok(Muxer::new(mux, strmgr)) -- 2.39.5