use alloc::vec::Vec;
use byteorder_lite::{ByteOrder, LittleEndian};
use core::fmt;
use crate::DecodeError;
#[derive(Clone)]
pub struct SliceReader<'a> {
data: &'a [u8],
pos: usize,
}
#[allow(dead_code)]
impl<'a> SliceReader<'a> {
#[inline]
pub fn new(data: &'a [u8]) -> Self {
Self { data, pos: 0 }
}
#[inline]
pub fn position(&self) -> u64 {
self.pos as u64
}
#[inline]
pub fn set_position(&mut self, pos: u64) {
self.pos = pos as usize;
}
#[inline]
pub fn get_ref(&self) -> &'a [u8] {
self.data
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline]
pub fn remaining(&self) -> usize {
self.data.len().saturating_sub(self.pos)
}
#[inline]
pub fn remaining_slice(&self) -> &'a [u8] {
&self.data[self.pos.min(self.data.len())..]
}
#[inline]
pub fn seek_from_start(&mut self, pos: u64) -> Result<u64, DecodeError> {
let pos = pos as usize;
if pos > self.data.len() {
return Err(DecodeError::BitStreamError);
}
self.pos = pos;
Ok(self.pos as u64)
}
#[inline]
pub fn seek_relative(&mut self, offset: i64) -> Result<(), DecodeError> {
let new_pos = if offset >= 0 {
self.pos.checked_add(offset as usize)
} else {
self.pos.checked_sub((-offset) as usize)
};
match new_pos {
Some(pos) if pos <= self.data.len() => {
self.pos = pos;
Ok(())
}
_ => Err(DecodeError::BitStreamError),
}
}
#[inline]
pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), DecodeError> {
let n = buf.len();
if self.pos + n > self.data.len() {
return Err(DecodeError::BitStreamError);
}
buf.copy_from_slice(&self.data[self.pos..self.pos + n]);
self.pos += n;
Ok(())
}
#[inline]
pub fn read(&mut self, buf: &mut [u8]) -> usize {
let available = self.data.len().saturating_sub(self.pos);
let to_read = buf.len().min(available);
buf[..to_read].copy_from_slice(&self.data[self.pos..self.pos + to_read]);
self.pos += to_read;
to_read
}
#[inline]
pub fn read_u8(&mut self) -> Result<u8, DecodeError> {
if self.pos >= self.data.len() {
return Err(DecodeError::BitStreamError);
}
let byte = self.data[self.pos];
self.pos += 1;
Ok(byte)
}
#[inline]
pub fn read_u16_le(&mut self) -> Result<u16, DecodeError> {
if self.pos + 2 > self.data.len() {
return Err(DecodeError::BitStreamError);
}
let val = LittleEndian::read_u16(&self.data[self.pos..]);
self.pos += 2;
Ok(val)
}
#[inline]
pub fn read_u24_le(&mut self) -> Result<u32, DecodeError> {
if self.pos + 3 > self.data.len() {
return Err(DecodeError::BitStreamError);
}
let val = LittleEndian::read_u24(&self.data[self.pos..]);
self.pos += 3;
Ok(val)
}
#[inline]
pub fn read_u32_le(&mut self) -> Result<u32, DecodeError> {
if self.pos + 4 > self.data.len() {
return Err(DecodeError::BitStreamError);
}
let val = LittleEndian::read_u32(&self.data[self.pos..]);
self.pos += 4;
Ok(val)
}
#[inline]
pub fn fill_buf(&self) -> &'a [u8] {
&self.data[self.pos.min(self.data.len())..]
}
#[inline]
pub fn consume(&mut self, amt: usize) {
self.pos = (self.pos + amt).min(self.data.len());
}
#[inline]
pub fn stream_position(&self) -> u64 {
self.pos as u64
}
#[inline]
pub fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, DecodeError> {
let remaining = self.remaining_slice();
let len = remaining.len();
buf.extend_from_slice(remaining);
self.pos = self.data.len();
Ok(len)
}
#[inline]
pub fn take_slice(&mut self, n: usize) -> Result<&'a [u8], DecodeError> {
if self.pos + n > self.data.len() {
return Err(DecodeError::BitStreamError);
}
let slice = &self.data[self.pos..self.pos + n];
self.pos += n;
Ok(slice)
}
#[inline]
pub fn peek_slice(&self, n: usize) -> Result<&'a [u8], DecodeError> {
if self.pos + n > self.data.len() {
return Err(DecodeError::BitStreamError);
}
Ok(&self.data[self.pos..self.pos + n])
}
}
impl fmt::Debug for SliceReader<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SliceReader")
.field("len", &self.data.len())
.field("pos", &self.pos)
.finish()
}
}
#[cfg(feature = "std")]
impl<'a> std::io::Read for SliceReader<'a> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
Ok(SliceReader::read(self, buf))
}
}
#[cfg(feature = "std")]
impl<'a> std::io::BufRead for SliceReader<'a> {
fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
Ok(SliceReader::fill_buf(self))
}
fn consume(&mut self, amt: usize) {
SliceReader::consume(self, amt)
}
}
#[cfg(feature = "std")]
impl<'a> std::io::Seek for SliceReader<'a> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
let new_pos = match pos {
std::io::SeekFrom::Start(n) => Some(n as usize),
std::io::SeekFrom::End(n) => {
if n >= 0 {
self.data.len().checked_add(n as usize)
} else {
self.data.len().checked_sub((-n) as usize)
}
}
std::io::SeekFrom::Current(n) => {
if n >= 0 {
self.pos.checked_add(n as usize)
} else {
self.pos.checked_sub((-n) as usize)
}
}
};
match new_pos {
Some(pos) if pos <= self.data.len() => {
self.pos = pos;
Ok(self.pos as u64)
}
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"seek out of bounds",
)),
}
}
}