1 use std::fmt;
2 
3 #[cfg(any(test, feature = "quickcheck"))]
4 use quickcheck::{Arbitrary, Gen};
5 
6 use crate::packet;
7 use crate::Packet;
8 use crate::types::CompressionAlgorithm;
9 
10 /// Holds a compressed data packet.
11 ///
12 /// A compressed data packet is a container.  See [Section 5.6 of RFC
13 /// 4880] for details.
14 ///
15 /// When the parser encounters a compressed data packet with an
16 /// unknown compress algorithm, it returns an `Unknown` packet instead
17 /// of a `CompressedData` packet.
18 ///
19 /// [Section 5.6 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.6
20 // IMPORTANT: If you add fields to this struct, you need to explicitly
21 // IMPORTANT: implement PartialEq, Eq, and Hash.
22 #[derive(Clone, PartialEq, Eq, Hash)]
23 pub struct CompressedData {
24     /// CTB packet header fields.
25     pub(crate) common: packet::Common,
26     /// Algorithm used to compress the payload.
27     algo: CompressionAlgorithm,
28 
29     /// This is a container packet.
30     container: packet::Container,
31 }
32 
33 impl std::ops::Deref for CompressedData {
34     type Target = packet::Container;
deref(&self) -> &Self::Target35     fn deref(&self) -> &Self::Target {
36         &self.container
37     }
38 }
39 
40 impl std::ops::DerefMut for CompressedData {
deref_mut(&mut self) -> &mut Self::Target41     fn deref_mut(&mut self) -> &mut Self::Target {
42         &mut self.container
43     }
44 }
45 
46 impl fmt::Debug for CompressedData {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result47     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48         f.debug_struct("CompressedData")
49             .field("algo", &self.algo)
50             .field("container", &self.container)
51             .finish()
52     }
53 }
54 
55 impl CompressedData {
56     /// Returns a new `CompressedData` packet.
new(algo: CompressionAlgorithm) -> Self57     pub fn new(algo: CompressionAlgorithm) -> Self {
58         CompressedData {
59             common: Default::default(),
60             algo,
61             container: Default::default(),
62         }
63     }
64 
65     /// Gets the compression algorithm.
algo(&self) -> CompressionAlgorithm66     pub fn algo(&self) -> CompressionAlgorithm {
67         self.algo
68     }
69 
70     /// Sets the compression algorithm.
set_algo(&mut self, algo: CompressionAlgorithm) -> CompressionAlgorithm71     pub fn set_algo(&mut self, algo: CompressionAlgorithm) -> CompressionAlgorithm {
72         ::std::mem::replace(&mut self.algo, algo)
73     }
74 
75     /// Adds a new packet to the container.
76     #[cfg(test)]
push(mut self, packet: Packet) -> Self77     pub fn push(mut self, packet: Packet) -> Self {
78         self.container.children_mut().unwrap().push(packet);
79         self
80     }
81 
82     /// Inserts a new packet to the container at a particular index.
83     /// If `i` is 0, the new packet is insert at the front of the
84     /// container.  If `i` is one, it is inserted after the first
85     /// packet, etc.
86     #[cfg(test)]
insert(mut self, i: usize, packet: Packet) -> Self87     pub fn insert(mut self, i: usize, packet: Packet) -> Self {
88         self.container.children_mut().unwrap().insert(i, packet);
89         self
90     }
91 }
92 
93 impl From<CompressedData> for Packet {
from(s: CompressedData) -> Self94     fn from(s: CompressedData) -> Self {
95         Packet::CompressedData(s)
96     }
97 }
98 
99 #[cfg(any(test, feature = "quickcheck"))]
100 impl Arbitrary for CompressedData {
arbitrary<G: Gen>(g: &mut G) -> Self101     fn arbitrary<G: Gen>(g: &mut G) -> Self {
102         use rand::Rng;
103         use crate::serialize::SerializeInto;
104         loop {
105             let a = CompressionAlgorithm::from(g.gen_range(0, 4));
106             if a.is_supported() {
107                 let mut c = CompressedData::new(a);
108                 // We arbitrarily chose to create packets with
109                 // processed bodies, so that
110                 // Packet::from_bytes(c.to_vec()) will roundtrip them.
111                 c.set_body(packet::Body::Processed(
112                     Packet::arbitrary(g).to_vec().unwrap()
113                 ));
114                 return c;
115             }
116         }
117     }
118 }
119