use super::{
BinaryReader, BinaryReaderError, CustomSectionKind, Range, Result, SectionCode, SectionHeader,
};
use super::{
read_data_count_section_content, read_sourcemappingurl_section_content,
read_start_section_content, CodeSectionReader, DataSectionReader, ElementSectionReader,
ExportSectionReader, FunctionSectionReader, GlobalSectionReader, ImportSectionReader,
LinkingSectionReader, MemorySectionReader, NameSectionReader, ProducersSectionReader,
RelocSectionReader, TableSectionReader, TypeSectionReader,
};
#[derive(Debug)]
pub struct Section<'a> {
pub code: SectionCode<'a>,
offset: usize,
data: &'a [u8],
}
impl<'a> Section<'a> {
pub fn get_type_section_reader<'b>(&self) -> Result<TypeSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Type => TypeSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_type_section_reader"),
}
}
pub fn get_function_section_reader<'b>(&self) -> Result<FunctionSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Function => FunctionSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_function_section_reader"),
}
}
pub fn get_code_section_reader<'b>(&self) -> Result<CodeSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Code => CodeSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_function_section_reader"),
}
}
pub fn get_export_section_reader<'b>(&self) -> Result<ExportSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Export => ExportSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_export_section_reader"),
}
}
pub fn get_import_section_reader<'b>(&self) -> Result<ImportSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Import => ImportSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_import_section_reader"),
}
}
pub fn get_global_section_reader<'b>(&self) -> Result<GlobalSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Global => GlobalSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_global_section_reader"),
}
}
pub fn get_memory_section_reader<'b>(&self) -> Result<MemorySectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Memory => MemorySectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_memory_section_reader"),
}
}
pub fn get_data_section_reader<'b>(&self) -> Result<DataSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Data => DataSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_data_section_reader"),
}
}
pub fn get_table_section_reader<'b>(&self) -> Result<TableSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Table => TableSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_table_section_reader"),
}
}
pub fn get_element_section_reader<'b>(&self) -> Result<ElementSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Element => ElementSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_element_section_reader"),
}
}
pub fn get_name_section_reader<'b>(&self) -> Result<NameSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Custom {
kind: CustomSectionKind::Name,
..
} => NameSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_name_section_reader"),
}
}
pub fn get_producers_section_reader<'b>(&self) -> Result<ProducersSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Custom {
kind: CustomSectionKind::Producers,
..
} => ProducersSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_producers_section_reader"),
}
}
pub fn get_linking_section_reader<'b>(&self) -> Result<LinkingSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Custom {
kind: CustomSectionKind::Linking,
..
} => LinkingSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_linking_section_reader"),
}
}
pub fn get_reloc_section_reader<'b>(&self) -> Result<RelocSectionReader<'b>>
where
'a: 'b,
{
match self.code {
SectionCode::Custom {
kind: CustomSectionKind::Reloc,
..
} => RelocSectionReader::new(self.data, self.offset),
_ => panic!("Invalid state for get_reloc_section_reader"),
}
}
pub fn get_start_section_content(&self) -> Result<u32> {
match self.code {
SectionCode::Start => read_start_section_content(self.data, self.offset),
_ => panic!("Invalid state for get_start_section_content"),
}
}
pub fn get_data_count_section_content(&self) -> Result<u32> {
match self.code {
SectionCode::DataCount => read_data_count_section_content(self.data, self.offset),
_ => panic!("Invalid state for get_data_count_section_content"),
}
}
pub fn get_sourcemappingurl_section_content<'b>(&self) -> Result<&'b str>
where
'a: 'b,
{
match self.code {
SectionCode::Custom {
kind: CustomSectionKind::SourceMappingURL,
..
} => read_sourcemappingurl_section_content(self.data, self.offset),
_ => panic!("Invalid state for get_start_section_content"),
}
}
pub fn get_binary_reader<'b>(&self) -> BinaryReader<'b>
where
'a: 'b,
{
BinaryReader::new_with_offset(self.data, self.offset)
}
pub fn range(&self) -> Range {
Range {
start: self.offset,
end: self.offset + self.data.len(),
}
}
pub fn content<'b>(&self) -> Result<SectionContent<'b>>
where
'a: 'b,
{
let c = match self.code {
SectionCode::Type => SectionContent::Type(self.get_type_section_reader()?),
SectionCode::Function => SectionContent::Function(self.get_function_section_reader()?),
SectionCode::Code => SectionContent::Code(self.get_code_section_reader()?),
SectionCode::Export => SectionContent::Export(self.get_export_section_reader()?),
SectionCode::Import => SectionContent::Import(self.get_import_section_reader()?),
SectionCode::Global => SectionContent::Global(self.get_global_section_reader()?),
SectionCode::Memory => SectionContent::Memory(self.get_memory_section_reader()?),
SectionCode::Data => SectionContent::Data(self.get_data_section_reader()?),
SectionCode::Table => SectionContent::Table(self.get_table_section_reader()?),
SectionCode::Element => SectionContent::Element(self.get_element_section_reader()?),
SectionCode::Start => SectionContent::Start(self.get_start_section_content()?),
SectionCode::DataCount => {
SectionContent::DataCount(self.get_data_count_section_content()?)
}
SectionCode::Custom { kind, name } => {
let binary = self.get_binary_reader();
let content = match kind {
CustomSectionKind::Name => {
Some(CustomSectionContent::Name(self.get_name_section_reader()?))
}
CustomSectionKind::Producers => Some(CustomSectionContent::Producers(
self.get_producers_section_reader()?,
)),
CustomSectionKind::Linking => Some(CustomSectionContent::Linking(
self.get_linking_section_reader()?,
)),
CustomSectionKind::Reloc => Some(CustomSectionContent::Reloc(
self.get_reloc_section_reader()?,
)),
CustomSectionKind::SourceMappingURL => {
Some(CustomSectionContent::SourceMappingURL(
self.get_sourcemappingurl_section_content()?,
))
}
_ => None,
};
SectionContent::Custom {
name,
binary,
content,
}
}
};
Ok(c)
}
}
pub enum SectionContent<'a> {
Type(TypeSectionReader<'a>),
Function(FunctionSectionReader<'a>),
Code(CodeSectionReader<'a>),
Export(ExportSectionReader<'a>),
Import(ImportSectionReader<'a>),
Global(GlobalSectionReader<'a>),
Memory(MemorySectionReader<'a>),
Data(DataSectionReader<'a>),
Table(TableSectionReader<'a>),
Element(ElementSectionReader<'a>),
Start(u32),
DataCount(u32),
Custom {
name: &'a str,
binary: BinaryReader<'a>,
content: Option<CustomSectionContent<'a>>,
},
}
pub enum CustomSectionContent<'a> {
Name(NameSectionReader<'a>),
Producers(ProducersSectionReader<'a>),
Linking(LinkingSectionReader<'a>),
Reloc(RelocSectionReader<'a>),
SourceMappingURL(&'a str),
}
pub struct ModuleReader<'a> {
reader: BinaryReader<'a>,
version: u32,
read_ahead: Option<(usize, SectionHeader<'a>)>,
}
impl<'a> ModuleReader<'a> {
pub fn new(data: &[u8]) -> Result<ModuleReader> {
let mut reader = BinaryReader::new(data);
let version = reader.read_file_header()?;
Ok(ModuleReader {
reader,
version,
read_ahead: None,
})
}
pub fn get_version(&self) -> u32 {
self.version
}
pub fn current_position(&self) -> usize {
match self.read_ahead {
Some((position, _)) => position,
_ => self.reader.current_position(),
}
}
pub fn eof(&self) -> bool {
self.read_ahead.is_none() && self.reader.eof()
}
fn verify_section_end(&self, end: usize) -> Result<()> {
if self.reader.buffer.len() < end {
return Err(BinaryReaderError {
message: "Section body extends past end of file",
offset: self.reader.buffer.len(),
});
}
if self.reader.position > end {
return Err(BinaryReaderError {
message: "Section header is too big to fit into section body",
offset: end,
});
}
Ok(())
}
pub fn read<'b>(&mut self) -> Result<Section<'b>>
where
'a: 'b,
{
let SectionHeader {
code,
payload_start,
payload_len,
} = match self.read_ahead.take() {
Some((_, section_header)) => section_header,
None => self.reader.read_section_header()?,
};
let payload_end = payload_start + payload_len;
self.verify_section_end(payload_end)?;
let body_start = self.reader.position;
self.reader.skip_to(payload_end);
Ok(Section {
code,
offset: body_start,
data: &self.reader.buffer[body_start..payload_end],
})
}
fn ensure_read_ahead(&mut self) -> Result<()> {
if self.read_ahead.is_none() && !self.eof() {
let position = self.reader.current_position();
self.read_ahead = Some((position, self.reader.read_section_header()?));
}
Ok(())
}
pub fn skip_custom_sections(&mut self) -> Result<()> {
loop {
self.ensure_read_ahead()?;
match self.read_ahead {
Some((
_,
SectionHeader {
code: SectionCode::Custom { .. },
payload_start,
payload_len,
},
)) => {
self.verify_section_end(payload_start + payload_len)?;
self.read_ahead = None;
self.reader.skip_to(payload_start + payload_len);
}
_ => break,
};
}
Ok(())
}
}
impl<'a> IntoIterator for ModuleReader<'a> {
type Item = Result<Section<'a>>;
type IntoIter = ModuleIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
ModuleIterator {
reader: self,
err: false,
}
}
}
pub struct ModuleIterator<'a> {
reader: ModuleReader<'a>,
err: bool,
}
impl<'a> Iterator for ModuleIterator<'a> {
type Item = Result<Section<'a>>;
fn next(&mut self) -> Option<Self::Item> {
if self.err || self.reader.eof() {
return None;
}
let result = self.reader.read();
self.err = result.is_err();
Some(result)
}
}