sequoia_openpgp/packet/
literal.rs1use std::fmt;
2use std::cmp;
3use std::convert::TryInto;
4use std::time;
5
6#[cfg(test)]
7use quickcheck::{Arbitrary, Gen};
8
9use crate::types::{DataFormat, Timestamp};
10use crate::Error;
11use crate::packet;
12use crate::Packet;
13use crate::Result;
14
15#[derive(Clone, PartialEq, Eq, Hash)]
29pub struct Literal {
30 pub(crate) common: packet::Common,
32 format: DataFormat,
34 filename: Option<Vec<u8>>,
40 date: Option<Timestamp>,
43 container: packet::Container,
49}
50assert_send_and_sync!(Literal);
51
52impl fmt::Debug for Literal {
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 let filename = self
55 .filename
56 .as_ref()
57 .map(|filename| String::from_utf8_lossy(filename));
58
59 let threshold = 36;
60 let body = self.body();
61 let prefix = &body[..cmp::min(threshold, body.len())];
62 let mut prefix_fmt = String::from_utf8_lossy(prefix).into_owned();
63 if body.len() > threshold {
64 prefix_fmt.push_str("...");
65 }
66 prefix_fmt.push_str(&format!(" ({} bytes)", body.len())[..]);
67
68 f.debug_struct("Literal")
69 .field("format", &self.format)
70 .field("filename", &filename)
71 .field("date", &self.date)
72 .field("body", &prefix_fmt)
73 .field("body_digest", &self.container.body_digest())
74 .finish()
75 }
76}
77
78impl Default for Literal {
79 fn default() -> Self {
80 Self::new(Default::default())
81 }
82}
83
84impl Literal {
85 pub fn new(format: DataFormat) -> Literal {
87 Literal {
88 common: Default::default(),
89 format,
90 filename: None,
91 date: None,
92 container: packet::Container::default_unprocessed(),
93 }
94 }
95
96 pub fn format(&self) -> DataFormat {
98 self.format
99 }
100
101 pub fn set_format(&mut self, format: DataFormat) -> DataFormat {
103 ::std::mem::replace(&mut self.format, format)
104 }
105
106 pub fn filename(&self) -> Option<&[u8]> {
112 self.filename.as_deref()
113 }
114
115 pub fn set_filename<F>(&mut self, filename: F)
124 -> Result<Option<Vec<u8>>>
125 where F: AsRef<[u8]>
126 {
127 let filename = filename.as_ref();
128 Ok(::std::mem::replace(&mut self.filename, match filename.len() {
129 0 => None,
130 1..=255 => Some(filename.to_vec()),
131 n => return
132 Err(Error::InvalidArgument(
133 format!("filename too long: {} bytes", n)).into()),
134 }))
135 }
136
137 pub fn date(&self) -> Option<time::SystemTime> {
143 self.date.map(|d| d.into())
144 }
145
146 pub fn set_date<T>(&mut self, timestamp: T)
152 -> Result<Option<time::SystemTime>>
153 where T: Into<Option<time::SystemTime>>
154 {
155 let date = if let Some(d) = timestamp.into() {
156 let t = d.try_into()?;
157 if u32::from(t) == 0 {
158 None } else {
160 Some(t)
161 }
162 } else {
163 None
164 };
165 Ok(std::mem::replace(&mut self.date, date).map(|d| d.into()))
166 }
167}
168
169impl_unprocessed_body_forwards!(Literal);
170
171impl From<Literal> for Packet {
172 fn from(s: Literal) -> Self {
173 Packet::Literal(s)
174 }
175}
176
177#[cfg(test)]
178impl Arbitrary for Literal {
179 fn arbitrary(g: &mut Gen) -> Self {
180 let mut l = Literal::new(DataFormat::arbitrary(g));
181 l.set_body(Vec::<u8>::arbitrary(g));
182 while let Err(_) = l.set_filename(&Vec::<u8>::arbitrary(g)) {
183 }
185 l.set_date(Some(Timestamp::arbitrary(g).into())).unwrap();
186 l
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193 use crate::parse::Parse;
194 use crate::serialize::MarshalInto;
195
196 quickcheck! {
197 fn roundtrip(p: Literal) -> bool {
198 let q = Literal::from_bytes(&p.to_vec().unwrap()).unwrap();
199 assert_eq!(p, q);
200 true
201 }
202 }
203
204 #[test]
206 fn partial_read_eq() -> Result<()> {
207 use buffered_reader::BufferedReader;
208 use crate::parse::PacketParserBuilder;
209
210 let mut l0 = Literal::new(Default::default());
211 l0.set_body(vec![0, 0]);
212 let l0 = Packet::from(l0);
213 let l0bin = l0.to_vec()?;
214 assert_eq!(l0, Packet::from_bytes(&l0bin)?);
216
217 for &buffer_unread_content in &[false, true] {
218 for read_n in 0..3 {
219 eprintln!("buffer_unread_content: {:?}, read_n: {}",
220 buffer_unread_content, read_n);
221
222 let mut b = PacketParserBuilder::from_bytes(&l0bin)?;
223 if buffer_unread_content {
224 b = b.buffer_unread_content();
225 }
226 let mut pp = b.build()?.unwrap();
227 let d = pp.steal(read_n)?;
228 d.into_iter().for_each(|b| assert_eq!(b, 0));
229 let l = pp.finish()?;
230 assert_eq!(&l0, l);
231 let l = pp.next()?.0;
232 assert_eq!(l0, l);
233 }
234 }
235 Ok(())
236 }
237}