use byteorder::{ReadBytesExt, LE}; use crate::vm::obj::syn::error::{Result, ParseError}; use std::{ collections::HashMap, convert::{TryFrom, TryInto}, fmt::Debug, io::{Cursor, Read}, }; pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11; const OBJECT_HEADER_LEN: usize = 16; // 8 + 4 + 4 #[derive(Debug)] pub struct Object { pub version: u32, pub sections: Vec
, } impl Object { pub fn from_bytes(bytes: &[u8]) -> Result { let mut cursor = Cursor::new(bytes); let magic = cursor.read_u64::()?; if magic != magic { return Err(ParseError::WrongMagic); } let version = cursor.read_u32::()?; let section_count = cursor.read_u32::()?; let mut sections = Vec::new(); for _ in 0 .. section_count { let section = Section::from_bytes(&mut cursor)?; sections.push(section); } Ok(Object { version, sections }) } } macro_rules! section_kind { ( pub enum $enum_name:ident { $($name:ident = $value:expr),* $(,)? } ) => { #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum $enum_name { $($name = $value),* } impl TryFrom for SectionKind { type Error = ParseError; fn try_from(other: u8) -> std::result::Result { match other { $( $value => Ok($enum_name::$name), )* _ => Err(ParseError::UnknownSectionKind { kind: other }), } } } }; } section_kind! { pub enum SectionKind { Data = 0x00, Code = 0x10, Meta = 0xFF, } } #[derive(Debug, Clone)] pub enum Section { Data { start: u64, end: u64, contents: Vec, }, Code { start: u64, end: u64, contents: Vec, }, Meta { entries: HashMap, }, } impl Section { fn from_bytes(cursor: &mut Cursor<&[u8]>) -> Result { let len = cursor.read_u64::()?; let start = cursor.position() as usize; let end = start + len as usize; let bytes = &cursor.get_ref()[start .. end]; let kind: SectionKind = cursor.read_u8()?.try_into()?; match kind { SectionKind::Data => Section::data_section_from_bytes(bytes), SectionKind::Code => Section::code_section_from_bytes(bytes), SectionKind::Meta => Section::meta_section_from_bytes(bytes), } } fn data_section_from_bytes(bytes: &[u8]) -> Result { let mut cursor = Cursor::new(bytes); let start = cursor.read_u64::()?; let end = cursor.read_u64::()?; let contents = &bytes[cursor.position() as usize..]; Ok(Section::Data { start, end, contents: From::from(contents), }) } fn code_section_from_bytes(bytes: &[u8]) -> Result { let mut cursor = Cursor::new(bytes); let start = cursor.read_u64::()?; let end = cursor.read_u64::()?; let contents = &bytes[cursor.position() as usize..]; Ok(Section::Code { start, end, contents: From::from(contents), }) } fn meta_section_from_bytes(bytes: &[u8]) -> Result { let mut cursor = Cursor::new(bytes); let entry_count = cursor.read_u64::()?; let mut entries = HashMap::new(); for _ in 0 .. entry_count { // key let key_len = cursor.read_u64::()?; let mut key_bytes = vec![0u8; key_len as usize]; cursor.read_exact(&mut key_bytes)?; let key = String::from_utf8(key_bytes)?; // value let value = cursor.read_u64::()?; entries.insert(key, value); } Ok(Section::Meta { entries }) } }