1#[cfg(test)]
4use pretty_hex::PrettyHex;
5
6use super::*;
7
8pub struct SubsectionIter<'a> {
10 rest: &'a [u8],
11}
12
13impl<'a> SubsectionIter<'a> {
14 pub fn new(rest: &'a [u8]) -> Self {
16 Self { rest }
17 }
18
19 pub fn rest(&self) -> &'a [u8] {
21 self.rest
22 }
23}
24
25impl<'a> HasRestLen for SubsectionIter<'a> {
26 fn rest_len(&self) -> usize {
27 self.rest.len()
28 }
29}
30
31pub struct SubsectionIterMut<'a> {
33 rest: &'a mut [u8],
34}
35
36impl<'a> SubsectionIterMut<'a> {
37 pub fn new(rest: &'a mut [u8]) -> Self {
39 Self { rest }
40 }
41
42 pub fn rest(&self) -> &[u8] {
44 self.rest
45 }
46}
47
48impl<'a> HasRestLen for SubsectionIterMut<'a> {
49 fn rest_len(&self) -> usize {
50 self.rest.len()
51 }
52}
53
54pub struct Subsection<'a> {
56 pub kind: SubsectionKind,
58 pub data: &'a [u8],
60}
61
62pub struct SubsectionMut<'a> {
64 pub kind: SubsectionKind,
66 pub data: &'a mut [u8],
68}
69
70#[derive(IntoBytes, FromBytes, KnownLayout, Immutable, Unaligned)]
72#[repr(C)]
73pub struct SubsectionHeader {
74 pub kind: U32<LE>,
76 pub size: U32<LE>,
78}
79
80impl<'a> Iterator for SubsectionIter<'a> {
81 type Item = Subsection<'a>;
82
83 fn next(&mut self) -> Option<Self::Item> {
84 if self.rest.is_empty() {
85 return None;
86 }
87
88 let mut p = Parser::new(self.rest);
89 let header: &SubsectionHeader = if let Ok(h) = p.get::<SubsectionHeader>() {
90 h
91 } else {
92 warn!(
93 "Failed to decode subsection data (incomplete header)! rest_len = {}",
94 self.rest.len()
95 );
96 return None;
97 };
98 let size = header.size.get() as usize;
99
100 let data = if let Ok(d) = p.bytes(size) {
101 d
102 } else {
103 warn!(
104 "Failed to decode subsection data (incomplete payload)! rest_len = {}",
105 self.rest.len()
106 );
107 return None;
108 };
109
110 let alignment_len = (4 - (size & 3)) & 3;
112 let _ = p.skip(alignment_len);
113
114 self.rest = p.into_rest();
115
116 Some(Subsection {
117 kind: SubsectionKind(header.kind.get()),
118 data,
119 })
120 }
121}
122
123impl<'a> Iterator for SubsectionIterMut<'a> {
124 type Item = SubsectionMut<'a>;
125
126 fn next(&mut self) -> Option<Self::Item> {
127 if self.rest.is_empty() {
128 return None;
129 }
130
131 let mut p = ParserMut::new(core::mem::take(&mut self.rest));
132 let header: &SubsectionHeader = p.get::<SubsectionHeader>().ok()?;
133 let size = header.size.get() as usize;
134 let data = p.bytes_mut(size).ok()?;
135
136 let alignment_len = (4 - (size & 3)) & 3;
137 let _ = p.skip(alignment_len);
138
139 self.rest = p.into_rest();
140
141 Some(SubsectionMut {
142 kind: SubsectionKind(header.kind.get()),
143 data,
144 })
145 }
146}
147
148#[test]
151fn empty_or_malformed_input() {
152 static CASES: &[(&str, &[u8])] = &[
153 ("empty input", &[]),
154 ("incomplete subsection_kind", &[0xf1, 0]),
155 ("incomplete subsection_size", &[0xf1, 0, 0, 0, 0xff, 0xff]),
156 (
157 "incomplete subsection_data",
158 &[
159 0xf1, 0, 0, 0, 0, 0, 1, 0, ],
162 ),
163 ];
164
165 for &(case_name, case_data) in CASES.iter() {
166 println!("case: {}\n{:?}", case_name, case_data.hex_dump());
168 let ld = LineData::new(case_data);
169 assert_eq!(ld.subsections().count(), 0);
170 assert!(ld.find_checksums().is_none());
171 assert!(ld.find_checksums_bytes().is_none());
172 ld.iter_name_index(|_name| panic!("should never be called"))
173 .unwrap();
174
175 let mut case_data_mut = case_data.to_vec();
177 let mut ld = LineDataMut::new(&mut case_data_mut);
178 assert_eq!(ld.subsections_mut().count(), 0);
179 }
180}
181
182#[test]
184fn test_subsection_alignment() {
185 const PAD: u8 = 0xaa;
186
187 #[rustfmt::skip]
188 static DATA: &[u8] = &[
189 0xf4, 0, 0, 0, 0x2, 0, 0, 0, 0xab, 0xcd, PAD, PAD, 0xf5, 0, 0, 0, 7, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, PAD, 0xf6, 0, 0, 0, 8, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1, 0xf7, 0, 0, 0, 5, 0, 0, 0, 10, 11, 12, 13, 14, PAD, PAD, PAD, ];
212
213 {
215 let mut iter = LineData::new(DATA).subsections();
216
217 let sub0 = iter.next().unwrap();
218 assert_eq!(sub0.kind, SubsectionKind::FILE_CHECKSUMS);
219 assert_eq!(sub0.data, &[0xab, 0xcd]);
220
221 let sub1 = iter.next().unwrap();
222 assert_eq!(sub1.kind, SubsectionKind::FRAMEDATA);
223 assert_eq!(sub1.data, &[1, 2, 3, 4, 5, 6, 7]);
224
225 let sub2 = iter.next().unwrap();
226 assert_eq!(sub2.kind, SubsectionKind::INLINEELINES);
227 assert_eq!(sub2.data, &[8, 7, 6, 5, 4, 3, 2, 1]);
228
229 let sub3 = iter.next().unwrap();
230 assert_eq!(sub3.kind, SubsectionKind::CROSSSCOPEIMPORTS);
231 assert_eq!(sub3.data, &[10, 11, 12, 13, 14]);
232
233 assert!(iter.rest().is_empty());
234 }
235
236 {
240 let mut data_mut = DATA.to_vec();
241 let mut iter = SubsectionIterMut::new(&mut data_mut);
242
243 let sub0 = iter.next().unwrap();
244 assert_eq!(sub0.kind, SubsectionKind::FILE_CHECKSUMS);
245 assert_eq!(sub0.data, &[0xab, 0xcd]);
246
247 let sub1 = iter.next().unwrap();
248 assert_eq!(sub1.kind, SubsectionKind::FRAMEDATA);
249 assert_eq!(sub1.data, &[1, 2, 3, 4, 5, 6, 7]);
250
251 let sub2 = iter.next().unwrap();
252 assert_eq!(sub2.kind, SubsectionKind::INLINEELINES);
253 assert_eq!(sub2.data, &[8, 7, 6, 5, 4, 3, 2, 1]);
254
255 let sub3 = iter.next().unwrap();
256 assert_eq!(sub3.kind, SubsectionKind::CROSSSCOPEIMPORTS);
257 assert_eq!(sub3.data, &[10, 11, 12, 13, 14]);
258
259 assert!(iter.rest().is_empty());
260 }
261}