wasmparser_nostd/
readers.rs

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