use std::boxed::Box;
use std::vec::Vec;
use crate::limits::{
MAX_WASM_FUNCTIONS, MAX_WASM_FUNCTION_LOCALS, MAX_WASM_STRING_SIZE, MAX_WASM_TABLE_ENTRIES,
};
use crate::primitives::{
BinaryReaderError, CustomSectionKind, ExternalKind, FuncType, GlobalType,
ImportSectionEntryType, LinkingType, MemoryType, Naming, Operator, RelocType, Result,
SectionCode, TableType, Type,
};
use crate::readers::{
CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItems, ElementKind,
ElementSectionReader, Export, ExportSectionReader, FunctionBody, FunctionSectionReader, Global,
GlobalSectionReader, Import, ImportSectionReader, LinkingSectionReader, MemorySectionReader,
ModuleReader, Name, NameSectionReader, NamingReader, OperatorsReader, Reloc,
RelocSectionReader, Section, SectionReader, TableSectionReader, TypeSectionReader,
};
use crate::binary_reader::{BinaryReader, Range};
const MAX_DATA_CHUNK_SIZE: usize = MAX_WASM_STRING_SIZE;
#[derive(Debug)]
pub struct LocalName<'a> {
pub index: u32,
pub locals: Box<[Naming<'a>]>,
}
#[derive(Debug)]
pub enum NameEntry<'a> {
Module(&'a str),
Function(Box<[Naming<'a>]>),
Local(Box<[LocalName<'a>]>),
}
#[derive(Debug)]
pub struct RelocEntry {
pub ty: RelocType,
pub offset: u32,
pub index: u32,
pub addend: Option<u32>,
}
enum InitExpressionContinuation {
GlobalSection,
ElementSection,
DataSection,
}
#[derive(Debug)]
pub enum ParserState<'a> {
Error(BinaryReaderError),
Initial,
BeginWasm {
version: u32,
},
EndWasm,
BeginSection {
code: SectionCode<'a>,
range: Range,
},
EndSection,
SkippingSection,
ReadingCustomSection(CustomSectionKind),
ReadingSectionRawData,
SectionRawData(&'a [u8]),
TypeSectionEntry(FuncType),
ImportSectionEntry {
module: &'a str,
field: &'a str,
ty: ImportSectionEntryType,
},
FunctionSectionEntry(u32),
TableSectionEntry(TableType),
MemorySectionEntry(MemoryType),
ExportSectionEntry {
field: &'a str,
kind: ExternalKind,
index: u32,
},
NameSectionEntry(NameEntry<'a>),
StartSectionEntry(u32),
DataCountSectionEntry(u32),
BeginInitExpressionBody,
InitExpressionOperator(Operator<'a>),
EndInitExpressionBody,
BeginFunctionBody {
range: Range,
},
FunctionBodyLocals {
locals: Box<[(u32, Type)]>,
},
CodeOperator(Operator<'a>),
EndFunctionBody,
SkippingFunctionBody,
BeginPassiveElementSectionEntry(Type),
BeginActiveElementSectionEntry(u32),
ElementSectionEntryBody(Box<[u32]>),
EndElementSectionEntry,
BeginPassiveDataSectionEntry,
BeginActiveDataSectionEntry(u32),
EndDataSectionEntry,
BeginDataSectionEntryBody(u32),
DataSectionEntryBodyChunk(&'a [u8]),
EndDataSectionEntryBody,
BeginGlobalSectionEntry(GlobalType),
EndGlobalSectionEntry,
RelocSectionHeader(SectionCode<'a>),
RelocSectionEntry(RelocEntry),
LinkingSectionEntry(LinkingType),
SourceMappingURL(&'a str),
}
#[derive(Debug, Copy, Clone)]
pub enum ParserInput {
Default,
SkipSection,
SkipFunctionBody,
ReadCustomSection,
ReadSectionRawData,
}
pub trait WasmDecoder<'a> {
fn read(&mut self) -> &ParserState<'a>;
fn push_input(&mut self, input: ParserInput);
fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a>;
fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b>
where
'a: 'b;
fn last_state(&self) -> &ParserState<'a>;
}
enum ParserSectionReader<'a> {
None,
CodeSectionReader(CodeSectionReader<'a>),
DataSectionReader(DataSectionReader<'a>),
ElementSectionReader(ElementSectionReader<'a>),
ExportSectionReader(ExportSectionReader<'a>),
FunctionSectionReader(FunctionSectionReader<'a>),
GlobalSectionReader(GlobalSectionReader<'a>),
ImportSectionReader(ImportSectionReader<'a>),
MemorySectionReader(MemorySectionReader<'a>),
TableSectionReader(TableSectionReader<'a>),
TypeSectionReader(TypeSectionReader<'a>),
NameSectionReader(NameSectionReader<'a>),
LinkingSectionReader(LinkingSectionReader<'a>),
RelocSectionReader(RelocSectionReader<'a>),
}
macro_rules! section_reader {
($self:ident, $ty_and_name:ident) => {
if let ParserSectionReader::$ty_and_name(ref mut reader) = $self.section_reader {
reader
} else {
panic!("expected {} reader", stringify!($ty_and_name));
}
};
}
macro_rules! start_section_reader {
($self:ident, $ty_and_name:ident, $factory:ident) => {{
let reader = $self
.current_section
.as_ref()
.expect("section")
.$factory()?;
$self.section_entries_left = reader.get_count();
$self.section_reader = ParserSectionReader::$ty_and_name(reader);
}};
}
pub struct Parser<'a> {
data: &'a [u8],
state: ParserState<'a>,
module_reader: Option<ModuleReader<'a>>,
current_section: Option<Section<'a>>,
section_reader: ParserSectionReader<'a>,
element_items: Option<ElementItems<'a>>,
current_function_body: Option<FunctionBody<'a>>,
init_expr_continuation: Option<InitExpressionContinuation>,
current_data_segment: Option<&'a [u8]>,
binary_reader: Option<BinaryReader<'a>>,
operators_reader: Option<OperatorsReader<'a>>,
section_entries_left: u32,
}
impl<'a> Parser<'a> {
pub fn new(data: &[u8]) -> Parser {
Parser {
data,
state: ParserState::Initial,
module_reader: None,
current_section: None,
section_reader: ParserSectionReader::None,
element_items: None,
current_function_body: None,
init_expr_continuation: None,
current_data_segment: None,
binary_reader: None,
operators_reader: None,
section_entries_left: 0,
}
}
pub fn eof(&self) -> bool {
match self.state {
ParserState::EndWasm => true,
ParserState::BeginWasm { .. } | ParserState::EndSection => {
self.module_reader.as_ref().expect("module reader").eof()
}
_ => false,
}
}
pub fn current_position(&self) -> usize {
if let ParserState::Initial = self.state {
return 0;
}
if self.binary_reader.is_some() {
return self
.binary_reader
.as_ref()
.expect("binary reader")
.original_position();
}
if self.operators_reader.is_some() {
return self
.operators_reader
.as_ref()
.expect("operators reader")
.original_position();
}
match self.section_reader {
ParserSectionReader::CodeSectionReader(ref reader) => {
return reader.original_position()
}
ParserSectionReader::DataSectionReader(ref reader) => {
return reader.original_position()
}
ParserSectionReader::ElementSectionReader(ref reader) => {
return reader.original_position();
}
ParserSectionReader::ExportSectionReader(ref reader) => {
return reader.original_position();
}
ParserSectionReader::FunctionSectionReader(ref reader) => {
return reader.original_position();
}
ParserSectionReader::GlobalSectionReader(ref reader) => {
return reader.original_position();
}
ParserSectionReader::ImportSectionReader(ref reader) => {
return reader.original_position();
}
ParserSectionReader::MemorySectionReader(ref reader) => {
return reader.original_position();
}
ParserSectionReader::TableSectionReader(ref reader) => {
return reader.original_position();
}
ParserSectionReader::TypeSectionReader(ref reader) => {
return reader.original_position()
}
ParserSectionReader::NameSectionReader(ref reader) => {
return reader.original_position()
}
ParserSectionReader::LinkingSectionReader(ref reader) => {
return reader.original_position();
}
ParserSectionReader::RelocSectionReader(ref reader) => {
return reader.original_position();
}
_ => (),
};
self.module_reader
.as_ref()
.expect("module reader")
.current_position()
}
fn read_module(&mut self) -> Result<()> {
let module_reader = ModuleReader::new(self.data)?;
let version = module_reader.get_version();
self.module_reader = Some(module_reader);
self.state = ParserState::BeginWasm { version };
Ok(())
}
fn read_section_header(&mut self) -> Result<()> {
let section = self.module_reader.as_mut().expect("module reader").read()?;
let code = section.code;
let range = section.range();
self.current_section = Some(section);
self.state = ParserState::BeginSection { code, range };
Ok(())
}
fn read_type_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let type_entry = section_reader!(self, TypeSectionReader).read()?;
self.state = ParserState::TypeSectionEntry(type_entry);
self.section_entries_left -= 1;
Ok(())
}
fn read_import_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let Import { module, field, ty } = section_reader!(self, ImportSectionReader).read()?;
self.state = ParserState::ImportSectionEntry { module, field, ty };
self.section_entries_left -= 1;
Ok(())
}
fn read_function_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let func_type = section_reader!(self, FunctionSectionReader).read()?;
self.state = ParserState::FunctionSectionEntry(func_type);
self.section_entries_left -= 1;
Ok(())
}
fn read_memory_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let memory_type = section_reader!(self, MemorySectionReader).read()?;
self.state = ParserState::MemorySectionEntry(memory_type);
self.section_entries_left -= 1;
Ok(())
}
fn read_global_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let Global { ty, init_expr } = section_reader!(self, GlobalSectionReader).read()?;
self.state = ParserState::BeginGlobalSectionEntry(ty);
self.operators_reader = Some(init_expr.get_operators_reader());
self.section_entries_left -= 1;
Ok(())
}
fn read_init_expression_body(&mut self, cont: InitExpressionContinuation) {
self.state = ParserState::BeginInitExpressionBody;
self.init_expr_continuation = Some(cont);
}
fn read_init_expression_operator(&mut self) -> Result<()> {
let op = self
.operators_reader
.as_mut()
.expect("operator reader")
.read()?;
if let Operator::End = op {
self.operators_reader = None;
self.state = ParserState::EndInitExpressionBody;
return Ok(());
}
self.state = ParserState::InitExpressionOperator(op);
Ok(())
}
fn read_export_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let Export { field, kind, index } = section_reader!(self, ExportSectionReader).read()?;
self.state = ParserState::ExportSectionEntry { field, kind, index };
self.section_entries_left -= 1;
Ok(())
}
fn read_element_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let Element { kind, items } = section_reader!(self, ElementSectionReader).read()?;
match kind {
ElementKind::Passive(ty) => {
self.state = ParserState::BeginPassiveElementSectionEntry(ty);
}
ElementKind::Active {
table_index,
init_expr,
} => {
self.state = ParserState::BeginActiveElementSectionEntry(table_index);
self.operators_reader = Some(init_expr.get_operators_reader());
}
}
self.element_items = Some(items);
self.section_entries_left -= 1;
Ok(())
}
fn read_element_entry_body(&mut self) -> Result<()> {
let mut reader = self
.element_items
.take()
.expect("element items")
.get_items_reader()?;
let num_elements = reader.get_count() as usize;
if num_elements > MAX_WASM_TABLE_ENTRIES {
return Err(BinaryReaderError {
message: "num_elements is out of bounds",
offset: 0,
});
}
let mut elements: Vec<u32> = Vec::with_capacity(num_elements);
for _ in 0..num_elements {
elements.push(reader.read()?);
}
self.state = ParserState::ElementSectionEntryBody(elements.into_boxed_slice());
Ok(())
}
fn read_function_body(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
self.current_function_body = None;
return self.check_section_end();
}
let function_body = section_reader!(self, CodeSectionReader).read()?;
let range = function_body.range();
self.state = ParserState::BeginFunctionBody { range };
self.current_function_body = Some(function_body);
self.section_entries_left -= 1;
Ok(())
}
fn read_function_body_locals(&mut self) -> Result<()> {
let function_body = self.current_function_body.as_mut().expect("function body");
let mut reader = function_body.get_locals_reader()?;
let local_count = reader.get_count() as usize;
if local_count > MAX_WASM_FUNCTION_LOCALS {
return Err(BinaryReaderError {
message: "local_count is out of bounds",
offset: reader.original_position() - 1,
});
}
let mut locals: Vec<(u32, Type)> = Vec::with_capacity(local_count);
let mut locals_total: usize = 0;
for _ in 0..local_count {
let (count, ty) = reader.read()?;
locals_total =
locals_total
.checked_add(count as usize)
.ok_or_else(|| BinaryReaderError {
message: "locals_total is out of bounds",
offset: reader.original_position() - 1,
})?;
if locals_total > MAX_WASM_FUNCTION_LOCALS {
return Err(BinaryReaderError {
message: "locals_total is out of bounds",
offset: reader.original_position() - 1,
});
}
locals.push((count, ty));
}
self.operators_reader = Some(function_body.get_operators_reader()?);
self.state = ParserState::FunctionBodyLocals {
locals: locals.into_boxed_slice(),
};
Ok(())
}
fn read_code_operator(&mut self) -> Result<()> {
if self
.operators_reader
.as_ref()
.expect("operator reader")
.eof()
{
if let ParserState::CodeOperator(Operator::End) = self.state {
self.state = ParserState::EndFunctionBody;
self.operators_reader = None;
self.current_function_body = None;
return Ok(());
}
let reader = self.operators_reader.as_ref().expect("operator reader");
return Err(BinaryReaderError {
message: "Expected end of function marker",
offset: reader.original_position(),
});
}
let reader = self.operators_reader.as_mut().expect("operator reader");
let op = reader.read()?;
self.state = ParserState::CodeOperator(op);
Ok(())
}
fn read_table_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let table_entry = section_reader!(self, TableSectionReader).read()?;
self.state = ParserState::TableSectionEntry(table_entry);
self.section_entries_left -= 1;
Ok(())
}
fn read_data_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let Data { kind, data } = section_reader!(self, DataSectionReader).read()?;
match kind {
DataKind::Passive => {
self.state = ParserState::BeginPassiveDataSectionEntry;
}
DataKind::Active {
memory_index,
init_expr,
} => {
self.state = ParserState::BeginActiveDataSectionEntry(memory_index);
self.operators_reader = Some(init_expr.get_operators_reader());
}
}
self.current_data_segment = Some(data);
self.section_entries_left -= 1;
Ok(())
}
fn read_data_entry_body(&mut self) -> Result<()> {
let size = self.current_data_segment.expect("data entry").len();
self.state = ParserState::BeginDataSectionEntryBody(size as u32);
Ok(())
}
fn read_naming<'b>(
mut naming_reader: NamingReader<'a>,
limit: usize,
) -> Result<Box<[Naming<'b>]>>
where
'a: 'b,
{
let count = naming_reader.get_count() as usize;
if count > limit {
return Err(BinaryReaderError {
message: "name map size is out of bound",
offset: naming_reader.original_position() - 1,
});
}
let mut result = Vec::with_capacity(count);
for _ in 0..count {
result.push(naming_reader.read()?);
}
Ok(result.into_boxed_slice())
}
fn read_name_entry(&mut self) -> Result<()> {
if section_reader!(self, NameSectionReader).eof() {
return self.position_to_section_end();
}
let entry = match section_reader!(self, NameSectionReader).read()? {
Name::Module(name) => NameEntry::Module(name.get_name()?),
Name::Function(func) => {
NameEntry::Function(Self::read_naming(func.get_map()?, MAX_WASM_FUNCTIONS)?)
}
Name::Local(locals) => {
let mut reader = locals.get_function_local_reader()?;
let funcs_len = reader.get_count() as usize;
if funcs_len > MAX_WASM_FUNCTIONS {
return Err(BinaryReaderError {
message: "function count is out of bounds",
offset: reader.original_position() - 1,
});
}
let mut funcs: Vec<LocalName<'a>> = Vec::with_capacity(funcs_len);
for _ in 0..funcs_len {
let func = reader.read()?;
funcs.push(LocalName {
index: func.func_index,
locals: Self::read_naming(func.get_map()?, MAX_WASM_FUNCTION_LOCALS)?,
});
}
NameEntry::Local(funcs.into_boxed_slice())
}
};
self.state = ParserState::NameSectionEntry(entry);
Ok(())
}
fn read_source_mapping(&mut self) -> Result<()> {
let url = self
.current_section
.as_ref()
.expect("section")
.get_sourcemappingurl_section_content()?;
self.state = ParserState::SourceMappingURL(url);
Ok(())
}
fn read_reloc_header(&mut self) -> Result<()> {
let section_code = section_reader!(self, RelocSectionReader).get_section_code();
self.state = ParserState::RelocSectionHeader(section_code);
Ok(())
}
fn read_reloc_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let Reloc {
ty,
offset,
index,
addend,
} = section_reader!(self, RelocSectionReader).read()?;
self.state = ParserState::RelocSectionEntry(RelocEntry {
ty,
offset,
index,
addend,
});
self.section_entries_left -= 1;
Ok(())
}
fn read_linking_entry(&mut self) -> Result<()> {
if self.section_entries_left == 0 {
return self.check_section_end();
}
let entry = section_reader!(self, LinkingSectionReader).read()?;
self.state = ParserState::LinkingSectionEntry(entry);
self.section_entries_left -= 1;
Ok(())
}
fn read_section_body(&mut self) -> Result<()> {
match self.state {
ParserState::BeginSection {
code: SectionCode::Type,
..
} => {
start_section_reader!(self, TypeSectionReader, get_type_section_reader);
self.read_type_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Import,
..
} => {
start_section_reader!(self, ImportSectionReader, get_import_section_reader);
self.read_import_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Function,
..
} => {
start_section_reader!(self, FunctionSectionReader, get_function_section_reader);
self.read_function_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Memory,
..
} => {
start_section_reader!(self, MemorySectionReader, get_memory_section_reader);
self.read_memory_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Global,
..
} => {
start_section_reader!(self, GlobalSectionReader, get_global_section_reader);
self.read_global_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Export,
..
} => {
start_section_reader!(self, ExportSectionReader, get_export_section_reader);
self.read_export_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Element,
..
} => {
start_section_reader!(self, ElementSectionReader, get_element_section_reader);
self.read_element_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Code,
..
} => {
start_section_reader!(self, CodeSectionReader, get_code_section_reader);
self.read_function_body()?;
}
ParserState::BeginSection {
code: SectionCode::Table,
..
} => {
start_section_reader!(self, TableSectionReader, get_table_section_reader);
self.read_table_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Data,
..
} => {
start_section_reader!(self, DataSectionReader, get_data_section_reader);
self.read_data_entry()?;
}
ParserState::BeginSection {
code: SectionCode::Start,
..
} => {
let func_index = self
.current_section
.as_ref()
.expect("section")
.get_start_section_content()?;
self.state = ParserState::StartSectionEntry(func_index);
}
ParserState::BeginSection {
code: SectionCode::DataCount,
..
} => {
let func_index = self
.current_section
.as_ref()
.expect("section")
.get_data_count_section_content()?;
self.state = ParserState::DataCountSectionEntry(func_index);
}
ParserState::BeginSection {
code: SectionCode::Custom { .. },
..
} => {
self.create_custom_section_binary_reader();
self.read_section_body_bytes()?;
}
_ => unreachable!(),
}
Ok(())
}
fn create_custom_section_binary_reader(&mut self) {
let reader = self
.current_section
.as_ref()
.expect("section")
.get_binary_reader();
self.binary_reader = Some(reader);
}
fn read_custom_section_body(&mut self) -> Result<()> {
match self.state {
ParserState::ReadingCustomSection(CustomSectionKind::Name) => {
let reader = self
.current_section
.as_ref()
.expect("section")
.get_name_section_reader()?;
self.section_reader = ParserSectionReader::NameSectionReader(reader);
self.read_name_entry()?;
}
ParserState::ReadingCustomSection(CustomSectionKind::SourceMappingURL) => {
self.read_source_mapping()?;
}
ParserState::ReadingCustomSection(CustomSectionKind::Reloc) => {
start_section_reader!(self, RelocSectionReader, get_reloc_section_reader);
self.read_reloc_header()?;
}
ParserState::ReadingCustomSection(CustomSectionKind::Linking) => {
start_section_reader!(self, LinkingSectionReader, get_linking_section_reader);
self.read_linking_entry()?;
}
ParserState::ReadingCustomSection(CustomSectionKind::Producers)
| ParserState::ReadingCustomSection(CustomSectionKind::Unknown) => {
self.create_custom_section_binary_reader();
self.read_section_body_bytes()?;
}
_ => unreachable!(),
}
Ok(())
}
fn position_to_section_end(&mut self) -> Result<()> {
self.current_section = None;
self.binary_reader = None;
self.state = ParserState::EndSection;
Ok(())
}
fn check_section_end(&mut self) -> Result<()> {
match self.section_reader {
ParserSectionReader::CodeSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::DataSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::ElementSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::ExportSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::FunctionSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::GlobalSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::ImportSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::MemorySectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::TableSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::TypeSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::LinkingSectionReader(ref reader) => reader.ensure_end()?,
ParserSectionReader::RelocSectionReader(ref reader) => reader.ensure_end()?,
_ => unreachable!(),
}
self.position_to_section_end()
}
fn read_section_body_bytes(&mut self) -> Result<()> {
if self.binary_reader.as_ref().expect("binary reader").eof() {
self.state = ParserState::EndSection;
self.binary_reader = None;
return Ok(());
}
let binary_reader = self.binary_reader.as_mut().expect("binary reader");
let to_read = if binary_reader.buffer.len() - binary_reader.position < MAX_DATA_CHUNK_SIZE {
binary_reader.buffer.len() - binary_reader.position
} else {
MAX_DATA_CHUNK_SIZE
};
let bytes = binary_reader.read_bytes(to_read)?;
self.state = ParserState::SectionRawData(bytes);
Ok(())
}
fn read_data_chunk(&mut self) -> Result<()> {
let data = self.current_data_segment.expect("data");
if data.len() == 0 {
self.state = ParserState::EndDataSectionEntryBody;
self.current_data_segment = None;
return Ok(());
}
let to_read = if data.len() > MAX_DATA_CHUNK_SIZE {
MAX_DATA_CHUNK_SIZE
} else {
data.len()
};
let (head, tail) = data.split_at(to_read);
self.current_data_segment = Some(tail);
self.state = ParserState::DataSectionEntryBodyChunk(head);
Ok(())
}
fn read_next_section(&mut self) -> Result<()> {
if self.module_reader.as_ref().expect("module_reader").eof() {
self.current_section = None;
self.state = ParserState::EndWasm;
} else {
self.read_section_header()?;
}
Ok(())
}
fn read_wrapped(&mut self) -> Result<()> {
match self.state {
ParserState::EndWasm => panic!("Parser in end state"),
ParserState::Error(_) => panic!("Parser in error state"),
ParserState::Initial => self.read_module()?,
ParserState::BeginWasm { .. } | ParserState::EndSection => self.read_next_section()?,
ParserState::BeginSection { .. } => self.read_section_body()?,
ParserState::SkippingSection => {
self.position_to_section_end()?;
self.read_next_section()?;
}
ParserState::TypeSectionEntry(_) => self.read_type_entry()?,
ParserState::ImportSectionEntry { .. } => self.read_import_entry()?,
ParserState::FunctionSectionEntry(_) => self.read_function_entry()?,
ParserState::MemorySectionEntry(_) => self.read_memory_entry()?,
ParserState::TableSectionEntry(_) => self.read_table_entry()?,
ParserState::ExportSectionEntry { .. } => self.read_export_entry()?,
ParserState::BeginGlobalSectionEntry(_) => {
self.read_init_expression_body(InitExpressionContinuation::GlobalSection)
}
ParserState::EndGlobalSectionEntry => self.read_global_entry()?,
ParserState::BeginPassiveElementSectionEntry(_) => self.read_element_entry_body()?,
ParserState::BeginActiveElementSectionEntry(_) => {
self.read_init_expression_body(InitExpressionContinuation::ElementSection)
}
ParserState::BeginInitExpressionBody | ParserState::InitExpressionOperator(_) => {
self.read_init_expression_operator()?
}
ParserState::BeginPassiveDataSectionEntry => {
self.read_data_entry_body()?;
}
ParserState::BeginActiveDataSectionEntry(_) => {
self.read_init_expression_body(InitExpressionContinuation::DataSection)
}
ParserState::EndInitExpressionBody => {
match self.init_expr_continuation {
Some(InitExpressionContinuation::GlobalSection) => {
self.state = ParserState::EndGlobalSectionEntry
}
Some(InitExpressionContinuation::ElementSection) => {
self.read_element_entry_body()?
}
Some(InitExpressionContinuation::DataSection) => self.read_data_entry_body()?,
None => unreachable!(),
}
self.init_expr_continuation = None;
}
ParserState::BeginFunctionBody { .. } => self.read_function_body_locals()?,
ParserState::FunctionBodyLocals { .. } | ParserState::CodeOperator(_) => {
self.read_code_operator()?
}
ParserState::EndFunctionBody => self.read_function_body()?,
ParserState::SkippingFunctionBody => {
self.current_function_body = None;
self.read_function_body()?;
}
ParserState::EndDataSectionEntry => self.read_data_entry()?,
ParserState::BeginDataSectionEntryBody(_)
| ParserState::DataSectionEntryBodyChunk(_) => self.read_data_chunk()?,
ParserState::EndDataSectionEntryBody => {
self.state = ParserState::EndDataSectionEntry;
}
ParserState::ElementSectionEntryBody(_) => {
self.state = ParserState::EndElementSectionEntry;
}
ParserState::EndElementSectionEntry => self.read_element_entry()?,
ParserState::StartSectionEntry(_) => self.position_to_section_end()?,
ParserState::DataCountSectionEntry(_) => self.position_to_section_end()?,
ParserState::NameSectionEntry(_) => self.read_name_entry()?,
ParserState::SourceMappingURL(_) => self.position_to_section_end()?,
ParserState::RelocSectionHeader(_) => {
let mut reader = self
.current_section
.as_ref()
.expect("section")
.get_binary_reader();
self.section_entries_left = reader.read_var_u32()?;
self.binary_reader = Some(reader);
self.read_reloc_entry()?;
}
ParserState::RelocSectionEntry(_) => self.read_reloc_entry()?,
ParserState::LinkingSectionEntry(_) => self.read_linking_entry()?,
ParserState::ReadingCustomSection(_) => self.read_custom_section_body()?,
ParserState::ReadingSectionRawData | ParserState::SectionRawData(_) => {
self.read_section_body_bytes()?
}
}
Ok(())
}
fn skip_section(&mut self) {
match self.state {
ParserState::Initial
| ParserState::EndWasm
| ParserState::Error(_)
| ParserState::BeginWasm { .. }
| ParserState::EndSection => panic!("Invalid reader state during skip section"),
_ => self.state = ParserState::SkippingSection,
}
}
fn skip_function_body(&mut self) {
match self.state {
ParserState::BeginFunctionBody { .. }
| ParserState::FunctionBodyLocals { .. }
| ParserState::CodeOperator(_) => self.state = ParserState::SkippingFunctionBody,
_ => panic!("Invalid reader state during skip function body"),
}
}
fn read_custom_section(&mut self) {
match self.state {
ParserState::BeginSection {
code: SectionCode::Custom { kind, .. },
..
} => {
self.state = ParserState::ReadingCustomSection(kind);
}
_ => panic!("Invalid reader state during reading custom section"),
}
}
fn read_raw_section_data(&mut self) {
match self.state {
ParserState::BeginSection { .. } => {
self.binary_reader = Some(
self.current_section
.as_ref()
.expect("section")
.get_binary_reader(),
);
self.state = ParserState::ReadingSectionRawData;
}
_ => panic!("Invalid reader state during reading raw section data"),
}
}
}
impl<'a> WasmDecoder<'a> for Parser<'a> {
fn read(&mut self) -> &ParserState<'a> {
let result = self.read_wrapped();
if result.is_err() {
self.state = ParserState::Error(result.err().unwrap());
}
&self.state
}
fn push_input(&mut self, input: ParserInput) {
match input {
ParserInput::Default => (),
ParserInput::SkipSection => self.skip_section(),
ParserInput::SkipFunctionBody => self.skip_function_body(),
ParserInput::ReadCustomSection => self.read_custom_section(),
ParserInput::ReadSectionRawData => self.read_raw_section_data(),
}
}
fn create_binary_reader<'b>(&mut self) -> BinaryReader<'b>
where
'a: 'b,
{
match self.state {
ParserState::BeginSection { .. } => self
.current_section
.as_ref()
.expect("section")
.get_binary_reader(),
ParserState::BeginFunctionBody { .. } | ParserState::FunctionBodyLocals { .. } => self
.current_function_body
.as_ref()
.expect("function body")
.get_binary_reader(),
_ => panic!("Invalid reader state during get binary reader operation"),
}
}
fn read_with_input(&mut self, input: ParserInput) -> &ParserState<'a> {
self.push_input(input);
self.read()
}
fn last_state(&self) -> &ParserState<'a> {
&self.state
}
}