use super::Reader;
use crate::{Decode, Error, ErrorKind, Header, Length, Result};
use core::cell::RefCell;
#[allow(clippy::integer_arithmetic)]
mod utils {
use crate::{Error, Length, Result};
use pem_rfc7468::Decoder;
#[derive(Clone)]
pub(super) struct BufReader<'i> {
decoder: Decoder<'i>,
remaining: usize,
buf: [u8; BufReader::CAPACITY],
pos: usize,
cap: usize,
}
impl<'i> BufReader<'i> {
const CAPACITY: usize = 256;
pub fn new(pem: &'i [u8]) -> Result<Self> {
let decoder = Decoder::new(pem)?;
let remaining = decoder.remaining_len();
Ok(Self {
decoder,
remaining,
buf: [0u8; 256],
pos: 0,
cap: 0,
})
}
pub fn remaining_len(&self) -> usize {
self.decoder.remaining_len() + self.cap - self.pos
}
fn fill_buffer(&mut self) -> Result<()> {
debug_assert!(self.pos <= self.cap);
if self.is_empty() {
self.pos = 0;
self.cap = 0;
}
let end = (self.cap + self.remaining).min(Self::CAPACITY);
let writable_slice = &mut self.buf[self.cap..end];
if writable_slice.is_empty() {
return Ok(());
}
let wrote = self.decoder.decode(writable_slice)?.len();
if wrote == 0 {
return Err(Error::incomplete(Length::try_from(self.pos)?));
}
self.cap += wrote;
self.remaining -= wrote;
debug_assert!(self.cap <= Self::CAPACITY);
Ok(())
}
pub fn type_label(&self) -> &'i str {
self.decoder.type_label()
}
fn is_empty(&self) -> bool {
self.pos == self.cap
}
fn as_slice(&self) -> &[u8] {
&self.buf[self.pos..self.cap]
}
}
impl<'i> BufReader<'i> {
pub fn peek_byte(&self) -> Option<u8> {
let s = self.as_slice();
s.first().copied()
}
pub fn copy_to_slice<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
let mut output_pos = 0;
while output_pos < buf.len() {
if self.is_empty() {
self.fill_buffer()?;
}
let available = &self.buf[self.pos..self.cap];
let window_len = (buf.len() - output_pos).min(available.len());
let window = &mut buf[output_pos..output_pos + window_len];
window.copy_from_slice(&available[..window_len]);
self.pos += window_len;
output_pos += window_len;
}
if self.is_empty() && self.decoder.remaining_len() != 0 {
self.fill_buffer()?
}
debug_assert_eq!(output_pos, buf.len());
Ok(buf)
}
}
}
#[cfg(feature = "pem")]
#[derive(Clone)]
pub struct PemReader<'i> {
reader: RefCell<utils::BufReader<'i>>,
input_len: Length,
position: Length,
}
#[cfg(feature = "pem")]
impl<'i> PemReader<'i> {
pub fn new(pem: &'i [u8]) -> Result<Self> {
let reader = utils::BufReader::new(pem)?;
let input_len = Length::try_from(reader.remaining_len())?;
Ok(Self {
reader: RefCell::new(reader),
input_len,
position: Length::ZERO,
})
}
pub fn type_label(&self) -> &'i str {
self.reader.borrow().type_label()
}
}
#[cfg(feature = "pem")]
impl<'i> Reader<'i> for PemReader<'i> {
fn input_len(&self) -> Length {
self.input_len
}
fn peek_byte(&self) -> Option<u8> {
if self.is_finished() {
None
} else {
self.reader.borrow().peek_byte()
}
}
fn peek_header(&self) -> Result<Header> {
if self.is_finished() {
Err(Error::incomplete(self.offset()))
} else {
Header::decode(&mut self.clone())
}
}
fn position(&self) -> Length {
self.position
}
fn read_slice(&mut self, _len: Length) -> Result<&'i [u8]> {
Err(ErrorKind::Reader.into())
}
fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
let bytes = self.reader.borrow_mut().copy_to_slice(buf)?;
self.position = (self.position + bytes.len())?;
debug_assert_eq!(
self.position,
(self.input_len - Length::try_from(self.reader.borrow().remaining_len())?)?
);
Ok(bytes)
}
}