der/reader/
pem.rs

1//! Streaming PEM reader.
2
3use super::Reader;
4use crate::{ErrorKind, Header, Length, Result};
5use pem_rfc7468::Decoder;
6
7/// `Reader` type which decodes PEM on-the-fly.
8#[cfg(feature = "pem")]
9#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
10#[derive(Clone)]
11pub struct PemReader<'i> {
12    /// Inner PEM decoder.
13    decoder: Decoder<'i>,
14
15    /// Input length (in bytes after Base64 decoding).
16    input_len: Length,
17
18    /// Position in the input buffer (in bytes after Base64 decoding).
19    position: Length,
20}
21
22#[cfg(feature = "pem")]
23#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
24impl<'i> PemReader<'i> {
25    /// Create a new PEM reader which decodes data on-the-fly.
26    ///
27    /// Uses the default 64-character line wrapping.
28    pub fn new(pem: &'i [u8]) -> Result<Self> {
29        let decoder = Decoder::new(pem)?;
30        let input_len = Length::try_from(decoder.remaining_len())?;
31
32        Ok(Self {
33            decoder,
34            input_len,
35            position: Length::ZERO,
36        })
37    }
38
39    /// Get the PEM label which will be used in the encapsulation boundaries
40    /// for this document.
41    pub fn type_label(&self) -> &'i str {
42        self.decoder.type_label()
43    }
44}
45
46#[cfg(feature = "pem")]
47#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
48impl<'i> Reader<'i> for PemReader<'i> {
49    fn input_len(&self) -> Length {
50        self.input_len
51    }
52
53    fn peek_byte(&self) -> Option<u8> {
54        // TODO(tarcieri): lookahead buffer
55        None
56    }
57
58    fn peek_header(&self) -> Result<Header> {
59        // TODO(tarcieri): lookahead buffer
60        Err(ErrorKind::Reader.into())
61    }
62
63    fn position(&self) -> Length {
64        self.position
65    }
66
67    fn read_slice(&mut self, _len: Length) -> Result<&'i [u8]> {
68        // Can't borrow from PEM because it requires decoding
69        Err(ErrorKind::Reader.into())
70    }
71
72    fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
73        let bytes = self.decoder.decode(buf)?;
74        self.position = (self.position + bytes.len())?;
75
76        debug_assert_eq!(
77            self.position,
78            (self.input_len - Length::try_from(self.decoder.remaining_len())?)?
79        );
80
81        Ok(bytes)
82    }
83}