1extern crate alloc;
2
3use crate::Encoding;
4use crate::reader::lexer::Token;
5
6use alloc::borrow::Cow;
7use alloc::boxed::Box;
8use alloc::string::String;
9
10use core::fmt;
11use core::str;
12
13use crate::common::{Position, TextPosition};
14use crate::util;
15
16#[derive(Debug)]
18pub enum ErrorKind {
19 Syntax(Cow<'static, str>),
21 Io(String),
22 Utf8(str::Utf8Error),
23 UnexpectedEof,
25}
26
27#[derive(Debug, Clone, PartialEq)]
28#[non_exhaustive]
29pub(crate) enum SyntaxError {
30 CannotRedefineXmlnsPrefix,
31 CannotRedefineXmlPrefix,
32 EntityTooBig,
34 EmptyEntity,
35 NoRootElement,
36 ProcessingInstructionWithoutName,
37 UnbalancedRootElement,
38 UnexpectedEof,
39 UnexpectedOpeningTag,
40 UnclosedCdata,
42 UnexpectedQualifiedName(Token),
43 UnexpectedTokenOutsideRoot(Token),
44 UnexpectedToken(Token),
45 UnexpectedTokenInEntity(Token),
46 UnexpectedTokenInClosingTag(Token),
47 UnexpectedTokenInOpeningTag(Token),
48 InvalidQualifiedName(Box<str>),
49 UnboundAttribute(Box<str>),
50 UnboundElementPrefix(Box<str>),
51 UnexpectedClosingTag(Box<str>),
52 UnexpectedName(Box<str>),
53 UnexpectedProcessingInstruction(Box<str>, Token),
56 CannotUndefinePrefix(Box<str>),
57 InvalidCharacterEntity(u32),
58 InvalidDefaultNamespace(Box<str>),
59 InvalidNamePrefix(Box<str>),
60 InvalidNumericEntity(Box<str>),
61 InvalidStandaloneDeclaration(Box<str>),
62 InvalidXmlProcessingInstruction(Box<str>),
63 RedefinedAttribute(Box<str>),
64 UndefinedEntity(Box<str>),
65 UnexpectedEntity(Box<str>),
66 UnexpectedNameInsideXml(Box<str>),
67 UnsupportedEncoding(Box<str>),
68 UnknownMarkupDeclaration(Box<str>),
70 UnexpectedXmlVersion(Box<str>),
71 ConflictingEncoding(Encoding, Encoding),
72 UnexpectedTokenBefore(&'static str, char),
73 ExceededConfiguredLimit,
75}
76
77impl fmt::Display for SyntaxError {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 self.to_cow().fmt(f)
80 }
81}
82
83impl SyntaxError {
84 #[inline(never)]
85 #[cold]
86 pub(crate) fn to_cow(&self) -> Cow<'static, str> {
87 match *self {
88 Self::CannotRedefineXmlnsPrefix => "Cannot redefine XMLNS prefix".into(),
89 Self::CannotRedefineXmlPrefix => "Default XMLNS prefix cannot be rebound to another value".into(),
90 Self::EmptyEntity => "Encountered empty entity".into(),
91 Self::EntityTooBig => "Entity too big".into(),
92 Self::NoRootElement => "Unexpected end of stream: no root element found".into(),
93 Self::ProcessingInstructionWithoutName => "Encountered processing instruction without a name".into(),
94 Self::UnbalancedRootElement => "Unexpected end of stream: still inside the root element".into(),
95 Self::UnclosedCdata => "Unclosed <![CDATA[".into(),
96 Self::UnexpectedEof => "Unexpected end of stream".into(),
97 Self::UnexpectedOpeningTag => "'<' is not allowed in attributes".into(),
98 Self::CannotUndefinePrefix(ref ln) => alloc::format!("Cannot undefine prefix '{ln}'").into(),
99 Self::ConflictingEncoding(a, b) => alloc::format!("Declared encoding {a}, but uses {b}").into(),
100 Self::InvalidCharacterEntity(num) => alloc::format!("Invalid character U+{num:04X}").into(),
101 Self::InvalidDefaultNamespace(ref name) => alloc::format!("Namespace '{name}' cannot be default").into(),
102 Self::InvalidNamePrefix(ref prefix) => alloc::format!("'{prefix}' cannot be an element name prefix").into(),
103 Self::InvalidNumericEntity(ref v) => alloc::format!("Invalid numeric entity: {v}").into(),
104 Self::InvalidQualifiedName(ref e) => alloc::format!("Qualified name is invalid: {e}").into(),
105 Self::InvalidStandaloneDeclaration(ref value) => alloc::format!("Invalid standalone declaration value: {value}").into(),
106 Self::InvalidXmlProcessingInstruction(ref name) => alloc::format!("Invalid processing instruction: <?{name}\nThe XML spec only allows \"<?xml\" at the very beginning of the file, with no whitespace, comments, or any elements before it").into(),
107 Self::RedefinedAttribute(ref name) => alloc::format!("Attribute '{name}' is redefined").into(),
108 Self::UnboundAttribute(ref name) => alloc::format!("Attribute {name} prefix is unbound").into(),
109 Self::UnboundElementPrefix(ref name) => alloc::format!("Element {name} prefix is unbound").into(),
110 Self::UndefinedEntity(ref v) => alloc::format!("Undefined entity: {v}").into(),
111 Self::UnexpectedClosingTag(ref expected_got) => alloc::format!("Unexpected closing tag: {expected_got}").into(),
112 Self::UnexpectedEntity(ref name) => alloc::format!("Unexpected entity: {name}").into(),
113 Self::UnexpectedName(ref name) => alloc::format!("Unexpected name: {name}").into(),
114 Self::UnexpectedNameInsideXml(ref name) => alloc::format!("Unexpected name inside XML declaration: {name}").into(),
115 Self::UnexpectedProcessingInstruction(ref buf, token) => alloc::format!("Unexpected token inside processing instruction: <?{buf}{token}").into(),
116 Self::UnexpectedQualifiedName(e) => alloc::format!("Unexpected token inside qualified name: {e}").into(),
117 Self::UnexpectedToken(token) => alloc::format!("Unexpected token: {token}").into(),
118 Self::UnexpectedTokenBefore(before, c) => alloc::format!("Unexpected token '{before}' before '{c}'").into(),
119 Self::UnexpectedTokenInClosingTag(token) => alloc::format!("Unexpected token inside closing tag: {token}").into(),
120 Self::UnexpectedTokenInEntity(token) => alloc::format!("Unexpected token inside entity: {token}").into(),
121 Self::UnexpectedTokenInOpeningTag(token) => alloc::format!("Unexpected token inside opening tag: {token}").into(),
122 Self::UnexpectedTokenOutsideRoot(token) => alloc::format!("Unexpected characters outside the root element: {token}").into(),
123 Self::UnexpectedXmlVersion(ref version) => alloc::format!("Invalid XML version: {version}").into(),
124 Self::UnknownMarkupDeclaration(ref v) => alloc::format!("Unknown markup declaration: {v}").into(),
125 Self::UnsupportedEncoding(ref v) => alloc::format!("Unsupported encoding: {v}").into(),
126 Self::ExceededConfiguredLimit => "This document is larger/more complex than allowed by the parser's configuration".into(),
127 }
128 }
129}
130
131#[derive(Clone, PartialEq, Eq, Debug)]
135pub struct Error {
136 pub(crate) pos: TextPosition,
137 pub(crate) kind: ErrorKind,
138}
139
140impl fmt::Display for Error {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 use self::ErrorKind::{Io, Syntax, UnexpectedEof, Utf8};
143
144 write!(f, "{} ", self.pos)?;
145 match &self.kind {
146 Io(io_error) => io_error.fmt(f),
147 Utf8(reason) => reason.fmt(f),
148 Syntax(msg) => f.write_str(msg),
149 UnexpectedEof => f.write_str("Unexpected EOF"),
150 }
151 }
152}
153
154impl Position for Error {
155 #[inline]
156 fn position(&self) -> TextPosition { self.pos }
157}
158
159impl Error {
160 #[cold]
162 #[doc(hidden)]
163 #[allow(deprecated)]
164 #[must_use] pub fn msg(&self) -> &str {
165 use self::ErrorKind::{Io, Syntax, UnexpectedEof, Utf8};
166 match &self.kind {
167 Io(io_error) => &io_error,
168 Utf8(_) => "UTF8 Error",
169 Syntax(msg) => msg.as_ref(),
170 UnexpectedEof => "Unexpected EOF",
171 }
172 }
173
174 #[must_use]
176 #[inline]
177 pub fn kind(&self) -> &ErrorKind {
178 &self.kind
179 }
180}
181
182impl<'a, P, M> From<(&'a P, M)> for Error where P: Position, M: Into<Cow<'static, str>> {
183 #[cold]
184 fn from(orig: (&'a P, M)) -> Self {
185 Error {
186 pos: orig.0.position(),
187 kind: ErrorKind::Syntax(orig.1.into()),
188 }
189 }
190}
191
192impl From<util::CharReadError> for Error {
193 #[cold]
194 fn from(e: util::CharReadError) -> Self {
195 use crate::util::CharReadError::{Io, UnexpectedEof, Utf8};
196 Error {
197 pos: TextPosition::new(),
198 kind: match e {
199 UnexpectedEof => ErrorKind::UnexpectedEof,
200 Utf8(reason) => ErrorKind::Utf8(reason),
201 Io(io_error) => ErrorKind::Io(io_error),
202 },
203 }
204 }
205}
206
207
208impl Clone for ErrorKind {
209 #[cold]
210 fn clone(&self) -> Self {
211 use self::ErrorKind::{Io, Syntax, UnexpectedEof, Utf8};
212 match self {
213 UnexpectedEof => UnexpectedEof,
214 Utf8(reason) => Utf8(*reason),
215 Io(io_error) => Io(io_error.clone()),
216 Syntax(msg) => Syntax(msg.clone()),
217 }
218 }
219}
220impl PartialEq for ErrorKind {
221 #[allow(deprecated)]
222 fn eq(&self, other: &ErrorKind) -> bool {
223 use self::ErrorKind::{Io, Syntax, UnexpectedEof, Utf8};
224 match (self, other) {
225 (UnexpectedEof, UnexpectedEof) => true,
226 (Utf8(left), Utf8(right)) => left == right,
227 (Io(left), Io(right)) =>
228 left == right,
229 (Syntax(left), Syntax(right)) =>
230 left == right,
231
232 (_, _) => false,
233 }
234 }
235}
236impl Eq for ErrorKind {}
237
238#[test]
239fn err_size() {
240 assert!(std::mem::size_of::<SyntaxError>() <= 24);
241}