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
16use crate::{BinaryReader, BinaryReaderError, Result};
17use ::core::fmt;
18use ::core::marker;
19use ::core::ops::Range;
20
21#[cfg(feature = "component-model")]
22mod component;
23mod core;
24
25#[cfg(feature = "component-model")]
26pub use self::component::*;
27pub 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.
34pub 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
40impl<'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
53impl<'a> FromReader<'a> for u32 {
54 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
55 reader.read_var_u32()
56 }
57}
58
59impl<'a> FromReader<'a> for &'a str {
60 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
61 reader.read_string()
62 }
63}
64
65impl<'a, T, U> FromReader<'a> for (T, U)
66where
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.
84pub struct SectionLimited<'a, T> {
85 reader: BinaryReader<'a>,
86 count: u32,
87 _marker: marker::PhantomData<T>,
88}
89
90impl<'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
138impl<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
148impl<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
157impl<'a, T> IntoIterator for SectionLimited<'a, T>
158where
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.
177pub struct SectionLimitedIntoIter<'a, T> {
178 section: SectionLimited<'a, T>,
179 remaining: u32,
180 end: bool,
181}
182
183impl<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
190impl<'a, T> Iterator for SectionLimitedIntoIter<'a, T>
191where
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
222impl<'a, T> ExactSizeIterator for SectionLimitedIntoIter<'a, T> where T: FromReader<'a> {}
223
224/// An iterator over a limited section iterator.
225pub struct SectionLimitedIntoIterWithOffsets<'a, T> {
226 iter: SectionLimitedIntoIter<'a, T>,
227}
228
229impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T>
230where
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
245impl<'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`].
253pub 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.
264pub struct Subsections<'a, T> {
265 reader: BinaryReader<'a>,
266 _marker: marker::PhantomData<T>,
267}
268
269impl<'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
300impl<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
309impl<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
317impl<'a, T> Iterator for Subsections<'a, T>
318where
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