1use roxmltree::{Document, Node};
6
7use crate::{
8 error::XmlError,
9 ext::{children_with_name, first_child_with_name_opt, int_attr, uint_attr, NodeExt},
10 XmlLoad,
11};
12
13#[derive(Debug)]
14pub struct Documentation {
16 pub contents: Option<String>,
18}
19
20impl<'input> XmlLoad<'input> for Documentation {
21 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
22 Ok(Self {
23 contents: node.text().map(|a| a.to_owned()),
24 })
25 }
26}
27
28#[derive(Debug)]
29pub enum ByteOrder {
31 BigEndian,
33 LittleEndian,
35}
36
37impl ByteOrder {
38 pub(crate) fn from_node(node: &Node<'_, '_>, attr: &str) -> Result<Option<Self>, XmlError> {
39 Ok(match node.attribute(attr) {
40 Some("LittleEndian") => Some(ByteOrder::LittleEndian),
41 Some("BigEndian") => Some(ByteOrder::BigEndian),
42 Some(r) => {
43 return Err(XmlError::other(
44 node,
45 &format!("Expected LittleEndian or BigEndian for {attr}, got {r}"),
46 ))
47 }
48 None => None,
49 })
50 }
51}
52
53#[derive(Debug)]
54pub struct TypeDescription {
56 pub documentation: Option<Documentation>,
58 pub name: String,
60 pub default_byte_order: Option<ByteOrder>,
62}
63
64impl<'input> XmlLoad<'input> for TypeDescription {
65 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
66 Ok(Self {
67 documentation: first_child_with_name_opt(node, "Documentation")?,
68 name: node.try_attribute("Name")?.to_owned(),
69 default_byte_order: ByteOrder::from_node(node, "DefaultByteOrder")?,
70 })
71 }
72}
73
74#[derive(Debug)]
75pub struct OpaqueType {
77 pub description: TypeDescription,
79 pub length_in_bits: Option<i64>,
81 pub byte_order_significant: bool,
83}
84
85impl<'input> XmlLoad<'input> for OpaqueType {
86 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
87 Ok(Self {
88 description: TypeDescription::load(node)?,
89 length_in_bits: int_attr(node, "LengthInBits")?,
90 byte_order_significant: node.attribute("ByteOrderSignificant") == Some("true"),
91 })
92 }
93}
94
95#[derive(Debug)]
96pub struct EnumeratedValue {
98 pub documentation: Option<Documentation>,
100 pub name: Option<String>,
102 pub value: Option<i64>,
104}
105impl<'input> XmlLoad<'input> for EnumeratedValue {
106 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
107 Ok(Self {
108 documentation: first_child_with_name_opt(node, "Documentation")?,
109 name: node.attribute("Name").map(|n| n.to_owned()),
110 value: int_attr(node, "Value")?,
111 })
112 }
113}
114
115#[derive(Debug)]
116pub struct EnumeratedType {
118 pub opaque: OpaqueType,
120 pub variants: Vec<EnumeratedValue>,
122 pub is_option_set: bool,
124}
125
126impl<'input> XmlLoad<'input> for EnumeratedType {
127 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
128 Ok(Self {
129 opaque: OpaqueType::load(node)?,
130 variants: children_with_name(node, "EnumeratedValue")?,
131 is_option_set: node.attribute("IsOptionSet") == Some("true"),
132 })
133 }
134}
135
136#[derive(Debug)]
137pub enum SwitchOperand {
139 Equals,
141 GreaterThan,
143 LessThan,
145 GreaterThanOrEqual,
147 LessThanOrEqual,
149 NotEqual,
151}
152
153impl SwitchOperand {
154 pub(crate) fn from_node(node: &Node<'_, '_>, attr: &str) -> Result<Option<Self>, XmlError> {
155 Ok(match node.attribute(attr) {
156 Some("Equals") => Some(SwitchOperand::Equals),
157 Some("GreaterThan") => Some(SwitchOperand::GreaterThan),
158 Some("LessThan") => Some(SwitchOperand::LessThan),
159 Some("GreaterThanOrEqual") => Some(SwitchOperand::GreaterThanOrEqual),
160 Some("LessThanOrEqual") => Some(SwitchOperand::LessThanOrEqual),
161 Some("NotEqual") => Some(SwitchOperand::NotEqual),
162 Some(r) => {
163 return Err(XmlError::other(
164 node,
165 &format!("Unexpected value for {attr}: {r}"),
166 ))
167 }
168 _ => None,
169 })
170 }
171}
172
173#[derive(Debug)]
174pub struct FieldType {
176 pub documentation: Option<Documentation>,
178 pub name: String,
180 pub type_name: Option<String>,
182 pub length: Option<u64>,
184 pub length_field: Option<String>,
186 pub is_length_in_bytes: bool,
188 pub switch_field: Option<String>,
190 pub switch_value: Option<u64>,
192 pub switch_operand: Option<SwitchOperand>,
194 pub terminator: Option<String>,
196}
197
198impl<'input> XmlLoad<'input> for FieldType {
199 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
200 Ok(Self {
201 documentation: first_child_with_name_opt(node, "Documentation")?,
202 name: node.try_attribute("Name")?.to_owned(),
203 type_name: node.attribute("TypeName").map(|a| a.to_owned()),
204 length: uint_attr(node, "Length")?,
205 length_field: node.attribute("LengthField").map(|a| a.to_owned()),
206 is_length_in_bytes: node.attribute("IsLengthInBytes") == Some("true"),
207 switch_field: node.attribute("SwitchField").map(|a| a.to_owned()),
208 switch_value: uint_attr(node, "SwitchValue")?,
209 switch_operand: SwitchOperand::from_node(node, "SwitchOperand")?,
210 terminator: node.attribute("Terminator").map(|a| a.to_owned()),
211 })
212 }
213}
214
215#[derive(Debug)]
216pub struct StructuredType {
218 pub description: TypeDescription,
220 pub fields: Vec<FieldType>,
222 pub base_type: Option<String>,
224}
225
226impl<'input> XmlLoad<'input> for StructuredType {
227 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
228 Ok(Self {
229 description: TypeDescription::load(node)?,
230 fields: children_with_name(node, "Field")?,
231 base_type: node.attribute("BaseType").map(|t| t.to_owned()),
232 })
233 }
234}
235
236#[derive(Debug)]
237pub struct ImportDirective {
239 pub namespace: Option<String>,
241 pub location: Option<String>,
243}
244
245impl<'input> XmlLoad<'input> for ImportDirective {
246 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
247 Ok(Self {
248 namespace: node.attribute("Namespace").map(|a| a.to_owned()),
249 location: node.attribute("Location").map(|a| a.to_owned()),
250 })
251 }
252}
253
254#[derive(Debug)]
255pub enum TypeDictionaryItem {
257 Opaque(OpaqueType),
259 Enumerated(EnumeratedType),
261 Structured(StructuredType),
263}
264
265#[derive(Debug)]
266pub struct TypeDictionary {
268 pub documentation: Option<Documentation>,
270 pub imports: Vec<ImportDirective>,
272 pub elements: Vec<TypeDictionaryItem>,
274 pub target_namespace: String,
276 pub default_byte_order: Option<ByteOrder>,
278}
279
280impl<'input> XmlLoad<'input> for TypeDictionary {
281 fn load(node: &Node<'_, 'input>) -> Result<Self, XmlError> {
282 Ok(Self {
283 documentation: first_child_with_name_opt(node, "Documentation")?,
284 imports: children_with_name(node, "Import")?,
285 elements: node
286 .children()
287 .filter_map(|e| match e.tag_name().name() {
288 "OpaqueType" => Some(OpaqueType::load(&e).map(TypeDictionaryItem::Opaque)),
289 "EnumeratedType" => {
290 Some(EnumeratedType::load(&e).map(TypeDictionaryItem::Enumerated))
291 }
292 "StructuredType" => {
293 Some(StructuredType::load(&e).map(TypeDictionaryItem::Structured))
294 }
295 _ => None,
296 })
297 .collect::<Result<Vec<_>, _>>()?,
298 target_namespace: node.try_attribute("TargetNamespace")?.to_owned(),
299 default_byte_order: ByteOrder::from_node(node, "DefaultByteOrder")?,
300 })
301 }
302}
303
304pub fn load_bsd_file(document: &str) -> Result<TypeDictionary, XmlError> {
306 let document = Document::parse(document).map_err(|e| XmlError {
307 span: 0..1,
308 error: crate::error::XmlErrorInner::Xml(e),
309 })?;
310 TypeDictionary::load(&document.root().first_child_with_name("TypeDictionary")?)
311}