Skip to main content

ironwork_rt/
xml.rs

1//! The events XML PARSE reports under XMLPARSE(XMLSS) (Language Reference SC27-8713-03, pp. 29-33,
2//! 489-494; Programming Guide SC27-8714-03, pp. 649-653). The document may arrive in segments: markup
3//! is held until it is complete, while character content, comments and processing-instruction data
4//! that a segment ends inside are reported in parts.
5
6use std::collections::VecDeque;
7
8pub mod generate;
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum EventKind {
12    StartOfDocument,
13    VersionInformation,
14    EncodingDeclaration,
15    StandaloneDeclaration,
16    DocumentTypeDeclaration,
17    Comment,
18    ProcessingInstructionTarget,
19    ProcessingInstructionData,
20    StartOfElement,
21    NamespaceDeclaration,
22    AttributeName,
23    AttributeCharacters,
24    AttributeNationalCharacter,
25    ContentCharacters,
26    ContentNationalCharacter,
27    StartOfCdataSection,
28    EndOfCdataSection,
29    EndOfElement,
30    UnresolvedReference,
31    EndOfInput,
32    EndOfDocument,
33    Exception,
34}
35
36impl EventKind {
37    /// The XML-EVENT value.
38    pub fn name(self) -> &'static str {
39        match self {
40            Self::StartOfDocument => "START-OF-DOCUMENT",
41            Self::VersionInformation => "VERSION-INFORMATION",
42            Self::EncodingDeclaration => "ENCODING-DECLARATION",
43            Self::StandaloneDeclaration => "STANDALONE-DECLARATION",
44            Self::DocumentTypeDeclaration => "DOCUMENT-TYPE-DECLARATION",
45            Self::Comment => "COMMENT",
46            Self::ProcessingInstructionTarget => "PROCESSING-INSTRUCTION-TARGET",
47            Self::ProcessingInstructionData => "PROCESSING-INSTRUCTION-DATA",
48            Self::StartOfElement => "START-OF-ELEMENT",
49            Self::NamespaceDeclaration => "NAMESPACE-DECLARATION",
50            Self::AttributeName => "ATTRIBUTE-NAME",
51            Self::AttributeCharacters => "ATTRIBUTE-CHARACTERS",
52            Self::AttributeNationalCharacter => "ATTRIBUTE-NATIONAL-CHARACTER",
53            Self::ContentCharacters => "CONTENT-CHARACTERS",
54            Self::ContentNationalCharacter => "CONTENT-NATIONAL-CHARACTER",
55            Self::StartOfCdataSection => "START-OF-CDATA-SECTION",
56            Self::EndOfCdataSection => "END-OF-CDATA-SECTION",
57            Self::EndOfElement => "END-OF-ELEMENT",
58            Self::UnresolvedReference => "UNRESOLVED-REFERENCE",
59            Self::EndOfInput => "END-OF-INPUT",
60            Self::EndOfDocument => "END-OF-DOCUMENT",
61            Self::Exception => "EXCEPTION",
62        }
63    }
64}
65
66#[derive(Clone, Debug, PartialEq, Eq)]
67pub struct Event {
68    pub kind: EventKind,
69    /// XML-TEXT or XML-NTEXT.
70    pub text: String,
71    /// XML-NAMESPACE: the identifier bound to the name's prefix, or to the default namespace.
72    pub namespace: String,
73    /// XML-NAMESPACE-PREFIX.
74    pub prefix: String,
75    /// XML-INFORMATION: 1 when attribute or content characters are complete, 2 when more follow,
76    /// 0 for every other event (p. 34).
77    pub information: i32,
78    /// XML-CODE for an EXCEPTION the parse goes on from when the processing procedure sets XML-CODE
79    /// to zero: an undeclared prefix's warning.
80    pub code: i32,
81}
82
83impl Event {
84    fn new(kind: EventKind, text: impl Into<String>) -> Self {
85        Self { kind, text: text.into(), namespace: String::new(), prefix: String::new(), information: 0, code: 0 }
86    }
87
88    /// The warning for a name with an undeclared prefix, which XML-TEXT holds whole (Programming
89    /// Guide SC27-8714-03, pp. 647, 656-658).
90    fn undeclared(why: Why, qualified: &str) -> Self {
91        Self { code: why.code(), ..Self::new(EventKind::Exception, qualified) }
92    }
93
94    fn characters(kind: EventKind, text: String, complete: bool) -> Self {
95        Self { information: if complete { 1 } else { 2 }, ..Self::new(kind, text) }
96    }
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq)]
100pub enum Why {
101    UnexpectedEnd,
102    InvalidCharacter,
103    MismatchedEndTag,
104    DuplicateAttribute,
105    UndeclaredElementPrefix,
106    UndeclaredAttributePrefix,
107    UndeclaredEntity,
108    BadReference,
109    ContentAfterRoot,
110    SecondRoot,
111    NoRoot,
112    BadDeclaration,
113    BadComment,
114    LessThanInAttribute,
115}
116
117impl Why {
118    /// XML-CODE: z/OS XML System Services' return code 12 (not well formed) and its reason code,
119    /// or return code 4 and Enterprise COBOL's own reason for an undeclared prefix (Programming
120    /// Guide SC27-8714-03, pp. 645, 809; z/OS XML System Services User's Guide SA38-0681-50,
121    /// Appendix B; assumption C118).
122    pub fn code(self) -> i32 {
123        let not_well_formed = |reason: i32| 0x000C_0000 | reason;
124        match self {
125            Why::UnexpectedEnd => not_well_formed(0x2004),
126            Why::NoRoot => not_well_formed(0x2019),
127            Why::DuplicateAttribute => not_well_formed(0x3000),
128            Why::BadComment => not_well_formed(0x3008),
129            Why::LessThanInAttribute => not_well_formed(0x3022),
130            Why::BadReference => not_well_formed(0x3028),
131            Why::MismatchedEndTag => not_well_formed(0x3035),
132            Why::BadDeclaration => not_well_formed(0x3060),
133            Why::UndeclaredEntity => not_well_formed(0x3061),
134            Why::InvalidCharacter | Why::ContentAfterRoot => not_well_formed(0x3062),
135            Why::SecondRoot => not_well_formed(0x3065),
136            Why::UndeclaredAttributePrefix => 0x0004_0800,
137            Why::UndeclaredElementPrefix => 0x0004_0801,
138        }
139    }
140}
141
142/// Where the document stops being well formed: the offset, in characters from the start of the
143/// document, of the first character in error, or of its end.
144#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145pub struct Malformed {
146    pub offset: usize,
147    pub why: Why,
148}
149
150#[derive(Clone, Debug, PartialEq, Eq)]
151pub enum Step {
152    Event(Event),
153    /// The segment is used up and the document is not finished: END-OF-INPUT.
154    EndOfInput,
155    Error(Malformed),
156    /// END-OF-DOCUMENT has been reported.
157    Done,
158}
159
160#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161enum Place {
162    Start,
163    Prolog,
164    Content,
165    Epilogue,
166    Finished,
167}
168
169/// A construct a segment ended inside, whose text is being reported in parts.
170#[derive(Clone, Debug, PartialEq, Eq)]
171enum Open {
172    Comment,
173    /// A processing instruction's target, and whether part of its data has been reported: the
174    /// target is reported again before each later part (p. 32).
175    Instruction(String, bool),
176    Cdata,
177}
178
179struct Element {
180    qualified: String,
181    local: String,
182    prefix: String,
183    namespace: String,
184    bindings: usize,
185}
186
187pub const XML_NAMESPACE: &str = "http://www.w3.org/XML/1998/namespace";
188
189pub struct Scanner<'r> {
190    buf: Vec<char>,
191    at: usize,
192    consumed: usize,
193    place: Place,
194    open: Option<Open>,
195    elements: Vec<Element>,
196    /// Namespace bindings in scope, innermost last: prefix ("" for the default) and identifier.
197    bindings: Vec<(String, String)>,
198    pending: VecDeque<Event>,
199    representable: &'r dyn Fn(char) -> bool,
200    last_segment: bool,
201    doctype: bool,
202    standalone_no: bool,
203    /// The last CONTENT-CHARACTERS piece ended at a segment's end, so XML-INFORMATION said more
204    /// may follow.
205    split: bool,
206}
207
208type Scan<T> = Result<T, Why>;
209
210/// Not enough input to finish a construct.
211const MORE: Why = Why::UnexpectedEnd;
212
213/// XML's white space and next line, EBCDIC's NL (Programming Guide SC27-8714-03, p. 641).
214fn is_space(c: char) -> bool {
215    matches!(c, ' ' | '\t' | '\n' | '\r' | '\u{85}')
216}
217
218fn name_start(c: char) -> bool {
219    c.is_ascii_alphabetic() || c == '_' || c == ':' || c as u32 >= 0xC0
220}
221
222fn name_char(c: char) -> bool {
223    name_start(c) || c.is_ascii_digit() || c == '-' || c == '.' || c == '\u{B7}'
224}
225
226fn xml_char(c: u32) -> bool {
227    matches!(c, 0x9 | 0xA | 0xD | 0x20..=0xD7FF | 0xE000..=0xFFFD | 0x10000..=0x10FFFF)
228}
229
230fn split(qualified: &str) -> (String, String) {
231    match qualified.split_once(':') {
232        Some((prefix, local)) => (prefix.to_owned(), local.to_owned()),
233        None => (String::new(), qualified.to_owned()),
234    }
235}
236
237impl<'r> Scanner<'r> {
238    /// `representable(c)` says whether the document's code page holds c: a character reference
239    /// to one it does not is reported as a NATIONAL-CHARACTER event.
240    pub fn new(segment: &str, representable: &'r dyn Fn(char) -> bool) -> Self {
241        Self {
242            buf: segment.chars().collect(),
243            at: 0,
244            consumed: 0,
245            place: Place::Start,
246            open: None,
247            elements: Vec::new(),
248            bindings: vec![("xml".into(), XML_NAMESPACE.into())],
249            pending: VecDeque::new(),
250            representable,
251            last_segment: false,
252            doctype: false,
253            standalone_no: false,
254            split: false,
255        }
256    }
257
258    /// The next segment, after END-OF-INPUT, joining what the last one left unfinished.
259    pub fn feed(&mut self, segment: &str) {
260        self.consumed += self.at;
261        self.buf.drain(..self.at);
262        self.at = 0;
263        self.buf.extend(segment.chars());
264    }
265
266    /// No segment follows: what is unfinished is an error.
267    pub fn finish(&mut self) {
268        self.last_segment = true;
269    }
270
271    fn peek(&self, ahead: usize) -> Option<char> {
272        self.buf.get(self.at + ahead).copied()
273    }
274
275    fn starts(&self, s: &str) -> bool {
276        let chars: Vec<char> = s.chars().collect();
277        self.buf[self.at..].starts_with(&chars)
278    }
279
280    /// Whether the rest of the buffer could still be the start of `s`.
281    fn could_start(&self, s: &str) -> bool {
282        let rest = &self.buf[self.at..];
283        rest.len() < s.chars().count() && s.chars().zip(rest).all(|(a, &b)| a == b)
284    }
285
286    fn find(&self, from: usize, s: &str) -> Option<usize> {
287        let chars: Vec<char> = s.chars().collect();
288        (from..=self.buf.len().saturating_sub(chars.len())).find(|&i| self.buf[i..].starts_with(&chars))
289    }
290
291    fn fail(&self, at: usize, why: Why) -> Step {
292        Step::Error(Malformed { offset: self.consumed + at, why })
293    }
294
295    pub fn advance(&mut self) -> Step {
296        if let Some(e) = self.pending.pop_front() {
297            return Step::Event(e);
298        }
299        if self.place == Place::Start {
300            self.place = Place::Prolog;
301            return Step::Event(Event::new(EventKind::StartOfDocument, ""));
302        }
303        if self.place == Place::Finished {
304            return Step::Done;
305        }
306        let before = self.at;
307        match self.step() {
308            Ok(()) => match self.pending.pop_front() {
309                Some(e) => Step::Event(e),
310                None if self.place == Place::Finished => Step::Event(Event::new(EventKind::EndOfDocument, "")),
311                None => self.advance(),
312            },
313            Err(MORE) => {
314                self.at = before;
315                self.at_end()
316            }
317            Err(why) => self.fail(self.at, why),
318        }
319    }
320
321    /// The segment is used up, or holds only part of a construct.
322    fn at_end(&mut self) -> Step {
323        if self.place == Place::Epilogue && self.buf[self.at..].iter().all(|&c| is_space(c)) {
324            self.at = self.buf.len();
325            self.place = Place::Finished;
326            return Step::Event(Event::new(EventKind::EndOfDocument, ""));
327        }
328        if !self.last_segment {
329            return Step::EndOfInput;
330        }
331        let why = if self.place == Place::Prolog && self.open.is_none() && self.buf[self.at..].iter().all(|&c| is_space(c)) { Why::NoRoot } else { Why::UnexpectedEnd };
332        Step::Error(Malformed { offset: self.consumed + self.buf.len(), why })
333    }
334
335    /// Scans one construct, queueing its events; `Err(MORE)` leaves the cursor where it was.
336    fn step(&mut self) -> Scan<()> {
337        if let Some(open) = self.open.clone() {
338            return self.continue_open(open);
339        }
340        // Content that a segment's end split is closed by a zero-length final piece when the next
341        // segment starts with markup (Programming Guide SC27-8714-03, pp. 639, 659-660).
342        if self.split && self.peek(0) == Some('<') {
343            self.split = false;
344            self.pending.push_back(Event::characters(EventKind::ContentCharacters, String::new(), true));
345            return Ok(());
346        }
347        while self.place != Place::Content && self.peek(0).is_some_and(is_space) {
348            self.at += 1;
349        }
350        let Some(c) = self.peek(0) else { return Err(MORE) };
351        if c != '<' {
352            if self.place == Place::Content {
353                return self.content();
354            }
355            return Err(if self.place == Place::Epilogue { Why::ContentAfterRoot } else { Why::InvalidCharacter });
356        }
357        if self.starts("<?xml") && self.peek(5).is_some_and(|c| is_space(c) || c == '?') && self.consumed == 0 && self.at == 0 {
358            return self.declaration();
359        }
360        if self.could_start("<!--") || self.could_start("<![CDATA[") || self.could_start("<!DOCTYPE") || self.buf.len() - self.at < 2 {
361            return Err(MORE);
362        }
363        if self.starts("<!--") {
364            self.at += 4;
365            self.open = Some(Open::Comment);
366            return Ok(());
367        }
368        if self.starts("<![CDATA[") {
369            if self.place != Place::Content {
370                return Err(Why::InvalidCharacter);
371            }
372            if self.peek(9).is_none() {
373                return Err(MORE);
374            }
375            self.at += 9;
376            self.pending.push_back(Event::new(EventKind::StartOfCdataSection, ""));
377            self.open = Some(Open::Cdata);
378            return Ok(());
379        }
380        if self.starts("<!DOCTYPE") {
381            return self.doctype();
382        }
383        if self.starts("<?") {
384            return self.instruction();
385        }
386        if self.starts("</") {
387            return self.end_tag();
388        }
389        if self.place == Place::Epilogue {
390            return Err(Why::SecondRoot);
391        }
392        self.start_tag()
393    }
394
395    fn name(&mut self) -> Scan<String> {
396        let start = self.at;
397        match self.peek(0) {
398            None => return Err(MORE),
399            Some(c) if !name_start(c) => return Err(Why::InvalidCharacter),
400            _ => {}
401        }
402        while self.peek(0).is_some_and(name_char) {
403            self.at += 1;
404        }
405        if self.at == self.buf.len() {
406            return Err(MORE);
407        }
408        let name: String = self.buf[start..self.at].iter().collect();
409        if name.matches(':').count() > 1 || name.starts_with(':') || name.ends_with(':') {
410            self.at = start;
411            return Err(Why::InvalidCharacter);
412        }
413        Ok(name)
414    }
415
416    fn spaces(&mut self) -> bool {
417        let start = self.at;
418        while self.peek(0).is_some_and(is_space) {
419            self.at += 1;
420        }
421        self.at > start
422    }
423
424    fn expect(&mut self, c: char) -> Scan<()> {
425        match self.peek(0) {
426            None => Err(MORE),
427            Some(d) if d == c => {
428                self.at += 1;
429                Ok(())
430            }
431            Some(_) => Err(Why::InvalidCharacter),
432        }
433    }
434
435    /// A reference after '&': the character it stands for, or `Err(name)` for an entity that is
436    /// not one of the five predefined.
437    fn reference(&mut self) -> Scan<Result<char, String>> {
438        let end = self.find(self.at, ";").ok_or(MORE)?;
439        let body: String = self.buf[self.at + 1..end].iter().collect();
440        let value = if let Some(hex) = body.strip_prefix("#x") {
441            u32::from_str_radix(hex, 16).ok().filter(|&v| xml_char(v) && !hex.is_empty()).and_then(char::from_u32).map(Ok).ok_or(Why::BadReference)?
442        } else if let Some(dec) = body.strip_prefix('#') {
443            dec.parse::<u32>().ok().filter(|&v| xml_char(v)).and_then(char::from_u32).map(Ok).ok_or(Why::BadReference)?
444        } else {
445            match body.as_str() {
446                "lt" => Ok('<'),
447                "gt" => Ok('>'),
448                "amp" => Ok('&'),
449                "apos" => Ok('\''),
450                "quot" => Ok('"'),
451                name if !name.is_empty() && name.chars().next().is_some_and(name_start) && name.chars().all(name_char) => Err(name.to_owned()),
452                _ => return Err(Why::BadReference),
453            }
454        };
455        self.at = end + 1;
456        Ok(value)
457    }
458
459    fn declaration(&mut self) -> Scan<()> {
460        let end = self.find(self.at, "?>").ok_or(MORE)?;
461        self.at += 5;
462        let mut seen = Vec::new();
463        loop {
464            self.spaces();
465            if self.at >= end {
466                break;
467            }
468            let name = self.name().map_err(|_| Why::BadDeclaration)?;
469            self.spaces();
470            self.expect('=').map_err(|_| Why::BadDeclaration)?;
471            self.spaces();
472            let quote = self.peek(0).filter(|&q| q == '"' || q == '\'').ok_or(Why::BadDeclaration)?;
473            let close = self.find(self.at + 1, &quote.to_string()).filter(|&c| c < end).ok_or(Why::BadDeclaration)?;
474            let value: String = self.buf[self.at + 1..close].iter().collect();
475            self.at = close + 1;
476            let kind = match name.as_str() {
477                "version" if seen.is_empty() => EventKind::VersionInformation,
478                "encoding" if seen == [EventKind::VersionInformation] => EventKind::EncodingDeclaration,
479                "standalone" if seen.first() == Some(&EventKind::VersionInformation) && !seen.contains(&EventKind::StandaloneDeclaration) && (value == "yes" || value == "no") => {
480                    self.standalone_no = value == "no";
481                    EventKind::StandaloneDeclaration
482                }
483                _ => return Err(Why::BadDeclaration),
484            };
485            seen.push(kind);
486            self.pending.push_back(Event::new(kind, value));
487        }
488        if seen.first() != Some(&EventKind::VersionInformation) {
489            return Err(Why::BadDeclaration);
490        }
491        self.at = end + 2;
492        Ok(())
493    }
494
495    fn doctype(&mut self) -> Scan<()> {
496        if self.place != Place::Prolog || self.doctype {
497            return Err(Why::InvalidCharacter);
498        }
499        let mut depth = 0i32;
500        let mut quote = None;
501        let mut i = self.at + 9;
502        let end = loop {
503            let c = *self.buf.get(i).ok_or(MORE)?;
504            match (quote, c) {
505                (Some(q), c) if c == q => quote = None,
506                (Some(_), _) => {}
507                (None, '"' | '\'') => quote = Some(c),
508                (None, '[') => depth += 1,
509                (None, ']') => depth -= 1,
510                (None, '>') if depth == 0 => break i,
511                _ => {}
512            }
513            i += 1;
514        };
515        self.at += 9;
516        if !self.spaces() {
517            return Err(Why::InvalidCharacter);
518        }
519        let root = self.name()?;
520        self.at = end + 1;
521        self.doctype = true;
522        self.pending.push_back(Event::new(EventKind::DocumentTypeDeclaration, root));
523        Ok(())
524    }
525
526    fn instruction(&mut self) -> Scan<()> {
527        self.at += 2;
528        let start = self.at;
529        let target = self.name()?;
530        if target.eq_ignore_ascii_case("xml") {
531            self.at = start;
532            return Err(Why::BadDeclaration);
533        }
534        match self.peek(0) {
535            None => return Err(MORE),
536            Some('?') if self.peek(1).is_none() => return Err(MORE),
537            Some('?') if self.peek(1) == Some('>') => {}
538            Some(c) if is_space(c) => {}
539            Some(_) => return Err(Why::InvalidCharacter),
540        }
541        self.spaces();
542        self.open = Some(Open::Instruction(target.clone(), false));
543        self.pending.push_back(Event::new(EventKind::ProcessingInstructionTarget, target));
544        Ok(())
545    }
546
547    /// Text up to `terminator`, or, when the segment ends first, what it holds short of a possible
548    /// start of the terminator.
549    fn open_text(&mut self, terminator: &str) -> (String, bool) {
550        match self.find(self.at, terminator) {
551            Some(end) => {
552                let text: String = self.buf[self.at..end].iter().collect();
553                self.at = end + terminator.chars().count();
554                (text, true)
555            }
556            None => {
557                let rest = &self.buf[self.at..];
558                let keep = (1..terminator.chars().count()).rev().find(|&n| n <= rest.len() && terminator.chars().take(n).eq(rest[rest.len() - n..].iter().copied())).unwrap_or(0);
559                let end = self.buf.len() - keep;
560                let text: String = self.buf[self.at..end].iter().collect();
561                self.at = end;
562                (text, false)
563            }
564        }
565    }
566
567    fn continue_open(&mut self, open: Open) -> Scan<()> {
568        let (terminator, kind) = match &open {
569            Open::Comment => ("-->", EventKind::Comment),
570            Open::Instruction(..) => ("?>", EventKind::ProcessingInstructionData),
571            Open::Cdata => ("]]>", EventKind::ContentCharacters),
572        };
573        let (text, complete) = self.open_text(terminator);
574        if open == Open::Comment && text.contains("--") {
575            return Err(Why::BadComment);
576        }
577        if !complete && text.is_empty() {
578            return Err(MORE);
579        }
580        if let Open::Instruction(target, true) = &open {
581            self.pending.push_back(Event::new(EventKind::ProcessingInstructionTarget, target.clone()));
582        }
583        if kind == EventKind::ContentCharacters {
584            if !text.is_empty() || std::mem::take(&mut self.split) {
585                self.pending.push_back(Event::characters(kind, text, complete));
586            }
587            self.split = !complete;
588        } else if !text.is_empty() || kind == EventKind::Comment || kind == EventKind::ProcessingInstructionData {
589            self.pending.push_back(Event::new(kind, text));
590        }
591        if complete {
592            self.open = None;
593            if open == Open::Cdata {
594                self.pending.push_back(Event::new(EventKind::EndOfCdataSection, ""));
595            }
596        } else if let Open::Instruction(target, _) = open {
597            self.open = Some(Open::Instruction(target, true));
598        }
599        Ok(())
600    }
601
602    /// A run of character content, its references resolved, up to markup or the segment's end.
603    fn content(&mut self) -> Scan<()> {
604        let mut run = String::new();
605        while let Some(c) = self.peek(0) {
606            match c {
607                '<' => break,
608                '&' => {
609                    let mark = self.at;
610                    match self.reference() {
611                        Ok(Ok(ch)) if (self.representable)(ch) || ch.is_ascii() => run.push(ch),
612                        Ok(Ok(ch)) => {
613                            if !run.is_empty() {
614                                self.pending.push_back(Event::characters(EventKind::ContentCharacters, std::mem::take(&mut run), true));
615                            }
616                            self.pending.push_back(Event::new(EventKind::ContentNationalCharacter, ch.to_string()));
617                        }
618                        Ok(Err(name)) if self.doctype && self.standalone_no => {
619                            if !run.is_empty() {
620                                self.pending.push_back(Event::characters(EventKind::ContentCharacters, std::mem::take(&mut run), true));
621                            }
622                            self.pending.push_back(Event::new(EventKind::UnresolvedReference, name));
623                        }
624                        Ok(Err(_)) => {
625                            self.at = mark;
626                            return Err(Why::UndeclaredEntity);
627                        }
628                        Err(MORE) => {
629                            self.at = mark;
630                            break;
631                        }
632                        Err(why) => {
633                            self.at = mark;
634                            return Err(why);
635                        }
636                    }
637                }
638                '\r' => {
639                    run.push('\n');
640                    self.at += 1;
641                    if self.peek(0) == Some('\n') {
642                        self.at += 1;
643                    }
644                }
645                c if !xml_char(c as u32) => return Err(Why::InvalidCharacter),
646                c => {
647                    run.push(c);
648                    self.at += 1;
649                }
650            }
651        }
652        let complete = self.peek(0) == Some('<');
653        if run.is_empty() && self.pending.is_empty() {
654            return Err(MORE);
655        }
656        if !run.is_empty() {
657            self.pending.push_back(Event::characters(EventKind::ContentCharacters, run, complete));
658            self.split = !complete;
659        }
660        Ok(())
661    }
662
663    fn bound(&self, prefix: &str) -> Option<&str> {
664        self.bindings.iter().rev().find(|(p, _)| p == prefix).map(|(_, uri)| uri.as_str())
665    }
666
667    fn start_tag(&mut self) -> Scan<()> {
668        self.at += 1;
669        let qualified = self.name()?;
670        let mut attributes: Vec<(String, usize, String, Vec<Event>)> = Vec::new();
671        let empty = loop {
672            let spaced = self.spaces();
673            match self.peek(0) {
674                None => return Err(MORE),
675                Some('>') => {
676                    self.at += 1;
677                    break false;
678                }
679                Some('/') => {
680                    self.at += 1;
681                    self.expect('>')?;
682                    break true;
683                }
684                Some(_) if !spaced => return Err(Why::InvalidCharacter),
685                Some(_) => {}
686            }
687            let name_at = self.at;
688            let name = self.name()?;
689            self.spaces();
690            self.expect('=')?;
691            self.spaces();
692            let quote = match self.peek(0) {
693                None => return Err(MORE),
694                Some(q @ ('"' | '\'')) => q,
695                Some(_) => return Err(Why::InvalidCharacter),
696            };
697            self.at += 1;
698            let (value, parts) = self.attribute_value(quote)?;
699            if attributes.iter().any(|(n, ..)| *n == name) {
700                return Err(Why::DuplicateAttribute);
701            }
702            attributes.push((name, name_at, value, parts));
703        };
704        let scope = self.bindings.len();
705        let mut declarations = Vec::new();
706        for (name, _, value, _) in &attributes {
707            let prefix = match name.as_str() {
708                "xmlns" => Some(String::new()),
709                n => n.strip_prefix("xmlns:").map(str::to_owned),
710            };
711            if let Some(prefix) = prefix {
712                self.bindings.push((prefix.clone(), value.clone()));
713                declarations.push(Event { namespace: value.clone(), prefix, ..Event::new(EventKind::NamespaceDeclaration, "") });
714            }
715        }
716        let (prefix, local) = split(&qualified);
717        let mut events = Vec::new();
718        let namespace = match self.bound(&prefix) {
719            Some(uri) => uri.to_owned(),
720            None => {
721                if !prefix.is_empty() {
722                    events.push(Event::undeclared(Why::UndeclaredElementPrefix, &qualified));
723                }
724                String::new()
725            }
726        };
727        events.push(Event { namespace: namespace.clone(), prefix: prefix.clone(), ..Event::new(EventKind::StartOfElement, local.clone()) });
728        events.extend(declarations);
729        for (name, _, _, parts) in attributes {
730            if name == "xmlns" || name.starts_with("xmlns:") {
731                continue;
732            }
733            let (attribute_prefix, attribute_local) = split(&name);
734            let attribute_namespace = if attribute_prefix.is_empty() {
735                String::new()
736            } else {
737                match self.bound(&attribute_prefix) {
738                    Some(uri) => uri.to_owned(),
739                    None => {
740                        events.push(Event::undeclared(Why::UndeclaredAttributePrefix, &name));
741                        String::new()
742                    }
743                }
744            };
745            events.push(Event { namespace: attribute_namespace, prefix: attribute_prefix, ..Event::new(EventKind::AttributeName, attribute_local) });
746            events.extend(parts);
747        }
748        if self.place == Place::Epilogue {
749            return Err(Why::ContentAfterRoot);
750        }
751        self.place = Place::Content;
752        if empty {
753            events.push(Event { namespace, prefix, ..Event::new(EventKind::EndOfElement, local) });
754            self.bindings.truncate(scope);
755            if self.elements.is_empty() {
756                self.place = Place::Epilogue;
757            }
758        } else {
759            self.elements.push(Element { qualified, local, prefix, namespace, bindings: scope });
760        }
761        self.pending.extend(events);
762        Ok(())
763    }
764
765    /// An attribute value after its opening quote: the value, and its ATTRIBUTE-CHARACTERS and
766    /// ATTRIBUTE-NATIONAL-CHARACTER events.
767    fn attribute_value(&mut self, quote: char) -> Scan<(String, Vec<Event>)> {
768        let (mut value, mut run, mut parts) = (String::new(), String::new(), Vec::new());
769        loop {
770            let Some(c) = self.peek(0) else { return Err(MORE) };
771            match c {
772                c if c == quote => {
773                    self.at += 1;
774                    break;
775                }
776                '<' => return Err(Why::LessThanInAttribute),
777                '&' => match self.reference()? {
778                    Ok(ch) if (self.representable)(ch) || ch.is_ascii() => {
779                        run.push(ch);
780                        value.push(ch);
781                    }
782                    Ok(ch) => {
783                        if !run.is_empty() {
784                            parts.push(Event::characters(EventKind::AttributeCharacters, std::mem::take(&mut run), true));
785                        }
786                        parts.push(Event::new(EventKind::AttributeNationalCharacter, ch.to_string()));
787                        value.push(ch);
788                    }
789                    Err(_) => return Err(Why::UndeclaredEntity),
790                },
791                '\t' | '\n' | '\r' => {
792                    run.push(' ');
793                    value.push(' ');
794                    self.at += 1;
795                }
796                c if !xml_char(c as u32) => return Err(Why::InvalidCharacter),
797                c => {
798                    run.push(c);
799                    value.push(c);
800                    self.at += 1;
801                }
802            }
803        }
804        if !run.is_empty() || parts.is_empty() {
805            parts.push(Event::characters(EventKind::AttributeCharacters, run, true));
806        }
807        Ok((value, parts))
808    }
809
810    fn end_tag(&mut self) -> Scan<()> {
811        let start = self.at;
812        self.at += 2;
813        let qualified = self.name()?;
814        self.spaces();
815        self.expect('>')?;
816        match self.elements.last() {
817            Some(e) if e.qualified == qualified => {}
818            _ => {
819                self.at = start;
820                return Err(Why::MismatchedEndTag);
821            }
822        }
823        let e = self.elements.pop().expect("checked above");
824        self.bindings.truncate(e.bindings);
825        self.pending.push_back(Event { namespace: e.namespace, prefix: e.prefix, ..Event::new(EventKind::EndOfElement, e.local) });
826        if self.elements.is_empty() {
827            self.place = Place::Epilogue;
828        }
829        Ok(())
830    }
831}
832
833#[cfg(test)]
834mod tests;