1 | /* Copyright 2018 Mozilla Foundation |
2 | * |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
4 | * you may not use this file except in compliance with the License. |
5 | * You may obtain a copy of the License at |
6 | * |
7 | * http://www.apache.org/licenses/LICENSE-2.0 |
8 | * |
9 | * Unless required by applicable law or agreed to in writing, software |
10 | * distributed under the License is distributed on an "AS IS" BASIS, |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | * See the License for the specific language governing permissions and |
13 | * limitations under the License. |
14 | */ |
15 | |
16 | use crate::{BinaryReader, BinaryReaderError, Result}; |
17 | use ::core::fmt; |
18 | use ::core::marker; |
19 | use ::core::ops::Range; |
20 | |
21 | #[cfg (feature = "component-model" )] |
22 | mod component; |
23 | mod core; |
24 | |
25 | #[cfg (feature = "component-model" )] |
26 | pub use self::component::*; |
27 | pub use self::core::*; |
28 | |
29 | /// A trait implemented for items that can be decoded directly from a |
30 | /// `BinaryReader`, or that which can be parsed from the WebAssembly binary |
31 | /// format. |
32 | /// |
33 | /// Note that this is also accessible as a [`BinaryReader::read`] method. |
34 | pub trait FromReader<'a>: Sized { |
35 | /// Attempts to read `Self` from the provided binary reader, returning an |
36 | /// error if it is unable to do so. |
37 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self>; |
38 | } |
39 | |
40 | impl<'a> FromReader<'a> for u32 { |
41 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
42 | reader.read_var_u32() |
43 | } |
44 | } |
45 | |
46 | impl<'a> FromReader<'a> for &'a str { |
47 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
48 | reader.read_string() |
49 | } |
50 | } |
51 | |
52 | impl<'a, T, U> FromReader<'a> for (T, U) |
53 | where |
54 | T: FromReader<'a>, |
55 | U: FromReader<'a>, |
56 | { |
57 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
58 | Ok((reader.read()?, reader.read()?)) |
59 | } |
60 | } |
61 | |
62 | /// A generic structure for reading a section of a WebAssembly binary which has |
63 | /// a limited number of items within it. |
64 | /// |
65 | /// Many WebAssembly sections are a count of items followed by that many items. |
66 | /// This helper structure can be used to parse these sections and provides |
67 | /// an iteration-based API for reading the contents. |
68 | /// |
69 | /// Note that this always implements the [`Clone`] trait to represent the |
70 | /// ability to parse the section multiple times. |
71 | pub struct SectionLimited<'a, T> { |
72 | reader: BinaryReader<'a>, |
73 | count: u32, |
74 | _marker: marker::PhantomData<T>, |
75 | } |
76 | |
77 | impl<'a, T> SectionLimited<'a, T> { |
78 | /// Creates a new section reader from the provided contents. |
79 | /// |
80 | /// The `data` provided here is the data of the section itself that will be |
81 | /// parsed. The `offset` argument is the byte offset, in the original wasm |
82 | /// binary, that the section was found. The `offset` argument is used |
83 | /// for error reporting. |
84 | /// |
85 | /// # Errors |
86 | /// |
87 | /// Returns an error if a 32-bit count couldn't be read from the `data`. |
88 | pub fn new(mut reader: BinaryReader<'a>) -> Result<Self> { |
89 | let count = reader.read_var_u32()?; |
90 | Ok(SectionLimited { |
91 | reader, |
92 | count, |
93 | _marker: marker::PhantomData, |
94 | }) |
95 | } |
96 | |
97 | /// Returns the count of total items within this section. |
98 | pub fn count(&self) -> u32 { |
99 | self.count |
100 | } |
101 | |
102 | /// Returns whether the original byte offset of this section. |
103 | pub fn original_position(&self) -> usize { |
104 | self.reader.original_position() |
105 | } |
106 | |
107 | /// Returns the range, as byte offsets, of this section within the original |
108 | /// wasm binary. |
109 | pub fn range(&self) -> Range<usize> { |
110 | self.reader.range() |
111 | } |
112 | |
113 | /// Returns an iterator which yields not only each item in this section but |
114 | /// additionally the offset of each item within the section. |
115 | pub fn into_iter_with_offsets(self) -> SectionLimitedIntoIterWithOffsets<'a, T> |
116 | where |
117 | T: FromReader<'a>, |
118 | { |
119 | SectionLimitedIntoIterWithOffsets { |
120 | iter: self.into_iter(), |
121 | } |
122 | } |
123 | } |
124 | |
125 | impl<T> Clone for SectionLimited<'_, T> { |
126 | fn clone(&self) -> Self { |
127 | SectionLimited { |
128 | reader: self.reader.clone(), |
129 | count: self.count, |
130 | _marker: self._marker, |
131 | } |
132 | } |
133 | } |
134 | |
135 | impl<T> fmt::Debug for SectionLimited<'_, T> { |
136 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
137 | f&mut DebugStruct<'_, '_>.debug_struct("SectionLimited" ) |
138 | .field("count" , &self.count) |
139 | .field(name:"range" , &self.range()) |
140 | .finish() |
141 | } |
142 | } |
143 | |
144 | impl<'a, T> IntoIterator for SectionLimited<'a, T> |
145 | where |
146 | T: FromReader<'a>, |
147 | { |
148 | type Item = Result<T>; |
149 | type IntoIter = SectionLimitedIntoIter<'a, T>; |
150 | |
151 | fn into_iter(self) -> Self::IntoIter { |
152 | SectionLimitedIntoIter { |
153 | remaining: self.count, |
154 | section: self, |
155 | end: false, |
156 | } |
157 | } |
158 | } |
159 | |
160 | /// A consuming iterator of a [`SectionLimited`]. |
161 | /// |
162 | /// This is created via the [`IntoIterator`] `impl` for the [`SectionLimited`] |
163 | /// type. |
164 | pub struct SectionLimitedIntoIter<'a, T> { |
165 | section: SectionLimited<'a, T>, |
166 | remaining: u32, |
167 | end: bool, |
168 | } |
169 | |
170 | impl<T> SectionLimitedIntoIter<'_, T> { |
171 | /// Returns the current byte offset of the section within this iterator. |
172 | pub fn original_position(&self) -> usize { |
173 | self.section.reader.original_position() |
174 | } |
175 | } |
176 | |
177 | impl<'a, T> Iterator for SectionLimitedIntoIter<'a, T> |
178 | where |
179 | T: FromReader<'a>, |
180 | { |
181 | type Item = Result<T>; |
182 | |
183 | fn next(&mut self) -> Option<Result<T>> { |
184 | if self.end { |
185 | return None; |
186 | } |
187 | if self.remaining == 0 { |
188 | self.end = true; |
189 | if self.section.reader.eof() { |
190 | return None; |
191 | } |
192 | return Some(Err(BinaryReaderError::new( |
193 | "section size mismatch: unexpected data at the end of the section" , |
194 | self.section.reader.original_position(), |
195 | ))); |
196 | } |
197 | let result = self.section.reader.read(); |
198 | self.end = result.is_err(); |
199 | self.remaining -= 1; |
200 | Some(result) |
201 | } |
202 | |
203 | fn size_hint(&self) -> (usize, Option<usize>) { |
204 | let remaining = self.remaining as usize; |
205 | (remaining, Some(remaining)) |
206 | } |
207 | } |
208 | |
209 | impl<'a, T> ExactSizeIterator for SectionLimitedIntoIter<'a, T> where T: FromReader<'a> {} |
210 | |
211 | /// An iterator over a limited section iterator. |
212 | pub struct SectionLimitedIntoIterWithOffsets<'a, T> { |
213 | iter: SectionLimitedIntoIter<'a, T>, |
214 | } |
215 | |
216 | impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T> |
217 | where |
218 | T: FromReader<'a>, |
219 | { |
220 | type Item = Result<(usize, T)>; |
221 | |
222 | fn next(&mut self) -> Option<Self::Item> { |
223 | let pos: usize = self.iter.section.reader.original_position(); |
224 | Some(self.iter.next()?.map(|item: T| (pos, item))) |
225 | } |
226 | |
227 | fn size_hint(&self) -> (usize, Option<usize>) { |
228 | self.iter.size_hint() |
229 | } |
230 | } |
231 | |
232 | impl<'a, T> ExactSizeIterator for SectionLimitedIntoIterWithOffsets<'a, T> where T: FromReader<'a> {} |
233 | |
234 | /// A trait implemented for subsections of another outer section. |
235 | /// |
236 | /// This is currently only used for subsections within custom sections, such as |
237 | /// the `name` section of core wasm. |
238 | /// |
239 | /// This is used in conjunction with [`Subsections`]. |
240 | pub trait Subsection<'a>: Sized { |
241 | /// Converts the section identifier provided with the section contents into |
242 | /// a typed section |
243 | fn from_reader(id: u8, reader: BinaryReader<'a>) -> Result<Self>; |
244 | } |
245 | |
246 | /// Iterator/reader over the contents of a section which is composed of |
247 | /// subsections. |
248 | /// |
249 | /// This reader is used for the core `name` section, for example. This type |
250 | /// primarily implements [`Iterator`] for advancing through the sections. |
251 | pub struct Subsections<'a, T> { |
252 | reader: BinaryReader<'a>, |
253 | _marker: marker::PhantomData<T>, |
254 | } |
255 | |
256 | impl<'a, T> Subsections<'a, T> { |
257 | /// Creates a new reader for the specified section contents starting at |
258 | /// `offset` within the original wasm file. |
259 | pub fn new(reader: BinaryReader<'a>) -> Self { |
260 | Subsections { |
261 | reader, |
262 | _marker: marker::PhantomData, |
263 | } |
264 | } |
265 | |
266 | /// Returns whether the original byte offset of this section. |
267 | pub fn original_position(&self) -> usize { |
268 | self.reader.original_position() |
269 | } |
270 | |
271 | /// Returns the range, as byte offsets, of this section within the original |
272 | /// wasm binary. |
273 | pub fn range(&self) -> Range<usize> { |
274 | self.reader.range() |
275 | } |
276 | |
277 | fn read(&mut self) -> Result<T> |
278 | where |
279 | T: Subsection<'a>, |
280 | { |
281 | let subsection_id = self.reader.read_u7()?; |
282 | let reader = self.reader.read_reader()?; |
283 | T::from_reader(subsection_id, reader) |
284 | } |
285 | } |
286 | |
287 | impl<T> Clone for Subsections<'_, T> { |
288 | fn clone(&self) -> Self { |
289 | Subsections { |
290 | reader: self.reader.clone(), |
291 | _marker: self._marker, |
292 | } |
293 | } |
294 | } |
295 | |
296 | impl<T> fmt::Debug for Subsections<'_, T> { |
297 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
298 | f&mut DebugStruct<'_, '_>.debug_struct("Subsections" ) |
299 | .field(name:"range" , &self.range()) |
300 | .finish() |
301 | } |
302 | } |
303 | |
304 | impl<'a, T> Iterator for Subsections<'a, T> |
305 | where |
306 | T: Subsection<'a>, |
307 | { |
308 | type Item = Result<T>; |
309 | |
310 | fn next(&mut self) -> Option<Result<T>> { |
311 | if self.reader.eof() { |
312 | None |
313 | } else { |
314 | Some(self.read()) |
315 | } |
316 | } |
317 | } |
318 | |