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 bool { |
41 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
42 | match reader.read_u8()? { |
43 | 0 => Ok(false), |
44 | 1 => Ok(true), |
45 | _ => Err(BinaryReaderError::new( |
46 | message:"invalid boolean value" , |
47 | offset:reader.original_position() - 1, |
48 | )), |
49 | } |
50 | } |
51 | } |
52 | |
53 | impl<'a> FromReader<'a> for u32 { |
54 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
55 | reader.read_var_u32() |
56 | } |
57 | } |
58 | |
59 | impl<'a> FromReader<'a> for &'a str { |
60 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
61 | reader.read_string() |
62 | } |
63 | } |
64 | |
65 | impl<'a, T, U> FromReader<'a> for (T, U) |
66 | where |
67 | T: FromReader<'a>, |
68 | U: FromReader<'a>, |
69 | { |
70 | fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { |
71 | Ok((reader.read()?, reader.read()?)) |
72 | } |
73 | } |
74 | |
75 | /// A generic structure for reading a section of a WebAssembly binary which has |
76 | /// a limited number of items within it. |
77 | /// |
78 | /// Many WebAssembly sections are a count of items followed by that many items. |
79 | /// This helper structure can be used to parse these sections and provides |
80 | /// an iteration-based API for reading the contents. |
81 | /// |
82 | /// Note that this always implements the [`Clone`] trait to represent the |
83 | /// ability to parse the section multiple times. |
84 | pub struct SectionLimited<'a, T> { |
85 | reader: BinaryReader<'a>, |
86 | count: u32, |
87 | _marker: marker::PhantomData<T>, |
88 | } |
89 | |
90 | impl<'a, T> SectionLimited<'a, T> { |
91 | /// Creates a new section reader from the provided contents. |
92 | /// |
93 | /// The `data` provided here is the data of the section itself that will be |
94 | /// parsed. The `offset` argument is the byte offset, in the original wasm |
95 | /// binary, that the section was found. The `offset` argument is used |
96 | /// for error reporting. |
97 | /// |
98 | /// # Errors |
99 | /// |
100 | /// Returns an error if a 32-bit count couldn't be read from the `data`. |
101 | pub fn new(mut reader: BinaryReader<'a>) -> Result<Self> { |
102 | let count = reader.read_var_u32()?; |
103 | Ok(SectionLimited { |
104 | reader, |
105 | count, |
106 | _marker: marker::PhantomData, |
107 | }) |
108 | } |
109 | |
110 | /// Returns the count of total items within this section. |
111 | pub fn count(&self) -> u32 { |
112 | self.count |
113 | } |
114 | |
115 | /// Returns whether the original byte offset of this section. |
116 | pub fn original_position(&self) -> usize { |
117 | self.reader.original_position() |
118 | } |
119 | |
120 | /// Returns the range, as byte offsets, of this section within the original |
121 | /// wasm binary. |
122 | pub fn range(&self) -> Range<usize> { |
123 | self.reader.range() |
124 | } |
125 | |
126 | /// Returns an iterator which yields not only each item in this section but |
127 | /// additionally the offset of each item within the section. |
128 | pub fn into_iter_with_offsets(self) -> SectionLimitedIntoIterWithOffsets<'a, T> |
129 | where |
130 | T: FromReader<'a>, |
131 | { |
132 | SectionLimitedIntoIterWithOffsets { |
133 | iter: self.into_iter(), |
134 | } |
135 | } |
136 | } |
137 | |
138 | impl<T> Clone for SectionLimited<'_, T> { |
139 | fn clone(&self) -> Self { |
140 | SectionLimited { |
141 | reader: self.reader.clone(), |
142 | count: self.count, |
143 | _marker: self._marker, |
144 | } |
145 | } |
146 | } |
147 | |
148 | impl<T> fmt::Debug for SectionLimited<'_, T> { |
149 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
150 | f&mut DebugStruct<'_, '_>.debug_struct("SectionLimited" ) |
151 | .field("count" , &self.count) |
152 | .field(name:"range" , &self.range()) |
153 | .finish() |
154 | } |
155 | } |
156 | |
157 | impl<'a, T> IntoIterator for SectionLimited<'a, T> |
158 | where |
159 | T: FromReader<'a>, |
160 | { |
161 | type Item = Result<T>; |
162 | type IntoIter = SectionLimitedIntoIter<'a, T>; |
163 | |
164 | fn into_iter(self) -> Self::IntoIter { |
165 | SectionLimitedIntoIter { |
166 | remaining: self.count, |
167 | section: self, |
168 | end: false, |
169 | } |
170 | } |
171 | } |
172 | |
173 | /// A consuming iterator of a [`SectionLimited`]. |
174 | /// |
175 | /// This is created via the [`IntoIterator`] `impl` for the [`SectionLimited`] |
176 | /// type. |
177 | pub struct SectionLimitedIntoIter<'a, T> { |
178 | section: SectionLimited<'a, T>, |
179 | remaining: u32, |
180 | end: bool, |
181 | } |
182 | |
183 | impl<T> SectionLimitedIntoIter<'_, T> { |
184 | /// Returns the current byte offset of the section within this iterator. |
185 | pub fn original_position(&self) -> usize { |
186 | self.section.reader.original_position() |
187 | } |
188 | } |
189 | |
190 | impl<'a, T> Iterator for SectionLimitedIntoIter<'a, T> |
191 | where |
192 | T: FromReader<'a>, |
193 | { |
194 | type Item = Result<T>; |
195 | |
196 | fn next(&mut self) -> Option<Result<T>> { |
197 | if self.end { |
198 | return None; |
199 | } |
200 | if self.remaining == 0 { |
201 | self.end = true; |
202 | if self.section.reader.eof() { |
203 | return None; |
204 | } |
205 | return Some(Err(BinaryReaderError::new( |
206 | "section size mismatch: unexpected data at the end of the section" , |
207 | self.section.reader.original_position(), |
208 | ))); |
209 | } |
210 | let result = self.section.reader.read(); |
211 | self.end = result.is_err(); |
212 | self.remaining -= 1; |
213 | Some(result) |
214 | } |
215 | |
216 | fn size_hint(&self) -> (usize, Option<usize>) { |
217 | let remaining = self.remaining as usize; |
218 | (remaining, Some(remaining)) |
219 | } |
220 | } |
221 | |
222 | impl<'a, T> ExactSizeIterator for SectionLimitedIntoIter<'a, T> where T: FromReader<'a> {} |
223 | |
224 | /// An iterator over a limited section iterator. |
225 | pub struct SectionLimitedIntoIterWithOffsets<'a, T> { |
226 | iter: SectionLimitedIntoIter<'a, T>, |
227 | } |
228 | |
229 | impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T> |
230 | where |
231 | T: FromReader<'a>, |
232 | { |
233 | type Item = Result<(usize, T)>; |
234 | |
235 | fn next(&mut self) -> Option<Self::Item> { |
236 | let pos: usize = self.iter.section.reader.original_position(); |
237 | Some(self.iter.next()?.map(|item: T| (pos, item))) |
238 | } |
239 | |
240 | fn size_hint(&self) -> (usize, Option<usize>) { |
241 | self.iter.size_hint() |
242 | } |
243 | } |
244 | |
245 | impl<'a, T> ExactSizeIterator for SectionLimitedIntoIterWithOffsets<'a, T> where T: FromReader<'a> {} |
246 | |
247 | /// A trait implemented for subsections of another outer section. |
248 | /// |
249 | /// This is currently only used for subsections within custom sections, such as |
250 | /// the `name` section of core wasm. |
251 | /// |
252 | /// This is used in conjunction with [`Subsections`]. |
253 | pub trait Subsection<'a>: Sized { |
254 | /// Converts the section identifier provided with the section contents into |
255 | /// a typed section |
256 | fn from_reader(id: u8, reader: BinaryReader<'a>) -> Result<Self>; |
257 | } |
258 | |
259 | /// Iterator/reader over the contents of a section which is composed of |
260 | /// subsections. |
261 | /// |
262 | /// This reader is used for the core `name` section, for example. This type |
263 | /// primarily implements [`Iterator`] for advancing through the sections. |
264 | pub struct Subsections<'a, T> { |
265 | reader: BinaryReader<'a>, |
266 | _marker: marker::PhantomData<T>, |
267 | } |
268 | |
269 | impl<'a, T> Subsections<'a, T> { |
270 | /// Creates a new reader for the specified section contents starting at |
271 | /// `offset` within the original wasm file. |
272 | pub fn new(reader: BinaryReader<'a>) -> Self { |
273 | Subsections { |
274 | reader, |
275 | _marker: marker::PhantomData, |
276 | } |
277 | } |
278 | |
279 | /// Returns whether the original byte offset of this section. |
280 | pub fn original_position(&self) -> usize { |
281 | self.reader.original_position() |
282 | } |
283 | |
284 | /// Returns the range, as byte offsets, of this section within the original |
285 | /// wasm binary. |
286 | pub fn range(&self) -> Range<usize> { |
287 | self.reader.range() |
288 | } |
289 | |
290 | fn read(&mut self) -> Result<T> |
291 | where |
292 | T: Subsection<'a>, |
293 | { |
294 | let subsection_id = self.reader.read_u7()?; |
295 | let reader = self.reader.read_reader()?; |
296 | T::from_reader(subsection_id, reader) |
297 | } |
298 | } |
299 | |
300 | impl<T> Clone for Subsections<'_, T> { |
301 | fn clone(&self) -> Self { |
302 | Subsections { |
303 | reader: self.reader.clone(), |
304 | _marker: self._marker, |
305 | } |
306 | } |
307 | } |
308 | |
309 | impl<T> fmt::Debug for Subsections<'_, T> { |
310 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
311 | f&mut DebugStruct<'_, '_>.debug_struct("Subsections" ) |
312 | .field(name:"range" , &self.range()) |
313 | .finish() |
314 | } |
315 | } |
316 | |
317 | impl<'a, T> Iterator for Subsections<'a, T> |
318 | where |
319 | T: Subsection<'a>, |
320 | { |
321 | type Item = Result<T>; |
322 | |
323 | fn next(&mut self) -> Option<Result<T>> { |
324 | if self.reader.eof() { |
325 | None |
326 | } else { |
327 | Some(self.read()) |
328 | } |
329 | } |
330 | } |
331 | |