use std::num; use roxmltree::{Node, TextPos}; use thiserror::Error; use crate::types::Module; #[derive(Debug, Error)] pub enum DomConversionError { #[error("attribute {attr} not found in element: {start} - {end}", start = pos.0, end = pos.1)] AttributeNotFound { attr: &'static str, pos: (TextPos, TextPos), }, #[error("string conversion error: {start} - {end}", start = pos.0, end = pos.1)] ParseIntError { attr: &'static str, pos: (TextPos, TextPos), #[source] source: num::ParseIntError, }, #[error("string conversion error: {start} - {end}", start = pos.0, end = pos.1)] ParsePrefixedU32Error { attr: &'static str, pos: (TextPos, TextPos), #[source] source: ParsePrefixedU32Error, }, #[error("invalid dom structure: {0}")] InvalidFormat(String), } impl DomConversionError { fn attr_not_found(attr: &'static str, node: Node) -> Self { let range = node.range(); let doc = node.document(); Self::AttributeNotFound { attr, pos: (doc.text_pos_at(range.start), doc.text_pos_at(range.end)), } } fn parse_int_error(e: num::ParseIntError, attr: &'static str, node: Node) -> Self { let range = node.range(); let doc = node.document(); Self::ParseIntError { attr, pos: (doc.text_pos_at(range.start), doc.text_pos_at(range.end)), source: e, } } fn parse_prefixed_u32_error(e: ParsePrefixedU32Error, attr: &'static str, node: Node) -> Self { let range = node.range(); let doc = node.document(); Self::ParsePrefixedU32Error { attr, pos: (doc.text_pos_at(range.start), doc.text_pos_at(range.end)), source: e, } } } #[derive(Debug, Error)] pub enum ParsePrefixedU32Error { #[error("invalid prefix: found {found}")] InvalidPrefix { found: char }, #[error("parse int error")] ParseIntError(#[from] num::ParseIntError), } trait ParsePrefixedU32 { fn parse_prefixed_u32(&self) -> Result; } impl ParsePrefixedU32 for &str { fn parse_prefixed_u32(&self) -> Result { let radix = match self.chars().nth(1) { Some('x') => 16, Some(c) if c.is_numeric() => 10, Some(c) => return Err(ParsePrefixedU32Error::InvalidPrefix { found: c }), None => return Err(ParsePrefixedU32Error::InvalidPrefix { found: ' ' }), }; match radix { 10 => Ok(self.parse()?), radix => Ok(u32::from_str_radix(&self[2..], radix)?), } } } impl Module { pub fn from_xml_dom(root: Node) -> Result { assert!(root.parent().unwrap().is_root()); assert_eq!(root.tag_name().name(), "module"); let name = root.tag_name().name(); println!("{}", name); let name = match root.attribute("name") { Some(name) => name.to_string(), None => return Err(DomConversionError::attr_not_found("name", root)), }; let addr = match root.attribute("addr") { Some(addr) => addr .parse_prefixed_u32() .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "addr", root))?, None => return Err(DomConversionError::attr_not_found("addr", root)), }; let size = match root.attribute("size") { Some(addr) => addr .parse_prefixed_u32() .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "size", root))?, None => return Err(DomConversionError::attr_not_found("size", root)), }; Ok(Self { name, addr, size, amod: todo!(), r#type: todo!(), desc: todo!(), elements_bitstring: todo!(), elements_other: todo!(), }) } }