summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2017-12-11 15:18:31 +0100
committerNeal H. Walfield <neal@pep.foundation>2017-12-11 15:19:16 +0100
commit221de50d96f311a8a5687307c1c1a2fd89406081 (patch)
tree7c3eb4842b3efa4f8b3952172eba72ee0a184207 /src
parent1d87c32b9536fd49b65a11364d882edb115650aa (diff)
Rework the parser interface and implementation to support streaming
- Our goal is to gradually parse messages so that it is possible to work with messages that don't fit in the available memory. The current implementation parsed the messages in their entirety using recursion. To provide to a generator interface, we need to be much more careful with lifetimes. This requires changing the interface. - Change the `BufferedReader` objects to own any encapsulated `BufferedReader`s rather than just holding a reference. This is necessary so the generator can keep a stack of filters. - Provide new decompressor implementations so that it is possible to extract the contained `BufferedReader`. - Use vectors instead of boxes slices to hold raw byte strings. - Store a packet's contents (either any children or the raw data) in the common area. Also provide a DerefMut implementation to access it. - Make packets comparable (PartialEq) and printable (Debug).
Diffstat (limited to 'src')
-rw-r--r--src/openpgp/openpgp.rs90
-rw-r--r--src/openpgp/parse/buffered_reader.rs176
-rw-r--r--src/openpgp/parse/buffered_reader_decompress.rs230
-rw-r--r--src/openpgp/parse/buffered_reader_partial_body.rs19
-rw-r--r--src/openpgp/parse/compression-quine.gpgbin0 -> 182 bytes
-rw-r--r--src/openpgp/parse/compression-quine.txt3
-rw-r--r--src/openpgp/parse/parse.rs843
7 files changed, 1080 insertions, 281 deletions
diff --git a/src/openpgp/openpgp.rs b/src/openpgp/openpgp.rs
index 31d09d50..9df0d0e7 100644
--- a/src/openpgp/openpgp.rs
+++ b/src/openpgp/openpgp.rs
@@ -1,8 +1,7 @@
// Machinery for parsing and serializing OpenPGP packet headers.
use std;
-use std::ops::Deref;
-use self::parse::BufferedReader;
+use std::ops::{Deref,DerefMut};
/// The OpenPGP packet types. The values correspond to the serialized
/// format. The packet types named UnassignedXX are not in use as of
@@ -130,7 +129,7 @@ pub enum PacketLengthType {
pub struct CTBOld {
common: CTBCommon,
length_type: PacketLengthType,
-}
+}
// Allow transparent access of common fields.
impl Deref for CTBOld {
@@ -176,8 +175,11 @@ pub enum BodyLength {
}
#[derive(Debug)]
+#[derive(PartialEq)]
pub struct PacketCommon {
tag: Tag,
+ children: Option<Container>,
+ content: Option<Vec<u8>>,
}
/// An OpenPGP packet's header.
@@ -187,16 +189,17 @@ pub struct Header {
length: BodyLength,
}
+#[derive(PartialEq)]
pub struct Signature {
common: PacketCommon,
version: u8,
sigtype: u8,
pk_algo: u8,
hash_algo: u8,
- hashed_area: Box<[u8]>,
- unhashed_area: Box<[u8]>,
+ hashed_area: Vec<u8>,
+ unhashed_area: Vec<u8>,
hash_prefix: [u8; 2],
- mpis: Box<[u8]>,
+ mpis: Vec<u8>,
}
impl std::fmt::Debug for Signature {
@@ -227,13 +230,14 @@ impl<'a> Deref for Signature {
}
}
+#[derive(PartialEq)]
pub struct Key {
common: PacketCommon,
version: u8,
/* When the key was created. */
creation_time: u32,
pk_algo: u8,
- mpis: Box<[u8]>,
+ mpis: Vec<u8>,
}
impl std::fmt::Debug for Key {
@@ -259,9 +263,10 @@ impl<'a> Deref for Key {
}
}
+#[derive(PartialEq)]
pub struct UserID {
common: PacketCommon,
- value: Box<[u8]>,
+ value: Vec<u8>,
}
impl std::fmt::Debug for UserID {
@@ -283,6 +288,7 @@ impl<'a> Deref for UserID {
}
}
+#[derive(PartialEq)]
pub struct Literal {
common: PacketCommon,
format: u8,
@@ -293,7 +299,6 @@ pub struct Literal {
// String::from_utf8_lossy().
filename: Option<Vec<u8>>,
date: u32,
- content: Box<[u8]>,
}
impl std::fmt::Debug for Literal {
@@ -304,13 +309,20 @@ impl std::fmt::Debug for Literal {
None
};
+ let content = if let Some(ref content) = self.common.content {
+ &content[..]
+ } else {
+ &b""[..]
+ };
+
let threshold = 36;
- let prefix = &self.content[..std::cmp::min(threshold, self.content.len())];
+ let prefix =
+ &content[..std::cmp::min(threshold, content.len())];
let mut prefix_fmt = String::from_utf8_lossy(prefix).into_owned();
- if self.content.len() > threshold {
+ if content.len() > threshold {
prefix_fmt.push_str("...");
}
- prefix_fmt.push_str(&format!(" ({} bytes)", self.content.len())[..]);
+ prefix_fmt.push_str(&format!(" ({} bytes)", content.len())[..]);
f.debug_struct("Literal")
.field("format", &(self.format as char))
@@ -330,10 +342,10 @@ impl<'a> Deref for Literal {
}
}
+#[derive(PartialEq)]
pub struct CompressedData {
common: PacketCommon,
algo: u8,
- content: Message,
}
// Allow transparent access of common fields.
@@ -349,12 +361,12 @@ impl std::fmt::Debug for CompressedData {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("CompressedData")
.field("algo", &self.algo)
- .field("content", &self.content)
.finish()
}
}
#[derive(Debug)]
+#[derive(PartialEq)]
pub enum Packet {
Signature(Signature),
PublicKey(Key),
@@ -373,18 +385,53 @@ impl<'a> Deref for Packet {
fn deref(&self) -> &Self::Target {
match self {
&Packet::Signature(ref packet) => &packet.common,
+ &Packet::PublicKey(ref packet) => &packet.common,
+ &Packet::PublicSubkey(ref packet) => &packet.common,
+ &Packet::SecretKey(ref packet) => &packet.common,
+ &Packet::SecretSubkey(ref packet) => &packet.common,
+ &Packet::UserID(ref packet) => &packet.common,
&Packet::Literal(ref packet) => &packet.common,
- _ => unimplemented!(),
+ &Packet::CompressedData(ref packet) => &packet.common,
+ }
+ }
+}
+
+impl<'a> DerefMut for Packet {
+ fn deref_mut(&mut self) -> &mut PacketCommon {
+ match self {
+ &mut Packet::Signature(ref mut packet) => &mut packet.common,
+ &mut Packet::PublicKey(ref mut packet) => &mut packet.common,
+ &mut Packet::PublicSubkey(ref mut packet) => &mut packet.common,
+ &mut Packet::SecretKey(ref mut packet) => &mut packet.common,
+ &mut Packet::SecretSubkey(ref mut packet) => &mut packet.common,
+ &mut Packet::UserID(ref mut packet) => &mut packet.common,
+ &mut Packet::Literal(ref mut packet) => &mut packet.common,
+ &mut Packet::CompressedData(ref mut packet) => &mut packet.common,
}
}
}
-/// A `Message` is a container that holds zero or more OpenPGP
+/// A `Container` is a container that holds zero or more OpenPGP
/// packets. This is used both as a top-level for an OpenPGP message
/// as well as by Packets that are containers (like a compressed data
/// packet).
+#[derive(PartialEq)]
+pub struct Container {
+ packets: Vec<Packet>,
+}
+
+impl std::fmt::Debug for Container {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ f.debug_struct("Container")
+ .field("packets", &self.packets)
+ .finish()
+ }
+}
+
+/// A `Message` holds a deserialized OpenPGP message.
pub struct Message {
- input: Option<Box<BufferedReader>>,
+ // At the top level, we have a sequence of packets, which may be
+ // containers.
packets: Vec<Packet>,
}
@@ -410,7 +457,7 @@ pub struct PacketIter<'a> {
impl Message {
pub fn from_packets(p: Vec<Packet>) -> Self {
- Message { input: None, packets: p }
+ Message { packets: p }
}
pub fn iter(&self) -> PacketIter {
@@ -447,7 +494,12 @@ impl Packet {
impl CompressedData {
pub fn iter(&self) -> PacketIter {
return PacketIter {
- children: self.content.packets.iter(),
+ children: if let Some(ref container) = self.common.children {
+ container.packets.iter()
+ } else {
+ let empty_packet_slice : &[Packet] = &[][..];
+ empty_packet_slice.iter()
+ },
child: None,
grandchildren: None,
}
diff --git a/src/openpgp/parse/buffered_reader.rs b/src/openpgp/parse/buffered_reader.rs
index 5316f531..ab6f96c6 100644
--- a/src/openpgp/parse/buffered_reader.rs
+++ b/src/openpgp/parse/buffered_reader.rs
@@ -5,7 +5,7 @@ use std::str;
use std::io;
use std::io::{Error,ErrorKind};
use std::cmp;
-use std::io::Read;
+use std::fmt;
// The default buffer size.
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
@@ -18,7 +18,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 : Read {
+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 the end of the file is
@@ -121,22 +121,25 @@ pub trait BufferedReader : Read {
/// Reads and consumes `amount` bytes, and returns them in a
/// caller owned buffer. Implementations may optimize this to
/// avoid a copy.
- fn steal(&mut self, amount: usize) -> Result<Box<[u8]>, std::io::Error> {
+ fn steal(&mut self, amount: usize) -> Result<Vec<u8>, std::io::Error> {
let mut data = self.data_consume_hard(amount)?;
assert!(data.len() >= amount);
if data.len() > amount {
data = &data[..amount];
}
- return Ok(data.to_vec().into_boxed_slice());
+ return Ok(data.to_vec());
}
/// Like steal, but instead of stealing a fixed number of bytes,
/// it steals all of the data it can.
- fn steal_eof(&mut self) -> Result<Box<[u8]>, std::io::Error> {
+ fn steal_eof(&mut self) -> Result<Vec<u8>, std::io::Error> {
let len = self.data_eof()?.len();
let data = self.steal(len)?;
return Ok(data);
}
+
+ fn into_inner<'a>(self: Box<Self>) -> Option<Box<BufferedReader + 'a>>
+ where Self: 'a;
}
/// This function implements the `std::io::Read::read` method in terms
@@ -174,37 +177,105 @@ pub fn buffered_reader_generic_read_impl<T: BufferedReader>
}
}
+/// Make a `Box<BufferedReader>` look like a BufferedReader.
+impl <'a> BufferedReader for Box<BufferedReader + 'a> {
+ fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.as_mut().data(amount);
+ }
+
+ fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.as_mut().data_hard(amount);
+ }
+
+ fn data_eof(&mut self) -> Result<&[u8], io::Error> {
+ return self.as_mut().data_eof();
+ }
+
+ fn consume(&mut self, amount: usize) -> &[u8] {
+ return self.as_mut().consume(amount);
+ }
+
+ fn data_consume(&mut self, amount: usize)
+ -> Result<&[u8], std::io::Error> {
+ return self.as_mut().data_consume(amount);
+ }
+
+ fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.as_mut().data_consume_hard(amount);
+ }
+
+ fn read_be_u16(&mut self) -> Result<u16, std::io::Error> {
+ return self.as_mut().read_be_u16();
+ }
+
+ fn read_be_u32(&mut self) -> Result<u32, std::io::Error> {
+ return self.as_mut().read_be_u32();
+ }
+
+ fn steal(&mut self, amount: usize) -> Result<Vec<u8>, std::io::Error> {
+ return self.as_mut().steal(amount);
+ }
+
+ fn steal_eof(&mut self) -> Result<Vec<u8>, std::io::Error> {
+ return self.as_mut().steal_eof();
+ }
+
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
+ where Self: 'b {
+ // Strip the outer box.
+ (*self).into_inner()
+ }
+}
+
/// A generic `BufferedReader` implementation that only requires a
/// 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).
-#[derive(Debug)]
-pub struct BufferedReaderGeneric<'a, T: Read + 'a> {
+pub struct BufferedReaderGeneric<T: io::Read> {
buffer: Option<Box<[u8]>>,
// The next byte to read in the buffer.
cursor: usize,
// The preferred chunk size. This is just a hint.
preferred_chunk_size: usize,
- reader: &'a mut T,
+ // XXX: This is pub for the decompressors. It would be better to
+ // change this to some accessor method.
+ pub reader: Box<T>,
// Whether we saw an EOF.
saw_eof: bool,
// The last error that we encountered, but have not yet returned.
error: Option<io::Error>,
}
-impl<'a, T: Read> BufferedReaderGeneric<'a, T> {
+impl<T: io::Read> std::fmt::Debug for BufferedReaderGeneric<T> {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ let buffered_data = if let Some(ref buffer) = self.buffer {
+ buffer.len() - self.cursor
+ } else {
+ 0
+ };
+
+ f.debug_struct("BufferedReaderGeneric")
+ .field("preferred_chunk_size", &self.preferred_chunk_size)
+ .field("buffer data", &buffered_data)
+ .field("saw eof", &self.saw_eof)
+ .field("error", &self.error)
+ .finish()
+ }
+}
+
+impl<T: io::Read> BufferedReaderGeneric<T> {
/// 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: &'a mut T, preferred_chunk_size: Option<usize>)
- -> BufferedReaderGeneric<'a, T> {
+ pub fn new(reader: T, preferred_chunk_size: Option<usize>)
+ -> BufferedReaderGeneric<T> {
BufferedReaderGeneric {
buffer: None,
cursor: 0,
preferred_chunk_size:
if let Some(s) = preferred_chunk_size { s } else { DEFAULT_BUF_SIZE },
- reader: reader,
+ reader: Box::new(reader),
saw_eof: false,
error: None,
}
@@ -321,13 +392,13 @@ impl<'a, T: Read> BufferedReaderGeneric<'a, T> {
}
}
-impl<'a, T: Read> Read for BufferedReaderGeneric<'a, T> {
+impl<T: io::Read> io::Read for BufferedReaderGeneric<T> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
return buffered_reader_generic_read_impl(self, buf);
}
}
-impl<'a, T: Read> BufferedReader for BufferedReaderGeneric<'a, T> {
+impl<T: io::Read> BufferedReader for BufferedReaderGeneric<T> {
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.data_helper(amount, false, false);
}
@@ -366,13 +437,18 @@ impl<'a, T: Read> BufferedReader for BufferedReaderGeneric<'a, T> {
fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.data_helper(amount, true, true);
}
+
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
+ where Self: 'b {
+ None
+ }
}
// 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<T: BufferedReader>(bio: &mut T) {
+fn buffered_reader_test_data_check<'a, T: BufferedReader + 'a>(bio: &mut T) {
for i in 0 .. 10000 {
let consumed = {
// Each number is 4 bytes plus a newline character.
@@ -417,13 +493,21 @@ fn buffered_reader_generic_test() {
}
/// A `BufferedReader` specialized for reading from memory buffers.
-#[derive(Debug)]
pub struct BufferedReaderMemory<'a> {
buffer: &'a [u8],
// The next byte to read in the buffer.
cursor: usize,
}
+impl <'a> std::fmt::Debug for BufferedReaderMemory<'a> {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ f.debug_struct("BufferedReaderMemory")
+ .field("buffer (bytes)", &&self.buffer.len())
+ .field("cursor", &self.cursor)
+ .finish()
+ }
+}
+
impl<'a> BufferedReaderMemory<'a> {
pub fn new(buffer: &'a [u8]) -> BufferedReaderMemory<'a> {
BufferedReaderMemory {
@@ -433,7 +517,7 @@ impl<'a> BufferedReaderMemory<'a> {
}
}
-impl<'a> Read for BufferedReaderMemory<'a> {
+impl<'a> io::Read for BufferedReaderMemory<'a> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
let amount = cmp::min(buf.len(), self.buffer.len() - self.cursor);
buf[0..amount].copy_from_slice(
@@ -471,6 +555,11 @@ impl<'a> BufferedReader for BufferedReaderMemory<'a> {
}
return Ok(self.consume(amount));
}
+
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
+ where Self: 'b {
+ None
+ }
}
#[test]
@@ -481,16 +570,16 @@ fn buffered_reader_memory_test () {
buffered_reader_test_data_check(&mut bio);
}
-/// A `BufferedReaderLimit` limits the amount of data that can be read
-/// from a `BufferedReader`.
+/// A `BufferedReaderLimitor` limits the amount of data that can be
+/// read from a `BufferedReader`.
#[derive(Debug)]
-pub struct BufferedReaderLimitor<'a, T: BufferedReader + 'a> {
- reader: &'a mut T,
+pub struct BufferedReaderLimitor<T: BufferedReader> {
+ reader: T,
limit: u64,
}
-impl<'a, T: BufferedReader> BufferedReaderLimitor<'a, T> {
- pub fn new(reader: &'a mut T, limit: u64) -> BufferedReaderLimitor<T> {
+impl<T: BufferedReader> BufferedReaderLimitor<T> {
+ pub fn new(reader: T, limit: u64) -> BufferedReaderLimitor<T> {
BufferedReaderLimitor {
reader: reader,
limit: limit,
@@ -498,14 +587,14 @@ impl<'a, T: BufferedReader> BufferedReaderLimitor<'a, T> {
}
}
-impl<'a, T: BufferedReader> Read for BufferedReaderLimitor<'a, T> {
+impl<T: BufferedReader> io::Read for BufferedReaderLimitor<T> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
let len = cmp::min(self.limit, buf.len() as u64) as usize;
return self.reader.read(&mut buf[0..len]);
}
}
-impl<'a, T: BufferedReader> BufferedReader for BufferedReaderLimitor<'a, T> {
+impl<T: BufferedReader> BufferedReader for BufferedReaderLimitor<T> {
/// Return the buffer. Ensure that it contains at least `amount`
/// bytes.
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
@@ -552,6 +641,11 @@ impl<'a, T: BufferedReader> BufferedReader for BufferedReaderLimitor<'a, T> {
}
return result;
}
+
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
+ where Self: 'b {
+ Some(Box::new(self.reader))
+ }
}
#[test]
@@ -560,10 +654,11 @@ fn buffered_reader_limitor_test() {
/* Add a single limitor. */
{
- let mut bio = BufferedReaderMemory::new(data);
+ let mut bio : Box<BufferedReader>
+ = Box::new(BufferedReaderMemory::new(data));
- {
- let mut bio2 = BufferedReaderLimitor::new(&mut bio, 5);
+ bio = {
+ let mut bio2 = Box::new(BufferedReaderLimitor::new(bio, 5));
{
let result = bio2.data(5).unwrap();
assert_eq!(result.len(), 5);
@@ -575,7 +670,9 @@ fn buffered_reader_limitor_test() {
assert_eq!(result.len(), 0);
assert_eq!(result, &b""[..]);
}
- }
+
+ bio2.into_inner().unwrap()
+ };
{
{
@@ -595,13 +692,16 @@ fn buffered_reader_limitor_test() {
/* Try with two limitors where the first one imposes the real
* limit. */
{
- let mut bio = BufferedReaderMemory::new(data);
+ let mut bio : Box<BufferedReader>
+ = Box::new(BufferedReaderMemory::new(data));
- {
- let mut bio2 = BufferedReaderLimitor::new(&mut bio, 5);
+ bio = {
+ let bio2 : Box<BufferedReader>
+ = Box::new(BufferedReaderLimitor::new(bio, 5));
// We limit to 15 bytes, but bio2 will still limit us to 5
// bytes.
- let mut bio3 = BufferedReaderLimitor::new(&mut bio2, 15);
+ let mut bio3 : Box<BufferedReader>
+ = Box::new(BufferedReaderLimitor::new(bio2, 15));
{
let result = bio3.data(100).unwrap();
assert_eq!(result.len(), 5);
@@ -613,7 +713,9 @@ fn buffered_reader_limitor_test() {
assert_eq!(result.len(), 0);
assert_eq!(result, &b""[..]);
}
- }
+
+ bio3.into_inner().unwrap().into_inner().unwrap()
+ };
{
{
@@ -651,8 +753,8 @@ mod test {
// Try it again with a limitor.
{
- let mut bio = BufferedReaderMemory::new(data);
- let mut bio2 = BufferedReaderLimitor::new(&mut bio, (data.len() / 2) as u64);
+ let bio = BufferedReaderMemory::new(data);
+ let mut bio2 = BufferedReaderLimitor::new(bio, (data.len() / 2) as u64);
let amount = {
bio2.data_eof().unwrap().len()
};
@@ -663,7 +765,7 @@ mod test {
}
#[cfg(test)]
- fn buffered_reader_read_test_aux<T: BufferedReader>
+ fn buffered_reader_read_test_aux<'a, T: BufferedReader + 'a>
(mut bio: T, data: &[u8]) {
let mut buffer = [0; 99];
diff --git a/src/openpgp/parse/buffered_reader_decompress.rs b/src/openpgp/parse/buffered_reader_decompress.rs
new file mode 100644
index 00000000..774275c2
--- /dev/null
+++ b/src/openpgp/parse/buffered_reader_decompress.rs
@@ -0,0 +1,230 @@
+use std::io;
+use std::fmt;
+
+use flate2::read::DeflateDecoder;
+use flate2::read::ZlibDecoder;
+use bzip2::read::BzDecoder;
+
+use super::buffered_reader::*;
+
+pub struct BufferedReaderDeflate<R: BufferedReader> {
+ reader: BufferedReaderGeneric<DeflateDecoder<R>>,
+}
+
+impl <R: BufferedReader> BufferedReaderDeflate<R> {
+ pub fn new(reader: R) -> BufferedReaderDeflate<R> {
+ BufferedReaderDeflate {
+ reader: BufferedReaderGeneric::new(DeflateDecoder::new(reader), None)
+ }
+ }
+}
+
+impl<R: BufferedReader> io::Read for BufferedReaderDeflate<R> {
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
+ self.reader.read(buf)
+ }
+}
+
+impl <R: BufferedReader> fmt::Debug for BufferedReaderDeflate<R> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("BufferedReaderDeflate")
+ .field("reader", self.reader.reader.get_ref())
+ .finish()
+ }
+}
+
+impl<R: BufferedReader> BufferedReader for BufferedReaderDeflate<R> {
+ fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.reader.data(amount);
+ }
+
+ fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.reader.data_hard(amount);
+ }
+
+ fn data_eof(&mut self) -> Result<&[u8], io::Error> {
+ return self.reader.data_eof();
+ }
+
+ fn consume(&mut self, amount: usize) -> &[u8] {
+ return self.reader.consume(amount);
+ }
+
+ fn data_consume(&mut self, amount: usize)
+ -> Result<&[u8], io::Error> {
+ return self.reader.data_consume(amount);
+ }
+
+ fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.reader.data_consume_hard(amount);
+ }
+
+ fn read_be_u16(&mut self) -> Result<u16, io::Error> {
+ return self.reader.read_be_u16();
+ }
+
+ fn read_be_u32(&mut self) -> Result<u32, io::Error> {
+ return self.reader.read_be_u32();
+ }
+
+ fn steal(&mut self, amount: usize) -> Result<Vec<u8>, io::Error> {
+ return self.reader.steal(amount);
+ }
+
+ fn steal_eof(&mut self) -> Result<Vec<u8>, io::Error> {
+ return self.reader.steal_eof();
+ }
+
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>> where Self: 'b {
+ // Strip the outer box.
+ Some(Box::new((*self).reader.reader.into_inner()))
+ }
+}
+
+pub struct BufferedReaderZlib<R: BufferedReader> {
+ reader: BufferedReaderGeneric<ZlibDecoder<R>>,
+}
+
+impl <R: BufferedReader> BufferedReaderZlib<R> {
+ pub fn new(reader: R) -> BufferedReaderZlib<R> {
+ BufferedReaderZlib {
+ reader: BufferedReaderGeneric::new(ZlibDecoder::new(reader), None)
+ }
+ }
+}
+
+impl<R: BufferedReader> io::Read for BufferedReaderZlib<R> {
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
+ self.reader.read(buf)
+ }
+}
+
+impl <R: BufferedReader> fmt::Debug for BufferedReaderZlib<R> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("BufferedReaderZlib")
+ .field("reader", self.reader.reader.get_ref())
+ .finish()
+ }
+}
+
+impl<R: BufferedReader> BufferedReader for BufferedReaderZlib<R> {
+ fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.reader.data(amount);
+ }
+
+ fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.reader.data_hard(amount);
+ }
+
+ fn data_eof(&mut self) -> Result<&[u8], io::Error> {
+ return self.reader.data_eof();
+ }
+
+ fn consume(&mut self, amount: usize) -> &[u8] {
+ return self.reader.consume(amount);
+ }
+
+ fn data_consume(&mut self, amount: usize)
+ -> Result<&[u8], io::Error> {
+ return self.reader.data_consume(amount);
+ }
+
+ fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ return self.reader.data_consume_hard(amount);
+ }
+
+ fn read_be_u16(&mut self) -> Result<u16, io::Error> {
+ return self.reader.read_be_u16();
+ }
+
+ fn read_be_u32(&mut self) -> Result<u32, io::Error> {
+ return self.reader.read_be_u32();
+ }
+
+ fn steal(&mut self, amount: usize) -> Result<Vec<u8>, io::Error> {
+ return self.reader.steal(amount);
+ }
+
+ fn steal_eof(&mut self) -> Result<Vec<u8>,