1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 ZeroDDS Contributors
//! `XmlError` — Fehler-Enum fuer den DDS-XML-Loader.
//!
//! Spec-Referenzen siehe Doc-Comment pro Variante.
use alloc::string::String;
use core::fmt;
/// Fehler beim Parsen oder Aufloesen eines DDS-XML-Dokuments.
///
/// Spec-Quelle: OMG DDS-XML 1.0 §7.1 (XML Representation Syntax) und
/// §7.2 (XML Representation of DDS IDL PSM).
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum XmlError {
/// XML ist nicht wohlgeformt gemaess [XML] §2.1.
///
/// Spec-Ref: DDS-XML 1.0 §7.1.1 ("XML shall be well-formed").
InvalidXml(String),
/// Ein gemaess Spec-Tabelle 7.2 / 7.3.x verpflichtendes Element fehlt.
///
/// Spec-Ref: DDS-XML 1.0 §7.1.4 Tab.7.1, §7.2.x.
MissingRequiredElement(String),
/// Ein Element, das nicht in der Element-Tabelle 7.1/7.2/7.3 steht,
/// wurde gefunden. Strict-Modus rejected; Lax-Modus ignoriert.
///
/// Spec-Ref: DDS-XML 1.0 §7.1.4 (Element-Werte-Tabelle).
UnknownElement(String),
/// Enum-String passt nicht in die DCPS-IDL-Whitelist
/// (Spec §7.1.4 Tab.7.1 — `enum`-Werte sind String-Literale, *nicht*
/// numerisch).
///
/// Spec-Ref: DDS-XML 1.0 §7.1.4 Tab.7.1 (enum), §7.2.1.
BadEnum(String),
/// `base_name`-Inheritance bildet einen Zyklus (A erbt von B erbt von A).
///
/// Spec-Ref: DDS-XML 1.0 §7.3.2.4.2 (QoS Profile Inheritance —
/// "shall only inherit from previously defined profiles"). Naive
/// Implementierungen koennen Zyklen ueber Bibliotheks-Grenzen
/// erzeugen; der Loader fuehrt darum DAG-Pruefung durch.
CircularInheritance(String),
/// Element-Wert ausserhalb des Spec-Wertebereichs (z.B. `long` >
/// `0x7fffffff` ohne Symbol-Aliasing).
///
/// Spec-Ref: DDS-XML 1.0 §7.1.4 Tab.7.1 (Wertebereiche), §7.2.2
/// (`LENGTH_UNLIMITED`, `DURATION_INFINITE_*`).
ValueOutOfRange(String),
/// DoS-Cap getroffen — Liste/String ueberschreitet die im Loader
/// konfigurierte Obergrenze (Default: 1024 Listen-Elemente, 64 KiB
/// Strings).
///
/// Kein direkter Spec-Bezug; folgt der ZeroDDS-Security-Posture
/// (`docs/spec-coverage/zerodds-xml-1.0.open.md` Risiken-Abschnitt).
LimitExceeded(String),
/// Eine Cross-Reference (z.B. `base_name` einer QoS-Profile-
/// Inheritance) konnte nicht aufgeloest werden, weil das referenzierte
/// Item nicht existiert.
///
/// Spec-Ref: DDS-XML 1.0 §7.3.2.4.2 (QoS-Profile-Inheritance).
UnresolvedReference(String),
}
impl fmt::Display for XmlError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidXml(msg) => write!(f, "invalid XML: {msg}"),
Self::MissingRequiredElement(name) => {
write!(f, "missing required element <{name}>")
}
Self::UnknownElement(name) => write!(f, "unknown element <{name}>"),
Self::BadEnum(value) => write!(f, "invalid enum value `{value}`"),
Self::CircularInheritance(chain) => {
write!(f, "circular base_name inheritance: {chain}")
}
Self::ValueOutOfRange(msg) => write!(f, "value out of range: {msg}"),
Self::LimitExceeded(msg) => write!(f, "DoS limit exceeded: {msg}"),
Self::UnresolvedReference(name) => write!(f, "unresolved reference `{name}`"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for XmlError {}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
use alloc::string::ToString;
#[test]
fn display_invalid_xml() {
let e = XmlError::InvalidXml("unexpected token".into());
assert_eq!(e.to_string(), "invalid XML: unexpected token");
}
#[test]
fn display_missing_required() {
let e = XmlError::MissingRequiredElement("qos_profile".into());
assert_eq!(e.to_string(), "missing required element <qos_profile>");
}
#[test]
fn display_unknown_element() {
let e = XmlError::UnknownElement("foo".into());
assert_eq!(e.to_string(), "unknown element <foo>");
}
#[test]
fn display_bad_enum() {
let e = XmlError::BadEnum("WRONG".into());
assert_eq!(e.to_string(), "invalid enum value `WRONG`");
}
#[test]
fn display_circular() {
let e = XmlError::CircularInheritance("A -> B -> A".into());
assert_eq!(e.to_string(), "circular base_name inheritance: A -> B -> A");
}
#[test]
fn display_value_out_of_range() {
let e = XmlError::ValueOutOfRange("long > 0x7fffffff".into());
assert_eq!(e.to_string(), "value out of range: long > 0x7fffffff");
}
#[test]
fn display_limit_exceeded() {
let e = XmlError::LimitExceeded("seq > 1024".into());
assert_eq!(e.to_string(), "DoS limit exceeded: seq > 1024");
}
#[test]
fn equality_and_clone() {
let a = XmlError::InvalidXml("x".into());
let b = a.clone();
assert_eq!(a, b);
}
#[test]
fn display_unresolved_reference() {
let e = XmlError::UnresolvedReference("MissingProfile".into());
assert_eq!(e.to_string(), "unresolved reference `MissingProfile`");
}
}