use crate::check::Check;
use crate::error::{Error, Result};
#[derive(Debug, Clone)]
pub struct Reader<'a> {
buf: &'a [u8],
pos: usize,
check: Check,
}
impl<'a> Reader<'a> {
pub fn new(buf: &'a [u8]) -> Self {
Reader {
buf,
pos: 0,
check: Check::DirChunkExtent,
}
}
pub fn checked(buf: &'a [u8], check: Check) -> Self {
Reader { buf, pos: 0, check }
}
pub fn with_check(mut self, check: Check) -> Self {
self.check = check;
self
}
pub fn check(&self) -> Check {
self.check
}
pub fn pos(&self) -> usize {
self.pos
}
pub fn remaining(&self) -> usize {
self.buf.len() - self.pos
}
pub fn is_empty(&self) -> bool {
self.pos == self.buf.len()
}
pub fn buffer(&self) -> &'a [u8] {
self.buf
}
pub fn tail(&self) -> &'a [u8] {
&self.buf[self.pos..]
}
fn truncate(&self, want: usize) -> Result<()> {
if self.remaining() < want {
return Err(Error::new(
self.check,
format!(
"truncated: need {want} byte(s) at offset {}, {} remaining",
self.pos,
self.remaining()
),
));
}
Ok(())
}
pub fn u8(&mut self) -> Result<u8> {
self.truncate(1)?;
let v = self.buf[self.pos];
self.pos += 1;
Ok(v)
}
pub fn u16(&mut self) -> Result<u16> {
Ok(u16::from_le_bytes(self.array::<2>()?))
}
pub fn u32(&mut self) -> Result<u32> {
Ok(u32::from_le_bytes(self.array::<4>()?))
}
pub fn u64(&mut self) -> Result<u64> {
Ok(u64::from_le_bytes(self.array::<8>()?))
}
pub fn array<const N: usize>(&mut self) -> Result<[u8; N]> {
self.truncate(N)?;
let mut out = [0u8; N];
out.copy_from_slice(&self.buf[self.pos..self.pos + N]);
self.pos += N;
Ok(out)
}
pub fn bytes(&mut self, n: usize) -> Result<&'a [u8]> {
self.truncate(n)?;
let out = &self.buf[self.pos..self.pos + n];
self.pos += n;
Ok(out)
}
pub fn rest(&mut self) -> &'a [u8] {
let out = &self.buf[self.pos..];
self.pos = self.buf.len();
out
}
pub fn skip(&mut self, n: usize) -> Result<()> {
self.truncate(n)?;
self.pos += n;
Ok(())
}
pub fn varint(&mut self) -> Result<u64> {
crate::varint::decode(self)
}
pub fn varint_bounded(&mut self, max: u64) -> Result<u64> {
let v = self.varint()?;
if v > max {
return Err(Error::new(
self.check,
format!("varint value {v} exceeds the bound {max}"),
));
}
Ok(v)
}
pub fn utf8(&mut self, n: usize) -> Result<&'a str> {
let bytes = self.bytes(n)?;
core::str::from_utf8(bytes).map_err(|e| {
Error::new(
self.check,
format!("invalid UTF-8 at offset {}: {e}", self.pos - n),
)
})
}
}
#[derive(Debug, Default, Clone)]
pub struct Writer {
buf: Vec<u8>,
}
impl Writer {
pub fn new() -> Self {
Writer { buf: Vec::new() }
}
pub fn with_capacity(capacity: usize) -> Self {
Writer {
buf: Vec::with_capacity(capacity),
}
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn as_slice(&self) -> &[u8] {
&self.buf
}
pub fn into_vec(self) -> Vec<u8> {
self.buf
}
pub fn u8(&mut self, v: u8) {
self.buf.push(v);
}
pub fn u16(&mut self, v: u16) {
self.buf.extend_from_slice(&v.to_le_bytes());
}
pub fn u32(&mut self, v: u32) {
self.buf.extend_from_slice(&v.to_le_bytes());
}
pub fn u64(&mut self, v: u64) {
self.buf.extend_from_slice(&v.to_le_bytes());
}
pub fn bytes(&mut self, v: &[u8]) {
self.buf.extend_from_slice(v);
}
pub fn varint(&mut self, v: u64) {
crate::varint::encode(self, v);
}
pub fn pad_to(&mut self, align: usize) {
debug_assert!(align.is_power_of_two());
while self.buf.len() % align != 0 {
self.buf.push(0);
}
}
pub fn patch_u32(&mut self, at: usize, v: u32) {
self.buf[at..at + 4].copy_from_slice(&v.to_le_bytes());
}
pub fn patch_u64(&mut self, at: usize, v: u64) {
self.buf[at..at + 8].copy_from_slice(&v.to_le_bytes());
}
pub fn patch_bytes(&mut self, at: usize, v: &[u8]) {
self.buf[at..at + v.len()].copy_from_slice(v);
}
}