paramdex_rs/deserialize/
mod.rs1use std::collections::HashMap;
2use std::num::{ParseFloatError, ParseIntError};
3use std::str::{FromStr, ParseBoolError};
4use roxmltree::Node;
5use thiserror::Error;
6use crate::{EditFlags, ParamDef, ParamdefEndian, ParamdefFormat, ParamField, ParamFieldDef};
7
8mod field_def_parse;
9
10pub use field_def_parse::DefParseError;
11
12const PARAM_DEF_ROOT: &'static str = "PARAMDEF";
14
15impl FromStr for ParamDef {
16 type Err = ParamdefDeserializeError;
17
18 fn from_str(s: &str) -> Result<Self, Self::Err> {
19 deserialize_def(s)
20 }
21}
22
23pub fn deserialize_def<S: AsRef<str>>(input: S) -> Result<ParamDef, ParamdefDeserializeError> {
25 let input = input.as_ref();
26
27 let doc = roxmltree::Document::parse(input)?;
28
29 let root = doc.root_element();
30 if root.tag_name().name() != PARAM_DEF_ROOT {
31 return Err(ParamdefDeserializeError::MissingParamData("Invalid root element".into()));
32 }
33
34 let mut root_config: HashMap<String, String> = HashMap::new();
35
36 let mut fields: Option<Node> = None;
37
38 for child in root.children() {
39 match child.tag_name().name() {
40 "Fields" => {
41 fields.replace(child);
42 }
43 name => {
44 root_config.insert(name.into(), child.text().ok_or(ParamdefDeserializeError::XmlBlankElement(name.into()))?.into());
45 }
46 }
47 }
48
49 let fields_node = fields.ok_or(ParamdefDeserializeError::MissingParamData("Fields".into()))?;
50
51 let mut paramdef = ParamDef {
52 param_type: get_or_error(&root_config, "ParamType").cloned()?,
53 data_version: u32::from_str(get_or_error(&root_config, "DataVersion")?)?,
54 endian: ParamdefEndian::from_str(get_or_error(&root_config, "BigEndian")?)?,
55 string_format: ParamdefFormat::from_str(get_or_error(&root_config, "BigEndian")?)?,
56 format_version: u32::from_str(get_or_error(&root_config, "FormatVersion")?)?,
57 fields: Vec::new()
58 };
59
60 let fields = &mut paramdef.fields;
61
62 for node in fields_node.children() {
63 fields.push(parse_field_node(node)?);
64 }
65
66 Ok(paramdef)
67}
68
69fn get_or_error<'a>(map: &'a HashMap<String, String>, key: &str) -> Result<&'a String, ParamdefDeserializeError> {
71 map.get(key).ok_or(ParamdefDeserializeError::MissingParamData(format!("{}", key)))
72}
73
74fn parse_field_node(field_node: Node) -> Result<ParamField, ParamdefDeserializeError> {
75 let attr = field_node.attribute("Def").ok_or(ParamdefDeserializeError::MissingParamData("Field Def".into()))?;
76
77 let mut field_config: HashMap<String, String> = HashMap::new();
78
79 for child in field_node.children() {
80 if let Some(text) = child.text() {
81 field_config.insert(child.tag_name().name().into(), text.into());
82 }
83 }
84
85
86 Ok(ParamField {
87
88 field_def: ParamFieldDef::from_str(attr)?,
89
90 display_name: field_config.get("DisplayName").cloned(),
91 enum_tdf: field_config.get("Enum").cloned(),
92 description: field_config.get("Description").cloned(),
93 printf_format: field_config.get("DisplayFormat").cloned(),
94
95 edit_flags: field_config.get("EditFlags").map(|a| EditFlags::from_str(a)).swap()?, minimum: field_config.get("Minimum").map(|a| f64::from_str(a.as_str())).swap()?,
98 maximum: field_config.get("Maximum").map(|a| f64::from_str(a.as_str())).swap()?,
99 increment: field_config.get("Increment").map(|a| f64::from_str(a.as_str())).swap()?,
100 sort_id: field_config.get("SortID").map(|a| usize::from_str(a.as_str())).swap()?,
101 })
102
103}
104
105impl FromStr for EditFlags {
106 type Err = ParamdefDeserializeError;
107
108 fn from_str(text: &str) -> Result<Self, Self::Err> {
109 Ok(EditFlags {
110 wrap: text.contains("Wrap"),
111 lock: text.contains("Lock"),
112 })
113 }
114}
115
116impl FromStr for ParamFieldDef {
117 type Err = DefParseError;
118
119 fn from_str(s: &str) -> Result<Self, Self::Err> {
120 field_def_parse::parse_param_field_def(s)
121 }
122}
123
124trait OptionResultExt<V, E> {
125 fn swap(self) -> Result<Option<V>, E>;
126}
127
128impl<V, E> OptionResultExt<V, E> for Option<Result<V, E>> {
129 fn swap(self) -> Result<Option<V>, E> {
130 match self {
131 Some(Ok(v)) => Ok(Some(v)),
132 Some(Err(e)) => Err(e),
133 None => Ok(None)
134 }
135 }
136}
137
138impl FromStr for ParamdefEndian {
139 type Err = ParseBoolError;
140
141 fn from_str(s: &str) -> Result<Self, Self::Err> {
142 bool::from_str(s.to_lowercase().as_str()).map(|a| a.into())
143 }
144}
145
146impl From<bool> for ParamdefEndian {
147 fn from(a: bool) -> Self {
148 if a {
149 Self::Big
150 } else {
151 Self::Little
152 }
153 }
154}
155
156impl FromStr for ParamdefFormat {
157 type Err = ParseBoolError;
158
159 fn from_str(s: &str) -> Result<Self, Self::Err> {
160 bool::from_str(s).map(|a| a.into())
161 }
162}
163
164impl From<bool> for ParamdefFormat {
165 fn from(a: bool) -> Self {
166 if a {
167 Self::UTF16
168 } else {
169 Self::ShiftJIS
170 }
171 }
172}
173
174#[derive(Error, Debug)]
175pub enum ParamdefDeserializeError {
176 #[error("XML parsing failed: {0}")]
177 XmlParsing(#[from] roxmltree::Error),
178
179 #[error("XML blank element: {0}")]
180 XmlBlankElement(String),
181
182 #[error("Parsing number from XML: {0}")]
183 XmlParsingNumber(#[from] ParseIntError),
184
185 #[error("Parsing bool from XML: {0}")]
186 XmlParsingBool(#[from] ParseBoolError),
187
188 #[error("Parsing float from XML: {0}")]
189 XmlParsingFloat(#[from] ParseFloatError),
190
191 #[error("A required field in the XML was missing")]
192 MissingParamData(String),
193
194 #[error("Failed to parse field def string")]
195 ParsingDefString(#[from] DefParseError)
196}