From 80f359aa53f5672bca64030535cb5afae080acce Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Thu, 2 Apr 2020 16:19:47 +0200 Subject: openpgp: Move the writer module to serialize::stream. --- openpgp-ffi/src/serialize.rs | 2 +- openpgp/src/serialize.rs | 1 - openpgp/src/serialize/partial_body.rs | 6 +- openpgp/src/serialize/stream.rs | 2 +- openpgp/src/serialize/stream/padding.rs | 6 +- .../serialize/stream/writer/compression_common.rs | 82 +++ openpgp/src/serialize/stream/writer/mod.rs | 573 +++++++++++++++++++++ .../src/serialize/stream/writer/writer_bzip2.rs | 74 +++ .../src/serialize/stream/writer/writer_deflate.rs | 142 +++++ openpgp/src/serialize/writer/compression_common.rs | 82 --- openpgp/src/serialize/writer/mod.rs | 573 --------------------- openpgp/src/serialize/writer/writer_bzip2.rs | 74 --- openpgp/src/serialize/writer/writer_deflate.rs | 142 ----- 13 files changed, 882 insertions(+), 877 deletions(-) create mode 100644 openpgp/src/serialize/stream/writer/compression_common.rs create mode 100644 openpgp/src/serialize/stream/writer/mod.rs create mode 100644 openpgp/src/serialize/stream/writer/writer_bzip2.rs create mode 100644 openpgp/src/serialize/stream/writer/writer_deflate.rs delete mode 100644 openpgp/src/serialize/writer/compression_common.rs delete mode 100644 openpgp/src/serialize/writer/mod.rs delete mode 100644 openpgp/src/serialize/writer/writer_bzip2.rs delete mode 100644 openpgp/src/serialize/writer/writer_deflate.rs diff --git a/openpgp-ffi/src/serialize.rs b/openpgp-ffi/src/serialize.rs index 4c623ffb..bcd2d6f2 100644 --- a/openpgp-ffi/src/serialize.rs +++ b/openpgp-ffi/src/serialize.rs @@ -24,8 +24,8 @@ use crate::RefRaw; use crate::RefMutRaw; use self::openpgp::serialize::{ - writer, stream::{ + writer, Message, Cookie, ArbitraryWriter, diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs index 246f3bdd..9f1eda4f 100644 --- a/openpgp/src/serialize.rs +++ b/openpgp/src/serialize.rs @@ -25,7 +25,6 @@ mod cert; pub use self::cert::TSK; mod cert_armored; use self::partial_body::PartialBodyFilter; -pub mod writer; pub mod stream; use crate::crypto::S2K; use crate::packet::header::{ diff --git a/openpgp/src/serialize/partial_body.rs b/openpgp/src/serialize/partial_body.rs index 47c0e8b9..f6e62280 100644 --- a/openpgp/src/serialize/partial_body.rs +++ b/openpgp/src/serialize/partial_body.rs @@ -8,7 +8,11 @@ use std::cmp; use crate::Error; use crate::Result; use crate::packet::header::BodyLength; -use super::{writer, write_byte, Marshal}; +use super::{ + stream::writer, + write_byte, + Marshal, +}; pub struct PartialBodyFilter<'a, C: 'a> { // The underlying writer. diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs index c347d29e..3c810a14 100644 --- a/openpgp/src/serialize/stream.rs +++ b/openpgp/src/serialize/stream.rs @@ -35,7 +35,6 @@ use crate::packet::header::BodyLength; use super::{ PartialBodyFilter, Marshal, - writer, }; use crate::types::{ AEADAlgorithm, @@ -45,6 +44,7 @@ use crate::types::{ SymmetricAlgorithm, }; +pub mod writer; #[cfg(feature = "compression-deflate")] pub mod padding; diff --git a/openpgp/src/serialize/stream/padding.rs b/openpgp/src/serialize/stream/padding.rs index 516e1a47..02bbe7ff 100644 --- a/openpgp/src/serialize/stream/padding.rs +++ b/openpgp/src/serialize/stream/padding.rs @@ -49,8 +49,10 @@ use crate::packet::header::CTB; use crate::serialize::{ PartialBodyFilter, Marshal, - writer, - stream::Cookie, + stream::{ + writer, + Cookie, + }, }; use crate::types::{ CompressionAlgorithm, diff --git a/openpgp/src/serialize/stream/writer/compression_common.rs b/openpgp/src/serialize/stream/writer/compression_common.rs new file mode 100644 index 00000000..7ac32d31 --- /dev/null +++ b/openpgp/src/serialize/stream/writer/compression_common.rs @@ -0,0 +1,82 @@ +//! Common code for the compression writers. + +use crate::{ + Error, + Result, +}; + +/// Compression level. +/// +/// This value is used by the encoders to tune their compression +/// strategy. The level is restricted to levels commonly used by +/// compression libraries, `0` to `9`, where `0` means no compression, +/// `1` means fastest compression, `6` being a good default, and +/// meaning `9` best compression. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct CompressionLevel(u8); + +impl Default for CompressionLevel { + fn default() -> Self { + Self(6) + } +} + +impl CompressionLevel { + /// Creates a new compression level. + /// + /// `level` must be in range `0..10`, where `0` means no + /// compression, `1` means fastest compression, `6` being a good + /// default, and meaning `9` best compression. + pub fn new(level: u8) -> Result { + if level < 10 { + Ok(Self(level)) + } else { + Err(Error::InvalidArgument( + format!("compression level out of range: {}", level)).into()) + } + } + + /// No compression. + pub fn none() -> CompressionLevel { + Self(0) + } + + /// Fastest compression. + pub fn fastest() -> CompressionLevel { + Self(1) + } + /// Best compression. + pub fn best() -> CompressionLevel { + Self(9) + } +} + +#[cfg(feature = "compression-deflate")] +mod into_deflate_compression { + use flate2::Compression; + use super::*; + + impl From for Compression { + fn from(l: CompressionLevel) -> Self { + Compression::new(l.0 as u32) + } + } +} + +#[cfg(feature = "compression-bzip2")] +mod into_bzip2_compression { + use bzip2::Compression; + use super::*; + + impl From for Compression { + fn from(l: CompressionLevel) -> Self { + if l <= CompressionLevel::fastest() { + Compression::Fastest + } else if l <= CompressionLevel::default() { + Compression::Default + } else { + Compression::Best + } + } + } +} diff --git a/openpgp/src/serialize/stream/writer/mod.rs b/openpgp/src/serialize/stream/writer/mod.rs new file mode 100644 index 00000000..2141ca98 --- /dev/null +++ b/openpgp/src/serialize/stream/writer/mod.rs @@ -0,0 +1,573 @@ +//! Stackable writers. + +#[cfg(feature = "compression-bzip2")] +mod writer_bzip2; +#[cfg(feature = "compression-bzip2")] +pub use self::writer_bzip2::BZ; +#[cfg(feature = "compression-deflate")] +mod writer_deflate; +#[cfg(feature = "compression-deflate")] +pub use self::writer_deflate::{ZIP, ZLIB}; +mod compression_common; +pub use compression_common::CompressionLevel; + +use std::fmt; +use std::io; + +use crate::crypto::{aead, symmetric}; +use crate::types::{ + AEADAlgorithm, + SymmetricAlgorithm, +}; +use crate::{ + Result, + crypto::SessionKey, +}; + +/// A stack of writers. +#[derive(Debug)] +pub struct Stack<'a, C>(BoxStack<'a, C>); + +impl<'a, C> Stack<'a, C> { + pub(crate) fn from(bs: BoxStack<'a, C>) -> Self { + Stack(bs) + } + + pub(crate) fn as_ref(&self) -> &BoxStack<'a, C> { + &self.0 + } + + pub(crate) fn as_mut(&mut self) -> &mut BoxStack<'a, C> { + &mut self.0 + } + + /// Finalizes this writer, returning the underlying writer. + pub fn finalize_one(self) -> Result>> { + Ok(self.0.into_inner()?.map(|bs| Self::from(bs))) + } + + /// Finalizes all writers, tearing down the whole stack. + pub fn finalize(self) -> Result<()> { + let mut stack = self; + while let Some(s) = stack.finalize_one()? { + stack = s; + } + Ok(()) + } +} + +impl<'a, C> io::Write for Stack<'a, C> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } +} + +impl<'a, C> From> for BoxStack<'a, C> { + fn from(s: Stack<'a, C>) -> Self { + s.0 + } +} + +pub(crate) type BoxStack<'a, C> = Box + 'a>; + +/// Makes a writer stackable and provides convenience functions. +pub(crate) trait Stackable<'a, C> : io::Write + fmt::Debug { + /// Recovers the inner stackable. + /// + /// This can fail if the current `Stackable` has buffered data + /// that hasn't been written to the underlying `Stackable`. + fn into_inner(self: Box) -> Result>>; + + /// Pops the stackable from the stack, detaching it. + /// + /// Returns the detached stack. + /// + /// Note: Only the Signer implements this interface. + fn pop(&mut self) -> Result>>; + + /// Sets the inner stackable. + /// + /// Note: Only the Signer implements this interface. + fn mount(&mut self, new: BoxStack<'a, C>); + + /// Returns a mutable reference to the inner `Writer`, if + /// any. + /// + /// It is a very bad idea to write any data from the inner + /// `Writer`, but it can sometimes be useful to get the cookie. + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>>; + + /// Returns a reference to the inner `Writer`. + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>>; + + /// Sets the cookie and returns the old value. + fn cookie_set(&mut self, cookie: C) -> C; + + /// Returns a reference to the cookie. + fn cookie_ref(&self) -> &C; + + /// Returns a mutable reference to the cookie. + fn cookie_mut(&mut self) -> &mut C; + + /// Returns the number of bytes written to this filter. + fn position(&self) -> u64; + + /// Writes a byte. + fn write_u8(&mut self, b: u8) -> io::Result<()> { + let b : [u8; 1] = [b; 1]; + self.write_all(&b[..]) + } + + /// Writes a big endian `u16`. + fn write_be_u16(&mut self, n: u16) -> io::Result<()> { + let b : [u8; 2] = [ ((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8 ]; + self.write_all(&b[..]) + } + + /// Writes a big endian `u32`. + fn write_be_u32(&mut self, n: u32) -> io::Result<()> { + let b : [u8; 4] = [ (n >> 24) as u8, ((n >> 16) & 0xFF) as u8, + ((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8 ]; + self.write_all(&b[..]) + } +} + +/// Make a `Box` look like a Stackable. +impl <'a, C> Stackable<'a, C> for BoxStack<'a, C> { + fn into_inner(self: Box) -> Result>> { + (*self).into_inner() + } + /// Recovers the inner stackable. + fn pop(&mut self) -> Result>> { + self.as_mut().pop() + } + /// Sets the inner stackable. + fn mount(&mut self, new: BoxStack<'a, C>) { + self.as_mut().mount(new); + } + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { + self.as_mut().inner_mut() + } + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { + self.as_ref().inner_ref() + } + 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() + } + fn position(&self) -> u64 { + self.as_ref().position() + } +} + +/// Maps a function over the stack of writers. +#[allow(dead_code)] +pub(crate) fn map(head: &dyn Stackable, mut fun: F) + where F: FnMut(&dyn Stackable) -> bool { + let mut ow = Some(head); + while let Some(w) = ow { + if ! fun(w) { + break; + } + ow = w.inner_ref() + } +} + +/// Maps a function over the stack of mutable writers. +#[allow(dead_code)] +pub(crate) fn map_mut(head: &mut dyn Stackable, mut fun: F) + where F: FnMut(&mut dyn Stackable) -> bool { + let mut ow = Some(head); + while let Some(w) = ow { + if ! fun(w) { + break; + } + ow = w.inner_mut() + } +} + +/// Dumps the writer stack. +#[allow(dead_code)] +pub(crate) fn dump(head: &dyn Stackable) { + let mut depth = 0; + map(head, |w| { + eprintln!("{}: {:?}", depth, w); + depth += 1; + true + }); +} + +/// The identity writer just relays anything written. +pub struct Identity<'a, C> { + inner: Option>, + cookie: C, +} + +impl<'a, C: 'a> Identity<'a, C> { + /// Makes an identity writer. + pub fn new(inner: Stack<'a, C>, cookie: C) + -> Stack<'a, C> { + Stack::from(Box::new(Self{inner: Some(inner.into()), cookie })) + } +} + +impl<'a, C> fmt::Debug for Identity<'a, C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Identity") + .field("inner", &self.inner) + .finish() + } +} + +impl<'a, C> io::Write for Identity<'a, C> { + fn write(&mut self, buf: &[u8]) -> io::Result { + let writer = self.inner.as_mut() + .ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe, + "Writer is finalized."))?; + writer.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + let writer = self.inner.as_mut() + .ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe, + "Writer is finalized."))?; + writer.flush() + } +} + +impl<'a, C> Stackable<'a, C> for Identity<'a, C> { + /// Recovers the inner stackable. + fn into_inner(self: Box) -> Result>> { + Ok(self.inner) + } + /// Recovers the inner stackable. + fn pop(&mut self) -> Result>> { + Ok(self.inner.take()) + } + /// Sets the inner stackable. + fn mount(&mut self, new: BoxStack<'a, C>) { + self.inner = Some(new); + } + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { + if let Some(ref i) = self.inner { + Some(i) + } else { + None + } + } + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { + if let Some(ref mut i) = self.inner { + Some(i) + } else { + None + } + } + fn cookie_set(&mut self, cookie: C) -> C { + ::std::mem::replace(&mut self.cookie, cookie) + } + fn cookie_ref(&self) -> &C { + &self.cookie + } + fn cookie_mut(&mut self) -> &mut C { + &mut self.cookie + } + fn position(&self) -> u64 { + self.inner.as_ref().map(|i| i.position()).unwrap_or(0) + } +} + +/// Generic writer wrapping `io::Write`. +pub struct Generic { + inner: W, + cookie: C, + position: u64, +} + +impl<'a, W: 'a + io::Write, C: 'a> Generic { + /// Wraps an `io::Write`r. + pub fn new(inner: W, cookie: C) -> Stack<'a, C> { + Stack::from(Box::new(Self::new_unboxed(inner.into(), cookie))) + } + + fn new_unboxed(inner: W, cookie: C) -> Self { + Generic { + inner, + cookie, + position: 0, + } + } +} + +impl fmt::Debug for Generic { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("writer::Generic") + .finish() + } +} + +impl io::Write for Generic { + fn write(&mut self, bytes: &[u8]) -> io::Result { + match self.inner.write(bytes) { + Ok(n) => { + self.position += n as u64; + Ok(n) + }, + Err(e) => Err(e), + } + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +impl<'a, W: io::Write, C> Stackable<'a, C> for Generic { + /// Recovers the inner stackable. + fn into_inner(self: Box) -> Result>> { + Ok(None) + } + /// Recovers the inner stackable. + fn pop(&mut self) -> Result>> { + Ok(None) + } + /// Sets the inner stackable. + fn mount(&mut self, _new: BoxStack<'a, C>) { + } + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { + // If you use Generic to wrap an io::Writer, and you know that + // the io::Writer's inner is also a Stackable, then return a + // reference to the innermost Stackable in your + // implementation. See e.g. writer::ZLIB. + None + } + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { + // If you use Generic to wrap an io::Writer, and you know that + // the io::Writer's inner is also a Stackable, then return a + // reference to the innermost Stackable in your + // implementation. See e.g. writer::ZLIB. + None + } + fn cookie_set(&mut self, cookie: C) -> C { + ::std::mem::replace(&mut self.cookie, cookie) + } + fn cookie_ref(&self) -> &C { + &self.cookie + } + fn cookie_mut(&mut self) -> &mut C { + &mut self.cookie + } + fn position(&self) -> u64 { + self.position + } +} + + +/// Encrypting writer. +pub struct Encryptor<'a, C: 'a> { + inner: Generic>, C>, +} + +impl<'a, C: 'a> Encryptor<'a, C> { + /// Makes an encrypting writer. + pub fn new(inner: Stack<'a, C>, cookie: C, algo: SymmetricAlgorithm, + key: &[u8]) + -> Result> + { + Ok(Stack::from(Box::new(Encryptor { + inner: Generic::new_unboxed( + symmetric::Encryptor::new(algo, key, inner.into())?, + cookie), + }))) + } +} + +impl<'a, C: 'a> fmt::Debug for Encryptor<'a, C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("writer::Encryptor") + .field("inner", &self.inner) + .finish() + } +} + +impl<'a, C: 'a> io::Write for Encryptor<'a, C> { + fn write(&mut self, bytes: &[u8]) -> io::Result { + self.inner.write(bytes) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +impl<'a, C: 'a> Stackable<'a, C> for Encryptor<'a, C> { + fn into_inner(mut self: Box) -> Result>> { + let inner = self.inner.inner.finish()?; + Ok(Some(inner)) + } + fn pop(&mut self) -> Result>> { + unreachable!("Only implemented by Signer") + } + fn mount(&mut self, _new: BoxStack<'a, C>) { + unreachable!("Only implemented by Signer") + } + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { + // XXX: Unfortunately, this doesn't work due to a lifetime mismatch: + // self.inner.inner.get_mut().map(|r| r.as_mut()) + None + } + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { + self.inner.inner.get_ref().map(|r| r.as_ref()) + } + fn cookie_set(&mut self, cookie: C) -> C { + self.inner.cookie_set(cookie) + } + fn cookie_ref(&self) -> &C { + self.inner.cookie_ref() + } + fn cookie_mut(&mut self) -> &mut C { + self.inner.cookie_mut() + } + fn position(&self) -> u64 { + self.inner.position + } +} + + +/// AEAD encrypting writer. +pub struct AEADEncryptor<'a, C: 'a> { + inner: Generic>, C>, +} + +impl<'a, C: 'a> AEADEncryptor<'a, C> { + /// Makes an encrypting writer. + pub fn new(inner: Stack<'a, C>, cookie: C, + cipher: SymmetricAlgorithm, aead: AEADAlgorithm, + chunk_size: usize, iv: &[u8], key: &SessionKey) + -> Result> + { + Ok(Stack::from(Box::new(AEADEncryptor { + inner: Generic::new_unboxed( + aead::Encryptor::new(1, cipher, aead, chunk_size, iv, key, + inner.into())?, + cookie), + }))) + } +} + +impl<'a, C: 'a> fmt::Debug for AEADEncryptor<'a, C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("writer::AEADEncryptor") + .field("inner", &self.inner) + .finish() + } +} + +impl<'a, C: 'a> io::Write for AEADEncryptor<'a, C> { + fn write(&mut self, bytes: &[u8]) -> io::Result { + self.inner.write(bytes) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +impl<'a, C: 'a> Stackable<'a, C> for AEADEncryptor<'a, C> { + fn into_inner(mut self: Box) -> Result>> { + let inner = self.inner.inner.finish()?; + Ok(Some(inner)) + } + fn pop(&mut self) -> Result>> { + unreachable!("Only implemented by Signer") + } + fn mount(&mut self, _new: BoxStack<'a, C>) { + unreachable!("Only implemented by Signer") + } + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { + // XXX: Unfortunately, this doesn't work due to a lifetime mismatch: + // self.inner.inner.get_mut().map(|r| r.as_mut()) + None + } + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { + self.inner.inner.get_ref().map(|r| r.as_ref()) + } + fn cookie_set(&mut self, cookie: C) -> C { + self.inner.cookie_set(cookie) + } + fn cookie_ref(&self) -> &C { + self.inner.cookie_ref() + } + fn cookie_mut(&mut self) -> &mut C { + self.inner.cookie_mut() + } + fn position(&self) -> u64 { + self.inner.position + } +} + +#[cfg(test)] +mod test { + use std::io::Write; + use super::*; + + #[derive(Debug)] + struct Cookie { + state: &'static str, + } + + #[test] + fn generic_writer() { + let mut inner = Vec::new(); + { + let mut w = Generic::new(&mut inner, Cookie { state: "happy" }); + assert_eq!(w.as_ref().cookie_ref().state, "happy"); + dump(w.as_ref()); + + w.as_mut().cookie_mut().state = "sad"; + assert_eq!(w.as_ref().cookie_ref().state, "sad"); + + w.write_all(b"be happy").unwrap(); + let mut count = 0; + map_mut(w.as_mut(), |g| { + let new = Cookie { state: "happy" }; + let old = g.cookie_set(new); + assert_eq!(old.state, "sad"); + count += 1; + true + }); + assert_eq!(count, 1); + assert_eq!(w.as_ref().cookie_ref().state, "happy"); + } + assert_eq!(&inner, b"be happy"); + } + + #[test] + fn stack() { + let mut inner = Vec::new(); + { + let w = Generic::new(&mut inner, Cookie { state: "happy" }); + dump(w.as_ref()); + + let w = Identity::new(w, Cookie { state: "happy" }); + dump(w.as_ref()); + + let mut count = 0; + map(w.as_ref(), |g| { + assert_eq!(g.cookie_ref().state, "happy"); + count += 1; + true + }); + assert_eq!(count, 2); + } + } + +} diff --git a/openpgp/src/serialize/stream/writer/writer_bzip2.rs b/openpgp/src/serialize/stream/writer/writer_bzip2.rs new file mode 100644 index 00000000..62affd0c --- /dev/null +++ b/openpgp/src/serialize/stream/writer/writer_bzip2.rs @@ -0,0 +1,74 @@ +use bzip2::write::BzEncoder; +use std::fmt; +use std::io; + +use crate::Result; +use super::{Generic, Stack, BoxStack, Stackable, CompressionLevel}; + +/// BZing writer. +pub struct BZ<'a, C: 'a> { + inner: Generic>, C>, +} + +impl<'a, C: 'a> BZ<'a, C> { + /// Makes a BZ compressing writer. + pub fn new(inner: Stack<'a, C>, cookie: C, level: L) -> Stack<'a, C> + where L: Into> + { + Stack::from(Box::new(BZ { + inner: Generic::new_unboxed( + BzEncoder::new(inner.into(), + level.into().unwrap_or_default().into()), + cookie), + })) + } +} + +impl<'a, C: 'a> fmt::Debug for BZ<'a, C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("writer::BZ") + .field("inner", &self.inner) + .finish() + } +} + +impl<'a, C: 'a> io::Write for BZ<'a, C> { + fn write(&mut self, bytes: &[u8]) -> io::Result { + self.inner.write(bytes) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +impl<'a, C: 'a> Stackable<'a, C> for BZ<'a, C> { + fn into_inner(self: Box) -> Result>> { + let inner = self.inner.inner.finish()?; + Ok(Some(inner)) + } + fn pop(&mut self) -> Result>> { + unreachable!("Only implemented by Signer") + } + fn mount(&mut self, _new: BoxStack<'a, C>) { + unreachable!("Only implemented by Signer") + } + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { + Some(self.inner.inner.get_mut()) + } + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { + Some(self.inner.inner.get_ref()) + } + fn cookie_set(&mut self, cookie: C) -> C { + self.inner.cookie_set(cookie) + } + fn cookie_ref(&self) -> &C { + self.inner.cookie_ref() + } + fn cookie_mut(&mut self) -> &mut C { + self.inner.cookie_mut() + } + fn position(&self) -> u64 { + self.inner.position + } +} diff --git a/openpgp/src/serialize/stream/writer/writer_deflate.rs b/openpgp/src/serialize/stream/writer/writer_deflate.rs new file mode 100644 index 00000000..387b3f2c --- /dev/null +++ b/openpgp/src/serialize/stream/writer/writer_deflate.rs @@ -0,0 +1,142 @@ +use flate2::write::{DeflateEncoder, ZlibEncoder}; +use std::fmt; +use std::io; + +use crate::Result; +use super::{Generic, Stack, BoxStack, Stackable, CompressionLevel}; + +/// ZIPing writer. +pub struct ZIP<'a, C: 'a> { + inner: Generic>, C>, +} + +impl<'a, C: 'a> ZIP<'a, C> { + /// Makes a ZIP compressing writer. + pub fn new(inner: Stack<'a, C>, cookie: C, level: L) -> Stack<'a, C> + where L: Into> + { + Stack::from(Box::new(ZIP { + inner: Generic::new_unboxed( + DeflateEncoder::new(inner.into(), + level.into().unwrap_or_default().into()), + cookie), + })) + } +} + +impl<'a, C: 'a> fmt::Debug for ZIP<'a, C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("writer::ZIP") + .field("inner", &self.inner) + .finish() + } +} + +impl<'a, C: 'a> io::Write for ZIP<'a, C> { + fn write(&mut self, bytes: &[u8]) -> io::Result { + self.inner.write(bytes) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +impl<'a, C: 'a> Stackable<'a, C> for ZIP<'a, C> { + fn into_inner(self: Box) -> Result>> { + let inner = self.inner.inner.finish()?; + Ok(Some(inner)) + } + fn pop(&mut self) -> Result>> { + unreachable!("Only implemented by Signer") + } + fn mount(&mut self, _new: BoxStack<'a, C>) { + unreachable!("Only implemented by Signer") + } + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { + Some(self.inner.inner.get_mut()) + } + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { + Some(self.inner.inner.get_ref()) + } + fn cookie_set(&mut self, cookie: C) -> C { + self.inner.cookie_set(cookie) + } + fn cookie_ref(&self) -> &C { + self.inner.cookie_ref() + } + fn cookie_mut(&mut self) -> &mut C { + self.inner.cookie_mut() + } + fn position(&self) -> u64 { + self.inner.position + } +} + +/// ZLIBing writer. +pub struct ZLIB<'a, C: 'a> { + inner: Generic>, C>, +} + +impl<'a, C: 'a> ZLIB<'a, C> { + /// Makes a ZLIB compressing writer. + pub fn new(inner: Stack<'a, C>, cookie: C, level: L) -> Stack<'a, C> + where L: Into> + { + Stack::from(Box::new(ZLIB { + inner: Generic::new_unboxed( + ZlibEncoder::new(inner.into(), + level.into().unwrap_or_default().into()), + cookie), + })) + } +} + +impl<'a, C:> fmt::Debug for ZLIB<'a, C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("writer::ZLIB") + .field("inner", &self.inner) + .finish() + } +} + +impl<'a, C: 'a> io::Write for ZLIB<'a, C> { + fn write(&mut self, bytes: &[u8]) -> io::Result { + self.inner.write(bytes) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +impl<'a, C: 'a> Stackable<'a, C> for ZLIB<'a, C> { + fn into_inner(self: Box) -> Result>> { + let inner = self.inner.inner.finish()?; + Ok(Some(inner)) + } + fn pop(&mut self) -> Result>> { + unreachable!("Only implemented by Signer") + } + fn mount(&mut self, _new: BoxStack<'a, C>) { + unreachable!("Only implemented by Signer") + } + fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { + Some(self.inner.inner.get_mut()) + } + fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { + Some(self.inner.inner.get_ref()) + } + fn cookie_set(&mut self, cookie: C) -> C { + self.inner.cookie_set(cookie) + } + fn cookie_ref(&self) -> &C { + self.inner.cookie_ref() + } + fn cookie_mut(&mut self) -> &mut C { + self.inner.cookie_mut() + } + fn position(&self) -> u64 { + self.inner.position + } +} diff --git a/openpgp/src/serialize/writer/compression_common.rs b/openpgp/src/serialize/writer/compression_common.rs deleted file mode 100644 index 7ac32d31..00000000 --- a/openpgp/src/serialize/writer/compression_common.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! Common code for the compression writers. - -use crate::{ - Error, - Result, -}; - -/// Compression level. -/// -/// This value is used by the encoders to tune their compression -/// strategy. The level is restricted to levels commonly used by -/// compression libraries, `0` to `9`, where `0` means no compression, -/// `1` means fastest compression, `6` being a good default, and -/// meaning `9` best compression. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct CompressionLevel(u8); - -impl Default for CompressionLevel { - fn default() -> Self { - Self(6) - } -} - -impl CompressionLevel { - /// Creates a new compression level. - /// - /// `level` must be in range `0..10`, where `0` means no - /// compression, `1` means fastest compression, `6` being a good - /// default, and meaning `9` best compression. - pub fn new(level: u8) -> Result { - if level < 10 { - Ok(Self(level)) - } else { - Err(Error::InvalidArgument( - format!("compression level out of range: {}", level)).into()) - } - } - - /// No compression. - pub fn none() -> CompressionLevel { - Self(0) - } - - /// Fastest compression. - pub fn fastest() -> CompressionLevel { - Self(1) - } - /// Best compression. - pub fn best() -> CompressionLevel { - Self(9) - } -} - -#[cfg(feature = "compression-deflate")] -mod into_deflate_compression { - use flate2::Compression; - use super::*; - - impl From for Compression { - fn from(l: CompressionLevel) -> Self { - Compression::new(l.0 as u32) - } - } -} - -#[cfg(feature = "compression-bzip2")] -mod into_bzip2_compression { - use bzip2::Compression; - use super::*; - - impl From for Compression { - fn from(l: CompressionLevel) -> Self { - if l <= CompressionLevel::fastest() { - Compression::Fastest - } else if l <= CompressionLevel::default() { - Compression::Default - } else { - Compression::Best - } - } - } -} diff --git a/openpgp/src/serialize/writer/mod.rs b/openpgp/src/serialize/writer/mod.rs deleted file mode 100644 index 2141ca98..00000000 --- a/openpgp/src/serialize/writer/mod.rs +++ /dev/null @@ -1,573 +0,0 @@ -//! Stackable writers. - -#[cfg(feature = "compression-bzip2")] -mod writer_bzip2; -#[cfg(feature = "compression-bzip2")] -pub use self::writer_bzip2::BZ; -#[cfg(feature = "compression-deflate")] -mod writer_deflate; -#[cfg(feature = "compression-deflate")] -pub use self::writer_deflate::{ZIP, ZLIB}; -mod compression_common; -pub use compression_common::CompressionLevel; - -use std::fmt; -use std::io; - -use crate::crypto::{aead, symmetric}; -use crate::types::{ - AEADAlgorithm, - SymmetricAlgorithm, -}; -use crate::{ - Result, - crypto::SessionKey, -}; - -/// A stack of writers. -#[derive(Debug)] -pub struct Stack<'a, C>(BoxStack<'a, C>); - -impl<'a, C> Stack<'a, C> { - pub(crate) fn from(bs: BoxStack<'a, C>) -> Self { - Stack(bs) - } - - pub(crate) fn as_ref(&self) -> &BoxStack<'a, C> { - &self.0 - } - - pub(crate) fn as_mut(&mut self) -> &mut BoxStack<'a, C> { - &mut self.0 - } - - /// Finalizes this writer, returning the underlying writer. - pub fn finalize_one(self) -> Result>> { - Ok(self.0.into_inner()?.map(|bs| Self::from(bs))) - } - - /// Finalizes all writers, tearing down the whole stack. - pub fn finalize(self) -> Result<()> { - let mut stack = self; - while let Some(s) = stack.finalize_one()? { - stack = s; - } - Ok(()) - } -} - -impl<'a, C> io::Write for Stack<'a, C> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } -} - -impl<'a, C> From> for BoxStack<'a, C> { - fn from(s: Stack<'a, C>) -> Self { - s.0 - } -} - -pub(crate) type BoxStack<'a, C> = Box + 'a>; - -/// Makes a writer stackable and provides convenience functions. -pub(crate) trait Stackable<'a, C> : io::Write + fmt::Debug { - /// Recovers the inner stackable. - /// - /// This can fail if the current `Stackable` has buffered data - /// that hasn't been written to the underlying `Stackable`. - fn into_inner(self: Box) -> Result>>; - - /// Pops the stackable from the stack, detaching it. - /// - /// Returns the detached stack. - /// - /// Note: Only the Signer implements this interface. - fn pop(&mut self) -> Result>>; - - /// Sets the inner stackable. - /// - /// Note: Only the Signer implements this interface. - fn mount(&mut self, new: BoxStack<'a, C>); - - /// Returns a mutable reference to the inner `Writer`, if - /// any. - /// - /// It is a very bad idea to write any data from the inner - /// `Writer`, but it can sometimes be useful to get the cookie. - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>>; - - /// Returns a reference to the inner `Writer`. - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>>; - - /// Sets the cookie and returns the old value. - fn cookie_set(&mut self, cookie: C) -> C; - - /// Returns a reference to the cookie. - fn cookie_ref(&self) -> &C; - - /// Returns a mutable reference to the cookie. - fn cookie_mut(&mut self) -> &mut C; - - /// Returns the number of bytes written to this filter. - fn position(&self) -> u64; - - /// Writes a byte. - fn write_u8(&mut self, b: u8) -> io::Result<()> { - let b : [u8; 1] = [b; 1]; - self.write_all(&b[..]) - } - - /// Writes a big endian `u16`. - fn write_be_u16(&mut self, n: u16) -> io::Result<()> { - let b : [u8; 2] = [ ((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8 ]; - self.write_all(&b[..]) - } - - /// Writes a big endian `u32`. - fn write_be_u32(&mut self, n: u32) -> io::Result<()> { - let b : [u8; 4] = [ (n >> 24) as u8, ((n >> 16) & 0xFF) as u8, - ((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8 ]; - self.write_all(&b[..]) - } -} - -/// Make a `Box` look like a Stackable. -impl <'a, C> Stackable<'a, C> for BoxStack<'a, C> { - fn into_inner(self: Box) -> Result>> { - (*self).into_inner() - } - /// Recovers the inner stackable. - fn pop(&mut self) -> Result>> { - self.as_mut().pop() - } - /// Sets the inner stackable. - fn mount(&mut self, new: BoxStack<'a, C>) { - self.as_mut().mount(new); - } - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { - self.as_mut().inner_mut() - } - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { - self.as_ref().inner_ref() - } - 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() - } - fn position(&self) -> u64 { - self.as_ref().position() - } -} - -/// Maps a function over the stack of writers. -#[allow(dead_code)] -pub(crate) fn map(head: &dyn Stackable, mut fun: F) - where F: FnMut(&dyn Stackable) -> bool { - let mut ow = Some(head); - while let Some(w) = ow { - if ! fun(w) { - break; - } - ow = w.inner_ref() - } -} - -/// Maps a function over the stack of mutable writers. -#[allow(dead_code)] -pub(crate) fn map_mut(head: &mut dyn Stackable, mut fun: F) - where F: FnMut(&mut dyn Stackable) -> bool { - let mut ow = Some(head); - while let Some(w) = ow { - if ! fun(w) { - break; - } - ow = w.inner_mut() - } -} - -/// Dumps the writer stack. -#[allow(dead_code)] -pub(crate) fn dump(head: &dyn Stackable) { - let mut depth = 0; - map(head, |w| { - eprintln!("{}: {:?}", depth, w); - depth += 1; - true - }); -} - -/// The identity writer just relays anything written. -pub struct Identity<'a, C> { - inner: Option>, - cookie: C, -} - -impl<'a, C: 'a> Identity<'a, C> { - /// Makes an identity writer. - pub fn new(inner: Stack<'a, C>, cookie: C) - -> Stack<'a, C> { - Stack::from(Box::new(Self{inner: Some(inner.into()), cookie })) - } -} - -impl<'a, C> fmt::Debug for Identity<'a, C> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Identity") - .field("inner", &self.inner) - .finish() - } -} - -impl<'a, C> io::Write for Identity<'a, C> { - fn write(&mut self, buf: &[u8]) -> io::Result { - let writer = self.inner.as_mut() - .ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe, - "Writer is finalized."))?; - writer.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - let writer = self.inner.as_mut() - .ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe, - "Writer is finalized."))?; - writer.flush() - } -} - -impl<'a, C> Stackable<'a, C> for Identity<'a, C> { - /// Recovers the inner stackable. - fn into_inner(self: Box) -> Result>> { - Ok(self.inner) - } - /// Recovers the inner stackable. - fn pop(&mut self) -> Result>> { - Ok(self.inner.take()) - } - /// Sets the inner stackable. - fn mount(&mut self, new: BoxStack<'a, C>) { - self.inner = Some(new); - } - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { - if let Some(ref i) = self.inner { - Some(i) - } else { - None - } - } - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { - if let Some(ref mut i) = self.inner { - Some(i) - } else { - None - } - } - fn cookie_set(&mut self, cookie: C) -> C { - ::std::mem::replace(&mut self.cookie, cookie) - } - fn cookie_ref(&self) -> &C { - &self.cookie - } - fn cookie_mut(&mut self) -> &mut C { - &mut self.cookie - } - fn position(&self) -> u64 { - self.inner.as_ref().map(|i| i.position()).unwrap_or(0) - } -} - -/// Generic writer wrapping `io::Write`. -pub struct Generic { - inner: W, - cookie: C, - position: u64, -} - -impl<'a, W: 'a + io::Write, C: 'a> Generic { - /// Wraps an `io::Write`r. - pub fn new(inner: W, cookie: C) -> Stack<'a, C> { - Stack::from(Box::new(Self::new_unboxed(inner.into(), cookie))) - } - - fn new_unboxed(inner: W, cookie: C) -> Self { - Generic { - inner, - cookie, - position: 0, - } - } -} - -impl fmt::Debug for Generic { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("writer::Generic") - .finish() - } -} - -impl io::Write for Generic { - fn write(&mut self, bytes: &[u8]) -> io::Result { - match self.inner.write(bytes) { - Ok(n) => { - self.position += n as u64; - Ok(n) - }, - Err(e) => Err(e), - } - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl<'a, W: io::Write, C> Stackable<'a, C> for Generic { - /// Recovers the inner stackable. - fn into_inner(self: Box) -> Result>> { - Ok(None) - } - /// Recovers the inner stackable. - fn pop(&mut self) -> Result>> { - Ok(None) - } - /// Sets the inner stackable. - fn mount(&mut self, _new: BoxStack<'a, C>) { - } - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { - // If you use Generic to wrap an io::Writer, and you know that - // the io::Writer's inner is also a Stackable, then return a - // reference to the innermost Stackable in your - // implementation. See e.g. writer::ZLIB. - None - } - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { - // If you use Generic to wrap an io::Writer, and you know that - // the io::Writer's inner is also a Stackable, then return a - // reference to the innermost Stackable in your - // implementation. See e.g. writer::ZLIB. - None - } - fn cookie_set(&mut self, cookie: C) -> C { - ::std::mem::replace(&mut self.cookie, cookie) - } - fn cookie_ref(&self) -> &C { - &self.cookie - } - fn cookie_mut(&mut self) -> &mut C { - &mut self.cookie - } - fn position(&self) -> u64 { - self.position - } -} - - -/// Encrypting writer. -pub struct Encryptor<'a, C: 'a> { - inner: Generic>, C>, -} - -impl<'a, C: 'a> Encryptor<'a, C> { - /// Makes an encrypting writer. - pub fn new(inner: Stack<'a, C>, cookie: C, algo: SymmetricAlgorithm, - key: &[u8]) - -> Result> - { - Ok(Stack::from(Box::new(Encryptor { - inner: Generic::new_unboxed( - symmetric::Encryptor::new(algo, key, inner.into())?, - cookie), - }))) - } -} - -impl<'a, C: 'a> fmt::Debug for Encryptor<'a, C> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("writer::Encryptor") - .field("inner", &self.inner) - .finish() - } -} - -impl<'a, C: 'a> io::Write for Encryptor<'a, C> { - fn write(&mut self, bytes: &[u8]) -> io::Result { - self.inner.write(bytes) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl<'a, C: 'a> Stackable<'a, C> for Encryptor<'a, C> { - fn into_inner(mut self: Box) -> Result>> { - let inner = self.inner.inner.finish()?; - Ok(Some(inner)) - } - fn pop(&mut self) -> Result>> { - unreachable!("Only implemented by Signer") - } - fn mount(&mut self, _new: BoxStack<'a, C>) { - unreachable!("Only implemented by Signer") - } - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { - // XXX: Unfortunately, this doesn't work due to a lifetime mismatch: - // self.inner.inner.get_mut().map(|r| r.as_mut()) - None - } - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { - self.inner.inner.get_ref().map(|r| r.as_ref()) - } - fn cookie_set(&mut self, cookie: C) -> C { - self.inner.cookie_set(cookie) - } - fn cookie_ref(&self) -> &C { - self.inner.cookie_ref() - } - fn cookie_mut(&mut self) -> &mut C { - self.inner.cookie_mut() - } - fn position(&self) -> u64 { - self.inner.position - } -} - - -/// AEAD encrypting writer. -pub struct AEADEncryptor<'a, C: 'a> { - inner: Generic>, C>, -} - -impl<'a, C: 'a> AEADEncryptor<'a, C> { - /// Makes an encrypting writer. - pub fn new(inner: Stack<'a, C>, cookie: C, - cipher: SymmetricAlgorithm, aead: AEADAlgorithm, - chunk_size: usize, iv: &[u8], key: &SessionKey) - -> Result> - { - Ok(Stack::from(Box::new(AEADEncryptor { - inner: Generic::new_unboxed( - aead::Encryptor::new(1, cipher, aead, chunk_size, iv, key, - inner.into())?, - cookie), - }))) - } -} - -impl<'a, C: 'a> fmt::Debug for AEADEncryptor<'a, C> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("writer::AEADEncryptor") - .field("inner", &self.inner) - .finish() - } -} - -impl<'a, C: 'a> io::Write for AEADEncryptor<'a, C> { - fn write(&mut self, bytes: &[u8]) -> io::Result { - self.inner.write(bytes) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl<'a, C: 'a> Stackable<'a, C> for AEADEncryptor<'a, C> { - fn into_inner(mut self: Box) -> Result>> { - let inner = self.inner.inner.finish()?; - Ok(Some(inner)) - } - fn pop(&mut self) -> Result>> { - unreachable!("Only implemented by Signer") - } - fn mount(&mut self, _new: BoxStack<'a, C>) { - unreachable!("Only implemented by Signer") - } - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { - // XXX: Unfortunately, this doesn't work due to a lifetime mismatch: - // self.inner.inner.get_mut().map(|r| r.as_mut()) - None - } - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { - self.inner.inner.get_ref().map(|r| r.as_ref()) - } - fn cookie_set(&mut self, cookie: C) -> C { - self.inner.cookie_set(cookie) - } - fn cookie_ref(&self) -> &C { - self.inner.cookie_ref() - } - fn cookie_mut(&mut self) -> &mut C { - self.inner.cookie_mut() - } - fn position(&self) -> u64 { - self.inner.position - } -} - -#[cfg(test)] -mod test { - use std::io::Write; - use super::*; - - #[derive(Debug)] - struct Cookie { - state: &'static str, - } - - #[test] - fn generic_writer() { - let mut inner = Vec::new(); - { - let mut w = Generic::new(&mut inner, Cookie { state: "happy" }); - assert_eq!(w.as_ref().cookie_ref().state, "happy"); - dump(w.as_ref()); - - w.as_mut().cookie_mut().state = "sad"; - assert_eq!(w.as_ref().cookie_ref().state, "sad"); - - w.write_all(b"be happy").unwrap(); - let mut count = 0; - map_mut(w.as_mut(), |g| { - let new = Cookie { state: "happy" }; - let old = g.cookie_set(new); - assert_eq!(old.state, "sad"); - count += 1; - true - }); - assert_eq!(count, 1); - assert_eq!(w.as_ref().cookie_ref().state, "happy"); - } - assert_eq!(&inner, b"be happy"); - } - - #[test] - fn stack() { - let mut inner = Vec::new(); - { - let w = Generic::new(&mut inner, Cookie { state: "happy" }); - dump(w.as_ref()); - - let w = Identity::new(w, Cookie { state: "happy" }); - dump(w.as_ref()); - - let mut count = 0; - map(w.as_ref(), |g| { - assert_eq!(g.cookie_ref().state, "happy"); - count += 1; - true - }); - assert_eq!(count, 2); - } - } - -} diff --git a/openpgp/src/serialize/writer/writer_bzip2.rs b/openpgp/src/serialize/writer/writer_bzip2.rs deleted file mode 100644 index 62affd0c..00000000 --- a/openpgp/src/serialize/writer/writer_bzip2.rs +++ /dev/null @@ -1,74 +0,0 @@ -use bzip2::write::BzEncoder; -use std::fmt; -use std::io; - -use crate::Result; -use super::{Generic, Stack, BoxStack, Stackable, CompressionLevel}; - -/// BZing writer. -pub struct BZ<'a, C: 'a> { - inner: Generic>, C>, -} - -impl<'a, C: 'a> BZ<'a, C> { - /// Makes a BZ compressing writer. - pub fn new(inner: Stack<'a, C>, cookie: C, level: L) -> Stack<'a, C> - where L: Into> - { - Stack::from(Box::new(BZ { - inner: Generic::new_unboxed( - BzEncoder::new(inner.into(), - level.into().unwrap_or_default().into()), - cookie), - })) - } -} - -impl<'a, C: 'a> fmt::Debug for BZ<'a, C> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("writer::BZ") - .field("inner", &self.inner) - .finish() - } -} - -impl<'a, C: 'a> io::Write for BZ<'a, C> { - fn write(&mut self, bytes: &[u8]) -> io::Result { - self.inner.write(bytes) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl<'a, C: 'a> Stackable<'a, C> for BZ<'a, C> { - fn into_inner(self: Box) -> Result>> { - let inner = self.inner.inner.finish()?; - Ok(Some(inner)) - } - fn pop(&mut self) -> Result>> { - unreachable!("Only implemented by Signer") - } - fn mount(&mut self, _new: BoxStack<'a, C>) { - unreachable!("Only implemented by Signer") - } - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { - Some(self.inner.inner.get_mut()) - } - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { - Some(self.inner.inner.get_ref()) - } - fn cookie_set(&mut self, cookie: C) -> C { - self.inner.cookie_set(cookie) - } - fn cookie_ref(&self) -> &C { - self.inner.cookie_ref() - } - fn cookie_mut(&mut self) -> &mut C { - self.inner.cookie_mut() - } - fn position(&self) -> u64 { - self.inner.position - } -} diff --git a/openpgp/src/serialize/writer/writer_deflate.rs b/openpgp/src/serialize/writer/writer_deflate.rs deleted file mode 100644 index 387b3f2c..00000000 --- a/openpgp/src/serialize/writer/writer_deflate.rs +++ /dev/null @@ -1,142 +0,0 @@ -use flate2::write::{DeflateEncoder, ZlibEncoder}; -use std::fmt; -use std::io; - -use crate::Result; -use super::{Generic, Stack, BoxStack, Stackable, CompressionLevel}; - -/// ZIPing writer. -pub struct ZIP<'a, C: 'a> { - inner: Generic>, C>, -} - -impl<'a, C: 'a> ZIP<'a, C> { - /// Makes a ZIP compressing writer. - pub fn new(inner: Stack<'a, C>, cookie: C, level: L) -> Stack<'a, C> - where L: Into> - { - Stack::from(Box::new(ZIP { - inner: Generic::new_unboxed( - DeflateEncoder::new(inner.into(), - level.into().unwrap_or_default().into()), - cookie), - })) - } -} - -impl<'a, C: 'a> fmt::Debug for ZIP<'a, C> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("writer::ZIP") - .field("inner", &self.inner) - .finish() - } -} - -impl<'a, C: 'a> io::Write for ZIP<'a, C> { - fn write(&mut self, bytes: &[u8]) -> io::Result { - self.inner.write(bytes) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl<'a, C: 'a> Stackable<'a, C> for ZIP<'a, C> { - fn into_inner(self: Box) -> Result>> { - let inner = self.inner.inner.finish()?; - Ok(Some(inner)) - } - fn pop(&mut self) -> Result>> { - unreachable!("Only implemented by Signer") - } - fn mount(&mut self, _new: BoxStack<'a, C>) { - unreachable!("Only implemented by Signer") - } - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { - Some(self.inner.inner.get_mut()) - } - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { - Some(self.inner.inner.get_ref()) - } - fn cookie_set(&mut self, cookie: C) -> C { - self.inner.cookie_set(cookie) - } - fn cookie_ref(&self) -> &C { - self.inner.cookie_ref() - } - fn cookie_mut(&mut self) -> &mut C { - self.inner.cookie_mut() - } - fn position(&self) -> u64 { - self.inner.position - } -} - -/// ZLIBing writer. -pub struct ZLIB<'a, C: 'a> { - inner: Generic>, C>, -} - -impl<'a, C: 'a> ZLIB<'a, C> { - /// Makes a ZLIB compressing writer. - pub fn new(inner: Stack<'a, C>, cookie: C, level: L) -> Stack<'a, C> - where L: Into> - { - Stack::from(Box::new(ZLIB { - inner: Generic::new_unboxed( - ZlibEncoder::new(inner.into(), - level.into().unwrap_or_default().into()), - cookie), - })) - } -} - -impl<'a, C:> fmt::Debug for ZLIB<'a, C> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("writer::ZLIB") - .field("inner", &self.inner) - .finish() - } -} - -impl<'a, C: 'a> io::Write for ZLIB<'a, C> { - fn write(&mut self, bytes: &[u8]) -> io::Result { - self.inner.write(bytes) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl<'a, C: 'a> Stackable<'a, C> for ZLIB<'a, C> { - fn into_inner(self: Box) -> Result>> { - let inner = self.inner.inner.finish()?; - Ok(Some(inner)) - } - fn pop(&mut self) -> Result>> { - unreachable!("Only implemented by Signer") - } - fn mount(&mut self, _new: BoxStack<'a, C>) { - unreachable!("Only implemented by Signer") - } - fn inner_mut(&mut self) -> Option<&mut dyn Stackable<'a, C>> { - Some(self.inner.inner.get_mut()) - } - fn inner_ref(&self) -> Option<&dyn Stackable<'a, C>> { - Some(self.inner.inner.get_ref()) - } - fn cookie_set(&mut self, cookie: C) -> C { - self.inner.cookie_set(cookie) - } - fn cookie_ref(&self) -> &C { - self.inner.cookie_ref() - } - fn cookie_mut(&mut self) -> &mut C { - self.inner.cookie_mut() - } - fn position(&self) -> u64 { - self.inner.position - } -} -- cgit v1.2.3