diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2022-05-12 15:42:51 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2022-06-08 10:54:52 +0200 |
commit | 0bc5fa77df3c9dc325afd824b413841b51a4e7ec (patch) | |
tree | 3890cc985bd58bf81e18ce71d909e7e9202968f3 /openpgp/src/packet | |
parent | e049498509107f93849e86fc902d0dff49ae0a93 (diff) |
openpgp: Implement TryFrom<Packet> for Unknown.
Diffstat (limited to 'openpgp/src/packet')
-rw-r--r-- | openpgp/src/packet/unknown.rs | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/openpgp/src/packet/unknown.rs b/openpgp/src/packet/unknown.rs index 50000a61..1302f407 100644 --- a/openpgp/src/packet/unknown.rs +++ b/openpgp/src/packet/unknown.rs @@ -146,3 +146,113 @@ impl From<Unknown> for Packet { Packet::Unknown(s) } } + +impl std::convert::TryFrom<Packet> for Unknown { + type Error = crate::Error; + + /// Tries to convert a packet to an `Unknown`. Returns an error + /// if the given packet is a container packet (i.e. a compressed + /// data packet or an encrypted data packet of any kind). + fn try_from(p: Packet) -> std::result::Result<Self, Self::Error> { + use std::ops::Deref; + use packet::{Any, Body, Common, Container}; + use crate::serialize::MarshalInto; + + let tag = p.tag(); + + // First, short-circuit happy and unhappy paths so that we + // avoid copying the potentially large packet parser maps in + // common. + match &p { + // Happy path. + Packet::Unknown(_) => + return Ok(p.downcast().expect("is an unknown")), + + // The container packets we flat-out refuse to convert. + // The Unknown packet has an unprocessed body, and we + // cannot recreate that from processed or structured + // bodies. + Packet::CompressedData(_) + | Packet::SEIP(_) + | Packet::AED(_) => + return Err(Self::Error::InvalidOperation( + format!("Cannot convert {} to unknown packets", tag))), + + _ => (), + } + + // Now we copy the common bits that we'll need. + let common = p.deref().clone(); + + fn convert<V>(tag: Tag, common: Common, body: V) + -> Result<Unknown, crate::Error> + where + V: MarshalInto, + { + let container = { + let mut c = Container::default_unprocessed(); + c.set_body(Body::Unprocessed( + body.to_vec().expect("infallible serialization"))); + c + }; + + Ok(Unknown { + container, + common, + tag, + error: crate::Error::MalformedPacket( + format!("Implicit conversion from {} to unknown packet", + tag)).into(), + }) + } + + match p { + // Happy path. + Packet::Unknown(_) => unreachable!("handled above"), + + // These packets convert infallibly. + Packet::Signature(v) => convert(tag, common, v), + Packet::OnePassSig(v) => convert(tag, common, v), + Packet::PublicKey(v) => convert(tag, common, v), + Packet::PublicSubkey(v) => convert(tag, common, v), + Packet::SecretKey(v) => convert(tag, common, v), + Packet::SecretSubkey(v) => convert(tag, common, v), + Packet::Marker(v) => convert(tag, common, v), + Packet::Trust(v) => convert(tag, common, v), + Packet::UserID(v) => convert(tag, common, v), + Packet::UserAttribute(v) => convert(tag, common, v), + Packet::PKESK(v) => convert(tag, common, v), + Packet::SKESK(v) => convert(tag, common, v), + Packet::MDC(v) => convert(tag, common, v), + + // Here we can avoid copying the body. + Packet::Literal(mut v) => { + let container = { + let mut c = Container::default_unprocessed(); + // Get v's body out without copying. + c.set_body(Body::Unprocessed(v.set_body( + Vec::with_capacity(0)))); + c + }; + let common = v.common.clone(); // XXX why can't I decompose `p`? + + Ok(Unknown { + container, + common, + tag, + error: crate::Error::MalformedPacket( + format!("Implicit conversion from {} to unknown packet", + tag)).into(), + }) + }, + + // The container packets we flat-out refuse to convert. + // The Unknown packet has an unprocessed body, and we + // cannot recreate that from processed or structured + // bodies. + Packet::CompressedData(_) + | Packet::SEIP(_) + | Packet::AED(_) => unreachable!("handled above"), + } + } +} |