From 18f76fce2141a2db396bd914719918ffe92ea290 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Mon, 1 Jan 2018 22:31:27 +0100 Subject: buffered_reader: Allow the user to store data in a BufferedReader. - We want to associate some data with a BufferedReader instance. Because a BufferedReader points to another BufferedReader, we can't use a wrapper object. This change provides a mechanism to store any required data inside the actual `BufferedReader`. Note: this is a zero-cost abstraction. If no data needs to be stored, then there is no cost. --- buffered-reader/src/decompress.rs | 132 ++++++++++++++++++++++++++++-------- buffered-reader/src/generic.rs | 46 ++++++++++--- buffered-reader/src/lib.rs | 40 ++++++++--- buffered-reader/src/limitor.rs | 60 +++++++++++++--- buffered-reader/src/memory.rs | 43 ++++++++++-- openpgp/src/parse/message_parser.rs | 4 +- openpgp/src/parse/parse.rs | 66 ++++++++++-------- openpgp/src/parse/partial_body.rs | 60 +++++++++++++--- openpgp/src/parse/subpacket.rs | 2 +- 9 files changed, 352 insertions(+), 101 deletions(-) diff --git a/buffered-reader/src/decompress.rs b/buffered-reader/src/decompress.rs index 648037fc..0bad2e48 100644 --- a/buffered-reader/src/decompress.rs +++ b/buffered-reader/src/decompress.rs @@ -7,25 +7,37 @@ use bzip2::read::BzDecoder; use super::*; -pub struct BufferedReaderDeflate { - reader: BufferedReaderGeneric>, +pub struct BufferedReaderDeflate, C> { + reader: BufferedReaderGeneric, C>, } -impl BufferedReaderDeflate { - pub fn new(reader: R) -> BufferedReaderDeflate { +impl > BufferedReaderDeflate { + /// Instantiate a new deflate decompression reader. `reader` is + /// the source to wrap. + pub fn new(reader: R) -> Self { + Self::with_cookie(reader, ()) + } +} + +impl , C> BufferedReaderDeflate { + /// Like `new()`, but sets a cookie, which can be retrieved using + /// the `cookie_ref` and `cookie_mut` methods, and set using + /// the `cookie_set` method. + pub fn with_cookie(reader: R, cookie: C) -> Self { BufferedReaderDeflate { - reader: BufferedReaderGeneric::new(DeflateDecoder::new(reader), None) + reader: BufferedReaderGeneric::with_cookie( + DeflateDecoder::new(reader), None, cookie), } } } -impl io::Read for BufferedReaderDeflate { +impl, C> io::Read for BufferedReaderDeflate { fn read(&mut self, buf: &mut [u8]) -> Result { self.reader.read(buf) } } -impl fmt::Debug for BufferedReaderDeflate { +impl , C> fmt::Debug for BufferedReaderDeflate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BufferedReaderDeflate") .field("reader", self.reader.reader.get_ref()) @@ -33,7 +45,8 @@ impl fmt::Debug for BufferedReaderDeflate { } } -impl BufferedReader for BufferedReaderDeflate { +impl, C> BufferedReader + for BufferedReaderDeflate { fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> { return self.reader.data(amount); } @@ -75,31 +88,56 @@ impl BufferedReader for BufferedReaderDeflate { return self.reader.steal_eof(); } - fn into_inner<'b>(self: Box) -> Option> where Self: 'b { + fn into_inner<'b>(self: Box) + -> Option + 'b>> where Self: 'b { // Strip the outer box. Some(Box::new((*self).reader.reader.into_inner())) } + + fn cookie_set(&mut self, cookie: C) -> C { + self.reader.cookie_set(cookie) + } + + fn cookie_ref(&self) -> &C { + self.reader.cookie_ref() + } + + fn cookie_mut(&mut self) -> &mut C { + self.reader.cookie_mut() + } } -pub struct BufferedReaderZlib { - reader: BufferedReaderGeneric>, +pub struct BufferedReaderZlib, C> { + reader: BufferedReaderGeneric, C>, } -impl BufferedReaderZlib { - pub fn new(reader: R) -> BufferedReaderZlib { +impl > BufferedReaderZlib { + /// Instantiate a new zlib decompression reader. `reader` is + /// the source to wrap. + pub fn new(reader: R) -> Self { + Self::with_cookie(reader, ()) + } +} + +impl , C> BufferedReaderZlib { + /// Like `new()`, but sets a cookie, which can be retrieved using + /// the `cookie_ref` and `cookie_mut` methods, and set using + /// the `cookie_set` method. + pub fn with_cookie(reader: R, cookie: C) -> Self { BufferedReaderZlib { - reader: BufferedReaderGeneric::new(ZlibDecoder::new(reader), None) + reader: BufferedReaderGeneric::with_cookie( + ZlibDecoder::new(reader), None, cookie), } } } -impl io::Read for BufferedReaderZlib { +impl, C> io::Read for BufferedReaderZlib { fn read(&mut self, buf: &mut [u8]) -> Result { self.reader.read(buf) } } -impl fmt::Debug for BufferedReaderZlib { +impl , C> fmt::Debug for BufferedReaderZlib { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BufferedReaderZlib") .field("reader", self.reader.reader.get_ref()) @@ -107,7 +145,8 @@ impl fmt::Debug for BufferedReaderZlib { } } -impl BufferedReader for BufferedReaderZlib { +impl, C> BufferedReader + for BufferedReaderZlib { fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> { return self.reader.data(amount); } @@ -149,31 +188,56 @@ impl BufferedReader for BufferedReaderZlib { return self.reader.steal_eof(); } - fn into_inner<'b>(self: Box) -> Option> where Self: 'b { + fn into_inner<'b>(self: Box) + -> Option + 'b>> where Self: 'b { // Strip the outer box. Some(Box::new((*self).reader.reader.into_inner())) } + + fn cookie_set(&mut self, cookie: C) -> C { + self.reader.cookie_set(cookie) + } + + fn cookie_ref(&self) -> &C { + self.reader.cookie_ref() + } + + fn cookie_mut(&mut self) -> &mut C { + self.reader.cookie_mut() + } } -pub struct BufferedReaderBzip { - reader: BufferedReaderGeneric>, +pub struct BufferedReaderBzip, C> { + reader: BufferedReaderGeneric, C>, +} + +impl > BufferedReaderBzip { + /// Instantiate a new bzip decompression reader. `reader` is + /// the source to wrap. + pub fn new(reader: R) -> Self { + Self::with_cookie(reader, ()) + } } -impl BufferedReaderBzip { - pub fn new(reader: R) -> BufferedReaderBzip { +impl , C> BufferedReaderBzip { + /// Like `new()`, but sets a cookie, which can be retrieved using + /// the `cookie_ref` and `cookie_mut` methods, and set using + /// the `cookie_set` method. + pub fn with_cookie(reader: R, cookie: C) -> Self { BufferedReaderBzip { - reader: BufferedReaderGeneric::new(BzDecoder::new(reader), None) + reader: BufferedReaderGeneric::with_cookie( + BzDecoder::new(reader), None, cookie), } } } -impl io::Read for BufferedReaderBzip { +impl, C> io::Read for BufferedReaderBzip { fn read(&mut self, buf: &mut [u8]) -> Result { self.reader.read(buf) } } -impl fmt::Debug for BufferedReaderBzip { +impl , C> fmt::Debug for BufferedReaderBzip { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BufferedReaderBzip") .field("reader", self.reader.reader.get_ref()) @@ -181,7 +245,7 @@ impl fmt::Debug for BufferedReaderBzip { } } -impl BufferedReader for BufferedReaderBzip { +impl, C> BufferedReader for BufferedReaderBzip { fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> { return self.reader.data(amount); } @@ -223,8 +287,22 @@ impl BufferedReader for BufferedReaderBzip { return self.reader.steal_eof(); } - fn into_inner<'b>(self: Box) -> Option> where Self: 'b { + fn into_inner<'b>(self: Box) + -> Option + 'b>> where Self: 'b { // Strip the outer box. Some(Box::new((*self).reader.reader.into_inner())) } + + fn cookie_set(&mut self, cookie: C) -> C { + self.reader.cookie_set(cookie) + } + + fn cookie_ref(&self) -> &C { + self.reader.cookie_ref() + } + + fn cookie_mut(&mut self) -> &mut C { + self.reader.cookie_mut() + } } + diff --git a/buffered-reader/src/generic.rs b/buffered-reader/src/generic.rs index 92ed6151..b8a0ad25 100644 --- a/buffered-reader/src/generic.rs +++ b/buffered-reader/src/generic.rs @@ -9,7 +9,7 @@ use super::*; /// source that implements the `Read` trait. This is sufficient when /// reading from a file, and it even works with a `&[u8]` (but /// `BufferedReaderMemory` is more efficient). -pub struct BufferedReaderGeneric { +pub struct BufferedReaderGeneric { buffer: Option>, // The next byte to read in the buffer. cursor: usize, @@ -22,9 +22,12 @@ pub struct BufferedReaderGeneric { saw_eof: bool, // The last error that we encountered, but have not yet returned. error: Option, + + // The user settable cookie. + cookie: C, } -impl fmt::Debug for BufferedReaderGeneric { +impl fmt::Debug for BufferedReaderGeneric { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let buffered_data = if let Some(ref buffer) = self.buffer { buffer.len() - self.cursor @@ -41,13 +44,23 @@ impl fmt::Debug for BufferedReaderGeneric { } } -impl BufferedReaderGeneric { +impl BufferedReaderGeneric { /// Instantiate a new generic reader. `reader` is the source to /// wrap. `preferred_chuck_size` is the preferred chuck size. If /// None, then the default will be used, which is usually what you /// want. - pub fn new(reader: T, preferred_chunk_size: Option) - -> BufferedReaderGeneric { + pub fn new(reader: T, preferred_chunk_size: Option) -> Self { + Self::with_cookie(reader, preferred_chunk_size, ()) + } +} + +impl BufferedReaderGeneric { + /// Like `new()`, but sets a cookie, which can be retrieved using + /// the `cookie_ref` and `cookie_mut` methods, and set using + /// the `cookie_set` method. + pub fn with_cookie( + reader: T, preferred_chunk_size: Option, cookie: C) + -> Self { BufferedReaderGeneric { buffer: None, cursor: 0, @@ -57,6 +70,7 @@ impl BufferedReaderGeneric { reader: Box::new(reader), saw_eof: false, error: None, + cookie: cookie, } } @@ -172,13 +186,13 @@ impl BufferedReaderGeneric { } } -impl io::Read for BufferedReaderGeneric { +impl io::Read for BufferedReaderGeneric { fn read(&mut self, buf: &mut [u8]) -> Result { return buffered_reader_generic_read_impl(self, buf); } } -impl BufferedReader for BufferedReaderGeneric { +impl BufferedReader for BufferedReaderGeneric { fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> { return self.data_helper(amount, false, false); } @@ -198,7 +212,7 @@ impl BufferedReader for BufferedReaderGeneric { if let Some(ref buffer) = self.buffer { assert!(self.cursor <= buffer.len()); assert!(amount <= buffer.len() - self.cursor, - "buffer contains just {} bytes, but you are trying to + "buffer contains just {} bytes, but you are trying to \ consume {} bytes. Did you forget to call data()?", buffer.len() - self.cursor, amount); @@ -218,10 +232,24 @@ impl BufferedReader for BufferedReaderGeneric { return self.data_helper(amount, true, true); } - fn into_inner<'b>(self: Box) -> Option> + fn into_inner<'b>(self: Box) -> Option + 'b>> where Self: 'b { None } + + fn cookie_set(&mut self, cookie: C) -> C { + use std::mem; + + mem::replace(&mut self.cookie, cookie) + } + + fn cookie_ref(&self) -> &C { + &self.cookie + } + + fn cookie_mut(&mut self) -> &mut C { + &mut self.cookie + } } #[test] diff --git a/buffered-reader/src/lib.rs b/buffered-reader/src/lib.rs index a8b4ee3c..4738ed2c 100644 --- a/buffered-reader/src/lib.rs +++ b/buffered-reader/src/lib.rs @@ -31,7 +31,7 @@ const DEFAULT_BUF_SIZE: usize = 8 * 1024; /// to first copy it to a local buffer. However, unlike `BufRead`, /// `BufferedReader` allows the caller to ensure that the internal /// buffer has a certain amount of data. -pub trait BufferedReader : io::Read + fmt::Debug { +pub trait BufferedReader : io::Read + fmt::Debug { /// Return the data in the internal buffer. Normally, the /// returned buffer will contain *at least* `amount` bytes worth /// of data. Less data may be returned if (and only if) the end @@ -169,8 +169,17 @@ pub trait BufferedReader : io::Read + fmt::Debug { Ok(()) } - fn into_inner<'a>(self: Box) -> Option> + fn into_inner<'a>(self: Box) -> Option + 'a>> where Self: 'a; + + /// Sets the `BufferedReader`'s cookie and returns the old value. + fn cookie_set(&mut self, cookie: C) -> C; + + /// Returns a reference to the `BufferedReader`'s cookie. + fn cookie_ref(&self) -> &C; + + /// Returns a mutable reference to the `BufferedReader`'s cookie. + fn cookie_mut(&mut self) -> &mut C; } /// This function implements the `std::io::Read::read` method in terms @@ -196,8 +205,8 @@ pub trait BufferedReader : io::Read + fmt::Debug { /// /// but, alas, Rust doesn't like that ("error[E0119]: conflicting /// implementations of trait `std::io::Read` for type `&mut _`"). -pub fn buffered_reader_generic_read_impl - (bio: &mut T, buf: &mut [u8]) -> Result { +pub fn buffered_reader_generic_read_impl, C> + (bio: &mut T, buf: &mut [u8]) -> Result { match bio.data_consume(buf.len()) { Ok(inner) => { let amount = cmp::min(buf.len(), inner.len()); @@ -209,7 +218,7 @@ pub fn buffered_reader_generic_read_impl } /// Make a `Box` look like a BufferedReader. -impl <'a> BufferedReader for Box { +impl <'a, C> BufferedReader for Box + 'a> { fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> { return self.as_mut().data(amount); } @@ -255,18 +264,30 @@ impl <'a> BufferedReader for Box { return self.as_mut().drop_eof(); } - fn into_inner<'b>(self: Box) -> Option> + fn into_inner<'b>(self: Box) -> Option + 'b>> where Self: 'b { // Strip the outer box. (*self).into_inner() } + + fn cookie_set(&mut self, cookie: C) -> C { + self.as_mut().cookie_set(cookie) + } + + fn cookie_ref(&self) -> &C { + self.as_ref().cookie_ref() + } + + fn cookie_mut(&mut self) -> &mut C { + self.as_mut().cookie_mut() + } } // The file was created as follows: // // for i in $(seq 0 9999); do printf "%04d\n" $i; done > buffered-reader-test.txt #[cfg(test)] -fn buffered_reader_test_data_check<'a, T: BufferedReader + 'a>(bio: &mut T) { +fn buffered_reader_test_data_check<'a, T: BufferedReader + 'a, C>(bio: &mut T) { use std::str; for i in 0 .. 10000 { @@ -308,7 +329,8 @@ mod test { // Try it again with a limitor. { let bio = BufferedReaderMemory::new(data); - let mut bio2 = BufferedReaderLimitor::new(bio, (data.len() / 2) as u64); + let mut bio2 = BufferedReaderLimitor::new( + bio, (data.len() / 2) as u64); let amount = { bio2.data_eof().unwrap().len() }; @@ -319,7 +341,7 @@ mod test { } #[cfg(test)] - fn buffered_reader_read_test_aux<'a, T: BufferedReader + 'a> + fn buffered_reader_read_test_aux<'a, T: BufferedReader + 'a, C> (mut bio: T, data: &[u8]) { let mut buffer = [0; 99]; diff --git a/buffered-reader/src/limitor.rs b/buffered-reader/src/limitor.rs index 052ceb0d..04916ef6 100644 --- a/buffered-reader/src/limitor.rs +++ b/buffered-reader/src/limitor.rs @@ -5,29 +5,53 @@ use super::*; /// A `BufferedReaderLimitor` limits the amount of data that can be /// read from a `BufferedReader`. -#[derive(Debug)] -pub struct BufferedReaderLimitor { +pub struct BufferedReaderLimitor, C> { reader: T, limit: u64, + + cookie: C, +} + +impl, C> fmt::Debug for BufferedReaderLimitor { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("BufferedReaderLimitor") + .field("limit", &self.limit) + .field("reader", &self.reader) + .finish() + } +} + +impl> BufferedReaderLimitor { + /// Instantiate a new limitor. `reader` is the source to wrap. + /// `limit` is the maximum number of bytes that will be returned + /// from the source. + pub fn new(reader: T, limit: u64) -> Self { + Self::with_cookie(reader, limit, ()) + } } -impl BufferedReaderLimitor { - pub fn new(reader: T, limit: u64) -> BufferedReaderLimitor { +impl, C> BufferedReaderLimitor { + /// Like `new()`, but sets a cookie, which can be retrieved using + /// the `cookie_ref` and `cookie_mut` methods, and set using + /// the `cookie_set` method. + pub fn with_cookie(reader: T, limit: u64, cookie: C) + -> BufferedReaderLimitor { BufferedReaderLimitor { reader: reader, limit: limit, + cookie: cookie, } } } -impl io::Read for BufferedReaderLimitor { +impl, C> io::Read for BufferedReaderLimitor { fn read(&mut self, buf: &mut [u8]) -> Result { let len = cmp::min(self.limit, buf.len() as u64) as usize; return self.reader.read(&mut buf[0..len]); } } -impl BufferedReader for BufferedReaderLimitor { +impl, C> BufferedReader for BufferedReaderLimitor { /// Return the buffer. Ensure that it contains at least `amount` /// bytes. fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> { @@ -75,10 +99,24 @@ impl BufferedReader for BufferedReaderLimitor { return result; } - fn into_inner<'b>(self: Box) -> Option> + fn into_inner<'b>(self: Box) -> Option + 'b>> where Self: 'b { Some(Box::new(self.reader)) } + + fn cookie_set(&mut self, cookie: C) -> C { + use std::mem; + + mem::replace(&mut self.cookie, cookie) + } + + fn cookie_ref(&self) -> &C { + &self.cookie + } + + fn cookie_mut(&mut self) -> &mut C { + &mut self.cookie + } } #[test] @@ -87,7 +125,7 @@ fn buffered_reader_limitor_test() { /* Add a single limitor. */ { - let mut bio : Box + let mut bio : Box> = Box::new(BufferedReaderMemory::new(data)); bio = { @@ -125,15 +163,15 @@ fn buffered_reader_limitor_test() { /* Try with two limitors where the first one imposes the real * limit. */ { - let mut bio : Box + let mut bio : Box> = Box::new(BufferedReaderMemory::new(data)); bio = { - let bio2 : Box + let bio2 : Box> = Box::new(BufferedReaderLimitor::new(bio, 5)); // We limit to 15 bytes, but bio2 will still limit us to 5 // bytes. - let mut bio3 : Box + let mut bio3 : Box> = Box::new(BufferedReaderLimitor::new(bio2, 15)); { let result = bio3.data(100).unwrap(); diff --git a/buffered-reader/src/memory.rs b/buffered-reader/src/memory.rs index 8d387c49..2bdc0eb2 100644 --- a/buffered-reader/src/memory.rs +++ b/buffered-reader/src/memory.rs @@ -7,13 +7,16 @@ use std::io::{Error,ErrorKind}; use super::*; /// A `BufferedReader` specialized for reading from memory buffers. -pub struct BufferedReaderMemory<'a> { +pub struct BufferedReaderMemory<'a, C> { buffer: &'a [u8], // The next byte to read in the buffer. cursor: usize, + + // The user settable cookie. + cookie: C, } -impl <'a> fmt::Debug for BufferedReaderMemory<'a> { +impl<'a, C> fmt::Debug for BufferedReaderMemory<'a, C> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BufferedReaderMemory") .field("buffer (bytes)", &&self.buffer.len()) @@ -22,11 +25,23 @@ impl <'a> fmt::Debug for BufferedReaderMemory<'a> { } } -impl<'a> BufferedReaderMemory<'a> { - pub fn new(buffer: &'a [u8]) -> BufferedReaderMemory<'a> { +impl<'a> BufferedReaderMemory<'a, ()> { + /// Instantiate a new memory-based reader. `buffer` contains the + /// reader's contents. + pub fn new(buffer: &'a [u8]) -> Self { + Self::with_cookie(buffer, ()) + } +} + +impl<'a, C> BufferedReaderMemory<'a, C> { + /// Like `new()`, but sets a cookie, which can be retrieved using + /// the `cookie_ref` and `cookie_mut` methods, and set using + /// the `cookie_set` method. + pub fn with_cookie(buffer: &'a [u8], cookie: C) -> Self { BufferedReaderMemory { buffer: buffer, cursor: 0, + cookie: cookie, } } @@ -37,7 +52,7 @@ impl<'a> BufferedReaderMemory<'a> { } } -impl<'a> io::Read for BufferedReaderMemory<'a> { +impl<'a, C> io::Read for BufferedReaderMemory<'a, C> { fn read(&mut self, buf: &mut [u8]) -> Result { let amount = cmp::min(buf.len(), self.buffer.len() - self.cursor); buf[0..amount].copy_from_slice( @@ -47,7 +62,7 @@ impl<'a> io::Read for BufferedReaderMemory<'a> { } } -impl<'a> BufferedReader for BufferedReaderMemory<'a> { +impl<'a, C> BufferedReader for BufferedReaderMemory<'a, C> { /// Return the buffer. Ensure that it contains at least `amount` /// bytes. fn data(&mut self, _amount: usize) -> Result<&[u8], io::Error> { @@ -77,10 +92,24 @@ impl<'a> BufferedReader for BufferedReaderMemory<'a> { return Ok(self.consume(amount)); } - fn into_inner<'b>(self: Box) -> Option> + fn into_inner<'b>(self: Box) -> Option + 'b>> where Self: 'b { None } + + fn cookie_set(&mut self, cookie: C) -> C { + use std::mem; + + mem::replace(&mut self.cookie, cookie) + } + + fn cookie_ref(&self) -> &C { + &self.cookie + } + + fn cookie_mut(&mut self) -> &mut C { + &mut self.cookie + } } #[test] diff --git a/openpgp/src/parse/message_parser.rs b/openpgp/src/parse/message_parser.rs index 179a7894..a9ad4c07 100644 --- a/openpgp/src/parse/message_parser.rs +++ b/openpgp/src/parse/message_parser.rs @@ -80,7 +80,7 @@ pub struct MessageParser<'a> { message: Message, } -impl PacketParserBuilder { +impl> PacketParserBuilder { /// Finishes configuring the `PacketParser` and returns a /// `MessageParser`. pub fn to_message_parser<'a>(self) @@ -103,7 +103,7 @@ impl<'a> MessageParser<'a> { /// Creates a `MessageParser` to parse the OpenPGP message stored /// in the `BufferedReader` object. - pub fn from_buffered_reader(bio: R) + pub fn from_buffered_reader + 'a>(bio: R) -> Result, io::Error> { Self::from_packet_parser(PacketParser::from_buffered_reader(bio)?) } diff --git a/openpgp/src/parse/parse.rs b/openpgp/src/parse/parse.rs index eeac51e1..a814d866 100644 --- a/openpgp/src/parse/parse.rs +++ b/openpgp/src/parse/parse.rs @@ -106,7 +106,7 @@ fn ctb_test() { /// Decodes a new format body length as described in [Section 4.2.2 of RFC 4880]. /// /// [Section 4.2.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-4.2.2 -pub fn body_length_new_format (bio: &mut T) +pub fn body_length_new_format, C> (bio: &mut T) -> Result { let octet1 = bio.data_consume_hard(1)?[0]; if octet1 < 192 { @@ -157,8 +157,8 @@ fn body_length_new_format_test() { /// Decodes an old format body length as described in [Section 4.2.1 of RFC 4880]. /// /// [Section 4.2.1 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-4.2.1 -pub fn body_length_old_format (bio: &mut T, - length_type: PacketLengthType) +pub fn body_length_old_format, C> + (bio: &mut T, length_type: PacketLengthType) -> Result { match length_type { PacketLengthType::OneOctet => @@ -196,7 +196,7 @@ fn body_length_old_format_test() { /// Parses an OpenPGP packet's header as described in [Section 4.2 of RFC 4880]. /// /// [Section 4.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-4.2 -pub fn header (bio: &mut R) +pub fn header, C> (bio: &mut R) -> Result { let ctb = ctb(bio.data_consume_hard(1)?[0])?; let length = match ctb { @@ -206,7 +206,7 @@ pub fn header (bio: &mut R) return Ok(Header { ctb: ctb, length: length }); } -fn unknown_parser<'a, R: BufferedReader + 'a>(bio: R, tag: Tag) +fn unknown_parser<'a, R: BufferedReader<()> + 'a>(bio: R, tag: Tag) -> Result, std::io::Error> { return Ok(PacketParser { packet: Packet::Unknown(Unknown { @@ -223,7 +223,7 @@ fn unknown_parser<'a, R: BufferedReader + 'a>(bio: R, tag: Tag) }); } -fn signature_parser<'a, R: BufferedReader + 'a>(mut bio: R) +fn signature_parser<'a, R: BufferedReader<()> + 'a>(mut bio: R) -> Result, std::io::Error> { let version = bio.data_consume_hard(1)?[0]; let sigtype = bio.data_consume_hard(1)?[0]; @@ -292,7 +292,7 @@ fn signature_parser_test () { // Parse the body of a public key, public subkey, secret key or secret // subkey packet. -fn key_parser<'a, R: BufferedReader + 'a>(mut bio: R, tag: Tag) +fn key_parser<'a, R: BufferedReader<()> + 'a>(mut bio: R, tag: Tag) -> Result, std::io::Error> { assert!(tag == Tag::PublicKey || tag == Tag::PublicSubkey @@ -331,7 +331,7 @@ fn key_parser<'a, R: BufferedReader + 'a>(mut bio: R, tag: Tag) } // Parse the body of a user id packet. -fn userid_parser<'a, R: BufferedReader + 'a>(mut bio: R) +fn userid_parser<'a, R: BufferedReader<()> + 'a>(mut bio: R) -> Result, std::io::Error> { return Ok(PacketParser { packet: Packet::UserID(UserID { @@ -349,7 +349,7 @@ fn userid_parser<'a, R: BufferedReader + 'a>(mut bio: R) } /// Parse the body of a literal packet. -fn literal_parser<'a, R: BufferedReader + 'a>(mut bio: R) +fn literal_parser<'a, R: BufferedReader<()> + 'a>(mut bio: R) -> Result, std::io::Error> { let format = bio.data_consume_hard(1)?[0]; let filename_len = bio.data_consume_hard(1)?[0]; @@ -437,7 +437,7 @@ fn literal_parser_test () { } // Parse the body of a compressed data packet. -fn compressed_data_parser<'a, R: BufferedReader + 'a>(mut bio: R) +fn compressed_data_parser<'a, R: BufferedReader<()> + 'a>(mut bio: R) -> Result, std::io::Error> { let algo = bio.data_hard(1)?[0]; @@ -446,7 +446,7 @@ fn compressed_data_parser<'a, R: BufferedReader + 'a>(mut bio: R) // 2 - ZLIB [RFC1950] // 3 - BZip2 [BZ2] // 100 to 110 - Private/Experimental algorithm - let bio : Box = match algo { + let bio : Box> = match algo { 0 => { // Uncompressed. bio.consume(1); @@ -588,12 +588,12 @@ const PACKET_PARSER_DEFAULTS : PacketParserSettings /// will only be needed in exceptional circumstances. Instead use, /// for instance, `PacketParser::from_file` or /// `PacketParser::from_reader` to start parsing an OpenPGP message. -pub struct PacketParserBuilder { +pub struct PacketParserBuilder> { bio: R, settings: PacketParserSettings, } -impl PacketParserBuilder { +impl> PacketParserBuilder { /// Creates a `PacketParserBuilder` for an OpenPGP message stored /// in a `BufferedReader` object. pub fn from_buffered_reader(bio: R) @@ -706,11 +706,11 @@ impl PacketParserBuilder { } } -impl <'a, R: io::Read + 'a> PacketParserBuilder> { +impl <'a, R: io::Read + 'a> PacketParserBuilder> { /// Creates a `PacketParserBuilder` for an OpenPGP message stored /// in a `std::io::Read` object. pub fn from_reader(reader: R) - -> Result>, + -> Result>, std::io::Error> { Ok(PacketParserBuilder { bio: BufferedReaderGeneric::new(reader, None), @@ -719,21 +719,21 @@ impl <'a, R: io::Read + 'a> PacketParserBuilder> { } } -impl PacketParserBuilder> { +impl PacketParserBuilder> { /// Creates a `PacketParserBuilder` for an OpenPGP message stored /// in the file named `path`. pub fn from_file>(path: P) - -> Result>, + -> Result>, std::io::Error> { PacketParserBuilder::from_reader(File::open(path)?) } } -impl <'a> PacketParserBuilder> { +impl <'a> PacketParserBuilder> { /// Creates a `PacketParserBuilder` for an OpenPGP message stored /// in specified buffer. pub fn from_bytes(bytes: &'a [u8]) - -> Result>, + -> Result>, std::io::Error> { PacketParserBuilder::from_buffered_reader( BufferedReaderMemory::new(bytes)) @@ -807,7 +807,7 @@ pub struct PacketParser<'a> { // what happens when we parse a compressed data packet: we return // a Decompressor (in fact, the actual type is only known at // run-time!). - reader: Box, + reader: Box + 'a>, // Whether the caller read the packets content. If so, then we // can't recurse, because we're missing some of the packet! @@ -832,7 +832,7 @@ impl <'a> std::fmt::Debug for PacketParser<'a> { // The return value of PacketParser::parse. enum PacketParserOrBufferedReader<'a> { PacketParser(PacketParser<'a>), - BufferedReader(Box), + BufferedReader(Box + 'a>), } // Converts an indentation level to whitespace. @@ -846,7 +846,7 @@ impl <'a> PacketParser<'a> { /// /// This function returns a `PacketParser` for the first packet in /// the stream. - pub fn from_buffered_reader(bio: R) + pub fn from_buffered_reader + 'a>(bio: R) -> Result>, std::io::Error> { PacketParserBuilder::from_buffered_reader(bio)?.finalize() } @@ -881,7 +881,7 @@ impl <'a> PacketParser<'a> { // Returns a packet parser for the next OpenPGP packet in the // stream. If there are no packets left, this function returns // `bio`. - fn parse(mut bio: R) + fn parse + 'a>(mut bio: R) -> Result, std::io::Error> { // When header encounters an EOF, it returns an error. But, // we want to return None. Try a one byte read. @@ -894,7 +894,7 @@ impl <'a> PacketParser<'a> { let header = header(&mut bio)?; - let bio : Box = match header.length { + let bio : Box> = match header.length { BodyLength::Full(len) => Box::new(BufferedReaderLimitor::new(bio, len as u64)), BodyLength::Partial(len) => @@ -1240,7 +1240,7 @@ impl<'a> io::Read for PacketParser<'a> { /// /// Note: it is safe to mix the use of the `std::io::Read` and /// `BufferedReader` interfaces. -impl<'a> BufferedReader for PacketParser<'a> { +impl<'a> BufferedReader<()> for PacketParser<'a> { fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> { // There is no need to set `content_was_read`, because this // doesn't actually consume any data. @@ -1306,10 +1306,22 @@ impl<'a> BufferedReader for PacketParser<'a> { return self.reader.drop_eof(); } - fn into_inner<'b>(self: Box) -> Option> + fn into_inner<'b>(self: Box) -> Option + 'b>> where Self: 'b { None } + + fn cookie_set(&mut self, cookie: ()) -> () { + self.reader.cookie_set(cookie) + } + + fn cookie_ref(&self) -> &() { + self.reader.cookie_ref() + } + + fn cookie_mut(&mut self) -> &mut () { + self.reader.cookie_mut() + } } // Check that we can use the read interface to stream the contents of @@ -1478,7 +1490,7 @@ impl Message { /// /// [`PacketParser`]: parse/struct.PacketParser.html /// [`MessageParser`]: parse/struct.MessageParser.html - pub fn from_buffered_reader(bio: R) + pub fn from_buffered_reader>(bio: R) -> Result { PacketParserBuilder::from_buffered_reader(bio)? .buffer_unread_content() diff --git a/openpgp/src/parse/partial_body.rs b/openpgp/src/parse/partial_body.rs index 0c7ca886..2773d310 100644 --- a/openpgp/src/parse/partial_body.rs +++ b/openpgp/src/parse/partial_body.rs @@ -9,8 +9,7 @@ use parse::body_length_new_format; /// A `BufferedReader` that transparently handles OpenPGP's chunking /// scheme. This implicitly implements a limitor. -#[derive(Debug)] -pub struct BufferedReaderPartialBodyFilter { +pub struct BufferedReaderPartialBodyFilter, C> { // The underlying reader. reader: T, @@ -28,20 +27,49 @@ pub struct BufferedReaderPartialBodyFilter { buffer: Option>, // The position within the buffer. cursor: usize, + + // The user-defined cookie. + cookie: C, } -impl BufferedReaderPartialBodyFilter { +impl, C> std::fmt::Debug + for BufferedReaderPartialBodyFilter { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("BufferedReaderPartialBodyFilter") + .field("reader", &self.reader) + .field("partial_body_length", &self.partial_body_length) + .field("last", &self.last) + .field("buffer (bytes left)", + &if let Some(ref buffer) = self.buffer { + Some(buffer.len()) + } else { + None + }) + .finish() + } +} + +impl> BufferedReaderPartialBodyFilter { /// 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 { + pub fn new(reader: T, partial_body_length: u32) -> Self { + Self::with_cookie(reader, partial_body_length, ()) + } +} + +impl, C> BufferedReaderPartialBodyFilter { + /// Create a new BufferedReaderPartialBodyFilter object. + /// `partial_body_length` is the amount of data in the initial + /// partial body chunk. + pub fn with_cookie(reader: T, partial_body_length: u32, cookie: C) -> Self { BufferedReaderPartialBodyFilter { reader: reader, partial_body_length: partial_body_length, last: false, buffer: None, cursor: 0, + cookie: cookie, } } @@ -246,13 +274,15 @@ impl BufferedReaderPartialBodyFilter { } -impl std::io::Read for BufferedReaderPartialBodyFilter { +impl, C> std::io::Read + for BufferedReaderPartialBodyFilter { fn read(&mut self, buf: &mut [u8]) -> Result { return buffered_reader_generic_read_impl(self, buf); } } -impl BufferedReader for BufferedReaderPartialBodyFilter { +impl, C> BufferedReader + for BufferedReaderPartialBodyFilter { /// Return the buffer. Ensure that it contains at least `amount` /// bytes. @@ -293,8 +323,22 @@ impl BufferedReader for BufferedReaderPartialBodyFilter { return self.data_helper(amount, true, true); } - fn into_inner<'b>(self: Box) -> Option> + fn into_inner<'b>(self: Box) -> Option + 'b>> where Self: 'b { Some(Box::new(self.reader)) } + + fn cookie_set(&mut self, cookie: C) -> C { + use std::mem; + + mem::replace(&mut self.cookie, cookie) + } + + fn cookie_ref(&self) -> &C { + &self.cookie + } + + fn cookie_mut(&mut self) -> &mut C { + &mut self.cookie + } } diff --git a/openpgp/src/parse/subpacket.rs b/openpgp/src/parse/subpacket.rs index bdc1dde9..e2cd694c 100644 --- a/openpgp/src/parse/subpacket.rs +++ b/openpgp/src/parse/subpacket.rs @@ -133,7 +133,7 @@ pub struct Subpacket<'a> { } /// Decode a subpacket length as described in Section 5.2.3.1 of RFC 4880. -fn subpacket_length(bio: &mut BufferedReaderMemory) +fn subpacket_length(bio: &mut BufferedReaderMemory<()>) -> Result { let octet1 = bio.data_consume_hard(1)?[0]; if octet1 < 192 { -- cgit v1.2.3