1mod decode;
25mod encode;
26mod text;
27
28use crate::android::{self, AttrDef, AttrFormat};
29use crate::res::{ChunkError, ResourceId, ResourceRef, ResourceRefError, StringPoolError, Value};
30
31pub use crate::android::NAMESPACE as ANDROID_NAMESPACE;
32
33#[derive(Debug, thiserror::Error)]
35#[non_exhaustive]
36pub enum XmlError {
37 #[error(transparent)]
38 Chunk(#[from] ChunkError),
39 #[error(transparent)]
40 StringPool(#[from] StringPoolError),
41 #[error("binary XML has no string pool before its first node")]
42 MissingStringPool,
43 #[error("string index {index} is outside the string pool")]
44 StringOutOfRange { index: u32 },
45 #[error("{kind} node at offset {offset:#x} is truncated")]
46 TruncatedNode { kind: NodeKind, offset: usize },
47 #[error("closing tag </{found}> does not match open element <{expected}>")]
48 MismatchedEnd { expected: String, found: String },
49 #[error("closing tag namespace {found:?} does not match open namespace {expected:?}")]
50 MismatchedNamespace { expected: Option<String>, found: Option<String> },
51 #[error("closing tag </{found}> has no open element")]
52 UnexpectedEnd { found: String },
53 #[error("{count} element(s) are never closed")]
54 Unclosed { count: usize },
55 #[error("document has no root element")]
56 NoRoot,
57 #[error("document has more than one root element")]
58 MultipleRoots,
59 #[error("elements nest deeper than {max} levels", max = MAX_DEPTH)]
60 TooDeep,
61 #[error("android:{name} is not a public framework attribute")]
62 UnknownAttribute { name: String },
63 #[error(transparent)]
64 Reference(#[from] ResourceRefError),
65 #[error("reference {reference} cannot be resolved")]
66 UnresolvedReference { reference: ResourceRef },
67 #[error("value {value:?} is not a valid {format:?} for android:{attribute}")]
68 InvalidAttributeValue { attribute: &'static str, value: String, format: AttrFormat },
69 #[error("android:{attribute} accepts {format:?}, not {value:?}")]
70 MistypedValue { attribute: &'static str, value: Value, format: AttrFormat },
71 #[error("{name} in {namespace} is an app-defined attribute, which this crate cannot compile")]
72 AppAttribute { namespace: String, name: String },
73 #[error("namespace prefix `{prefix}` is not declared")]
74 UndeclaredPrefix { prefix: String },
75 #[error("entity &{name}; is not defined (only the predefined XML entities are)")]
76 UnknownEntity { name: String },
77 #[error("XML syntax error: {0}")]
78 Syntax(#[from] quick_xml::Error),
79}
80
81#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
83pub enum NodeKind {
84 Namespace,
85 StartElement,
86 Attribute,
87 EndElement,
88 Text,
89}
90
91impl std::fmt::Display for NodeKind {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.write_str(match self {
94 Self::Namespace => "namespace",
95 Self::StartElement => "element start",
96 Self::Attribute => "attribute",
97 Self::EndElement => "element end",
98 Self::Text => "text",
99 })
100 }
101}
102
103pub const MAX_DEPTH: usize = 512;
105
106#[derive(Clone, Debug, PartialEq)]
108pub struct Document {
109 pub root: Element,
110}
111
112impl Document {
113 pub fn new(root: Element) -> Self {
114 Self { root }
115 }
116}
117
118#[derive(Clone, Debug, Eq, Hash, PartialEq)]
120pub struct Namespace {
121 pub prefix: Option<String>,
123 pub uri: String,
124}
125
126impl Namespace {
127 pub fn android() -> Self {
129 Self { prefix: Some("android".into()), uri: ANDROID_NAMESPACE.into() }
130 }
131}
132
133#[derive(Clone, Debug, PartialEq)]
135pub enum Node {
136 Element(Element),
137 Text(String),
138}
139
140#[derive(Clone, Debug, Default, PartialEq)]
142pub struct Element {
143 pub name: String,
145 pub namespace: Option<String>,
147 pub namespaces: Vec<Namespace>,
149 pub attributes: Vec<Attribute>,
150 pub children: Vec<Node>,
151}
152
153#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
158pub struct AttrName {
159 pub namespace: Option<String>,
160 pub name: String,
161 pub id: Option<ResourceId>,
162}
163
164impl AttrName {
165 pub fn plain(name: impl Into<String>) -> Self {
167 Self { namespace: None, name: name.into(), id: None }
168 }
169
170 pub fn android(def: &AttrDef) -> Self {
172 Self { namespace: Some(ANDROID_NAMESPACE.into()), name: def.name().into(), id: Some(def.id()) }
173 }
174
175 pub fn android_def(&self) -> Option<&'static AttrDef> {
177 if self.namespace.as_deref() != Some(ANDROID_NAMESPACE) {
178 return None;
179 }
180 match self.id {
181 Some(id) => android::attr_by_id(id),
182 None => android::find_attr(&self.name),
183 }
184 }
185
186 pub fn resource_id(&self) -> Option<ResourceId> {
188 self.id.or_else(|| self.android_def().map(AttrDef::id))
189 }
190
191 pub(crate) fn sort_key(&self) -> (bool, Option<ResourceId>, Option<&str>, &str) {
194 let id = self.resource_id();
195 (id.is_none(), id, self.namespace.as_deref(), &self.name)
196 }
197
198 fn matches(&self, namespace: Option<&str>, name: &str) -> bool {
199 self.namespace.as_deref() == namespace && self.name == name
200 }
201
202 fn same(&self, other: &Self) -> bool {
205 match (self.resource_id(), other.resource_id()) {
206 (Some(a), Some(b)) => a == b,
207 _ => self.matches(other.namespace.as_deref(), &other.name),
208 }
209 }
210}
211
212impl From<&AttrDef> for AttrName {
213 fn from(def: &AttrDef) -> Self {
214 Self::android(def)
215 }
216}
217
218impl From<&str> for AttrName {
219 fn from(name: &str) -> Self {
220 Self::plain(name)
221 }
222}
223
224#[derive(Clone, Debug, PartialEq)]
226pub struct Attribute {
227 pub name: AttrName,
228 pub value: Value,
229}
230
231impl Element {
232 pub fn new(name: impl Into<String>) -> Self {
233 Self { name: name.into(), ..Self::default() }
234 }
235
236 pub fn with_android_namespace(mut self) -> Self {
238 self.namespaces.push(Namespace::android());
239 self
240 }
241
242 pub fn with_attr(mut self, name: impl Into<AttrName>, value: impl Into<Value>) -> Self {
244 self.set_attr(name, value);
245 self
246 }
247
248 pub fn with_opt_attr<V: Into<Value>>(mut self, name: impl Into<AttrName>, value: Option<V>) -> Self {
250 if let Some(value) = value {
251 self.set_attr(name, value);
252 }
253 self
254 }
255
256 pub fn with_child(mut self, child: Element) -> Self {
257 self.children.push(Node::Element(child));
258 self
259 }
260
261 pub fn with_children(mut self, children: impl IntoIterator<Item = Element>) -> Self {
262 self.children.extend(children.into_iter().map(Node::Element));
263 self
264 }
265
266 pub fn set_attr(&mut self, name: impl Into<AttrName>, value: impl Into<Value>) -> &mut Self {
272 let name = name.into();
273 let value = value.into();
274 match self.attributes.iter_mut().find(|a| a.name.same(&name)) {
275 Some(existing) => existing.value = value,
276 None => {
277 let key = name.sort_key();
278 let index = self.attributes.partition_point(|a| a.name.sort_key() <= key);
279 self.attributes.insert(index, Attribute { name, value });
280 }
281 }
282 self
283 }
284
285 pub fn push_child(&mut self, child: Element) -> &mut Self {
286 self.children.push(Node::Element(child));
287 self
288 }
289
290 pub fn attr(&self, namespace: Option<&str>, name: &str) -> Option<&Value> {
292 self.attributes.iter().find(|a| a.name.matches(namespace, name)).map(|a| &a.value)
293 }
294
295 pub fn android_attr(&self, def: &AttrDef) -> Option<&Value> {
297 self.attributes
298 .iter()
299 .find(|a| a.name.id == Some(def.id()) || a.name.matches(Some(ANDROID_NAMESPACE), def.name()))
300 .map(|a| &a.value)
301 }
302
303 pub fn elements(&self) -> impl Iterator<Item = &Element> {
305 self.children.iter().filter_map(|node| match node {
306 Node::Element(element) => Some(element),
307 Node::Text(_) => None,
308 })
309 }
310
311 pub fn elements_named<'a>(&'a self, name: &'a str) -> impl Iterator<Item = &'a Element> + 'a {
313 self.elements().filter(move |e| e.name == name)
314 }
315
316 pub fn element(&self, name: &str) -> Option<&Element> {
318 self.elements().find(|e| e.name == name)
319 }
320
321 pub fn elements_mut(&mut self) -> impl Iterator<Item = &mut Element> {
323 self.children.iter_mut().filter_map(|node| match node {
324 Node::Element(element) => Some(element),
325 Node::Text(_) => None,
326 })
327 }
328
329 pub fn element_mut(&mut self, name: &str) -> Option<&mut Element> {
331 self.elements_mut().find(|e| e.name == name)
332 }
333}
334
335#[derive(Clone, Copy, Debug)]
337pub(crate) enum Step<'a> {
338 Open(&'a Element),
339 Text(&'a str),
340 Close(&'a Element),
341}
342
343pub(crate) fn walk<'a>(root: &'a Element) -> impl Iterator<Item = (usize, Step<'a>)> {
347 let mut open: Vec<(&'a Element, usize)> = Vec::new();
349 let mut start = Some(root);
350 std::iter::from_fn(move || {
351 if let Some(root) = start.take() {
352 open.push((root, 0));
353 return Some((0, Step::Open(root)));
354 }
355 let depth = open.len().checked_sub(1)?;
356 let (element, next) = open.last_mut()?;
357 let element = *element;
359 let child = element.children.get(*next);
360 *next += 1;
361 Some(match child {
362 Some(Node::Element(child)) => {
363 open.push((child, 0));
364 (depth + 1, Step::Open(child))
365 }
366 Some(Node::Text(text)) => (depth, Step::Text(text)),
367 None => {
368 open.pop();
369 (depth, Step::Close(element))
370 }
371 })
372 })
373}