import section, examples

This commit is contained in:
NikVolf
2017-03-30 20:55:25 +03:00
parent cac5de598f
commit 779f3257cd
8 changed files with 253 additions and 37 deletions

25
examples/info.rs Normal file
View File

@ -0,0 +1,25 @@
extern crate parity_wasm;
use std::env;
use parity_wasm::Section;
fn main() {
let args = env::args().collect::<Vec<_>>();
if args.len() != 2 {
println!("Usage: {} somefile.wasm", args[0]);
return;
}
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
println!("Module sections: {}", module.sections().len());
for section in module.sections() {
match section {
&Section::Import(ref import_section) => {
println!("Imports {}", import_section.entries().len());
},
_ => {},
}
}
}

View File

@ -0,0 +1,142 @@
use std::io;
use super::{Deserialize, Error, VarUint7, VarInt7, VarUint32, VarUint1, ValueType};
pub struct GlobalType {
content_type: ValueType,
is_mutable: bool,
}
impl GlobalType {
pub fn content_type(&self) -> ValueType { self.content_type }
pub fn is_mutable(&self) -> bool { self.is_mutable }
}
impl Deserialize for GlobalType {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let content_type = ValueType::deserialize(reader)?;
let is_mutable = VarUint1::deserialize(reader)?;
Ok(GlobalType {
content_type: content_type,
is_mutable: is_mutable.into(),
})
}
}
pub struct TableType {
_elem_type: i8,
limits: ResizableLimits,
}
impl TableType {
pub fn limits(&self) -> &ResizableLimits { &self.limits }
}
impl Deserialize for TableType {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let elem_type = VarInt7::deserialize(reader)?;
let limits = ResizableLimits::deserialize(reader)?;
Ok(TableType {
_elem_type: elem_type.into(),
limits: limits,
})
}
}
pub struct ResizableLimits {
initial: u32,
maximum: Option<u32>,
}
impl ResizableLimits {
pub fn initial(&self) -> u32 { self.initial }
pub fn maximum(&self) -> Option<u32> { self.maximum }
}
impl Deserialize for ResizableLimits {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let has_max = VarUint1::deserialize(reader)?;
let initial = VarUint32::deserialize(reader)?;
let maximum = if has_max.into() {
Some(VarUint32::deserialize(reader)?.into())
} else {
None
};
Ok(ResizableLimits {
initial: initial.into(),
maximum: maximum,
})
}
}
pub struct MemoryType(ResizableLimits);
impl MemoryType {
pub fn limits(&self) -> &ResizableLimits {
&self.0
}
}
impl Deserialize for MemoryType {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
Ok(MemoryType(ResizableLimits::deserialize(reader)?))
}
}
pub enum External {
Function(u32),
Table(TableType),
Memory(MemoryType),
Global(GlobalType),
}
impl Deserialize for External {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let kind = VarUint7::deserialize(reader)?;
match kind.into() {
0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
_ => Err(Error::UnknownExternalKind(kind.into())),
}
}
}
pub struct ImportEntry {
module_str: String,
field_str: String,
external: External,
}
impl ImportEntry {
pub fn module(&self) -> &str { &self.module_str }
pub fn field(&self) -> &str { &self.field_str }
pub fn external(&self) -> &External { &self.external }
}
impl Deserialize for ImportEntry {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let module_str = String::deserialize(reader)?;
let field_str = String::deserialize(reader)?;
let external = External::deserialize(reader)?;
Ok(ImportEntry {
module_str: module_str,
field_str: field_str,
external: external,
})
}
}

View File

@ -4,10 +4,13 @@ mod module;
mod section;
mod primitives;
mod types;
mod import_entry;
pub use self::module::Module;
pub use self::section::Section;
pub use self::import_entry::ImportEntry;
pub use self::primitives::{VarUint32, VarUint7, VarUint1, VarInt7, Uint32, CountedList};
pub use self::types::ValueType;
pub trait Deserialize : Sized {
type Error;
@ -21,6 +24,8 @@ pub enum Error {
Other(&'static str),
HeapOther(String),
UnknownValueType(i8),
NonUtf8String,
UnknownExternalKind(u8),
}
impl From<io::Error> for Error {
@ -48,7 +53,7 @@ impl From<Unparsed> for Vec<u8> {
}
}
fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
use std::io::Read;
let mut contents = Vec::new();
@ -57,7 +62,7 @@ fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error>
deserialize_buffer(contents)
}
fn deserialize_buffer<T: Deserialize>(contents: Vec<u8>) -> Result<T, T::Error> {
pub fn deserialize_buffer<T: Deserialize>(contents: Vec<u8>) -> Result<T, T::Error> {
let mut reader = io::Cursor::new(contents);
T::deserialize(&mut reader)
}

View File

@ -1,9 +1,9 @@
use std::io;
use super::{Deserialize, VarUint32, Error, Uint32};
use super::{Deserialize, Error, Uint32};
use super::section::Section;
pub struct Module {
magic: u32,
_magic: u32,
version: u32,
sections: Vec<Section>,
}
@ -35,7 +35,7 @@ impl Deserialize for Module {
}
Ok(Module {
magic: magic.into(),
_magic: magic.into(),
version: version.into(),
sections: sections,
})
@ -48,19 +48,12 @@ mod integration_tests {
use std::io::{self, Read};
use std::fs::File;
use super::super::Deserialize;
use super::super::{Deserialize, deserialize_file};
use super::Module;
#[test]
fn hello() {
let mut contents = Vec::new();
File::open("./res/cases/v1/hello.wasm")
.expect("readable file")
.read_to_end(&mut contents)
.expect("read succeeds");
let mut reader = io::Cursor::new(contents);
let module = Module::deserialize(&mut reader).expect("Should be deserialized");
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
assert_eq!(module.version(), 1);
assert_eq!(module.sections().len(), 8);

View File

@ -25,7 +25,6 @@ impl Deserialize for VarUint32 {
let mut shift = 0;
let mut u8buf = [0u8; 1];
loop {
println!("read 1 byte");
reader.read_exact(&mut u8buf)?;
let b = u8buf[0] as u32;
res |= (b & 0x7f) << shift;
@ -119,6 +118,22 @@ impl Deserialize for VarUint1 {
}
}
impl Deserialize for String {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let length = VarUint32::deserialize(reader)?.into();
if length > 0 {
let mut buf = vec![0u8; length];
reader.read_exact(&mut buf)?;
String::from_utf8(buf).map_err(|_| Error::NonUtf8String)
}
else {
Ok(String::new())
}
}
}
pub struct CountedList<T: Deserialize>(Vec<T>);
impl<T: Deserialize> CountedList<T> {
@ -130,13 +145,13 @@ impl<T: Deserialize> Deserialize for CountedList<T> where T::Error : From<Error>
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let count: usize = VarUint32::deserialize(reader)?.into();
println!("count={}", count);
let mut result = Vec::new();
for _ in 0..count { result.push(T::deserialize(reader)?); }
Ok(CountedList(result))
}
}
#[cfg(test)]
mod tests {
use super::super::deserialize_buffer;
@ -162,5 +177,4 @@ mod tests {
let v3: i8 = (*vars.get(1).unwrap()).into();
assert_eq!(-0x03i8, v3);
}
}

View File

@ -1,5 +1,5 @@
use std::io;
use super::{Deserialize, Unparsed, Error, VarUint7, VarUint32, CountedList};
use super::{Deserialize, Unparsed, Error, VarUint7, VarUint32, CountedList, ImportEntry};
use super::types::Type;
pub enum Section {
@ -9,6 +9,7 @@ pub enum Section {
},
Custom(Vec<u8>),
Type(TypeSection),
Import(ImportSection),
}
impl Deserialize for Section {
@ -29,6 +30,9 @@ impl Deserialize for Section {
1 => {
Section::Type(TypeSection::deserialize(reader)?)
},
2 => {
Section::Import(ImportSection::deserialize(reader)?)
},
_ => {
Section::Unparsed { id: id.into(), payload: Unparsed::deserialize(reader)?.into() }
}
@ -37,13 +41,11 @@ impl Deserialize for Section {
}
}
pub struct TypeSection {
types: Vec<Type>,
}
pub struct TypeSection(Vec<Type>);
impl TypeSection {
fn types(&self) -> &[Type] {
&self.types
pub fn types(&self) -> &[Type] {
&self.0
}
}
@ -54,15 +56,50 @@ impl Deserialize for TypeSection {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let types: Vec<Type> = CountedList::deserialize(reader)?.into_inner();
Ok(TypeSection { types: types })
Ok(TypeSection(types))
}
}
pub struct ImportSection(Vec<ImportEntry>);
impl ImportSection {
pub fn entries(&self) -> &[ImportEntry] {
&self.0
}
}
impl Deserialize for ImportSection {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let entries: Vec<ImportEntry> = CountedList::deserialize(reader)?.into_inner();
Ok(ImportSection(entries))
}
}
#[cfg(test)]
mod tests {
use super::super::{deserialize_buffer};
use super::{TypeSection, Type};
use super::super::{deserialize_buffer, deserialize_file};
use super::{Section, TypeSection, Type};
#[test]
fn import_section() {
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
let mut found = false;
for section in module.sections() {
match section {
&Section::Import(ref import_section) => {
assert_eq!(25, import_section.entries().len());
found = true
},
_ => { }
}
}
assert!(found, "There should be import section in test5.wasm");
}
#[test]
fn type_section() {

View File

@ -1,5 +1,5 @@
use std::io;
use super::{Deserialize, Unparsed, Error, VarUint7, VarInt7, VarUint32, VarUint1};
use super::{Deserialize, Error, VarUint7, VarInt7, VarUint1, CountedList};
pub enum Type {
Function(FunctionType),
@ -13,6 +13,7 @@ impl Deserialize for Type {
}
}
#[derive(Clone, Copy)]
pub enum ValueType {
I32,
I64,
@ -42,20 +43,19 @@ pub struct FunctionType {
return_type: Option<ValueType>,
}
impl FunctionType {
pub fn form(&self) -> u8 { self.form }
pub fn params(&self) -> &[ValueType] { &self.params }
pub fn return_type(&self) -> Option<ValueType> { self.return_type }
}
impl Deserialize for FunctionType {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let form: u8 = VarUint7::deserialize(reader)?.into();
println!("function form {}", form);
let param_count: usize = VarUint32::deserialize(reader)?.into();
println!("type param count {}", param_count);
let mut params = Vec::new();
for _ in 0..param_count {
params.push(ValueType::deserialize(reader)?);
}
let params: Vec<ValueType> = CountedList::deserialize(reader)?.into_inner();
let has_return_type = VarUint1::deserialize(reader)?;
let return_type = if has_return_type.into() {

View File

@ -2,4 +2,4 @@ extern crate byteorder;
mod elements;
pub use elements::{Section, Module, Error as DeserializeError};
pub use elements::{Section, Module, Error as DeserializeError, deserialize_buffer, deserialize_file};