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