Skip to main content

aster_forge_xml/
document.rs

1//! Source-backed, non-recursive XML document tree.
2
3use std::borrow::Cow;
4use std::io::{Read, Write};
5use std::num::NonZeroU32;
6use std::ops::Range;
7use std::sync::Arc;
8
9use aster_forge_utils::numbers::{u32_to_usize, u64_to_usize, usize_to_u32, usize_to_u64};
10use quick_xml::Reader;
11use quick_xml::XmlVersion;
12use quick_xml::escape::unescape;
13use quick_xml::events::{BytesStart, Event};
14
15use crate::syntax::{
16    XML_NAMESPACE_URI, map_quick_xml_error_at, split_qualified_name, utf8,
17    validate_namespace_binding, validate_qualified_name,
18};
19use crate::{Error, ParseOptions, XmlSafetyError, XmlSafetyPolicy};
20
21const OWNED_VALUE_OFFSET: u64 = u64::MAX;
22
23/// Stable identifier for a node in an [`XmlDocument`].
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub struct NodeId(NonZeroU32);
26
27impl NodeId {
28    fn from_index(index: usize) -> Result<Self, Error> {
29        let value = usize_to_u32(index, "XML node index")
30            .ok()
31            .and_then(|index| index.checked_add(1))
32            .and_then(NonZeroU32::new)
33            .ok_or(XmlSafetyError::TooManyElements)?;
34        Ok(Self(value))
35    }
36
37    fn index(self) -> usize {
38        stored_index(self.0.get() - 1, "XML node index")
39    }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43struct ScopeId(NonZeroU32);
44
45impl ScopeId {
46    fn from_index(index: usize) -> Result<Self, Error> {
47        let value = usize_to_u32(index, "XML namespace scope index")
48            .ok()
49            .and_then(|index| index.checked_add(1))
50            .and_then(NonZeroU32::new)
51            .ok_or_else(|| Error::InvalidXml("too many namespace scopes".into()))?;
52        Ok(Self(value))
53    }
54
55    fn index(self) -> usize {
56        stored_index(self.0.get() - 1, "XML namespace scope index")
57    }
58}
59
60/// A byte range in the original XML source.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct SourceSpan {
63    pub start: u64,
64    pub end: u64,
65}
66
67impl SourceSpan {
68    fn as_range(self, source_len: usize) -> Option<Range<usize>> {
69        let start = u64_to_usize(self.start, "XML source span start").ok()?;
70        let end = u64_to_usize(self.end, "XML source span end").ok()?;
71        (start <= end && end <= source_len).then_some(start..end)
72    }
73}
74
75#[derive(Debug, Clone, Copy)]
76struct ValueRef {
77    offset: u64,
78    length: u32,
79    owned_index: u32,
80}
81
82impl ValueRef {
83    fn source(offset: u64, length: u32) -> Self {
84        Self {
85            offset,
86            length,
87            owned_index: 0,
88        }
89    }
90
91    fn owned(index: u32, length: u32) -> Self {
92        Self {
93            offset: OWNED_VALUE_OFFSET,
94            length,
95            owned_index: index,
96        }
97    }
98}
99
100#[derive(Debug)]
101struct ArenaNode {
102    parent: Option<NodeId>,
103    first_child: Option<NodeId>,
104    last_child: Option<NodeId>,
105    next_sibling: Option<NodeId>,
106    kind: NodeKind,
107}
108
109#[derive(Debug)]
110enum NodeKind {
111    Element(ElementData),
112    Text(ValueRef),
113    CData(ValueRef),
114    Comment(ValueRef),
115    ProcessingInstruction {
116        target: ValueRef,
117        content: Option<ValueRef>,
118    },
119}
120
121#[derive(Debug)]
122struct ElementData {
123    qualified_name: ValueRef,
124    attributes: Range<u32>,
125    namespace_scope: Option<ScopeId>,
126    source: SourceSpan,
127}
128
129#[derive(Debug)]
130struct AttributeData {
131    qualified_name: ValueRef,
132    value: ValueRef,
133}
134
135#[derive(Debug)]
136struct NamespaceScope {
137    parent: Option<ScopeId>,
138    bindings: Range<u32>,
139}
140
141#[derive(Debug)]
142struct NamespaceBinding {
143    prefix: ValueRef,
144    uri: Option<ValueRef>,
145}
146
147#[derive(Clone, Copy)]
148struct ArenaView<'a> {
149    source: &'a [u8],
150    namespace_scopes: &'a [NamespaceScope],
151    namespace_bindings: &'a [NamespaceBinding],
152    owned_values: &'a [Box<str>],
153}
154
155impl<'a> ArenaView<'a> {
156    fn value(self, value: ValueRef) -> &'a str {
157        let resolved = self.checked_value(value);
158        debug_assert!(resolved.is_some(), "invalid internal XML value reference");
159        resolved.unwrap_or("")
160    }
161
162    fn checked_value(self, value: ValueRef) -> Option<&'a str> {
163        let length = u32_to_usize(value.length, "XML value length").ok()?;
164        if value.offset == OWNED_VALUE_OFFSET {
165            let index = u32_to_usize(value.owned_index, "owned XML value index").ok()?;
166            let value = self.owned_values.get(index)?.as_ref();
167            return (value.len() == length).then_some(value);
168        }
169
170        let start = u64_to_usize(value.offset, "XML value offset").ok()?;
171        let end = start.checked_add(length)?;
172        std::str::from_utf8(self.source.get(start..end)?).ok()
173    }
174
175    fn resolve_namespace(self, scope: Option<ScopeId>, prefix: &str) -> Option<&'a str> {
176        match self.checked_resolve_namespace(scope, prefix) {
177            Ok(namespace) => namespace,
178            Err(()) => {
179                debug_assert!(false, "invalid internal XML namespace reference");
180                None
181            }
182        }
183    }
184
185    fn checked_resolve_namespace(
186        self,
187        mut scope: Option<ScopeId>,
188        prefix: &str,
189    ) -> Result<Option<&'a str>, ()> {
190        if prefix == "xml" {
191            return Ok(Some(XML_NAMESPACE_URI));
192        }
193        while let Some(scope_id) = scope {
194            let scope_data = self.namespace_scopes.get(scope_id.index()).ok_or(())?;
195            for binding_index in scope_data.bindings.clone().rev() {
196                let binding_index =
197                    u32_to_usize(binding_index, "XML namespace binding index").map_err(|_| ())?;
198                let binding = self.namespace_bindings.get(binding_index).ok_or(())?;
199                if self.checked_value(binding.prefix).ok_or(())? == prefix {
200                    return binding
201                        .uri
202                        .map(|uri| self.checked_value(uri).ok_or(()))
203                        .transpose();
204                }
205            }
206            scope = scope_data.parent;
207        }
208        Ok(None)
209    }
210}
211
212/// An immutable XML tree whose nodes reference ranges in `source` whenever possible.
213///
214/// `S` may be `&[u8]`, `Arc<[u8]>`, `Vec<u8>`, or another byte container.
215#[derive(Debug)]
216pub struct XmlDocument<S> {
217    source: S,
218    nodes: Box<[ArenaNode]>,
219    attributes: Box<[AttributeData]>,
220    namespace_scopes: Box<[NamespaceScope]>,
221    namespace_bindings: Box<[NamespaceBinding]>,
222    owned_values: Box<[Box<str>]>,
223    root: NodeId,
224}
225
226/// A document borrowing its complete source buffer.
227pub type BorrowedDocument<'a> = XmlDocument<&'a [u8]>;
228
229/// A document sharing ownership of its source buffer.
230pub type OwnedDocument = XmlDocument<Arc<[u8]>>;
231
232impl<S: AsRef<[u8]>> XmlDocument<S> {
233    /// Parses a complete XML document with the default bounded policy.
234    pub fn parse(source: S) -> Result<Self, Error> {
235        Self::parse_with_options(source, &ParseOptions::default())
236    }
237
238    /// Parses a complete XML document into a flat arena.
239    pub fn parse_with_options(source: S, options: &ParseOptions) -> Result<Self, Error> {
240        options.safety.validate()?;
241        if source.as_ref().len() > options.safety.max_input_bytes {
242            return Err(XmlSafetyError::InputTooLarge.into());
243        }
244
245        let (nodes, attributes, namespace_scopes, namespace_bindings, owned_values, root) = {
246            let mut builder = DocumentBuilder::new(source.as_ref(), options);
247            builder.parse()?;
248            let root = builder.root.ok_or(XmlSafetyError::Malformed)?;
249            (
250                builder.nodes.into_boxed_slice(),
251                builder.attributes.into_boxed_slice(),
252                builder.namespace_scopes.into_boxed_slice(),
253                builder.namespace_bindings.into_boxed_slice(),
254                builder.owned_values.into_boxed_slice(),
255                root,
256            )
257        };
258        Ok(Self {
259            source,
260            nodes,
261            attributes,
262            namespace_scopes,
263            namespace_bindings,
264            owned_values,
265            root,
266        })
267    }
268
269    pub fn source(&self) -> &[u8] {
270        self.source.as_ref()
271    }
272
273    pub fn into_source(self) -> S {
274        self.source
275    }
276
277    pub fn root(&self) -> ElementRef<'_, S> {
278        ElementRef {
279            document: self,
280            id: self.root,
281        }
282    }
283
284    pub fn node(&self, id: NodeId) -> Option<NodeRef<'_, S>> {
285        let node = self.nodes.get(id.index())?;
286        Some(match &node.kind {
287            NodeKind::Element(_) => NodeRef::Element(ElementRef { document: self, id }),
288            NodeKind::Text(value) => NodeRef::Text(self.value(*value)),
289            NodeKind::CData(value) => NodeRef::CData(self.value(*value)),
290            NodeKind::Comment(value) => NodeRef::Comment(self.value(*value)),
291            NodeKind::ProcessingInstruction { target, content } => {
292                NodeRef::ProcessingInstruction(ProcessingInstructionRef {
293                    target: self.value(*target),
294                    content: content.map(|value| self.value(value)),
295                })
296            }
297        })
298    }
299
300    pub fn node_count(&self) -> usize {
301        self.nodes.len()
302    }
303
304    pub fn allocated_value_count(&self) -> usize {
305        self.owned_values.len()
306    }
307
308    pub fn write_original<W: Write>(&self, mut writer: W) -> Result<(), Error> {
309        writer.write_all(self.source())?;
310        Ok(())
311    }
312
313    fn value(&self, value: ValueRef) -> &str {
314        self.arena_view().value(value)
315    }
316
317    fn element_data(&self, id: NodeId) -> Option<&ElementData> {
318        match &self.nodes.get(id.index())?.kind {
319            NodeKind::Element(element) => Some(element),
320            _ => None,
321        }
322    }
323
324    fn resolve_namespace(&self, scope: Option<ScopeId>, prefix: &str) -> Option<&str> {
325        self.arena_view().resolve_namespace(scope, prefix)
326    }
327
328    fn arena_view(&self) -> ArenaView<'_> {
329        ArenaView {
330            source: self.source.as_ref(),
331            namespace_scopes: &self.namespace_scopes,
332            namespace_bindings: &self.namespace_bindings,
333            owned_values: &self.owned_values,
334        }
335    }
336}
337
338impl XmlDocument<Arc<[u8]>> {
339    /// Reads and parses a complete document with the default bounded policy.
340    pub fn from_reader<R: Read>(reader: R) -> Result<Self, Error> {
341        Self::from_reader_with_options(reader, &ParseOptions::default())
342    }
343
344    /// Reads at most one byte beyond the configured limit before parsing an owned document.
345    pub fn from_reader_with_options<R: Read>(
346        reader: R,
347        options: &ParseOptions,
348    ) -> Result<Self, Error> {
349        options.safety.validate()?;
350        let read_limit = options.safety.max_input_bytes.saturating_add(1);
351        let read_limit = usize_to_u64(read_limit, "XML reader byte limit").unwrap_or(u64::MAX);
352        let mut reader = reader.take(read_limit);
353        let mut source = Vec::new();
354        reader.read_to_end(&mut source)?;
355        if source.len() > options.safety.max_input_bytes {
356            return Err(XmlSafetyError::InputTooLarge.into());
357        }
358        Self::parse_with_options(Arc::from(source), options)
359    }
360}
361
362/// A cheap-to-clone, validated XML document retaining the exact original bytes.
363#[derive(Debug, Clone)]
364pub struct ValidatedXml(Arc<OwnedDocument>);
365
366impl ValidatedXml {
367    pub fn new(bytes: impl Into<Arc<[u8]>>) -> Result<Self, Error> {
368        Self::with_policy(bytes, XmlSafetyPolicy::untrusted())
369    }
370
371    pub fn with_policy(
372        bytes: impl Into<Arc<[u8]>>,
373        policy: XmlSafetyPolicy,
374    ) -> Result<Self, Error> {
375        let source = bytes.into();
376        let document =
377            XmlDocument::parse_with_options(source, &ParseOptions::new().safety_policy(policy))?;
378        Ok(Self(Arc::new(document)))
379    }
380
381    pub fn from_reader<R: Read>(reader: R) -> Result<Self, Error> {
382        let document = OwnedDocument::from_reader(reader)?;
383        Ok(Self(Arc::new(document)))
384    }
385
386    pub fn as_bytes(&self) -> &[u8] {
387        self.0.source()
388    }
389
390    pub fn document(&self) -> &OwnedDocument {
391        &self.0
392    }
393}
394
395/// A borrowed view of an element node.
396pub struct ElementRef<'document, S> {
397    document: &'document XmlDocument<S>,
398    id: NodeId,
399}
400
401impl<S> Copy for ElementRef<'_, S> {}
402
403impl<S> Clone for ElementRef<'_, S> {
404    fn clone(&self) -> Self {
405        *self
406    }
407}
408
409impl<'document, S: AsRef<[u8]>> ElementRef<'document, S> {
410    pub fn id(self) -> NodeId {
411        self.id
412    }
413
414    pub fn parent(self) -> Option<ElementRef<'document, S>> {
415        self.document.nodes[self.id.index()]
416            .parent
417            .map(|id| ElementRef {
418                document: self.document,
419                id,
420            })
421    }
422
423    pub fn qualified_name(self) -> &'document str {
424        let Some(data) = self.document.element_data(self.id) else {
425            return "";
426        };
427        self.document.value(data.qualified_name)
428    }
429
430    pub fn prefix(self) -> Option<&'document str> {
431        split_qualified_name(self.qualified_name()).0
432    }
433
434    pub fn name(self) -> &'document str {
435        split_qualified_name(self.qualified_name()).1
436    }
437
438    pub fn namespace(self) -> Option<&'document str> {
439        let data = self.document.element_data(self.id)?;
440        self.document
441            .resolve_namespace(data.namespace_scope, self.prefix().unwrap_or(""))
442    }
443
444    pub fn raw_xml(self) -> &'document [u8] {
445        let Some(data) = self.document.element_data(self.id) else {
446            return &[];
447        };
448        let Some(range) = data.source.as_range(self.document.source().len()) else {
449            return &[];
450        };
451        &self.document.source()[range]
452    }
453
454    pub fn attributes(self) -> Attributes<'document, S> {
455        let range = self
456            .document
457            .element_data(self.id)
458            .map(|data| data.attributes.clone())
459            .unwrap_or(0..0);
460        Attributes {
461            element: self,
462            next: range.start,
463            end: range.end,
464        }
465    }
466
467    pub fn attribute(self, qualified_name: &str) -> Option<&'document str> {
468        self.attributes()
469            .find(|attribute| attribute.qualified_name() == qualified_name)
470            .map(AttributeRef::value)
471    }
472
473    pub fn attribute_ns(self, name: &str, namespace: Option<&str>) -> Option<&'document str> {
474        self.attributes()
475            .find(|attribute| attribute.name() == name && attribute.namespace() == namespace)
476            .map(AttributeRef::value)
477    }
478
479    pub fn children(self) -> Children<'document, S> {
480        Children {
481            document: self.document,
482            next: self.document.nodes[self.id.index()].first_child,
483        }
484    }
485
486    pub fn child_elements(self) -> ChildElements<'document, S> {
487        ChildElements {
488            children: self.children(),
489        }
490    }
491
492    pub fn get_child(self, name: &str) -> Option<ElementRef<'document, S>> {
493        self.child_elements().find(|element| element.name() == name)
494    }
495
496    pub fn get_child_ns(self, name: &str, namespace: &str) -> Option<ElementRef<'document, S>> {
497        self.child_elements()
498            .find(|element| element.name() == name && element.namespace() == Some(namespace))
499    }
500
501    pub fn descendants(self) -> DescendantElements<'document, S> {
502        DescendantElements { stack: vec![self] }
503    }
504
505    pub fn text(self) -> Option<Cow<'document, str>> {
506        let mut values = self.children().filter_map(|node| match node {
507            NodeRef::Text(text) | NodeRef::CData(text) => Some(text),
508            _ => None,
509        });
510        let first = values.next()?;
511        match values.next() {
512            None => Some(Cow::Borrowed(first)),
513            Some(second) => {
514                let mut output = String::with_capacity(first.len() + second.len());
515                output.push_str(first);
516                output.push_str(second);
517                values.for_each(|value| output.push_str(value));
518                Some(Cow::Owned(output))
519            }
520        }
521    }
522}
523
524/// A borrowed XML node view.
525pub enum NodeRef<'document, S> {
526    Element(ElementRef<'document, S>),
527    Text(&'document str),
528    CData(&'document str),
529    Comment(&'document str),
530    ProcessingInstruction(ProcessingInstructionRef<'document>),
531}
532
533impl<S> Copy for NodeRef<'_, S> {}
534
535impl<S> Clone for NodeRef<'_, S> {
536    fn clone(&self) -> Self {
537        *self
538    }
539}
540
541#[derive(Debug, Clone, Copy, PartialEq, Eq)]
542pub struct ProcessingInstructionRef<'a> {
543    pub target: &'a str,
544    pub content: Option<&'a str>,
545}
546
547pub struct Children<'document, S> {
548    document: &'document XmlDocument<S>,
549    next: Option<NodeId>,
550}
551
552impl<'document, S: AsRef<[u8]>> Iterator for Children<'document, S> {
553    type Item = NodeRef<'document, S>;
554
555    fn next(&mut self) -> Option<Self::Item> {
556        let id = self.next?;
557        self.next = self.document.nodes[id.index()].next_sibling;
558        self.document.node(id)
559    }
560}
561
562pub struct ChildElements<'document, S> {
563    children: Children<'document, S>,
564}
565
566impl<'document, S: AsRef<[u8]>> Iterator for ChildElements<'document, S> {
567    type Item = ElementRef<'document, S>;
568
569    fn next(&mut self) -> Option<Self::Item> {
570        self.children.find_map(|node| match node {
571            NodeRef::Element(element) => Some(element),
572            _ => None,
573        })
574    }
575}
576
577pub struct DescendantElements<'document, S> {
578    stack: Vec<ElementRef<'document, S>>,
579}
580
581impl<'document, S: AsRef<[u8]>> Iterator for DescendantElements<'document, S> {
582    type Item = ElementRef<'document, S>;
583
584    fn next(&mut self) -> Option<Self::Item> {
585        let element = self.stack.pop()?;
586        let child_start = self.stack.len();
587        self.stack.extend(element.child_elements());
588        self.stack[child_start..].reverse();
589        Some(element)
590    }
591}
592
593pub struct Attributes<'document, S> {
594    element: ElementRef<'document, S>,
595    next: u32,
596    end: u32,
597}
598
599impl<'document, S: AsRef<[u8]>> Iterator for Attributes<'document, S> {
600    type Item = AttributeRef<'document, S>;
601
602    fn next(&mut self) -> Option<Self::Item> {
603        if self.next >= self.end {
604            return None;
605        }
606        let index = self.next;
607        self.next += 1;
608        Some(AttributeRef {
609            element: self.element,
610            index,
611        })
612    }
613}
614
615pub struct AttributeRef<'document, S> {
616    element: ElementRef<'document, S>,
617    index: u32,
618}
619
620impl<S> Copy for AttributeRef<'_, S> {}
621
622impl<S> Clone for AttributeRef<'_, S> {
623    fn clone(&self) -> Self {
624        *self
625    }
626}
627
628impl<'document, S: AsRef<[u8]>> AttributeRef<'document, S> {
629    fn data(self) -> Option<&'document AttributeData> {
630        let data = self.checked_data();
631        debug_assert!(data.is_some(), "invalid internal XML attribute index");
632        data
633    }
634
635    fn checked_data(self) -> Option<&'document AttributeData> {
636        self.document()
637            .attributes
638            .get(stored_index(self.index, "XML attribute index"))
639    }
640
641    fn document(self) -> &'document XmlDocument<S> {
642        self.element.document
643    }
644
645    pub fn qualified_name(self) -> &'document str {
646        self.data()
647            .map(|data| self.document().value(data.qualified_name))
648            .unwrap_or("")
649    }
650
651    pub fn prefix(self) -> Option<&'document str> {
652        split_qualified_name(self.qualified_name()).0
653    }
654
655    pub fn name(self) -> &'document str {
656        split_qualified_name(self.qualified_name()).1
657    }
658
659    pub fn namespace(self) -> Option<&'document str> {
660        let prefix = self.prefix()?;
661        let scope = self
662            .document()
663            .element_data(self.element.id)
664            .and_then(|element| element.namespace_scope);
665        self.document().resolve_namespace(scope, prefix)
666    }
667
668    pub fn value(self) -> &'document str {
669        self.data()
670            .map(|data| self.document().value(data.value))
671            .unwrap_or("")
672    }
673}
674
675struct DocumentBuilder<'a> {
676    source: &'a [u8],
677    options: &'a ParseOptions,
678    nodes: Vec<ArenaNode>,
679    attributes: Vec<AttributeData>,
680    namespace_scopes: Vec<NamespaceScope>,
681    namespace_bindings: Vec<NamespaceBinding>,
682    owned_values: Vec<Box<str>>,
683    open: Vec<NodeId>,
684    root: Option<NodeId>,
685    root_complete: bool,
686    element_count: usize,
687    text_bytes: usize,
688    event_count: usize,
689}
690
691impl<'a> DocumentBuilder<'a> {
692    fn new(source: &'a [u8], options: &'a ParseOptions) -> Self {
693        Self {
694            source,
695            options,
696            nodes: Vec::new(),
697            attributes: Vec::new(),
698            namespace_scopes: Vec::new(),
699            namespace_bindings: Vec::new(),
700            owned_values: Vec::new(),
701            open: Vec::new(),
702            root: None,
703            root_complete: false,
704            element_count: 0,
705            text_bytes: 0,
706            event_count: 0,
707        }
708    }
709
710    fn parse(&mut self) -> Result<(), Error> {
711        let mut reader = Reader::from_reader(self.source);
712        reader.config_mut().trim_text(false);
713        reader.config_mut().check_end_names = true;
714        loop {
715            let event_start = reader.buffer_position();
716            let event = reader.read_event().map_err(|error| {
717                let error_position =
718                    usize::try_from(reader.error_position()).unwrap_or(self.source.len());
719                map_quick_xml_error_at(
720                    error,
721                    error_position,
722                    self.source,
723                    self.options.safety.reject_doctype,
724                )
725            })?;
726            let event_end = reader.buffer_position();
727            if !matches!(event, Event::Eof) {
728                self.count_event()?;
729            }
730            match event {
731                Event::Start(start) => {
732                    self.start_element(&reader, &start, event_start, event_end)?
733                }
734                Event::Empty(start) => {
735                    self.empty_element(&reader, &start, event_start, event_end)?
736                }
737                Event::End(_) => self.end_element(event_end)?,
738                Event::Text(text) => {
739                    let raw = utf8(text.as_ref())?;
740                    let value =
741                        unescape(raw).map_err(|error| Error::InvalidXml(error.to_string()))?;
742                    self.text_node(value, false)?;
743                }
744                Event::CData(text) => self.text_node(Cow::Borrowed(utf8(text.as_ref())?), true)?,
745                Event::Comment(comment) => {
746                    let value = self.source_value(utf8(comment.as_ref())?)?;
747                    self.push_content(NodeKind::Comment(value))?;
748                }
749                Event::PI(pi) => {
750                    let target = self.source_value(utf8(pi.target())?)?;
751                    let content = utf8(pi.content())?
752                        .trim_start_matches(|character: char| character.is_ascii_whitespace());
753                    let content = (!content.is_empty())
754                        .then(|| self.source_value(content))
755                        .transpose()?;
756                    self.push_content(NodeKind::ProcessingInstruction { target, content })?;
757                }
758                Event::GeneralRef(reference) => {
759                    let value = if let Some(character) = reference
760                        .resolve_char_ref()
761                        .map_err(|error| Error::InvalidXml(error.to_string()))?
762                    {
763                        Cow::Owned(character.to_string())
764                    } else {
765                        Cow::Owned(
766                            match utf8(reference.as_ref())? {
767                                "amp" => "&",
768                                "lt" => "<",
769                                "gt" => ">",
770                                "apos" => "'",
771                                "quot" => "\"",
772                                _ => return Err(XmlSafetyError::ExternalEntity.into()),
773                            }
774                            .to_owned(),
775                        )
776                    };
777                    self.text_node(value, false)?;
778                }
779                Event::Decl(_) => {
780                    if self.root.is_some() || !self.open.is_empty() || self.root_complete {
781                        return Err(XmlSafetyError::Malformed.into());
782                    }
783                }
784                Event::DocType(_) => {
785                    if self.options.safety.reject_doctype {
786                        return Err(XmlSafetyError::ExternalEntity.into());
787                    }
788                    if self.root.is_some() || !self.open.is_empty() || self.root_complete {
789                        return Err(XmlSafetyError::Malformed.into());
790                    }
791                }
792                Event::Eof => {
793                    if !self.open.is_empty() || !self.root_complete {
794                        return Err(XmlSafetyError::Malformed.into());
795                    }
796                    return Ok(());
797                }
798            }
799        }
800    }
801
802    fn start_element(
803        &mut self,
804        reader: &Reader<&[u8]>,
805        start: &BytesStart<'a>,
806        source_start: u64,
807        source_end: u64,
808    ) -> Result<(), Error> {
809        self.check_element()?;
810        let id = self.build_element(reader, start, source_start, source_end)?;
811        self.open.push(id);
812        Ok(())
813    }
814
815    fn empty_element(
816        &mut self,
817        reader: &Reader<&[u8]>,
818        start: &BytesStart<'a>,
819        source_start: u64,
820        source_end: u64,
821    ) -> Result<(), Error> {
822        self.check_element()?;
823        self.build_element(reader, start, source_start, source_end)?;
824        if self.open.is_empty() {
825            self.root_complete = true;
826        }
827        Ok(())
828    }
829
830    fn end_element(&mut self, source_end: u64) -> Result<(), Error> {
831        let id = self.open.pop().ok_or(XmlSafetyError::Malformed)?;
832        let NodeKind::Element(element) = &mut self.nodes[id.index()].kind else {
833            return Err(XmlSafetyError::Malformed.into());
834        };
835        element.source.end = source_end;
836        if self.open.is_empty() {
837            self.root_complete = true;
838        }
839        Ok(())
840    }
841
842    fn build_element(
843        &mut self,
844        reader: &Reader<&[u8]>,
845        start: &BytesStart<'a>,
846        source_start: u64,
847        source_end: u64,
848    ) -> Result<NodeId, Error> {
849        if self.open.is_empty() && self.root_complete {
850            return Err(XmlSafetyError::Malformed.into());
851        }
852        let start_name = start.name();
853        let qualified_name = utf8(start_name.as_ref())?;
854        let (prefix, _) = validate_qualified_name(qualified_name)?;
855        let parent_scope = self.open.last().and_then(|id| {
856            let NodeKind::Element(element) = &self.nodes[id.index()].kind else {
857                return None;
858            };
859            element.namespace_scope
860        });
861        let binding_start = arena_len(self.namespace_bindings.len(), "namespace bindings")?;
862        let mut attribute_count = 0usize;
863        for attribute in start.attributes() {
864            attribute_count = attribute_count
865                .checked_add(1)
866                .ok_or(XmlSafetyError::TooManyAttributes)?;
867            if attribute_count > self.options.safety.max_attributes_per_element {
868                return Err(XmlSafetyError::TooManyAttributes.into());
869            }
870            let attribute = attribute.map_err(|error| Error::InvalidXml(error.to_string()))?;
871            let name = utf8(attribute.key.as_ref())?;
872            validate_qualified_name(name)?;
873            if name == "xmlns" || name.starts_with("xmlns:") {
874                let namespace_prefix = name.strip_prefix("xmlns:").unwrap_or("");
875                let uri = attribute
876                    .decoded_and_normalized_value(XmlVersion::Explicit1_0, reader.decoder())
877                    .map_err(|error| Error::InvalidXml(error.to_string()))?;
878                validate_namespace_binding(namespace_prefix, &uri)?;
879                let prefix_value = if namespace_prefix.is_empty() {
880                    ValueRef::source(0, 0)
881                } else {
882                    self.source_value(namespace_prefix)?
883                };
884                let uri_value = if uri.is_empty() {
885                    None
886                } else {
887                    Some(self.cow_value(uri)?)
888                };
889                self.namespace_bindings.push(NamespaceBinding {
890                    prefix: prefix_value,
891                    uri: uri_value,
892                });
893            }
894        }
895        let binding_end = arena_len(self.namespace_bindings.len(), "namespace bindings")?;
896        let namespace_scope = if binding_start == binding_end {
897            parent_scope
898        } else {
899            let id = ScopeId::from_index(self.namespace_scopes.len())?;
900            self.namespace_scopes.push(NamespaceScope {
901                parent: parent_scope,
902                bindings: binding_start..binding_end,
903            });
904            Some(id)
905        };
906        if let Some(prefix) = prefix
907            && self
908                .arena_view()
909                .resolve_namespace(namespace_scope, prefix)
910                .is_none()
911        {
912            return Err(XmlSafetyError::Malformed.into());
913        }
914
915        let attribute_start = arena_len(self.attributes.len(), "attributes")?;
916        for attribute in start.attributes() {
917            let attribute = attribute.map_err(|error| Error::InvalidXml(error.to_string()))?;
918            let name = utf8(attribute.key.as_ref())?;
919            if name == "xmlns" || name.starts_with("xmlns:") {
920                continue;
921            }
922            let (prefix, _) = split_qualified_name(name);
923            if let Some(prefix) = prefix
924                && prefix != "xml"
925                && self
926                    .arena_view()
927                    .resolve_namespace(namespace_scope, prefix)
928                    .is_none()
929            {
930                return Err(XmlSafetyError::Malformed.into());
931            }
932            let value = attribute
933                .decoded_and_normalized_value(XmlVersion::Explicit1_0, reader.decoder())
934                .map_err(|error| Error::InvalidXml(error.to_string()))?;
935            let qualified_name = self.source_value(name)?;
936            let value = self.cow_value(value)?;
937            self.attributes.push(AttributeData {
938                qualified_name,
939                value,
940            });
941        }
942        let attribute_end = arena_len(self.attributes.len(), "attributes")?;
943        let qualified_name = self.source_value(qualified_name)?;
944        let id = self.push_node(NodeKind::Element(ElementData {
945            qualified_name,
946            attributes: attribute_start..attribute_end,
947            namespace_scope,
948            source: SourceSpan {
949                start: source_start,
950                end: source_end,
951            },
952        }))?;
953        if self.root.is_none() {
954            self.root = Some(id);
955        }
956        Ok(id)
957    }
958
959    fn check_element(&mut self) -> Result<(), Error> {
960        let depth = self
961            .open
962            .len()
963            .checked_add(1)
964            .ok_or(XmlSafetyError::TooDeep)?;
965        if depth > self.options.safety.max_depth {
966            return Err(XmlSafetyError::TooDeep.into());
967        }
968        self.element_count = self
969            .element_count
970            .checked_add(1)
971            .ok_or(XmlSafetyError::TooManyElements)?;
972        if self.element_count > self.options.safety.max_elements {
973            return Err(XmlSafetyError::TooManyElements.into());
974        }
975        Ok(())
976    }
977
978    fn count_event(&mut self) -> Result<(), Error> {
979        self.event_count = self
980            .event_count
981            .checked_add(1)
982            .ok_or(XmlSafetyError::TooManyEvents)?;
983        if self.event_count > self.options.safety.max_events {
984            return Err(XmlSafetyError::TooManyEvents.into());
985        }
986        Ok(())
987    }
988
989    fn text_node(&mut self, value: Cow<'_, str>, cdata: bool) -> Result<(), Error> {
990        self.text_bytes = self
991            .text_bytes
992            .checked_add(value.len())
993            .ok_or(XmlSafetyError::TextTooLarge)?;
994        if self.text_bytes > self.options.safety.max_text_bytes {
995            return Err(XmlSafetyError::TextTooLarge.into());
996        }
997        let value = if self.options.trim_whitespace {
998            match value {
999                Cow::Borrowed(value) => Cow::Borrowed(value.trim()),
1000                Cow::Owned(value) => Cow::Owned(value.trim().to_owned()),
1001            }
1002        } else {
1003            value
1004        };
1005        if value.is_empty() {
1006            return Ok(());
1007        }
1008        if self.open.is_empty() {
1009            if value.chars().all(char::is_whitespace) {
1010                return Ok(());
1011            }
1012            return Err(XmlSafetyError::Malformed.into());
1013        }
1014        let value = self.cow_value(value)?;
1015        self.push_content(if cdata {
1016            NodeKind::CData(value)
1017        } else {
1018            NodeKind::Text(value)
1019        })?;
1020        Ok(())
1021    }
1022
1023    fn push_content(&mut self, kind: NodeKind) -> Result<(), Error> {
1024        if self.open.is_empty() {
1025            return Ok(());
1026        }
1027        self.push_node(kind).map(|_| ())
1028    }
1029
1030    fn push_node(&mut self, kind: NodeKind) -> Result<NodeId, Error> {
1031        let id = NodeId::from_index(self.nodes.len())?;
1032        let parent = self.open.last().copied();
1033        self.nodes.push(ArenaNode {
1034            parent,
1035            first_child: None,
1036            last_child: None,
1037            next_sibling: None,
1038            kind,
1039        });
1040        if let Some(parent) = parent {
1041            if let Some(previous) = self.nodes[parent.index()].last_child {
1042                self.nodes[previous.index()].next_sibling = Some(id);
1043            } else {
1044                self.nodes[parent.index()].first_child = Some(id);
1045            }
1046            self.nodes[parent.index()].last_child = Some(id);
1047        }
1048        Ok(id)
1049    }
1050
1051    fn source_value(&self, value: &str) -> Result<ValueRef, Error> {
1052        let source_start = self.source.as_ptr() as usize;
1053        let value_start = value.as_ptr() as usize;
1054        let offset = value_start
1055            .checked_sub(source_start)
1056            .filter(|offset| offset.saturating_add(value.len()) <= self.source.len())
1057            .ok_or_else(|| Error::InvalidXml("borrowed value is outside XML source".into()))?;
1058        Ok(ValueRef::source(
1059            usize_to_u64(offset, "XML value offset").map_err(|_| XmlSafetyError::InputTooLarge)?,
1060            usize_to_u32(value.len(), "XML value length")
1061                .map_err(|_| XmlSafetyError::InputTooLarge)?,
1062        ))
1063    }
1064
1065    fn cow_value(&mut self, value: Cow<'_, str>) -> Result<ValueRef, Error> {
1066        match value {
1067            Cow::Borrowed(value) => self.source_value(value),
1068            Cow::Owned(value) => {
1069                let index = arena_len(self.owned_values.len(), "owned XML values")?;
1070                let length = usize_to_u32(value.len(), "owned XML value length")
1071                    .map_err(|_| XmlSafetyError::InputTooLarge)?;
1072                self.owned_values.push(value.into_boxed_str());
1073                Ok(ValueRef::owned(index, length))
1074            }
1075        }
1076    }
1077
1078    fn arena_view(&self) -> ArenaView<'_> {
1079        ArenaView {
1080            source: self.source,
1081            namespace_scopes: &self.namespace_scopes,
1082            namespace_bindings: &self.namespace_bindings,
1083            owned_values: &self.owned_values,
1084        }
1085    }
1086}
1087
1088fn arena_len(length: usize, label: &str) -> Result<u32, Error> {
1089    usize_to_u32(length, label).map_err(|_| Error::InvalidXml(format!("too many {label}")))
1090}
1091
1092fn stored_index(value: u32, label: &str) -> usize {
1093    // Rust's supported platforms can represent every u32 as usize. Keep the checked Forge
1094    // conversion at the representation boundary and make malformed internal state fail indexing.
1095    u32_to_usize(value, label).unwrap_or(usize::MAX)
1096}
1097
1098#[cfg(test)]
1099mod layout_tests {
1100    use std::mem::size_of_val;
1101
1102    use super::*;
1103
1104    fn arena_payload_bytes<S>(document: &XmlDocument<S>) -> usize {
1105        size_of_val(document.nodes.as_ref())
1106            + size_of_val(document.attributes.as_ref())
1107            + size_of_val(document.namespace_scopes.as_ref())
1108            + size_of_val(document.namespace_bindings.as_ref())
1109            + size_of_val(document.owned_values.as_ref())
1110            + document
1111                .owned_values
1112                .iter()
1113                .map(|value| value.len())
1114                .sum::<usize>()
1115    }
1116
1117    #[test]
1118    fn arena_view_rejects_invalid_value_ranges_and_namespace_indices() {
1119        let source = b"value\xFF";
1120        let owned_values = [Box::<str>::from("owned")];
1121        let scope = ScopeId::from_index(0).expect("scope id");
1122        let namespace_scopes = [NamespaceScope {
1123            parent: None,
1124            bindings: 0..1,
1125        }];
1126        let view = ArenaView {
1127            source,
1128            namespace_scopes: &namespace_scopes,
1129            namespace_bindings: &[],
1130            owned_values: &owned_values,
1131        };
1132
1133        assert_eq!(view.checked_value(ValueRef::source(0, 5)), Some("value"));
1134        assert_eq!(view.checked_value(ValueRef::owned(0, 5)), Some("owned"));
1135        assert_eq!(view.checked_value(ValueRef::source(5, 1)), None);
1136        assert_eq!(view.checked_value(ValueRef::source(u64::MAX, 2)), None);
1137        assert_eq!(view.checked_value(ValueRef::owned(1, 5)), None);
1138        assert_eq!(view.checked_value(ValueRef::owned(0, 4)), None);
1139        assert_eq!(view.checked_resolve_namespace(Some(scope), "p"), Err(()));
1140    }
1141
1142    #[test]
1143    fn attribute_lookup_reports_invalid_internal_indices_without_indexing() {
1144        let document = BorrowedDocument::parse(br#"<root id="7"/>"#.as_slice())
1145            .expect("document should parse");
1146        let attribute = AttributeRef {
1147            element: document.root(),
1148            index: u32::MAX,
1149        };
1150
1151        assert!(attribute.checked_data().is_none());
1152    }
1153
1154    #[test]
1155    fn large_owned_document_payload_stays_below_six_times_input() {
1156        const RESPONSES: usize = 10_000;
1157        let mut source = String::from("<D:multistatus xmlns:D=\"DAV:\">");
1158        for index in 0..RESPONSES {
1159            source.push_str(&format!(
1160                "<D:response><D:href>/files/{index}</D:href><D:propstat><D:prop><D:displayname>file-{index}</D:displayname><D:getcontentlength>{}</D:getcontentlength><D:getetag>&quot;etag-{index}&quot;</D:getetag></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>",
1161                index * 1024
1162            ));
1163        }
1164        source.push_str("</D:multistatus>");
1165        let input_bytes = source.len();
1166        let options = ParseOptions::new()
1167            .max_size(input_bytes)
1168            .max_elements(RESPONSES * 8 + 1);
1169        let document = XmlDocument::parse_with_options(Arc::from(source.into_bytes()), &options)
1170            .expect("large document");
1171        let retained_payload = input_bytes + arena_payload_bytes(&document);
1172
1173        assert!(
1174            retained_payload <= input_bytes * 6,
1175            "retained payload {retained_payload} exceeds 6x input {input_bytes}"
1176        );
1177    }
1178}