| 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 | |