sequoia_openpgp/parse/
map.rs

1//! Packet maps.
2//!
3//! If configured to do so, a `PacketParser` will create a map that
4//! charts the byte-stream, describing where the information was
5//! extracted from.
6//!
7//! # Examples
8//!
9//! ```
10//! # fn main() -> sequoia_openpgp::Result<()> {
11//! use sequoia_openpgp as openpgp;
12//! use openpgp::parse::{Parse, PacketParserBuilder};
13//!
14//! let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
15//! let pp = PacketParserBuilder::from_bytes(message_data)?
16//!     .map(true) // Enable mapping.
17//!     .buffer_unread_content() // For the packet body.
18//!     .build()?
19//!     .expect("One packet, not EOF");
20//! let map = pp.map().expect("Mapping is enabled");
21//!
22//! assert_eq!(map.iter().nth(0).unwrap().name(), "CTB");
23//! assert_eq!(map.iter().nth(0).unwrap().offset(), 0);
24//! assert_eq!(map.iter().nth(0).unwrap().as_bytes(), &[0xcb]);
25//! # Ok(()) }
26//! ```
27
28use std::cmp;
29
30/// Map created during parsing.
31#[derive(Clone, Debug)]
32pub struct Map {
33    length: usize,
34    entries: Vec<Entry>,
35    header: Vec<u8>,
36    data: Vec<u8>,
37}
38assert_send_and_sync!(Map);
39
40/// Represents an entry in the map.
41#[derive(Clone, Debug)]
42struct Entry {
43    offset: usize,
44    length: usize,
45    field: &'static str,
46}
47
48impl Map {
49    /// Creates a new map.
50    pub(super) fn new(header: Vec<u8>) -> Self {
51        Map {
52            length: 0,
53            entries: Vec::new(),
54            header,
55            data: Vec::new(),
56        }
57    }
58
59    /// Adds a field to the map.
60    pub(super) fn add(&mut self, field: &'static str, length: usize) {
61        self.entries.push(Entry {
62            offset: self.length, length, field
63        });
64        self.length += length;
65    }
66
67    /// Finalizes the map providing the actual data.
68    pub(super) fn finalize(&mut self, data: Vec<u8>) {
69        self.data = data;
70    }
71
72    /// Creates an iterator over the map.
73    ///
74    /// Returns references to [`Field`]s.
75    ///
76    ///
77    /// # Examples
78    ///
79    /// ```
80    /// # fn main() -> sequoia_openpgp::Result<()> {
81    /// use sequoia_openpgp as openpgp;
82    /// use openpgp::parse::{Parse, PacketParserBuilder};
83    ///
84    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
85    /// let pp = PacketParserBuilder::from_bytes(message_data)?
86    ///     .map(true) // Enable mapping.
87    ///     .buffer_unread_content() // For the packet body.
88    ///     .build()?
89    ///     .expect("One packet, not EOF");
90    /// let map = pp.map().expect("Mapping is enabled");
91    ///
92    /// assert_eq!(map.iter().count(), 6);
93    /// # Ok(()) }
94    /// ```
95    pub fn iter(&self) -> impl Iterator<Item = Field> + Send + Sync {
96        Iter::new(self)
97    }
98}
99
100/// Represents an entry in the map.
101///
102/// A field has a [`name`] returning a human-readable field name
103/// (e.g. "CTB", or "version"), an [`offset`] into the packet, and the
104/// read [`data`].
105///
106///   [`name`]: Field::name
107///   [`offset`]: Field::offset
108///   [`data`]: Field::as_bytes
109#[derive(Clone, Debug)]
110pub struct Field<'a> {
111    /// Name of the field.
112    name: &'static str,
113    /// Offset of the field in the packet.
114    offset: usize,
115    /// Value of the field.
116    data: &'a [u8],
117}
118assert_send_and_sync!(Field<'_>);
119
120impl<'a> Field<'a> {
121    fn new(map: &'a Map, i: usize) -> Option<Field<'a>> {
122        // Synthetic packets have no CTB.
123        let has_ctb = ! map.header.is_empty();
124
125        // Old-style CTB with indeterminate length emits no length
126        // field.
127        let has_length = map.header.len() > 1;
128
129        if i == 0 && has_ctb {
130            Some(Field {
131                offset: 0,
132                name: "CTB",
133                data: &map.header.as_slice()[..1],
134            })
135        } else if i == 1 && has_length {
136            Some(Field {
137                offset: 1,
138                name: "length",
139                data: &map.header.as_slice()[1..]
140            })
141        } else {
142            let offset =
143                if has_ctb { 1 } else { 0 }
144                + if has_length { 1 } else { 0 };
145
146            map.entries.get(i - offset).map(|e| {
147                let len = map.data.len();
148                let start = cmp::min(len, e.offset);
149                let end = cmp::min(len, e.offset + e.length);
150                Field {
151                    offset: map.header.len() + e.offset,
152                    name: e.field,
153                    data: &map.data[start..end],
154                }
155            })
156        }
157    }
158
159    /// Returns the name of the field.
160    ///
161    /// Note: The returned names are for display purposes only and may
162    /// change in the future.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// # fn main() -> sequoia_openpgp::Result<()> {
168    /// use sequoia_openpgp as openpgp;
169    /// use openpgp::parse::{Parse, PacketParserBuilder};
170    ///
171    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
172    /// let pp = PacketParserBuilder::from_bytes(message_data)?
173    ///     .map(true) // Enable mapping.
174    ///     .buffer_unread_content() // For the packet body.
175    ///     .build()?
176    ///     .expect("One packet, not EOF");
177    /// let map = pp.map().expect("Mapping is enabled");
178    ///
179    /// assert_eq!(map.iter().nth(0).unwrap().name(), "CTB");
180    /// assert_eq!(map.iter().nth(1).unwrap().name(), "length");
181    /// assert_eq!(map.iter().nth(2).unwrap().name(), "format");
182    /// assert_eq!(map.iter().nth(3).unwrap().name(), "filename_len");
183    /// assert_eq!(map.iter().nth(4).unwrap().name(), "date");
184    /// assert_eq!(map.iter().nth(5).unwrap().name(), "body");
185    /// assert!(map.iter().nth(6).is_none());
186    /// # Ok(()) }
187    /// ```
188    pub fn name(&self) -> &'a str {
189        self.name
190    }
191
192    /// Returns the offset of the field in the packet.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// # fn main() -> sequoia_openpgp::Result<()> {
198    /// use sequoia_openpgp as openpgp;
199    /// use openpgp::parse::{Parse, PacketParserBuilder};
200    ///
201    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
202    /// let pp = PacketParserBuilder::from_bytes(message_data)?
203    ///     .map(true) // Enable mapping.
204    ///     .buffer_unread_content() // For the packet body.
205    ///     .build()?
206    ///     .expect("One packet, not EOF");
207    /// let map = pp.map().expect("Mapping is enabled");
208    ///
209    /// assert_eq!(map.iter().nth(0).unwrap().offset(), 0);
210    /// assert_eq!(map.iter().nth(1).unwrap().offset(), 1);
211    /// assert_eq!(map.iter().nth(2).unwrap().offset(), 2);
212    /// assert_eq!(map.iter().nth(3).unwrap().offset(), 3);
213    /// assert_eq!(map.iter().nth(4).unwrap().offset(), 4);
214    /// assert_eq!(map.iter().nth(5).unwrap().offset(), 8);
215    /// assert!(map.iter().nth(6).is_none());
216    /// # Ok(()) }
217    /// ```
218    pub fn offset(&self) -> usize {
219        self.offset
220    }
221
222    /// Returns the value of the field.
223    ///
224    /// # Examples
225    ///
226    /// ```
227    /// # fn main() -> sequoia_openpgp::Result<()> {
228    /// use sequoia_openpgp as openpgp;
229    /// use openpgp::parse::{Parse, PacketParserBuilder};
230    ///
231    /// let message_data = b"\xcb\x12t\x00\x00\x00\x00\x00Hello world.";
232    /// let pp = PacketParserBuilder::from_bytes(message_data)?
233    ///     .map(true) // Enable mapping.
234    ///     .buffer_unread_content() // For the packet body.
235    ///     .build()?
236    ///     .expect("One packet, not EOF");
237    /// let map = pp.map().expect("Mapping is enabled");
238    ///
239    /// assert_eq!(map.iter().nth(0).unwrap().as_bytes(), &[0xcb]);
240    /// assert_eq!(map.iter().nth(1).unwrap().as_bytes(), &[0x12]);
241    /// assert_eq!(map.iter().nth(2).unwrap().as_bytes(), "t".as_bytes());
242    /// assert_eq!(map.iter().nth(3).unwrap().as_bytes(), &[0x00]);
243    /// assert_eq!(map.iter().nth(4).unwrap().as_bytes(),
244    ///            &[0x00, 0x00, 0x00, 0x00]);
245    /// assert_eq!(map.iter().nth(5).unwrap().as_bytes(),
246    ///            "Hello world.".as_bytes());
247    /// assert!(map.iter().nth(6).is_none());
248    /// # Ok(()) }
249    /// ```
250    pub fn as_bytes(&self) -> &'a [u8] {
251        self.data
252    }
253}
254
255/// An iterator over the map.
256struct Iter<'a> {
257    map: &'a Map,
258    i: usize,
259}
260
261impl<'a> Iter<'a> {
262    fn new(map: &'a Map) -> Iter<'a> {
263        Iter {
264            map,
265            i: 0,
266        }
267    }
268}
269
270impl<'a> Iterator for Iter<'a> {
271    type Item = Field<'a>;
272
273    fn next(&mut self) -> Option<Self::Item> {
274        let field = Field::new(self.map, self.i);
275        if field.is_some() {
276            self.i += 1;
277        }
278        field
279    }
280}