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}