1#![cfg_attr(docsrs, feature(doc_cfg))]
2use std::future::Future;
5
6use quick_xml::events::{BytesStart, Event};
7use quick_xml::name::QName;
8use quick_xml::Reader;
9use thiserror::Error;
10use tracing::warn;
11
12const FIRST_URL_ADDRESS: u64 = 0x0000;
13const FIRST_URL_MAX_LEN: usize = 512;
14
15const TAG_P_ADDRESS: &[u8] = b"pAddress";
17const TAG_VALUE: &[u8] = b"Value";
19const TAG_P_VALUE: &[u8] = b"pValue";
21const TAG_DISPLAY_NAME: &[u8] = b"DisplayName";
23const TAG_LSB: &[u8] = b"Lsb";
25const TAG_MSB: &[u8] = b"Msb";
27const TAG_BIT: &[u8] = b"Bit";
29const TAG_MASK: &[u8] = b"Mask";
31const TAG_ENDIANNESS: &[u8] = b"Endianness";
33const TAG_ENDIANESS: &[u8] = b"Endianess";
35const TAG_BYTE_ORDER: &[u8] = b"ByteOrder";
37
38#[derive(Debug, Clone, PartialEq, Eq)]
40pub enum EnumValueSrc {
41 Literal(i64),
43 FromNode(String),
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct EnumEntryDecl {
50 pub name: String,
52 pub value: EnumValueSrc,
54 pub display_name: Option<String>,
56}
57
58#[derive(Debug, Error)]
59pub enum XmlError {
60 #[error("xml: {0}")]
61 Xml(String),
62 #[error("invalid descriptor: {0}")]
63 Invalid(String),
64 #[error("transport: {0}")]
65 Transport(String),
66 #[error("unsupported URL: {0}")]
67 Unsupported(String),
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum AccessMode {
73 RO,
75 WO,
77 RW,
79}
80
81impl AccessMode {
82 fn parse(value: &str) -> Result<Self, XmlError> {
83 match value.trim().to_ascii_uppercase().as_str() {
84 "RO" => Ok(AccessMode::RO),
85 "WO" => Ok(AccessMode::WO),
86 "RW" => Ok(AccessMode::RW),
87 other => Err(XmlError::Invalid(format!("unknown access mode: {other}"))),
88 }
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
94pub enum Addressing {
95 Fixed { address: u64, len: u32 },
97 BySelector {
99 selector: String,
101 map: Vec<(String, (u64, u32))>,
103 },
104 Indirect {
106 p_address_node: String,
108 len: u32,
110 },
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub enum ByteOrder {
116 Little,
118 Big,
120}
121
122impl ByteOrder {
123 fn parse(tag: &str) -> Option<Self> {
124 match tag.trim().to_ascii_lowercase().as_str() {
125 "littleendian" => Some(ByteOrder::Little),
126 "bigendian" => Some(ByteOrder::Big),
127 _ => None,
128 }
129 }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134pub struct BitField {
135 pub bit_offset: u16,
137 pub bit_length: u16,
139 pub byte_order: ByteOrder,
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
145pub enum SkOutput {
146 Integer,
149 #[default]
152 Float,
153}
154
155impl SkOutput {
156 fn parse(tag: &str) -> Option<Self> {
157 match tag.trim().to_ascii_lowercase().as_str() {
158 "integer" => Some(SkOutput::Integer),
159 "float" => Some(SkOutput::Float),
160 _ => None,
161 }
162 }
163}
164
165#[derive(Debug, Clone)]
167pub struct SwissKnifeDecl {
168 pub name: String,
170 pub expr: String,
172 pub variables: Vec<(String, String)>,
174 pub output: SkOutput,
176}
177
178#[derive(Debug, Clone)]
180pub enum NodeDecl {
181 Integer {
183 name: String,
185 addressing: Addressing,
187 len: u32,
189 access: AccessMode,
191 min: i64,
193 max: i64,
195 inc: Option<i64>,
197 unit: Option<String>,
199 bitfield: Option<BitField>,
201 selectors: Vec<String>,
203 selected_if: Vec<(String, Vec<String>)>,
205 },
206 Float {
208 name: String,
209 addressing: Addressing,
210 access: AccessMode,
211 min: f64,
212 max: f64,
213 unit: Option<String>,
214 scale: Option<(i64, i64)>,
216 offset: Option<f64>,
218 selectors: Vec<String>,
219 selected_if: Vec<(String, Vec<String>)>,
220 },
221 Enum {
223 name: String,
224 addressing: Addressing,
225 access: AccessMode,
226 entries: Vec<EnumEntryDecl>,
227 default: Option<String>,
228 selectors: Vec<String>,
229 selected_if: Vec<(String, Vec<String>)>,
230 },
231 Boolean {
233 name: String,
234 addressing: Addressing,
235 len: u32,
236 access: AccessMode,
237 bitfield: BitField,
238 selectors: Vec<String>,
239 selected_if: Vec<(String, Vec<String>)>,
240 },
241 Command {
243 name: String,
244 address: u64,
245 len: u32,
246 },
247 Category { name: String, children: Vec<String> },
249 SwissKnife(SwissKnifeDecl),
251}
252
253#[derive(Debug, Clone)]
255pub struct XmlModel {
256 pub version: String,
258 pub nodes: Vec<NodeDecl>,
260}
261
262pub async fn fetch_and_load_xml<F, Fut>(mut read_mem: F) -> Result<String, XmlError>
267where
268 F: FnMut(u64, usize) -> Fut,
269 Fut: Future<Output = Result<Vec<u8>, XmlError>>,
270{
271 let url_bytes = read_mem(FIRST_URL_ADDRESS, FIRST_URL_MAX_LEN).await?;
272 let url = first_cstring(&url_bytes)
273 .ok_or_else(|| XmlError::Invalid("FirstURL register is empty".into()))?;
274 let location = UrlLocation::parse(&url)?;
275 match location {
276 UrlLocation::Local { address, length } => {
277 let xml_bytes = read_mem(address, length).await?;
278 String::from_utf8(xml_bytes)
279 .map_err(|err| XmlError::Xml(format!("invalid UTF-8: {err}")))
280 }
281 UrlLocation::LocalNamed(name) => Err(XmlError::Unsupported(format!(
282 "named local URL '{name}' is not supported"
283 ))),
284 UrlLocation::Http(url) => Err(XmlError::Unsupported(format!(
285 "HTTP retrieval is not implemented ({url})"
286 ))),
287 UrlLocation::File(path) => Err(XmlError::Unsupported(format!(
288 "file URL '{path}' is not supported"
289 ))),
290 }
291}
292
293pub fn parse_into_minimal_nodes(xml: &str) -> Result<MinimalXmlInfo, XmlError> {
295 let mut reader = Reader::from_str(xml);
296 reader.trim_text(true);
297 let mut buf = Vec::new();
298 let mut depth = 0usize;
299 let mut schema_version: Option<String> = None;
300 let mut top_level_features = Vec::new();
301
302 loop {
303 match reader.read_event_into(&mut buf) {
304 Ok(Event::Start(e)) => {
305 depth += 1;
306 handle_start(&e, depth, &mut schema_version, &mut top_level_features)?;
307 }
308 Ok(Event::Empty(e)) => {
309 depth += 1;
310 handle_start(&e, depth, &mut schema_version, &mut top_level_features)?;
311 if depth > 0 {
312 depth = depth.saturating_sub(1);
313 }
314 }
315 Ok(Event::End(_)) => {
316 if depth > 0 {
317 depth = depth.saturating_sub(1);
318 }
319 }
320 Ok(Event::Eof) => break,
321 Err(err) => return Err(XmlError::Xml(err.to_string())),
322 _ => {}
323 }
324 buf.clear();
325 }
326
327 Ok(MinimalXmlInfo {
328 schema_version,
329 top_level_features,
330 })
331}
332
333pub fn parse(xml: &str) -> Result<XmlModel, XmlError> {
339 let mut reader = Reader::from_str(xml);
340 reader.trim_text(true);
341 let mut buf = Vec::new();
342 let mut version = String::from("0.0.0");
343 let mut nodes = Vec::new();
344
345 loop {
346 match reader.read_event_into(&mut buf) {
347 Ok(Event::Start(ref e)) => match e.name().as_ref() {
348 b"RegisterDescription" => {
349 version = schema_version_from(e)?;
350 }
351 b"Integer" => {
352 let node = parse_integer(&mut reader, e.clone())?;
353 nodes.push(node);
354 }
355 b"Float" => {
356 let node = parse_float(&mut reader, e.clone())?;
357 nodes.push(node);
358 }
359 b"Enumeration" => {
360 let node = parse_enum(&mut reader, e.clone())?;
361 nodes.push(node);
362 }
363 b"Boolean" => {
364 let node = parse_boolean(&mut reader, e.clone())?;
365 nodes.push(node);
366 }
367 b"Command" => {
368 let node = parse_command(&mut reader, e.clone())?;
369 nodes.push(node);
370 }
371 b"Category" => {
372 let node = parse_category(&mut reader, e.clone())?;
373 nodes.push(node);
374 }
375 b"SwissKnife" => {
376 let node = parse_swissknife(&mut reader, e.clone())?;
377 nodes.push(node);
378 }
379 _ => {
380 skip_element(&mut reader, e.name().as_ref())?;
381 }
382 },
383 Ok(Event::Empty(ref e)) => match e.name().as_ref() {
384 b"RegisterDescription" => {
385 version = schema_version_from(e)?;
386 }
387 b"Command" => {
388 let node = parse_command_empty(e)?;
389 nodes.push(node);
390 }
391 b"Category" => {
392 let node = parse_category_empty(e)?;
393 nodes.push(node);
394 }
395 _ => {}
396 },
397 Ok(Event::Eof) => break,
398 Err(err) => return Err(XmlError::Xml(err.to_string())),
399 _ => {}
400 }
401 buf.clear();
402 }
403
404 Ok(XmlModel { version, nodes })
405}
406
407fn schema_version_from(event: &BytesStart<'_>) -> Result<String, XmlError> {
408 let major = attribute_value(event, b"SchemaMajorVersion")?;
409 let minor = attribute_value(event, b"SchemaMinorVersion")?;
410 let sub = attribute_value(event, b"SchemaSubMinorVersion")?;
411 let major = major.unwrap_or_else(|| "0".to_string());
412 let minor = minor.unwrap_or_else(|| "0".to_string());
413 let sub = sub.unwrap_or_else(|| "0".to_string());
414 Ok(format!("{major}.{minor}.{sub}"))
415}
416
417#[derive(Debug, Default)]
418struct AddressingBuilder {
419 fixed_address: Option<u64>,
420 length: Option<u32>,
421 selector: Option<String>,
422 entries: Vec<AddressEntry>,
423 pending_value: Option<String>,
424 pending_len: Option<u32>,
425 p_address_node: Option<String>,
426}
427
428#[derive(Debug, Clone)]
429struct AddressEntry {
430 value: String,
431 address: u64,
432 len: Option<u32>,
433}
434
435impl AddressingBuilder {
436 fn set_fixed_address(&mut self, address: u64) {
437 self.fixed_address = Some(address);
438 }
439
440 fn set_length(&mut self, len: u32) {
441 self.length = Some(len);
442 }
443
444 fn set_p_address_node(&mut self, node: &str) {
445 self.p_address_node = Some(node.to_string());
446 }
447
448 fn register_selector(&mut self, selector: &str) {
449 if self.selector.is_none() {
450 self.selector = Some(selector.to_string());
451 }
452 }
453
454 fn push_selected_value(&mut self, value: String) {
455 self.pending_value = Some(value);
456 self.pending_len = None;
457 }
458
459 fn apply_length(&mut self, len: u32) {
460 if self.pending_value.is_some() {
461 self.pending_len = Some(len);
462 } else {
463 self.length = Some(len);
464 }
465 }
466
467 fn attach_selected_address(&mut self, address: u64, len_override: Option<u32>) {
468 if let Some(value) = self.pending_value.take() {
469 let len = len_override.or(self.pending_len.take());
470 self.entries.push(AddressEntry {
471 value,
472 address,
473 len,
474 });
475 } else {
476 self.fixed_address = Some(address);
477 if let Some(len) = len_override {
478 self.length = Some(len);
479 }
480 }
481 }
482
483 fn finalize(self, node: &str, default_len: Option<u32>) -> Result<Addressing, XmlError> {
484 if !self.entries.is_empty() {
485 let selector = self.selector.ok_or_else(|| {
486 XmlError::Invalid(format!(
487 "node {node} provides <Selected> addresses without <pSelected>"
488 ))
489 })?;
490 let mut map = Vec::new();
491 for entry in self.entries {
492 let len = entry.len.or(self.length).or(default_len).ok_or_else(|| {
493 XmlError::Invalid(format!(
494 "node {node} is missing <Length> for selector value {}",
495 entry.value
496 ))
497 })?;
498 if let Some(existing) = map.iter_mut().find(|(value, _)| *value == entry.value) {
499 *existing = (entry.value.clone(), (entry.address, len));
500 } else {
501 map.push((entry.value.clone(), (entry.address, len)));
502 }
503 }
504 if self.p_address_node.is_some() {
505 warn!(
506 node = %node,
507 "ignoring <pAddress> in favour of selector table"
508 );
509 }
510 if self.fixed_address.is_some() {
511 warn!(
512 node = %node,
513 selector = %selector,
514 "ignoring fixed <Address> in favour of selector table"
515 );
516 }
517 Ok(Addressing::BySelector { selector, map })
518 } else {
519 let len = self
520 .length
521 .or(default_len)
522 .ok_or_else(|| XmlError::Invalid(format!("node {node} is missing <Length>")))?;
523 if let Some(p_address_node) = self.p_address_node {
524 if self.fixed_address.is_some() {
525 warn!(
526 node = %node,
527 address_node = %p_address_node,
528 "ignoring fixed <Address> in favour of <pAddress>"
529 );
530 }
531 Ok(Addressing::Indirect {
532 p_address_node,
533 len,
534 })
535 } else {
536 let address = self.fixed_address.ok_or_else(|| {
537 XmlError::Invalid(format!("node {node} is missing <Address>"))
538 })?;
539 Ok(Addressing::Fixed { address, len })
540 }
541 }
542 }
543}
544
545#[derive(Debug, Clone, Copy, PartialEq, Eq)]
546enum BitfieldSource {
547 LsbMsb,
548 BitLength,
549 Mask,
550}
551
552#[derive(Debug, Default)]
553struct BitfieldBuilder {
554 lsb: Option<u32>,
555 msb: Option<u32>,
556 bit: Option<u32>,
557 bit_length: Option<u32>,
558 mask: Option<u64>,
559 byte_order: Option<ByteOrder>,
560 source: Option<BitfieldSource>,
561}
562
563impl BitfieldBuilder {
564 fn note_lsb(&mut self, value: u32) {
565 if self
566 .source
567 .map(|source| source != BitfieldSource::LsbMsb)
568 .unwrap_or(false)
569 {
570 return;
571 }
572 self.source.get_or_insert(BitfieldSource::LsbMsb);
573 self.lsb = Some(value);
574 }
575
576 fn note_msb(&mut self, value: u32) {
577 if self
578 .source
579 .map(|source| source != BitfieldSource::LsbMsb)
580 .unwrap_or(false)
581 {
582 return;
583 }
584 self.source.get_or_insert(BitfieldSource::LsbMsb);
585 self.msb = Some(value);
586 }
587
588 fn note_bit(&mut self, value: u32) {
589 if self
590 .source
591 .map(|source| source != BitfieldSource::BitLength)
592 .unwrap_or(false)
593 {
594 return;
595 }
596 self.source.get_or_insert(BitfieldSource::BitLength);
597 self.bit = Some(value);
598 }
599
600 fn note_bit_length(&mut self, value: u32) {
601 if self
602 .source
603 .map(|source| source != BitfieldSource::BitLength)
604 .unwrap_or(false)
605 {
606 return;
607 }
608 self.source.get_or_insert(BitfieldSource::BitLength);
609 self.bit_length = Some(value);
610 }
611
612 fn note_mask(&mut self, mask: u64) {
613 if self.source.is_some() {
614 return;
615 }
616 self.source = Some(BitfieldSource::Mask);
617 self.mask = Some(mask);
618 }
619
620 fn note_byte_order(&mut self, order: ByteOrder) {
621 self.byte_order = Some(order);
622 }
623
624 fn finish(self, node: &str, lengths: &[u32]) -> Result<Option<BitField>, XmlError> {
625 let source = match self.source {
626 Some(source) => source,
627 None => return Ok(None),
628 };
629 let byte_order = self.byte_order.unwrap_or(ByteOrder::Little);
630 if lengths.is_empty() {
631 return Err(XmlError::Invalid(format!(
632 "node {node} is missing register length information"
633 )));
634 }
635 let mut unique_len = None;
636 for len in lengths {
637 if *len == 0 {
638 return Err(XmlError::Invalid(format!(
639 "node {node} declares zero-length register"
640 )));
641 }
642 if let Some(existing) = unique_len {
643 if existing != *len {
644 return Err(XmlError::Invalid(format!(
645 "node {node} uses inconsistent register lengths"
646 )));
647 }
648 } else {
649 unique_len = Some(*len);
650 }
651 }
652 let len_bytes = unique_len.unwrap_or(0);
653 let total_bits = len_bytes
654 .checked_mul(8)
655 .ok_or_else(|| XmlError::Invalid(format!("node {node} register length overflow")))?;
656
657 let (offset_lsb, bit_length) = match source {
658 BitfieldSource::LsbMsb => {
659 let lsb = self
660 .lsb
661 .ok_or_else(|| XmlError::Invalid(format!("node {node} is missing <Lsb>")))?;
662 let msb = self
663 .msb
664 .ok_or_else(|| XmlError::Invalid(format!("node {node} is missing <Msb>")))?;
665 let lower = lsb.min(msb);
666 let upper = lsb.max(msb);
667 let length = upper
668 .checked_sub(lower)
669 .and_then(|value| value.checked_add(1))
670 .ok_or_else(|| {
671 XmlError::Invalid(format!(
672 "node {node} has invalid bit range <Lsb>={lsb}, <Msb>={msb}"
673 ))
674 })?;
675 (lower, length)
676 }
677 BitfieldSource::BitLength => {
678 let bit = self
679 .bit
680 .ok_or_else(|| XmlError::Invalid(format!("node {node} is missing <Bit>")))?;
681 let length = self.bit_length.unwrap_or(1);
682 (bit, length)
683 }
684 BitfieldSource::Mask => {
685 let mask = self.mask.ok_or_else(|| {
686 XmlError::Invalid(format!("node {node} is missing <Mask> value"))
687 })?;
688 if mask == 0 {
689 return Err(XmlError::Invalid(format!(
690 "node {node} mask must be non-zero"
691 )));
692 }
693 let offset = mask.trailing_zeros();
694 let length = mask.count_ones();
695 (offset, length)
696 }
697 };
698
699 if bit_length == 0 {
700 return Err(XmlError::Invalid(format!(
701 "node {node} bitfield must have positive length"
702 )));
703 }
704 if bit_length > 64 {
705 return Err(XmlError::Invalid(format!(
706 "node {node} bitfield length {bit_length} exceeds 64 bits"
707 )));
708 }
709
710 if offset_lsb > u16::MAX as u32 {
711 return Err(XmlError::Invalid(format!(
712 "node {node} bit offset {offset_lsb} exceeds u16 range"
713 )));
714 }
715
716 if bit_length > u16::MAX as u32 {
717 return Err(XmlError::Invalid(format!(
718 "node {node} bit length {bit_length} exceeds u16 range"
719 )));
720 }
721
722 if offset_lsb + bit_length > total_bits {
723 return Err(XmlError::Invalid(format!(
724 "node {node} bitfield exceeds register width"
725 )));
726 }
727
728 let offset = match byte_order {
729 ByteOrder::Little => offset_lsb,
730 ByteOrder::Big => total_bits - bit_length - offset_lsb,
731 };
732
733 Ok(Some(BitField {
734 bit_offset: u16::try_from(offset).map_err(|_| {
735 XmlError::Invalid(format!("node {node} bit offset {offset} exceeds u16 range"))
736 })?,
737 bit_length: u16::try_from(bit_length).map_err(|_| {
738 XmlError::Invalid(format!(
739 "node {node} bit length {bit_length} exceeds u16 range"
740 ))
741 })?,
742 byte_order,
743 }))
744 }
745}
746
747fn addressing_lengths(addressing: &Addressing) -> Vec<u32> {
748 match addressing {
749 Addressing::Fixed { len, .. } => vec![*len],
750 Addressing::Indirect { len, .. } => vec![*len],
751 Addressing::BySelector { map, .. } => map.iter().map(|(_, (_, len))| *len).collect(),
752 }
753}
754
755fn parse_integer(reader: &mut Reader<&[u8]>, start: BytesStart<'_>) -> Result<NodeDecl, XmlError> {
756 let name = attribute_value_required(&start, b"Name")?;
757 let mut addressing = AddressingBuilder::default();
758 if let Some(addr) = attribute_value(&start, b"Address")? {
759 addressing.set_fixed_address(parse_u64(&addr)?);
760 }
761 if let Some(len) = attribute_value(&start, b"Length")? {
762 let value = parse_u64(&len)?;
763 let len = u32::try_from(value)
764 .map_err(|_| XmlError::Invalid(format!("length out of range for node {name}")))?;
765 addressing.set_length(len);
766 }
767 let mut access = AccessMode::RW;
768 let mut min = None;
769 let mut max = None;
770 let mut inc = None;
771 let mut unit = None;
772 let mut selectors = Vec::new();
773 let mut selected_if: Vec<(String, Vec<String>)> = Vec::new();
774 let mut last_selector: Option<usize> = None;
775 let node_name = start.name().as_ref().to_vec();
776 let mut buf = Vec::new();
777 let mut bitfield = BitfieldBuilder::default();
778 let mut pending_bit_length = false;
779
780 loop {
781 match reader.read_event_into(&mut buf) {
782 Ok(Event::Start(ref e)) => match e.name().as_ref() {
783 b"Address" => {
784 let text = read_text_start(reader, e)?;
785 addressing.attach_selected_address(parse_u64(&text)?, None);
786 }
787 TAG_P_ADDRESS => {
788 let text = read_text_start(reader, e)?;
789 let target = text.trim();
790 if !target.is_empty() {
791 addressing.set_p_address_node(target);
792 }
793 }
794 b"Length" => {
795 let text = read_text_start(reader, e)?;
796 let value = parse_u64(&text)?;
797 let mut handled = false;
798 if pending_bit_length {
799 if let Ok(bit_len) = u32::try_from(value) {
800 bitfield.note_bit_length(bit_len);
801 pending_bit_length = false;
802 handled = true;
803 } else {
804 return Err(XmlError::Invalid(format!(
805 "bitfield length out of range for node {name}"
806 )));
807 }
808 }
809 if !handled {
810 let len = u32::try_from(value).map_err(|_| {
811 XmlError::Invalid(format!("length out of range for node {name}"))
812 })?;
813 addressing.apply_length(len);
814 }
815 }
816 b"AccessMode" => {
817 let text = read_text_start(reader, e)?;
818 access = AccessMode::parse(&text)?;
819 }
820 b"Min" => {
821 let text = read_text_start(reader, e)?;
822 min = Some(parse_i64(&text)?);
823 }
824 b"Max" => {
825 let text = read_text_start(reader, e)?;
826 max = Some(parse_i64(&text)?);
827 }
828 b"Inc" => {
829 let text = read_text_start(reader, e)?;
830 inc = Some(parse_i64(&text)?);
831 }
832 b"Unit" => {
833 let text = read_text_start(reader, e)?;
834 let trimmed = text.trim();
835 if !trimmed.is_empty() {
836 unit = Some(trimmed.to_string());
837 }
838 }
839 TAG_LSB => {
840 let text = read_text_start(reader, e)?;
841 let value = parse_u64(&text)?;
842 let lsb = u32::try_from(value).map_err(|_| {
843 XmlError::Invalid(format!("<Lsb> out of range for node {name}"))
844 })?;
845 bitfield.note_lsb(lsb);
846 }
847 TAG_MSB => {
848 let text = read_text_start(reader, e)?;
849 let value = parse_u64(&text)?;
850 let msb = u32::try_from(value).map_err(|_| {
851 XmlError::Invalid(format!("<Msb> out of range for node {name}"))
852 })?;
853 bitfield.note_msb(msb);
854 }
855 TAG_BIT => {
856 let text = read_text_start(reader, e)?;
857 let value = parse_u64(&text)?;
858 let bit = u32::try_from(value).map_err(|_| {
859 XmlError::Invalid(format!("<Bit> out of range for node {name}"))
860 })?;
861 bitfield.note_bit(bit);
862 pending_bit_length = true;
863 }
864 TAG_MASK => {
865 let text = read_text_start(reader, e)?;
866 let mask = parse_u64(&text)?;
867 bitfield.note_mask(mask);
868 pending_bit_length = false;
869 }
870 TAG_ENDIANNESS | TAG_ENDIANESS | TAG_BYTE_ORDER => {
871 let text = read_text_start(reader, e)?;
872 if let Some(order) = ByteOrder::parse(&text) {
873 bitfield.note_byte_order(order);
874 }
875 }
876 b"pSelected" => {
877 let text = read_text_start(reader, e)?;
878 let selector = text.trim().to_string();
879 if !selector.is_empty() {
880 selectors.push(selector.clone());
881 selected_if.push((selector.clone(), Vec::new()));
882 last_selector = Some(selected_if.len() - 1);
883 addressing.register_selector(&selector);
884 }
885 }
886 b"Selected" => {
887 let mut value = attribute_value(e, b"Value")?;
888 if value.is_none() {
889 value = attribute_value(e, b"Name")?;
890 }
891 let text = read_text_start(reader, e)?;
892 let trimmed = text.trim();
893 if value.is_none() && !trimmed.is_empty() {
894 value = Some(trimmed.to_string());
895 }
896 if let Some(val) = value.clone() {
897 addressing.push_selected_value(val.clone());
898 if let Some(address_attr) = attribute_value(e, b"Address")? {
899 let len_override = attribute_value(e, b"Length")?
900 .map(|len| -> Result<u32, XmlError> {
901 let value = parse_u64(&len)?;
902 u32::try_from(value).map_err(|_| {
903 XmlError::Invalid(format!(
904 "length out of range for node {name}"
905 ))
906 })
907 })
908 .transpose()?;
909 addressing
910 .attach_selected_address(parse_u64(&address_attr)?, len_override);
911 } else if let Some(len_attr) = attribute_value(e, b"Length")? {
912 let value = parse_u64(&len_attr)?;
913 let len = u32::try_from(value).map_err(|_| {
914 XmlError::Invalid(format!("length out of range for node {name}"))
915 })?;
916 addressing.apply_length(len);
917 }
918 }
919 if let Some(idx) = last_selector {
920 if let Some(value) = value {
921 let trimmed = value.trim();
922 if !trimmed.is_empty() {
923 selected_if[idx].1.push(trimmed.to_string());
924 }
925 } else if !trimmed.is_empty() {
926 selected_if[idx].1.push(trimmed.to_string());
927 }
928 }
929 }
930 _ => skip_element(reader, e.name().as_ref())?,
931 },
932 Ok(Event::Empty(ref e)) => match e.name().as_ref() {
933 b"pSelected" => {
934 if let Some(value) = attribute_value(e, b"Name")? {
935 addressing.register_selector(&value);
936 selectors.push(value.clone());
937 selected_if.push((value, Vec::new()));
938 last_selector = Some(selected_if.len() - 1);
939 }
940 }
941 TAG_P_ADDRESS => {
942 if let Some(value) = attribute_value(e, b"Name")? {
943 let trimmed = value.trim();
944 if !trimmed.is_empty() {
945 addressing.set_p_address_node(trimmed);
946 }
947 }
948 }
949 TAG_LSB => {
950 if let Some(value) = attribute_value(e, TAG_VALUE)? {
951 let parsed = parse_u64(&value)?;
952 let lsb = u32::try_from(parsed).map_err(|_| {
953 XmlError::Invalid(format!("<Lsb> out of range for node {name}"))
954 })?;
955 bitfield.note_lsb(lsb);
956 }
957 }
958 TAG_MSB => {
959 if let Some(value) = attribute_value(e, TAG_VALUE)? {
960 let parsed = parse_u64(&value)?;
961 let msb = u32::try_from(parsed).map_err(|_| {
962 XmlError::Invalid(format!("<Msb> out of range for node {name}"))
963 })?;
964 bitfield.note_msb(msb);
965 }
966 }
967 TAG_BIT => {
968 if let Some(value) = attribute_value(e, TAG_VALUE)? {
969 let parsed = parse_u64(&value)?;
970 let bit = u32::try_from(parsed).map_err(|_| {
971 XmlError::Invalid(format!("<Bit> out of range for node {name}"))
972 })?;
973 bitfield.note_bit(bit);
974 pending_bit_length = true;
975 }
976 }
977 TAG_MASK => {
978 if let Some(value) = attribute_value(e, TAG_VALUE)? {
979 let mask = parse_u64(&value)?;
980 bitfield.note_mask(mask);
981 pending_bit_length = false;
982 }
983 }
984 TAG_ENDIANNESS | TAG_ENDIANESS | TAG_BYTE_ORDER => {
985 if let Some(value) = attribute_value(e, TAG_VALUE)? {
986 if let Some(order) = ByteOrder::parse(&value) {
987 bitfield.note_byte_order(order);
988 }
989 }
990 }
991 b"Selected" => {
992 if let Some(val) = attribute_value(e, b"Value")? {
993 addressing.push_selected_value(val.clone());
994 if let Some(address_attr) = attribute_value(e, b"Address")? {
995 let len_override = attribute_value(e, b"Length")?
996 .map(|len| -> Result<u32, XmlError> {
997 let value = parse_u64(&len)?;
998 u32::try_from(value).map_err(|_| {
999 XmlError::Invalid(format!(
1000 "length out of range for node {name}"
1001 ))
1002 })
1003 })
1004 .transpose()?;
1005 addressing
1006 .attach_selected_address(parse_u64(&address_attr)?, len_override);
1007 } else if let Some(len_attr) = attribute_value(e, b"Length")? {
1008 let value = parse_u64(&len_attr)?;
1009 let len = u32::try_from(value).map_err(|_| {
1010 XmlError::Invalid(format!("length out of range for node {name}"))
1011 })?;
1012 addressing.apply_length(len);
1013 }
1014 if let Some(idx) = last_selector {
1015 selected_if[idx].1.push(val);
1016 }
1017 }
1018 }
1019 _ => {}
1020 },
1021 Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
1022 Ok(Event::Eof) => {
1023 return Err(XmlError::Invalid(format!(
1024 "unterminated Integer node {name}"
1025 )))
1026 }
1027 Err(err) => return Err(XmlError::Xml(err.to_string())),
1028 _ => {}
1029 }
1030 buf.clear();
1031 }
1032
1033 let min =
1034 min.ok_or_else(|| XmlError::Invalid(format!("Integer node {name} is missing <Min>")))?;
1035 let max =
1036 max.ok_or_else(|| XmlError::Invalid(format!("Integer node {name} is missing <Max>")))?;
1037
1038 let addressing = addressing.finalize(&name, Some(4))?;
1039 let lengths = addressing_lengths(&addressing);
1040 let len = lengths
1041 .first()
1042 .copied()
1043 .ok_or_else(|| XmlError::Invalid(format!("node {name} is missing <Length>")))?;
1044 let bitfield = bitfield.finish(&name, &lengths)?;
1045
1046 Ok(NodeDecl::Integer {
1047 name,
1048 addressing,
1049 len,
1050 access,
1051 min,
1052 max,
1053 inc,
1054 unit,
1055 bitfield,
1056 selectors,
1057 selected_if,
1058 })
1059}
1060
1061fn parse_float(reader: &mut Reader<&[u8]>, start: BytesStart<'_>) -> Result<NodeDecl, XmlError> {
1062 let name = attribute_value_required(&start, b"Name")?;
1063 let mut addressing = AddressingBuilder::default();
1064 if let Some(addr) = attribute_value(&start, b"Address")? {
1065 addressing.set_fixed_address(parse_u64(&addr)?);
1066 }
1067 if let Some(len) = attribute_value(&start, b"Length")? {
1068 let value = parse_u64(&len)?;
1069 let len = u32::try_from(value)
1070 .map_err(|_| XmlError::Invalid(format!("length out of range for node {name}")))?;
1071 addressing.set_length(len);
1072 }
1073 let mut access = AccessMode::RW;
1074 let mut min = None;
1075 let mut max = None;
1076 let mut unit = None;
1077 let mut scale_num: Option<i64> = None;
1078 let mut scale_den: Option<i64> = None;
1079 let mut offset = None;
1080 let mut selectors = Vec::new();
1081 let mut selected_if = Vec::new();
1082 let mut last_selector = None;
1083 let node_name = start.name().as_ref().to_vec();
1084 let mut buf = Vec::new();
1085
1086 loop {
1087 match reader.read_event_into(&mut buf) {
1088 Ok(Event::Start(ref e)) => match e.name().as_ref() {
1089 b"Address" => {
1090 let text = read_text_start(reader, e)?;
1091 addressing.attach_selected_address(parse_u64(&text)?, None);
1092 }
1093 TAG_P_ADDRESS => {
1094 let text = read_text_start(reader, e)?;
1095 let target = text.trim();
1096 if !target.is_empty() {
1097 addressing.set_p_address_node(target);
1098 }
1099 }
1100 b"Length" => {
1101 let text = read_text_start(reader, e)?;
1102 let value = parse_u64(&text)?;
1103 let len = u32::try_from(value).map_err(|_| {
1104 XmlError::Invalid(format!("length out of range for node {name}"))
1105 })?;
1106 addressing.apply_length(len);
1107 }
1108 b"AccessMode" => {
1109 let text = read_text_start(reader, e)?;
1110 access = AccessMode::parse(&text)?;
1111 }
1112 b"Min" => {
1113 let text = read_text_start(reader, e)?;
1114 min = Some(parse_f64(&text)?);
1115 }
1116 b"Max" => {
1117 let text = read_text_start(reader, e)?;
1118 max = Some(parse_f64(&text)?);
1119 }
1120 b"Unit" => {
1121 let text = read_text_start(reader, e)?;
1122 let trimmed = text.trim();
1123 if !trimmed.is_empty() {
1124 unit = Some(trimmed.to_string());
1125 }
1126 }
1127 b"Scale" => {
1128 let text = read_text_start(reader, e)?;
1129 let (num, den) = parse_scale(&text)?;
1130 scale_num = Some(num);
1131 scale_den = Some(den);
1132 }
1133 b"ScaleNumerator" => {
1134 let text = read_text_start(reader, e)?;
1135 scale_num = Some(parse_i64(&text)?);
1136 }
1137 b"ScaleDenominator" => {
1138 let text = read_text_start(reader, e)?;
1139 scale_den = Some(parse_i64(&text)?);
1140 }
1141 b"Offset" => {
1142 let text = read_text_start(reader, e)?;
1143 offset = Some(parse_f64(&text)?);
1144 }
1145 b"pSelected" => {
1146 let text = read_text_start(reader, e)?;
1147 let selector = text.trim().to_string();
1148 if !selector.is_empty() {
1149 selectors.push(selector.clone());
1150 selected_if.push((selector.clone(), Vec::new()));
1151 last_selector = Some(selected_if.len() - 1);
1152 addressing.register_selector(&selector);
1153 }
1154 }
1155 b"Selected" => {
1156 let mut value = attribute_value(e, b"Value")?;
1157 if value.is_none() {
1158 value = attribute_value(e, b"Name")?;
1159 }
1160 let text = read_text_start(reader, e)?;
1161 let trimmed = text.trim();
1162 if value.is_none() && !trimmed.is_empty() {
1163 value = Some(trimmed.to_string());
1164 }
1165 if let Some(val) = value.clone() {
1166 addressing.push_selected_value(val.clone());
1167 if let Some(address_attr) = attribute_value(e, b"Address")? {
1168 let len_override = attribute_value(e, b"Length")?
1169 .map(|len| -> Result<u32, XmlError> {
1170 let value = parse_u64(&len)?;
1171 u32::try_from(value).map_err(|_| {
1172 XmlError::Invalid(format!(
1173 "length out of range for node {name}"
1174 ))
1175 })
1176 })
1177 .transpose()?;
1178 addressing
1179 .attach_selected_address(parse_u64(&address_attr)?, len_override);
1180 } else if let Some(len_attr) = attribute_value(e, b"Length")? {
1181 let value = parse_u64(&len_attr)?;
1182 let len = u32::try_from(value).map_err(|_| {
1183 XmlError::Invalid(format!("length out of range for node {name}"))
1184 })?;
1185 addressing.apply_length(len);
1186 }
1187 }
1188 if let Some(idx) = last_selector {
1189 if let Some(value) = value {
1190 let trimmed = value.trim();
1191 if !trimmed.is_empty() {
1192 selected_if[idx].1.push(trimmed.to_string());
1193 }
1194 } else if !trimmed.is_empty() {
1195 selected_if[idx].1.push(trimmed.to_string());
1196 }
1197 }
1198 }
1199 _ => skip_element(reader, e.name().as_ref())?,
1200 },
1201 Ok(Event::Empty(ref e)) => match e.name().as_ref() {
1202 b"pSelected" => {
1203 if let Some(value) = attribute_value(e, b"Name")? {
1204 addressing.register_selector(&value);
1205 selectors.push(value.clone());
1206 selected_if.push((value, Vec::new()));
1207 last_selector = Some(selected_if.len() - 1);
1208 }
1209 }
1210 TAG_P_ADDRESS => {
1211 if let Some(value) = attribute_value(e, b"Name")? {
1212 let trimmed = value.trim();
1213 if !trimmed.is_empty() {
1214 addressing.set_p_address_node(trimmed);
1215 }
1216 }
1217 }
1218 b"Selected" => {
1219 if let Some(val) = attribute_value(e, b"Value")? {
1220 addressing.push_selected_value(val.clone());
1221 if let Some(address_attr) = attribute_value(e, b"Address")? {
1222 let len_override = attribute_value(e, b"Length")?
1223 .map(|len| -> Result<u32, XmlError> {
1224 let value = parse_u64(&len)?;
1225 u32::try_from(value).map_err(|_| {
1226 XmlError::Invalid(format!(
1227 "length out of range for node {name}"
1228 ))
1229 })
1230 })
1231 .transpose()?;
1232 addressing
1233 .attach_selected_address(parse_u64(&address_attr)?, len_override);
1234 } else if let Some(len_attr) = attribute_value(e, b"Length")? {
1235 let value = parse_u64(&len_attr)?;
1236 let len = u32::try_from(value).map_err(|_| {
1237 XmlError::Invalid(format!("length out of range for node {name}"))
1238 })?;
1239 addressing.apply_length(len);
1240 }
1241 if let Some(idx) = last_selector {
1242 selected_if[idx].1.push(val);
1243 }
1244 }
1245 }
1246 _ => {}
1247 },
1248 Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
1249 Ok(Event::Eof) => {
1250 return Err(XmlError::Invalid(format!("unterminated Float node {name}")))
1251 }
1252 Err(err) => return Err(XmlError::Xml(err.to_string())),
1253 _ => {}
1254 }
1255 buf.clear();
1256 }
1257
1258 let min =
1259 min.ok_or_else(|| XmlError::Invalid(format!("Float node {name} is missing <Min>")))?;
1260 let max =
1261 max.ok_or_else(|| XmlError::Invalid(format!("Float node {name} is missing <Max>")))?;
1262 let scale = match (scale_num, scale_den) {
1263 (Some(num), Some(den)) if den != 0 => Some((num, den)),
1264 (None, None) => None,
1265 (Some(num), None) => Some((num, 1)),
1266 _ => None,
1267 };
1268
1269 let addressing = addressing.finalize(&name, Some(8))?;
1270
1271 Ok(NodeDecl::Float {
1272 name,
1273 addressing,
1274 access,
1275 min,
1276 max,
1277 unit,
1278 scale,
1279 offset,
1280 selectors,
1281 selected_if,
1282 })
1283}
1284
1285fn parse_enum(reader: &mut Reader<&[u8]>, start: BytesStart<'_>) -> Result<NodeDecl, XmlError> {
1286 let name = attribute_value_required(&start, b"Name")?;
1287 let mut addressing = AddressingBuilder::default();
1288 if let Some(addr) = attribute_value(&start, b"Address")? {
1289 addressing.set_fixed_address(parse_u64(&addr)?);
1290 }
1291 if let Some(len) = attribute_value(&start, b"Length")? {
1292 let value = parse_u64(&len)?;
1293 let len = u32::try_from(value)
1294 .map_err(|_| XmlError::Invalid(format!("length out of range for node {name}")))?;
1295 addressing.set_length(len);
1296 }
1297 let mut access = AccessMode::RW;
1298 let mut entries = Vec::new();
1299 let mut default = None;
1300 let mut selectors = Vec::new();
1301 let mut selected_if = Vec::new();
1302 let mut last_selector = None;
1303 let node_name = start.name().as_ref().to_vec();
1304 let mut buf = Vec::new();
1305
1306 loop {
1307 match reader.read_event_into(&mut buf) {
1308 Ok(Event::Start(ref e)) => match e.name().as_ref() {
1309 b"Address" => {
1310 let text = read_text_start(reader, e)?;
1311 addressing.attach_selected_address(parse_u64(&text)?, None);
1312 }
1313 TAG_P_ADDRESS => {
1314 let text = read_text_start(reader, e)?;
1315 let target = text.trim();
1316 if !target.is_empty() {
1317 addressing.set_p_address_node(target);
1318 }
1319 }
1320 b"Length" => {
1321 let text = read_text_start(reader, e)?;
1322 let value = parse_u64(&text)?;
1323 let len = u32::try_from(value).map_err(|_| {
1324 XmlError::Invalid(format!("length out of range for node {name}"))
1325 })?;
1326 addressing.apply_length(len);
1327 }
1328 b"AccessMode" => {
1329 let text = read_text_start(reader, e)?;
1330 access = AccessMode::parse(&text)?;
1331 }
1332 b"EnumEntry" => {
1333 let entry = parse_enum_entry(reader, e.clone())?;
1334 entries.push(entry);
1335 }
1336 b"pSelected" => {
1337 let text = read_text_start(reader, e)?;
1338 let selector = text.trim().to_string();
1339 if !selector.is_empty() {
1340 selectors.push(selector.clone());
1341 selected_if.push((selector.clone(), Vec::new()));
1342 last_selector = Some(selected_if.len() - 1);
1343 addressing.register_selector(&selector);
1344 }
1345 }
1346 b"Selected" => {
1347 let mut value = attribute_value(e, b"Value")?;
1348 if value.is_none() {
1349 value = attribute_value(e, b"Name")?;
1350 }
1351 let text = read_text_start(reader, e)?;
1352 let trimmed = text.trim();
1353 if value.is_none() && !trimmed.is_empty() {
1354 value = Some(trimmed.to_string());
1355 }
1356 if let Some(val) = value.clone() {
1357 addressing.push_selected_value(val.clone());
1358 if let Some(address_attr) = attribute_value(e, b"Address")? {
1359 let len_override = attribute_value(e, b"Length")?
1360 .map(|len| -> Result<u32, XmlError> {
1361 let value = parse_u64(&len)?;
1362 u32::try_from(value).map_err(|_| {
1363 XmlError::Invalid(format!(
1364 "length out of range for node {name}"
1365 ))
1366 })
1367 })
1368 .transpose()?;
1369 addressing
1370 .attach_selected_address(parse_u64(&address_attr)?, len_override);
1371 } else if let Some(len_attr) = attribute_value(e, b"Length")? {
1372 let value = parse_u64(&len_attr)?;
1373 let len = u32::try_from(value).map_err(|_| {
1374 XmlError::Invalid(format!("length out of range for node {name}"))
1375 })?;
1376 addressing.apply_length(len);
1377 }
1378 }
1379 if let Some(idx) = last_selector {
1380 if let Some(value) = value {
1381 let trimmed = value.trim();
1382 if !trimmed.is_empty() {
1383 selected_if[idx].1.push(trimmed.to_string());
1384 }
1385 } else if !trimmed.is_empty() {
1386 selected_if[idx].1.push(trimmed.to_string());
1387 }
1388 }
1389 }
1390 b"pValueDefault" => {
1391 let text = read_text_start(reader, e)?;
1392 let trimmed = text.trim();
1393 if !trimmed.is_empty() {
1394 default = Some(trimmed.to_string());
1395 }
1396 }
1397 _ => skip_element(reader, e.name().as_ref())?,
1398 },
1399 Ok(Event::Empty(ref e)) => match e.name().as_ref() {
1400 b"EnumEntry" => {
1401 let entry = parse_enum_entry_empty(e)?;
1402 entries.push(entry);
1403 }
1404 b"pSelected" => {
1405 if let Some(value) = attribute_value(e, b"Name")? {
1406 addressing.register_selector(&value);
1407 selectors.push(value.clone());
1408 selected_if.push((value, Vec::new()));
1409 last_selector = Some(selected_if.len() - 1);
1410 }
1411 }
1412 b"Selected" => {
1413 if let Some(val) = attribute_value(e, b"Value")? {
1414 addressing.push_selected_value(val.clone());
1415 if let Some(address_attr) = attribute_value(e, b"Address")? {
1416 let len_override = attribute_value(e, b"Length")?
1417 .map(|len| -> Result<u32, XmlError> {
1418 let value = parse_u64(&len)?;
1419 u32::try_from(value).map_err(|_| {
1420 XmlError::Invalid(format!(
1421 "length out of range for node {name}"
1422 ))
1423 })
1424 })
1425 .transpose()?;
1426 addressing
1427 .attach_selected_address(parse_u64(&address_attr)?, len_override);
1428 } else if let Some(len_attr) = attribute_value(e, b"Length")? {
1429 let value = parse_u64(&len_attr)?;
1430 let len = u32::try_from(value).map_err(|_| {
1431 XmlError::Invalid(format!("length out of range for node {name}"))
1432 })?;
1433 addressing.apply_length(len);
1434 }
1435 if let Some(idx) = last_selector {
1436 selected_if[idx].1.push(val);
1437 }
1438 }
1439 }
1440 _ => {}
1441 },
1442 Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
1443 Ok(Event::Eof) => {
1444 return Err(XmlError::Invalid(format!(
1445 "unterminated Enumeration node {name}"
1446 )))
1447 }
1448 Err(err) => return Err(XmlError::Xml(err.to_string())),
1449 _ => {}
1450 }
1451 buf.clear();
1452 }
1453
1454 if entries.is_empty() {
1455 return Err(XmlError::Invalid(format!(
1456 "Enumeration node {name} declares no <EnumEntry> elements"
1457 )));
1458 }
1459
1460 let addressing = addressing.finalize(&name, Some(4))?;
1461
1462 Ok(NodeDecl::Enum {
1463 name,
1464 addressing,
1465 access,
1466 entries,
1467 default,
1468 selectors,
1469 selected_if,
1470 })
1471}
1472
1473fn parse_boolean(reader: &mut Reader<&[u8]>, start: BytesStart<'_>) -> Result<NodeDecl, XmlError> {
1474 let name = attribute_value_required(&start, b"Name")?;
1475 let mut addressing = AddressingBuilder::default();
1476 if let Some(addr) = attribute_value(&start, b"Address")? {
1477 addressing.set_fixed_address(parse_u64(&addr)?);
1478 }
1479 if let Some(len) = attribute_value(&start, b"Length")? {
1480 let value = parse_u64(&len)?;
1481 let len = u32::try_from(value)
1482 .map_err(|_| XmlError::Invalid(format!("length out of range for node {name}")))?;
1483 addressing.set_length(len);
1484 }
1485 let mut access = AccessMode::RW;
1486 let mut selectors = Vec::new();
1487 let mut selected_if = Vec::new();
1488 let mut last_selector = None;
1489 let node_name = start.name().as_ref().to_vec();
1490 let mut buf = Vec::new();
1491 let mut bitfield = BitfieldBuilder::default();
1492 let mut pending_bit_length = false;
1493
1494 loop {
1495 match reader.read_event_into(&mut buf) {
1496 Ok(Event::Start(ref e)) => match e.name().as_ref() {
1497 b"Address" => {
1498 let text = read_text_start(reader, e)?;
1499 addressing.attach_selected_address(parse_u64(&text)?, None);
1500 }
1501 TAG_P_ADDRESS => {
1502 let text = read_text_start(reader, e)?;
1503 let target = text.trim();
1504 if !target.is_empty() {
1505 addressing.set_p_address_node(target);
1506 }
1507 }
1508 b"Length" => {
1509 let text = read_text_start(reader, e)?;
1510 let value = parse_u64(&text)?;
1511 let mut handled = false;
1512 if pending_bit_length {
1513 if let Ok(bit_len) = u32::try_from(value) {
1514 bitfield.note_bit_length(bit_len);
1515 pending_bit_length = false;
1516 handled = true;
1517 } else {
1518 return Err(XmlError::Invalid(format!(
1519 "bitfield length out of range for node {name}"
1520 )));
1521 }
1522 }
1523 if !handled {
1524 let len = u32::try_from(value).map_err(|_| {
1525 XmlError::Invalid(format!("length out of range for node {name}"))
1526 })?;
1527 addressing.apply_length(len);
1528 }
1529 }
1530 b"AccessMode" => {
1531 let text = read_text_start(reader, e)?;
1532 access = AccessMode::parse(&text)?;
1533 }
1534 TAG_LSB => {
1535 let text = read_text_start(reader, e)?;
1536 let value = parse_u64(&text)?;
1537 let lsb = u32::try_from(value).map_err(|_| {
1538 XmlError::Invalid(format!("<Lsb> out of range for node {name}"))
1539 })?;
1540 bitfield.note_lsb(lsb);
1541 }
1542 TAG_MSB => {
1543 let text = read_text_start(reader, e)?;
1544 let value = parse_u64(&text)?;
1545 let msb = u32::try_from(value).map_err(|_| {
1546 XmlError::Invalid(format!("<Msb> out of range for node {name}"))
1547 })?;
1548 bitfield.note_msb(msb);
1549 }
1550 TAG_BIT => {
1551 let text = read_text_start(reader, e)?;
1552 let value = parse_u64(&text)?;
1553 let bit = u32::try_from(value).map_err(|_| {
1554 XmlError::Invalid(format!("<Bit> out of range for node {name}"))
1555 })?;
1556 bitfield.note_bit(bit);
1557 pending_bit_length = true;
1558 }
1559 TAG_MASK => {
1560 let text = read_text_start(reader, e)?;
1561 let mask = parse_u64(&text)?;
1562 bitfield.note_mask(mask);
1563 pending_bit_length = false;
1564 }
1565 TAG_ENDIANNESS | TAG_ENDIANESS | TAG_BYTE_ORDER => {
1566 let text = read_text_start(reader, e)?;
1567 if let Some(order) = ByteOrder::parse(&text) {
1568 bitfield.note_byte_order(order);
1569 }
1570 }
1571 b"pSelected" => {
1572 let text = read_text_start(reader, e)?;
1573 let selector = text.trim().to_string();
1574 if !selector.is_empty() {
1575 selectors.push(selector.clone());
1576 selected_if.push((selector.clone(), Vec::new()));
1577 last_selector = Some(selected_if.len() - 1);
1578 addressing.register_selector(&selector);
1579 }
1580 }
1581 b"Selected" => {
1582 let mut value = attribute_value(e, b"Value")?;
1583 if value.is_none() {
1584 value = attribute_value(e, b"Name")?;
1585 }
1586 let text = read_text_start(reader, e)?;
1587 let trimmed = text.trim();
1588 if value.is_none() && !trimmed.is_empty() {
1589 value = Some(trimmed.to_string());
1590 }
1591 if let Some(val) = value.clone() {
1592 addressing.push_selected_value(val.clone());
1593 if let Some(address_attr) = attribute_value(e, b"Address")? {
1594 let len_override = attribute_value(e, b"Length")?
1595 .map(|len| -> Result<u32, XmlError> {
1596 let value = parse_u64(&len)?;
1597 u32::try_from(value).map_err(|_| {
1598 XmlError::Invalid(format!(
1599 "length out of range for node {name}"
1600 ))
1601 })
1602 })
1603 .transpose()?;
1604 addressing
1605 .attach_selected_address(parse_u64(&address_attr)?, len_override);
1606 } else if let Some(len_attr) = attribute_value(e, b"Length")? {
1607 let value = parse_u64(&len_attr)?;
1608 let len = u32::try_from(value).map_err(|_| {
1609 XmlError::Invalid(format!("length out of range for node {name}"))
1610 })?;
1611 addressing.apply_length(len);
1612 }
1613 }
1614 if let Some(idx) = last_selector {
1615 if let Some(value) = value {
1616 let trimmed = value.trim();
1617 if !trimmed.is_empty() {
1618 selected_if[idx].1.push(trimmed.to_string());
1619 }
1620 } else if !trimmed.is_empty() {
1621 selected_if[idx].1.push(trimmed.to_string());
1622 }
1623 }
1624 }
1625 _ => skip_element(reader, e.name().as_ref())?,
1626 },
1627 Ok(Event::Empty(ref e)) => match e.name().as_ref() {
1628 b"pSelected" => {
1629 if let Some(value) = attribute_value(e, b"Name")? {
1630 addressing.register_selector(&value);
1631 selectors.push(value.clone());
1632 selected_if.push((value, Vec::new()));
1633 last_selector = Some(selected_if.len() - 1);
1634 }
1635 }
1636 TAG_P_ADDRESS => {
1637 if let Some(value) = attribute_value(e, b"Name")? {
1638 let trimmed = value.trim();
1639 if !trimmed.is_empty() {
1640 addressing.set_p_address_node(trimmed);
1641 }
1642 }
1643 }
1644 TAG_LSB => {
1645 if let Some(value) = attribute_value(e, TAG_VALUE)? {
1646 let parsed = parse_u64(&value)?;
1647 let lsb = u32::try_from(parsed).map_err(|_| {
1648 XmlError::Invalid(format!("<Lsb> out of range for node {name}"))
1649 })?;
1650 bitfield.note_lsb(lsb);
1651 }
1652 }
1653 TAG_MSB => {
1654 if let Some(value) = attribute_value(e, TAG_VALUE)? {
1655 let parsed = parse_u64(&value)?;
1656 let msb = u32::try_from(parsed).map_err(|_| {
1657 XmlError::Invalid(format!("<Msb> out of range for node {name}"))
1658 })?;
1659 bitfield.note_msb(msb);
1660 }
1661 }
1662 TAG_BIT => {
1663 if let Some(value) = attribute_value(e, TAG_VALUE)? {
1664 let parsed = parse_u64(&value)?;
1665 let bit = u32::try_from(parsed).map_err(|_| {
1666 XmlError::Invalid(format!("<Bit> out of range for node {name}"))
1667 })?;
1668 bitfield.note_bit(bit);
1669 pending_bit_length = true;
1670 }
1671 }
1672 TAG_MASK => {
1673 if let Some(value) = attribute_value(e, TAG_VALUE)? {
1674 let mask = parse_u64(&value)?;
1675 bitfield.note_mask(mask);
1676 pending_bit_length = false;
1677 }
1678 }
1679 TAG_ENDIANNESS | TAG_ENDIANESS | TAG_BYTE_ORDER => {
1680 if let Some(value) = attribute_value(e, TAG_VALUE)? {
1681 if let Some(order) = ByteOrder::parse(&value) {
1682 bitfield.note_byte_order(order);
1683 }
1684 }
1685 }
1686 b"Selected" => {
1687 if let Some(val) = attribute_value(e, b"Value")? {
1688 addressing.push_selected_value(val.clone());
1689 if let Some(address_attr) = attribute_value(e, b"Address")? {
1690 let len_override = attribute_value(e, b"Length")?
1691 .map(|len| -> Result<u32, XmlError> {
1692 let value = parse_u64(&len)?;
1693 u32::try_from(value).map_err(|_| {
1694 XmlError::Invalid(format!(
1695 "length out of range for node {name}"
1696 ))
1697 })
1698 })
1699 .transpose()?;
1700 addressing
1701 .attach_selected_address(parse_u64(&address_attr)?, len_override);
1702 } else if let Some(len_attr) = attribute_value(e, b"Length")? {
1703 let value = parse_u64(&len_attr)?;
1704 let len = u32::try_from(value).map_err(|_| {
1705 XmlError::Invalid(format!("length out of range for node {name}"))
1706 })?;
1707 addressing.apply_length(len);
1708 }
1709 if let Some(idx) = last_selector {
1710 selected_if[idx].1.push(val);
1711 }
1712 }
1713 }
1714 _ => {}
1715 },
1716 Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
1717 Ok(Event::Eof) => {
1718 return Err(XmlError::Invalid(format!(
1719 "unterminated Boolean node {name}"
1720 )))
1721 }
1722 Err(err) => return Err(XmlError::Xml(err.to_string())),
1723 _ => {}
1724 }
1725 buf.clear();
1726 }
1727
1728 let addressing = addressing.finalize(&name, Some(4))?;
1729 let lengths = addressing_lengths(&addressing);
1730 let len = lengths
1731 .first()
1732 .copied()
1733 .ok_or_else(|| XmlError::Invalid(format!("node {name} is missing <Length>")))?;
1734 let bitfield = match bitfield.finish(&name, &lengths)? {
1735 Some(field) => field,
1736 None if len == 1 => BitField {
1737 bit_offset: 0,
1738 bit_length: 1,
1739 byte_order: ByteOrder::Little,
1740 },
1741 None => {
1742 return Err(XmlError::Invalid(format!(
1743 "Boolean node {name} requires explicit bitfield metadata"
1744 )))
1745 }
1746 };
1747
1748 Ok(NodeDecl::Boolean {
1749 name,
1750 addressing,
1751 len,
1752 access,
1753 bitfield,
1754 selectors,
1755 selected_if,
1756 })
1757}
1758
1759fn parse_command(reader: &mut Reader<&[u8]>, start: BytesStart<'_>) -> Result<NodeDecl, XmlError> {
1760 let name = attribute_value_required(&start, b"Name")?;
1761 let mut address = None;
1762 let mut length = None;
1763 let node_name = start.name().as_ref().to_vec();
1764 let mut buf = Vec::new();
1765
1766 loop {
1767 match reader.read_event_into(&mut buf) {
1768 Ok(Event::Start(ref e)) => match e.name().as_ref() {
1769 b"Address" => {
1770 let text = read_text_start(reader, e)?;
1771 address = Some(parse_u64(&text)?);
1772 }
1773 b"Length" => {
1774 let text = read_text_start(reader, e)?;
1775 let value = parse_u64(&text)?;
1776 length = Some(u32::try_from(value).map_err(|_| {
1777 XmlError::Invalid(format!("length out of range for node {name}"))
1778 })?);
1779 }
1780 _ => skip_element(reader, e.name().as_ref())?,
1781 },
1782 Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
1783 Ok(Event::Eof) => {
1784 return Err(XmlError::Invalid(format!(
1785 "unterminated Command node {name}"
1786 )))
1787 }
1788 Err(err) => return Err(XmlError::Xml(err.to_string())),
1789 _ => {}
1790 }
1791 buf.clear();
1792 }
1793
1794 let address = address
1795 .ok_or_else(|| XmlError::Invalid(format!("Command node {name} is missing <Address>")))?;
1796 let length = length.unwrap_or(1);
1797
1798 Ok(NodeDecl::Command {
1799 name,
1800 address,
1801 len: length,
1802 })
1803}
1804
1805fn parse_command_empty(start: &BytesStart<'_>) -> Result<NodeDecl, XmlError> {
1806 let name = attribute_value_required(start, b"Name")?;
1807 let address = attribute_value_required(start, b"Address")?;
1808 let address = parse_u64(&address)?;
1809 let length = attribute_value(start, b"Length")?;
1810 let length = match length {
1811 Some(value) => {
1812 let raw = parse_u64(&value)?;
1813 u32::try_from(raw)
1814 .map_err(|_| XmlError::Invalid("command length out of range".into()))?
1815 }
1816 None => 1,
1817 };
1818 Ok(NodeDecl::Command {
1819 name,
1820 address,
1821 len: length,
1822 })
1823}
1824
1825fn parse_category(reader: &mut Reader<&[u8]>, start: BytesStart<'_>) -> Result<NodeDecl, XmlError> {
1826 let name = attribute_value_required(&start, b"Name")?;
1827 let node_name = start.name().as_ref().to_vec();
1828 let mut children = Vec::new();
1829 let mut buf = Vec::new();
1830
1831 loop {
1832 match reader.read_event_into(&mut buf) {
1833 Ok(Event::Start(ref e)) => match e.name().as_ref() {
1834 b"pFeature" => {
1835 let text = read_text_start(reader, e)?;
1836 let trimmed = text.trim();
1837 if !trimmed.is_empty() {
1838 children.push(trimmed.to_string());
1839 }
1840 }
1841 _ => skip_element(reader, e.name().as_ref())?,
1842 },
1843 Ok(Event::Empty(ref e)) if e.name().as_ref() == b"pFeature" => {
1844 if let Some(value) = attribute_value(e, b"Name")? {
1845 if !value.is_empty() {
1846 children.push(value);
1847 }
1848 }
1849 }
1850 Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
1851 Ok(Event::Eof) => {
1852 return Err(XmlError::Invalid(format!(
1853 "unterminated Category node {name}"
1854 )))
1855 }
1856 Err(err) => return Err(XmlError::Xml(err.to_string())),
1857 _ => {}
1858 }
1859 buf.clear();
1860 }
1861
1862 Ok(NodeDecl::Category { name, children })
1863}
1864
1865fn parse_category_empty(start: &BytesStart<'_>) -> Result<NodeDecl, XmlError> {
1866 let name = attribute_value_required(start, b"Name")?;
1867 Ok(NodeDecl::Category {
1868 name,
1869 children: Vec::new(),
1870 })
1871}
1872
1873fn parse_swissknife(
1874 reader: &mut Reader<&[u8]>,
1875 start: BytesStart<'_>,
1876) -> Result<NodeDecl, XmlError> {
1877 let name = attribute_value_required(&start, b"Name")?;
1878 let mut expr: Option<String> = None;
1879 let mut variables: Vec<(String, String)> = Vec::new();
1880 let mut output = SkOutput::Float;
1881 let node_name = start.name().as_ref().to_vec();
1882 let mut buf = Vec::new();
1883
1884 loop {
1885 match reader.read_event_into(&mut buf) {
1886 Ok(Event::Start(ref e)) => match e.name().as_ref() {
1887 b"Expression" => {
1888 let text = read_text_start(reader, e)?;
1889 let trimmed = text.trim();
1890 if trimmed.is_empty() {
1891 return Err(XmlError::Invalid(format!(
1892 "SwissKnife node {name} has empty <Expression>"
1893 )));
1894 }
1895 expr = Some(trimmed.to_string());
1896 }
1897 b"pVariable" => {
1898 let var_name = attribute_value_required(e, b"Name")?;
1899 let text = read_text_start(reader, e)?;
1900 let target = text.trim();
1901 if target.is_empty() {
1902 return Err(XmlError::Invalid(format!(
1903 "SwissKnife node {name} has empty <pVariable>"
1904 )));
1905 }
1906 variables.push((var_name, target.to_string()));
1907 }
1908 b"Output" => {
1909 let text = read_text_start(reader, e)?;
1910 if let Some(kind) = SkOutput::parse(&text) {
1911 output = kind;
1912 }
1913 }
1914 _ => skip_element(reader, e.name().as_ref())?,
1915 },
1916 Ok(Event::Empty(ref e)) => match e.name().as_ref() {
1917 b"pVariable" => {
1918 let var_name = attribute_value_required(e, b"Name")?;
1919 if let Some(target) = attribute_value(e, TAG_VALUE)? {
1920 if target.is_empty() {
1921 return Err(XmlError::Invalid(format!(
1922 "SwissKnife node {name} has empty <pVariable/>"
1923 )));
1924 }
1925 variables.push((var_name, target));
1926 } else {
1927 return Err(XmlError::Invalid(format!(
1928 "SwissKnife node {name} missing variable target"
1929 )));
1930 }
1931 }
1932 b"Expression" => {
1933 let text = attribute_value_required(e, TAG_VALUE)?;
1934 let trimmed = text.trim();
1935 if trimmed.is_empty() {
1936 return Err(XmlError::Invalid(format!(
1937 "SwissKnife node {name} has empty <Expression/>"
1938 )));
1939 }
1940 expr = Some(trimmed.to_string());
1941 }
1942 b"Output" => {
1943 if let Some(value) = attribute_value(e, TAG_VALUE)? {
1944 if let Some(kind) = SkOutput::parse(&value) {
1945 output = kind;
1946 }
1947 }
1948 }
1949 _ => {}
1950 },
1951 Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
1952 Ok(Event::Eof) => {
1953 return Err(XmlError::Invalid(format!(
1954 "unterminated SwissKnife node {name}"
1955 )))
1956 }
1957 Err(err) => return Err(XmlError::Xml(err.to_string())),
1958 _ => {}
1959 }
1960 buf.clear();
1961 }
1962
1963 let expr = expr.ok_or_else(|| {
1964 XmlError::Invalid(format!("SwissKnife node {name} is missing <Expression>"))
1965 })?;
1966 if variables.is_empty() {
1967 return Err(XmlError::Invalid(format!(
1968 "SwissKnife node {name} must declare at least one <pVariable>"
1969 )));
1970 }
1971
1972 Ok(NodeDecl::SwissKnife(SwissKnifeDecl {
1973 name,
1974 expr,
1975 variables,
1976 output,
1977 }))
1978}
1979
1980fn parse_enum_entry(
1981 reader: &mut Reader<&[u8]>,
1982 start: BytesStart<'_>,
1983) -> Result<EnumEntryDecl, XmlError> {
1984 let mut name = attribute_value_required(&start, b"Name")?;
1985 let mut literal = attribute_value(&start, TAG_VALUE)?;
1986 let mut provider = attribute_value(&start, TAG_P_VALUE)?;
1987 let mut display_name = attribute_value(&start, TAG_DISPLAY_NAME)?;
1988 let node_name = start.name().as_ref().to_vec();
1989 let mut buf = Vec::new();
1990
1991 loop {
1992 match reader.read_event_into(&mut buf) {
1993 Ok(Event::Start(ref e)) => match e.name().as_ref() {
1994 TAG_VALUE => {
1995 let text = read_text_start(reader, e)?;
1996 let trimmed = text.trim();
1997 if !trimmed.is_empty() {
1998 literal = Some(trimmed.to_string());
1999 }
2000 }
2001 TAG_P_VALUE => {
2002 let text = read_text_start(reader, e)?;
2003 let trimmed = text.trim();
2004 if !trimmed.is_empty() {
2005 provider = Some(trimmed.to_string());
2006 }
2007 }
2008 TAG_DISPLAY_NAME => {
2009 let text = read_text_start(reader, e)?;
2010 let trimmed = text.trim();
2011 if !trimmed.is_empty() {
2012 display_name = Some(trimmed.to_string());
2013 }
2014 }
2015 b"Name" => {
2016 let text = read_text_start(reader, e)?;
2017 let trimmed = text.trim();
2018 if !trimmed.is_empty() {
2019 name = trimmed.to_string();
2020 }
2021 }
2022 _ => skip_element(reader, e.name().as_ref())?,
2023 },
2024 Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
2025 Ok(Event::Eof) => {
2026 return Err(XmlError::Invalid("unterminated EnumEntry element".into()))
2027 }
2028 Err(err) => return Err(XmlError::Xml(err.to_string())),
2029 _ => {}
2030 }
2031 buf.clear();
2032 }
2033
2034 build_enum_entry(name, literal, provider, display_name)
2035}
2036
2037fn parse_enum_entry_empty(start: &BytesStart<'_>) -> Result<EnumEntryDecl, XmlError> {
2038 let name = attribute_value_required(start, b"Name")?;
2039 let literal = attribute_value(start, TAG_VALUE)?;
2040 let provider = attribute_value(start, TAG_P_VALUE)?;
2041 let display_name = attribute_value(start, TAG_DISPLAY_NAME)?;
2042 build_enum_entry(name, literal, provider, display_name)
2043}
2044
2045fn build_enum_entry(
2046 name: String,
2047 literal: Option<String>,
2048 provider: Option<String>,
2049 display_name: Option<String>,
2050) -> Result<EnumEntryDecl, XmlError> {
2051 let literal = literal.and_then(|value| {
2052 let trimmed = value.trim();
2053 if trimmed.is_empty() {
2054 None
2055 } else {
2056 Some(trimmed.to_string())
2057 }
2058 });
2059 let provider = provider.and_then(|value| {
2060 let trimmed = value.trim();
2061 if trimmed.is_empty() {
2062 None
2063 } else {
2064 Some(trimmed.to_string())
2065 }
2066 });
2067
2068 if literal.is_some() && provider.is_some() {
2069 warn!(
2070 entry = %name,
2071 "EnumEntry specifies both <Value> and <pValue>; preferring provider"
2072 );
2073 }
2074
2075 let value = if let Some(node) = provider {
2076 EnumValueSrc::FromNode(node)
2077 } else if let Some(value) = literal {
2078 EnumValueSrc::Literal(parse_i64(&value)?)
2079 } else {
2080 return Err(XmlError::Invalid(format!(
2081 "EnumEntry {name} is missing <Value> or <pValue>"
2082 )));
2083 };
2084
2085 Ok(EnumEntryDecl {
2086 name,
2087 value,
2088 display_name,
2089 })
2090}
2091
2092fn parse_scale(text: &str) -> Result<(i64, i64), XmlError> {
2093 let trimmed = text.trim();
2094 if trimmed.is_empty() {
2095 return Err(XmlError::Invalid("empty scale value".into()));
2096 }
2097 if let Some((num, den)) = trimmed.split_once('/') {
2098 let num = parse_i64(num)?;
2099 let den = parse_i64(den)?;
2100 if den == 0 {
2101 return Err(XmlError::Invalid("scale denominator is zero".into()));
2102 }
2103 Ok((num, den))
2104 } else {
2105 let value = parse_f64(trimmed)?;
2106 if value == 0.0 {
2107 return Err(XmlError::Invalid("scale value is zero".into()));
2108 }
2109 let den = 1_000_000i64;
2111 let num = (value * den as f64).round() as i64;
2112 Ok((num, den))
2113 }
2114}
2115
2116fn handle_start(
2117 event: &BytesStart<'_>,
2118 depth: usize,
2119 schema_version: &mut Option<String>,
2120 top_level: &mut Vec<String>,
2121) -> Result<(), XmlError> {
2122 if depth == 1 && schema_version.is_none() {
2123 *schema_version = extract_schema_version(event);
2124 } else if depth == 2 {
2125 if let Some(name) = attribute_value(event, b"Name")? {
2126 top_level.push(name);
2127 } else {
2128 top_level.push(String::from_utf8_lossy(event.name().as_ref()).to_string());
2129 }
2130 }
2131 Ok(())
2132}
2133
2134fn extract_schema_version(event: &BytesStart<'_>) -> Option<String> {
2135 let major = attribute_value(event, b"SchemaMajorVersion").ok().flatten();
2136 let minor = attribute_value(event, b"SchemaMinorVersion").ok().flatten();
2137 let sub = attribute_value(event, b"SchemaSubMinorVersion")
2138 .ok()
2139 .flatten();
2140 if major.is_none() && minor.is_none() && sub.is_none() {
2141 None
2142 } else {
2143 let major = major.unwrap_or_else(|| "0".to_string());
2144 let minor = minor.unwrap_or_else(|| "0".to_string());
2145 let sub = sub.unwrap_or_else(|| "0".to_string());
2146 Some(format!("{major}.{minor}.{sub}"))
2147 }
2148}
2149
2150fn read_text_start(reader: &mut Reader<&[u8]>, start: &BytesStart<'_>) -> Result<String, XmlError> {
2151 let end_buf = start.name().as_ref().to_vec();
2152 reader
2153 .read_text(QName(&end_buf))
2154 .map(|cow| cow.into_owned())
2155 .map_err(|err| XmlError::Xml(err.to_string()))
2156}
2157
2158fn attribute_value(event: &BytesStart<'_>, name: &[u8]) -> Result<Option<String>, XmlError> {
2159 for attr in event.attributes() {
2160 let attr = attr.map_err(|err| XmlError::Xml(err.to_string()))?;
2161 if attr.key.as_ref() == name {
2162 let value = attr
2163 .unescape_value()
2164 .map_err(|err| XmlError::Xml(err.to_string()))?;
2165 let trimmed = value.trim().to_string();
2166 if trimmed.is_empty() {
2167 return Ok(None);
2168 }
2169 return Ok(Some(trimmed));
2170 }
2171 }
2172 Ok(None)
2173}
2174
2175fn attribute_value_required(event: &BytesStart<'_>, name: &[u8]) -> Result<String, XmlError> {
2176 attribute_value(event, name)?.ok_or_else(|| {
2177 XmlError::Invalid(format!(
2178 "missing attribute {}",
2179 String::from_utf8_lossy(name)
2180 ))
2181 })
2182}
2183
2184fn parse_u64(value: &str) -> Result<u64, XmlError> {
2185 let trimmed = value.trim();
2186 if let Some(hex) = trimmed.strip_prefix("0x") {
2187 let hex = hex.replace('_', "");
2188 u64::from_str_radix(&hex, 16)
2189 .map_err(|err| XmlError::Invalid(format!("invalid hex value: {err}")))
2190 } else {
2191 let dec = trimmed.replace('_', "");
2192 dec.parse()
2193 .map_err(|err| XmlError::Invalid(format!("invalid integer: {err}")))
2194 }
2195}
2196
2197fn parse_i64(value: &str) -> Result<i64, XmlError> {
2198 let trimmed = value.trim();
2199 if let Some(hex) = trimmed.strip_prefix("0x") {
2200 let hex = hex.replace('_', "");
2201 i64::from_str_radix(&hex, 16)
2202 .map_err(|err| XmlError::Invalid(format!("invalid hex value: {err}")))
2203 } else {
2204 let dec = trimmed.replace('_', "");
2205 dec.parse()
2206 .map_err(|err| XmlError::Invalid(format!("invalid integer: {err}")))
2207 }
2208}
2209
2210fn parse_f64(value: &str) -> Result<f64, XmlError> {
2211 value
2212 .trim()
2213 .parse()
2214 .map_err(|err| XmlError::Invalid(format!("invalid float: {err}")))
2215}
2216
2217fn skip_element(reader: &mut Reader<&[u8]>, name: &[u8]) -> Result<(), XmlError> {
2218 let mut depth = 1usize;
2219 let mut buf = Vec::new();
2220 while depth > 0 {
2221 match reader.read_event_into(&mut buf) {
2222 Ok(Event::Start(_)) => depth += 1,
2223 Ok(Event::End(ref e)) => {
2224 if e.name().as_ref() == name {
2225 depth -= 1;
2226 }
2227 }
2228 Ok(Event::Eof) => {
2229 return Err(XmlError::Invalid("unexpected end of file".into()));
2230 }
2231 Err(err) => return Err(XmlError::Xml(err.to_string())),
2232 _ => {}
2233 }
2234 buf.clear();
2235 }
2236 Ok(())
2237}
2238
2239#[derive(Debug, Clone, PartialEq, Eq)]
2240pub struct MinimalXmlInfo {
2241 pub schema_version: Option<String>,
2242 pub top_level_features: Vec<String>,
2243}
2244
2245fn first_cstring(bytes: &[u8]) -> Option<String> {
2246 let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
2247 let slice = &bytes[..end];
2248 let value = String::from_utf8_lossy(slice).trim().to_string();
2249 if value.is_empty() {
2250 None
2251 } else {
2252 Some(value)
2253 }
2254}
2255
2256#[derive(Debug)]
2257enum UrlLocation {
2258 Local { address: u64, length: usize },
2259 LocalNamed(String),
2260 Http(String),
2261 File(String),
2262}
2263
2264impl UrlLocation {
2265 fn parse(url: &str) -> Result<Self, XmlError> {
2266 if let Some(rest) = url.strip_prefix("local:") {
2267 parse_local_url(rest)
2268 } else if url.starts_with("http://") || url.starts_with("https://") {
2269 Ok(UrlLocation::Http(url.to_string()))
2270 } else if url.starts_with("file://") {
2271 Ok(UrlLocation::File(url.to_string()))
2272 } else {
2273 Err(XmlError::Unsupported(format!("unknown URL scheme: {url}")))
2274 }
2275 }
2276}
2277
2278fn parse_local_url(rest: &str) -> Result<UrlLocation, XmlError> {
2279 let trimmed = rest.trim();
2280 if trimmed.is_empty() {
2281 return Err(XmlError::Invalid("empty local URL".into()));
2282 }
2283 let mut address = None;
2284 let mut length = None;
2285 for part in trimmed.split([';', ',']) {
2286 let token = part.trim();
2287 if token.is_empty() {
2288 continue;
2289 }
2290 if let Some((key, value)) = token.split_once('=') {
2291 let key = key.trim().to_ascii_lowercase();
2292 let value = value.trim();
2293 match key.as_str() {
2294 "address" | "addr" | "offset" => {
2295 address = Some(parse_u64(value)?);
2296 }
2297 "length" | "size" => {
2298 let len = parse_u64(value)?;
2299 length = Some(
2300 len.try_into()
2301 .map_err(|_| XmlError::Invalid("length does not fit usize".into()))?,
2302 );
2303 }
2304 _ => {}
2305 }
2306 } else if token.starts_with("0x") {
2307 address = Some(parse_u64(token)?);
2308 } else {
2309 return Ok(UrlLocation::LocalNamed(token.to_string()));
2310 }
2311 }
2312 match (address, length) {
2313 (Some(address), Some(length)) => Ok(UrlLocation::Local { address, length }),
2314 _ => Err(XmlError::Invalid(format!("unsupported local URL: {rest}"))),
2315 }
2316}
2317
2318#[cfg(test)]
2319mod tests {
2320 use super::*;
2321
2322 const FIXTURE: &str = r#"
2323 <RegisterDescription SchemaMajorVersion="1" SchemaMinorVersion="2" SchemaSubMinorVersion="3">
2324 <Category Name="Root">
2325 <pFeature>Gain</pFeature>
2326 <pFeature>GainSelector</pFeature>
2327 </Category>
2328 <Integer Name="Width">
2329 <Address>0x0000_0100</Address>
2330 <Length>4</Length>
2331 <AccessMode>RW</AccessMode>
2332 <Min>16</Min>
2333 <Max>4096</Max>
2334 <Inc>2</Inc>
2335 </Integer>
2336 <Float Name="ExposureTime">
2337 <Address>0x0000_0200</Address>
2338 <Length>4</Length>
2339 <AccessMode>RW</AccessMode>
2340 <Min>10.0</Min>
2341 <Max>200000.0</Max>
2342 <Scale>1/1000</Scale>
2343 <Offset>0.0</Offset>
2344 </Float>
2345 <Enumeration Name="GainSelector">
2346 <Address>0x0000_0300</Address>
2347 <Length>2</Length>
2348 <AccessMode>RW</AccessMode>
2349 <EnumEntry Name="AnalogAll" Value="0" />
2350 <EnumEntry Name="DigitalAll" Value="1" />
2351 </Enumeration>
2352 <Integer Name="Gain">
2353 <Address>0x0000_0304</Address>
2354 <Length>2</Length>
2355 <AccessMode>RW</AccessMode>
2356 <Min>0</Min>
2357 <Max>48</Max>
2358 <pSelected>GainSelector</pSelected>
2359 <Selected>AnalogAll</Selected>
2360 </Integer>
2361 <Boolean Name="GammaEnable">
2362 <Address>0x0000_0400</Address>
2363 <Length>1</Length>
2364 <AccessMode>RW</AccessMode>
2365 </Boolean>
2366 <Command Name="AcquisitionStart">
2367 <Address>0x0000_0500</Address>
2368 <Length>4</Length>
2369 </Command>
2370 </RegisterDescription>
2371 "#;
2372
2373 #[tokio::test]
2374 async fn parse_minimal_xml() {
2375 let info = parse_into_minimal_nodes(FIXTURE).expect("parse xml");
2376 assert_eq!(info.schema_version.as_deref(), Some("1.2.3"));
2377 assert_eq!(info.top_level_features.len(), 7);
2378 assert_eq!(info.top_level_features[0], "Root");
2379
2380 let data = b"local:address=0x10;length=0x3\0".to_vec();
2381 let xml_payload = b"<a/>".to_vec();
2382 let loaded = fetch_and_load_xml(|addr, len| {
2383 let data = data.clone();
2384 let xml_payload = xml_payload.clone();
2385 async move {
2386 if addr == FIRST_URL_ADDRESS {
2387 Ok(data)
2388 } else if addr == 0x10 && len == 0x3 {
2389 Ok(xml_payload)
2390 } else {
2391 Err(XmlError::Transport("unexpected read".into()))
2392 }
2393 }
2394 })
2395 .await
2396 .expect("load xml");
2397 assert_eq!(loaded, "<a/>");
2398 }
2399
2400 #[test]
2401 fn parse_fixture_model() {
2402 let model = parse(FIXTURE).expect("parse fixture");
2403 assert_eq!(model.version, "1.2.3");
2404 assert_eq!(model.nodes.len(), 7);
2405 match &model.nodes[0] {
2406 NodeDecl::Category { name, children } => {
2407 assert_eq!(name, "Root");
2408 assert_eq!(
2409 children,
2410 &vec!["Gain".to_string(), "GainSelector".to_string()]
2411 );
2412 }
2413 other => panic!("unexpected node: {other:?}"),
2414 }
2415 match &model.nodes[1] {
2416 NodeDecl::Integer {
2417 name,
2418 min,
2419 max,
2420 inc,
2421 ..
2422 } => {
2423 assert_eq!(name, "Width");
2424 assert_eq!(*min, 16);
2425 assert_eq!(*max, 4096);
2426 assert_eq!(*inc, Some(2));
2427 }
2428 other => panic!("unexpected node: {other:?}"),
2429 }
2430 match &model.nodes[2] {
2431 NodeDecl::Float {
2432 name,
2433 scale,
2434 offset,
2435 ..
2436 } => {
2437 assert_eq!(name, "ExposureTime");
2438 assert_eq!(*scale, Some((1, 1000)));
2439 assert_eq!(*offset, Some(0.0));
2440 }
2441 other => panic!("unexpected node: {other:?}"),
2442 }
2443 match &model.nodes[3] {
2444 NodeDecl::Enum { name, entries, .. } => {
2445 assert_eq!(name, "GainSelector");
2446 assert_eq!(entries.len(), 2);
2447 assert!(matches!(entries[0].value, EnumValueSrc::Literal(0)));
2448 assert!(matches!(entries[1].value, EnumValueSrc::Literal(1)));
2449 }
2450 other => panic!("unexpected node: {other:?}"),
2451 }
2452 match &model.nodes[4] {
2453 NodeDecl::Integer {
2454 name, selected_if, ..
2455 } => {
2456 assert_eq!(name, "Gain");
2457 assert_eq!(selected_if.len(), 1);
2458 assert_eq!(selected_if[0].0, "GainSelector");
2459 assert_eq!(selected_if[0].1, vec!["AnalogAll".to_string()]);
2460 }
2461 other => panic!("unexpected node: {other:?}"),
2462 }
2463 }
2464
2465 #[test]
2466 fn parse_swissknife_node() {
2467 const XML: &str = r#"
2468 <RegisterDescription SchemaMajorVersion="1" SchemaMinorVersion="0" SchemaSubMinorVersion="0">
2469 <Integer Name="GainRaw">
2470 <Address>0x3000</Address>
2471 <Length>4</Length>
2472 <AccessMode>RW</AccessMode>
2473 <Min>0</Min>
2474 <Max>1000</Max>
2475 </Integer>
2476 <Float Name="Offset">
2477 <Address>0x3008</Address>
2478 <Length>4</Length>
2479 <AccessMode>RW</AccessMode>
2480 <Min>-100.0</Min>
2481 <Max>100.0</Max>
2482 </Float>
2483 <SwissKnife Name="ComputedGain">
2484 <Expression>(GainRaw * 0.5) + Offset</Expression>
2485 <pVariable Name="GainRaw">GainRaw</pVariable>
2486 <pVariable Name="Offset">Offset</pVariable>
2487 <Output>Float</Output>
2488 </SwissKnife>
2489 </RegisterDescription>
2490 "#;
2491
2492 let model = parse(XML).expect("parse swissknife xml");
2493 assert_eq!(model.nodes.len(), 3);
2494 let swiss = model
2495 .nodes
2496 .iter()
2497 .find_map(|decl| match decl {
2498 NodeDecl::SwissKnife(node) => Some(node),
2499 _ => None,
2500 })
2501 .expect("swissknife present");
2502 assert_eq!(swiss.name, "ComputedGain");
2503 assert_eq!(swiss.expr, "(GainRaw * 0.5) + Offset");
2504 assert_eq!(swiss.output, SkOutput::Float);
2505 assert_eq!(swiss.variables.len(), 2);
2506 assert_eq!(
2507 swiss.variables[0],
2508 ("GainRaw".to_string(), "GainRaw".to_string())
2509 );
2510 assert_eq!(
2511 swiss.variables[1],
2512 ("Offset".to_string(), "Offset".to_string())
2513 );
2514 }
2515
2516 #[test]
2517 fn parse_enum_entry_with_pvalue() {
2518 const XML: &str = r#"
2519 <RegisterDescription SchemaMajorVersion="1" SchemaMinorVersion="0" SchemaSubMinorVersion="0">
2520 <Enumeration Name="Mode">
2521 <Address>0x0000_4000</Address>
2522 <Length>4</Length>
2523 <AccessMode>RW</AccessMode>
2524 <EnumEntry Name="Fixed10">
2525 <Value>10</Value>
2526 </EnumEntry>
2527 <EnumEntry Name="DynFromReg">
2528 <pValue>RegModeVal</pValue>
2529 </EnumEntry>
2530 </Enumeration>
2531 <Integer Name="RegModeVal">
2532 <Address>0x0000_4100</Address>
2533 <Length>4</Length>
2534 <AccessMode>RW</AccessMode>
2535 <Min>0</Min>
2536 <Max>65535</Max>
2537 </Integer>
2538 </RegisterDescription>
2539 "#;
2540
2541 let model = parse(XML).expect("parse enum pvalue");
2542 assert_eq!(model.nodes.len(), 2);
2543 match &model.nodes[0] {
2544 NodeDecl::Enum { entries, .. } => {
2545 assert_eq!(entries.len(), 2);
2546 assert!(matches!(entries[0].value, EnumValueSrc::Literal(10)));
2547 match &entries[1].value {
2548 EnumValueSrc::FromNode(node) => assert_eq!(node, "RegModeVal"),
2549 other => panic!("unexpected entry value: {other:?}"),
2550 }
2551 }
2552 other => panic!("unexpected node: {other:?}"),
2553 }
2554 }
2555
2556 #[test]
2557 fn parse_indirect_addressing() {
2558 const XML: &str = r#"
2559 <RegisterDescription SchemaMajorVersion="1" SchemaMinorVersion="0" SchemaSubMinorVersion="0">
2560 <Integer Name="RegAddr">
2561 <Address>0x2000</Address>
2562 <Length>4</Length>
2563 <AccessMode>RW</AccessMode>
2564 <Min>0</Min>
2565 <Max>65535</Max>
2566 </Integer>
2567 <Integer Name="Gain" Address="0xFFFF">
2568 <pAddress>RegAddr</pAddress>
2569 <Length>4</Length>
2570 <AccessMode>RW</AccessMode>
2571 <Min>0</Min>
2572 <Max>255</Max>
2573 </Integer>
2574 </RegisterDescription>
2575 "#;
2576
2577 let model = parse(XML).expect("parse indirect xml");
2578 assert_eq!(model.nodes.len(), 2);
2579 match &model.nodes[0] {
2580 NodeDecl::Integer {
2581 name, addressing, ..
2582 } => {
2583 assert_eq!(name, "RegAddr");
2584 assert!(
2585 matches!(addressing, Addressing::Fixed { address, len } if *address == 0x2000 && *len == 4)
2586 );
2587 }
2588 other => panic!("unexpected node: {other:?}"),
2589 }
2590 match &model.nodes[1] {
2591 NodeDecl::Integer {
2592 name, addressing, ..
2593 } => {
2594 assert_eq!(name, "Gain");
2595 match addressing {
2596 Addressing::Indirect {
2597 p_address_node,
2598 len,
2599 } => {
2600 assert_eq!(p_address_node, "RegAddr");
2601 assert_eq!(*len, 4);
2602 }
2603 other => panic!("expected indirect addressing, got {other:?}"),
2604 }
2605 }
2606 other => panic!("unexpected node: {other:?}"),
2607 }
2608 }
2609
2610 #[test]
2611 fn parse_integer_bitfield_big_endian() {
2612 const XML: &str = r#"
2613 <RegisterDescription SchemaMajorVersion="1" SchemaMinorVersion="0" SchemaSubMinorVersion="0">
2614 <Integer Name="Packed">
2615 <Address>0x1000</Address>
2616 <Length>4</Length>
2617 <AccessMode>RW</AccessMode>
2618 <Min>0</Min>
2619 <Max>65535</Max>
2620 <Lsb>8</Lsb>
2621 <Msb>15</Msb>
2622 <Endianness>BigEndian</Endianness>
2623 </Integer>
2624 </RegisterDescription>
2625 "#;
2626
2627 let model = parse(XML).expect("parse big-endian bitfield");
2628 assert_eq!(model.nodes.len(), 1);
2629 match &model.nodes[0] {
2630 NodeDecl::Integer { len, bitfield, .. } => {
2631 assert_eq!(*len, 4);
2632 let field = bitfield.expect("bitfield present");
2633 assert_eq!(field.byte_order, ByteOrder::Big);
2634 assert_eq!(field.bit_length, 8);
2635 assert_eq!(field.bit_offset, 16);
2636 }
2637 other => panic!("unexpected node: {other:?}"),
2638 }
2639 }
2640
2641 #[test]
2642 fn parse_boolean_bitfield_default_length() {
2643 const XML: &str = r#"
2644 <RegisterDescription SchemaMajorVersion="1" SchemaMinorVersion="0" SchemaSubMinorVersion="0">
2645 <Boolean Name="Flag">
2646 <Address>0x2000</Address>
2647 <Length>1</Length>
2648 <AccessMode>RW</AccessMode>
2649 <Bit>3</Bit>
2650 </Boolean>
2651 </RegisterDescription>
2652 "#;
2653
2654 let model = parse(XML).expect("parse boolean bitfield");
2655 assert_eq!(model.nodes.len(), 1);
2656 match &model.nodes[0] {
2657 NodeDecl::Boolean { len, bitfield, .. } => {
2658 assert_eq!(*len, 1);
2659 assert_eq!(bitfield.byte_order, ByteOrder::Little);
2660 assert_eq!(bitfield.bit_length, 1);
2661 assert_eq!(bitfield.bit_offset, 3);
2662 }
2663 other => panic!("unexpected node: {other:?}"),
2664 }
2665 }
2666
2667 #[test]
2668 fn parse_integer_bitfield_mask() {
2669 const XML: &str = r#"
2670 <RegisterDescription SchemaMajorVersion="1" SchemaMinorVersion="0" SchemaSubMinorVersion="0">
2671 <Integer Name="Masked">
2672 <Address>0x3000</Address>
2673 <Length>4</Length>
2674 <AccessMode>RW</AccessMode>
2675 <Min>0</Min>
2676 <Max>65535</Max>
2677 <Mask>0x0000FF00</Mask>
2678 </Integer>
2679 </RegisterDescription>
2680 "#;
2681
2682 let model = parse(XML).expect("parse mask bitfield");
2683 assert_eq!(model.nodes.len(), 1);
2684 match &model.nodes[0] {
2685 NodeDecl::Integer { bitfield, .. } => {
2686 let field = bitfield.expect("bitfield present");
2687 assert_eq!(field.byte_order, ByteOrder::Little);
2688 assert_eq!(field.bit_length, 8);
2689 assert_eq!(field.bit_offset, 8);
2690 }
2691 other => panic!("unexpected node: {other:?}"),
2692 }
2693 }
2694}