| //! Streaming PEM reader. | |
| use super::Reader; | |
| use crate::{ErrorKind, Header, Length, Result}; | |
| use pem_rfc7468::Decoder; | |
| /// `Reader` type which decodes PEM on-the-fly. | |
| #[cfg(feature = "pem")] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] | |
| #[derive(Clone)] | |
| pub struct PemReader<'i> { | |
| /// Inner PEM decoder. | |
| decoder: Decoder<'i>, | |
| /// Input length (in bytes after Base64 decoding). | |
| input_len: Length, | |
| /// Position in the input buffer (in bytes after Base64 decoding). | |
| position: Length, | |
| } | |
| #[cfg(feature = "pem")] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] | |
| impl<'i> PemReader<'i> { | |
| /// Create a new PEM reader which decodes data on-the-fly. | |
| /// | |
| /// Uses the default 64-character line wrapping. | |
| pub fn new(pem: &'i [u8]) -> Result<Self> { | |
| let decoder = Decoder::new(pem)?; | |
| let input_len = Length::try_from(decoder.remaining_len())?; | |
| Ok(Self { | |
| decoder, | |
| input_len, | |
| position: Length::ZERO, | |
| }) | |
| } | |
| /// Get the PEM label which will be used in the encapsulation boundaries | |
| /// for this document. | |
| pub fn type_label(&self) -> &'i str { | |
| self.decoder.type_label() | |
| } | |
| } | |
| #[cfg(feature = "pem")] | |
| #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] | |
| impl<'i> Reader<'i> for PemReader<'i> { | |
| fn input_len(&self) -> Length { | |
| self.input_len | |
| } | |
| fn peek_byte(&self) -> Option<u8> { | |
| // TODO(tarcieri): lookahead buffer | |
| None | |
| } | |
| fn peek_header(&self) -> Result<Header> { | |
| // TODO(tarcieri): lookahead buffer | |
| Err(ErrorKind::Reader.into()) | |
| } | |
| fn position(&self) -> Length { | |
| self.position | |
| } | |
| fn read_slice(&mut self, _len: Length) -> Result<&'i [u8]> { | |
| // Can't borrow from PEM because it requires decoding | |
| Err(ErrorKind::Reader.into()) | |
| } | |
| fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { | |
| let bytes = self.decoder.decode(buf)?; | |
| self.position = (self.position + bytes.len())?; | |
| debug_assert_eq!( | |
| self.position, | |
| (self.input_len - Length::try_from(self.decoder.remaining_len())?)? | |
| ); | |
| Ok(bytes) | |
| } | |
| } |