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 u32 {
41 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
42 reader.read_var_u32()
43 }
44}
45
46impl<'a> FromReader<'a> for &'a str {
47 fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
48 reader.read_string()
49 }
50}
51
52impl<'a, T, U> FromReader<'a> for (T, U)
53where
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.
71pub struct SectionLimited<'a, T> {
72 reader: BinaryReader<'a>,
73 count: u32,
74 _marker: marker::PhantomData<T>,
75}
76
77impl<'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
125impl<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
135impl<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
144impl<'a, T> IntoIterator for SectionLimited<'a, T>
145where
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.
164pub struct SectionLimitedIntoIter<'a, T> {
165 section: SectionLimited<'a, T>,
166 remaining: u32,
167 end: bool,
168}
169
170impl<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
177impl<'a, T> Iterator for SectionLimitedIntoIter<'a, T>
178where
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
209impl<'a, T> ExactSizeIterator for SectionLimitedIntoIter<'a, T> where T: FromReader<'a> {}
210
211/// An iterator over a limited section iterator.
212pub struct SectionLimitedIntoIterWithOffsets<'a, T> {
213 iter: SectionLimitedIntoIter<'a, T>,
214}
215
216impl<'a, T> Iterator for SectionLimitedIntoIterWithOffsets<'a, T>
217where
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
232impl<'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`].
240pub 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.
251pub struct Subsections<'a, T> {
252 reader: BinaryReader<'a>,
253 _marker: marker::PhantomData<T>,
254}
255
256impl<'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
287impl<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
296impl<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
304impl<'a, T> Iterator for Subsections<'a, T>
305where
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