summaryrefslogtreecommitdiffstats
path: root/src/openpgp/parse/buffered_reader_partial_body.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/openpgp/parse/buffered_reader_partial_body.rs')
-rw-r--r--src/openpgp/parse/buffered_reader_partial_body.rs300
1 files changed, 0 insertions, 300 deletions
diff --git a/src/openpgp/parse/buffered_reader_partial_body.rs b/src/openpgp/parse/buffered_reader_partial_body.rs
deleted file mode 100644
index db476626..00000000
--- a/src/openpgp/parse/buffered_reader_partial_body.rs
+++ /dev/null
@@ -1,300 +0,0 @@
-use std;
-use std::cmp;
-use std::io;
-use std::io::{Error,ErrorKind};
-
-use super::buffered_reader;
-use super::buffered_reader::BufferedReader;
-use super::super::BodyLength;
-
-/// A `BufferedReader` that transparently handles OpenPGP's chunking
-/// scheme. This implicitly implements a limitor.
-#[derive(Debug)]
-pub struct BufferedReaderPartialBodyFilter<T: BufferedReader> {
- // The underlying reader.
- reader: T,
-
- // The amount of unread data in the current partial body chunk.
- // That is, if `buffer` contains 10 bytes and
- // `partial_body_length` is 20, then there are 30 bytes of
- // unprocessed (unconsumed) data in the current chunk.
- partial_body_length: u32,
- // Whether this is the last partial body chuck.
- last: bool,
-
- // Sometimes we have to double buffer. This happens if the caller
- // requests X bytes and that chuck straddles a partial body length
- // boundary.
- buffer: Option<Box<[u8]>>,
- // The position within the buffer.
- cursor: usize,
-}
-
-impl<T: BufferedReader> BufferedReaderPartialBodyFilter<T> {
- /// Create a new BufferedReaderPartialBodyFilter object.
- /// `partial_body_length` is the amount of data in the initial
- /// partial body chunk.
- pub fn new(reader: T, partial_body_length: u32)
- -> BufferedReaderPartialBodyFilter<T> {
- BufferedReaderPartialBodyFilter {
- reader: reader,
- partial_body_length: partial_body_length,
- last: false,
- buffer: None,
- cursor: 0,
- }
- }
-
- // Make sure that the local buffer contains `amount` bytes.
- fn do_fill_buffer (&mut self, amount: usize) -> Result<(), std::io::Error> {
- //println!("BufferedReaderPartialBodyFilter::do_fill_buffer(\
- // amount: {}) (partial body length: {}, last: {})",
- // amount, self.partial_body_length, self.last);
-
- // We want to avoid double buffering as much as possible.
- // Thus, we only buffer as much as needed.
- let mut buffer = vec![0; amount];
- let mut amount_buffered = 0;
-
- if let Some(ref old_buffer) = self.buffer {
- // The amount of data that is left in the old buffer.
- let amount_left = old_buffer.len() - self.cursor;
-
- // This function should only be called if we actually need
- // to read something.
- assert!(amount > amount_left);
-
- amount_buffered = amount_left;
-
- // Copy the data that is still in buffer.
- buffer[..amount_buffered]
- .copy_from_slice(&old_buffer[self.cursor..]);
-
- }
-
- let mut err = None;
-
- loop {
- let to_read = cmp::min(
- // Data in current chunk.
- self.partial_body_length as usize,
- // Space left in the buffer.
- buffer.len() - amount_buffered);
- //println!("Trying to buffer {} bytes (partial body length: {}; space: {})",
- // to_read, self.partial_body_length,
- // buffer.len() - amount_buffered);
- if to_read > 0 {
- let result = self.reader.read(
- &mut buffer[amount_buffered..amount_buffered + to_read]);
- match result {
- Ok(did_read) => {
- //println!("Buffered {} bytes", did_read);
- amount_buffered += did_read;
- self.partial_body_length -= did_read as u32;
-
- if did_read < to_read {
- // Short read => EOF. We're done.
- // (Although the underlying message is
- // probably corrupt.)
- break;
- }
- },
- Err(e) => {
- //println!("Err reading: {:?}", e);
- err = Some(e);
- break;
- },
- }
- }
-
- if amount_buffered == amount || self.last {
- // We're read enough or we've read everything.
- break;
- }
-
- // Read the next partial body length header.
- assert_eq!(self.partial_body_length, 0);
-
- match super::body_length_new_format(&mut self.reader) {
- Ok(BodyLength::Full(len)) => {
- //println!("Last chuck: {} bytes", len);
- self.last = true;
- self.partial_body_length = len;
- },
- Ok(BodyLength::Partial(len)) => {
- //println!("Next chuck: {} bytes", len);
- self.partial_body_length = len;
- },
- Ok(BodyLength::Indeterminate) => {
- // A new format packet can't return Indeterminate.
- unreachable!();
- },
- Err(e) => {
- //println!("Err reading next chuck: {:?}", e);
- err = Some(e);
- break;
- }
- }
- }
-
- buffer.truncate(amount_buffered);
- buffer.shrink_to_fit();
-
- // We're done.
- self.buffer = Some(buffer.into_boxed_slice());
- self.cursor = 0;
-
- if let Some(err) = err {
- return Err(err)
- } else {
- return Ok(());
- }
- }
-
- fn data_helper(&mut self, amount: usize, hard: bool, and_consume: bool)
- -> Result<&[u8], std::io::Error> {
- let mut need_fill = false;
-
- //println!("BufferedReaderPartialBodyFilter::data_helper({})", amount);
-
- if let Some(ref buffer) = self.buffer {
- // We have some data buffered locally.
-
- //println!(" Reading from buffer");
-
- let amount_buffered = buffer.len() - self.cursor;
- if amount > amount_buffered {
- // The requested amount exceeds what is in the buffer.
- // Read more.
-
- // We can't call self.do_fill_buffer here, because self
- // is borrowed. Set a flag and do it after the borrow
- // ends.
- need_fill = true;
- }
- } else {
- // We don't have any data buffered.
-
- assert_eq!(self.cursor, 0);
-
- if amount <= self.partial_body_length as usize
- || /* Short read. */ self.last {
- // The amount of data that the caller requested does
- // not exceed the amount of data in the current chunk.
- // As such, there is no need to double buffer.
-
- //println!(" Reading from inner reader");
-
- let result = if hard && and_consume {
- self.reader.data_consume_hard (amount)
- } else if and_consume {
- self.reader.data_consume (amount)
- } else {
- self.reader.data(amount)
- };
- match result {
- Ok(buffer) => {
- let amount_buffered =
- std::cmp::min(buffer.len(), self.partial_body_length as usize);
- if hard && amount_buffered < amount {
- return Err(Error::new(ErrorKind::UnexpectedEof, "unepxected EOF"));
- } else {
- if and_consume {
- self.partial_body_length -=
- cmp::min(amount, amount_buffered) as u32;
- }
- return Ok(&buffer[..amount_buffered]);
- }
- },
- Err(err) => return Err(err),
- }
- } else {
- // `amount` crosses a partial body length boundary.
- // Do some buffering.
-
- //println!(" Read crosses chunk boundary. Need to buffer.");
-
- need_fill = true;
- }
- }
-
- if need_fill {
- //println!(" Need to refill the buffer.");
- let result = self.do_fill_buffer(amount);
- if let Err(err) = result {
- return Err(err);
- }
- }
-
- //println!(" Buffer: {:?} (cursor at {})",
- // if let Some(ref buffer) = self.buffer { Some(buffer.len()) } else { None },
- // self.cursor);
-
-
- // Note: if we hit the EOF, then we might still have less
- // than `amount` data. But, that's okay. We just need to
- // return as much as we can in that case.
- let buffer = &self.buffer.as_ref().unwrap()[self.cursor..];
- if hard && buffer.len() < amount {
- return Err(Error::new(ErrorKind::UnexpectedEof, "unepxected EOF"));
- }
- if and_consume {
- self.cursor += cmp::min(amount, buffer.len());
- }
- return Ok(buffer);
- }
-
-}
-
-impl<T: BufferedReader> std::io::Read for BufferedReaderPartialBodyFilter<T> {
- fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
- return buffered_reader::buffered_reader_generic_read_impl(self, buf);
- }
-}
-
-impl<T: BufferedReader> BufferedReader for BufferedReaderPartialBodyFilter<T> {
- /// Return the buffer. Ensure that it contains at least `amount`
- /// bytes.
-
- // Due to the mixing of usize (for lengths) and u32 (for OpenPGP),
- // we require that usize is at least as large as u32.
- // #[cfg(target_point_with = "32") or cfg(target_point_with = "64")]
- fn data(&mut self, amount: usize) -> Result<&[u8], std::io::Error> {
- return self.data_helper(amount, false, false);
- }
-
- fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
- return self.data_helper(amount, true, false);
- }
-
- fn consume(&mut self, amount: usize) -> &[u8] {
- if let Some(ref buffer) = self.buffer {
- // We have a local buffer.
-
- self.cursor += amount;
- // The caller can't consume more than is buffered!
- assert!(self.cursor <= buffer.len());
-
- return &buffer[self.cursor - amount..];
- } else {
- // Since we don't have a buffer, just pass through to the
- // underlying reader.
- assert!(amount <= self.partial_body_length as usize);
- self.partial_body_length -= amount as u32;
- return self.reader.consume(amount);
- }
- }
-
- fn data_consume(&mut self, amount: usize) -> Result<&[u8], std::io::Error> {
- return self.data_helper(amount, false, true);
- }
-
- fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], std::io::Error> {
- return self.data_helper(amount, true, true);
- }
-
- fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
- where Self: 'b {
- Some(Box::new(self.reader))
- }
-}