1use crate::reader::lexer::Token;
2use crate::writer::Error as EmitterError;
3use crate::Encoding;
4
5use std::borrow::Cow;
6use std::error::Error as _;
7use std::{error, fmt, io, str};
8
9use crate::common::{Position, TextPosition};
10use crate::util;
11
12#[derive(Debug)]
14#[non_exhaustive]
15pub enum ErrorKind {
16 Syntax(Cow<'static, str>),
18 Io(io::Error),
20 Utf8(str::Utf8Error),
22 UnexpectedEof,
24 EmitterError(Box<EmitterError>),
26}
27
28#[derive(Clone, PartialEq)]
30#[non_exhaustive]
31pub enum ImmutableEntitiesError {
32 ElementEncountered,
34 StandaloneDocument,
36}
37
38#[derive(Debug, Clone, PartialEq)]
39#[non_exhaustive]
40pub(crate) enum SyntaxError {
41 CannotRedefineXmlnsPrefix,
42 CannotRedefineXmlPrefix,
43 EntityTooBig,
45 EmptyEntity,
46 NoRootElement,
47 ProcessingInstructionWithoutName,
48 UnbalancedRootElement,
49 UnexpectedEof,
50 UnexpectedOpeningTag,
51 UnclosedCdata,
53 UnexpectedQualifiedName(Token),
54 UnexpectedTokenOutsideRoot(Token),
55 UnexpectedToken(Token),
56 UnexpectedTokenInEntity(Token),
57 UnexpectedTokenInClosingTag(Token),
58 UnexpectedTokenInOpeningTag(Token),
59 InvalidQualifiedName(Box<str>),
60 UnboundAttribute(Box<str>),
61 UnboundElementPrefix(Box<str>),
62 UnexpectedClosingTag(Box<str>),
63 UnexpectedName(Box<str>),
64 UnexpectedProcessingInstruction(Box<str>, Token),
67 CannotUndefinePrefix(Box<str>),
68 InvalidCharacterEntity(u32),
69 InvalidDefaultNamespace(Box<str>),
70 InvalidNamePrefix(Box<str>),
71 InvalidNumericEntity(Box<str>),
72 InvalidStandaloneDeclaration(Box<str>),
73 InvalidXmlProcessingInstruction(Box<str>),
74 RedefinedAttribute(Box<str>),
75 UndefinedEntity(Box<str>),
76 UnexpectedEntity(Box<str>),
77 UnexpectedNameInsideXml(Box<str>),
78 UnsupportedEncoding(Box<str>),
79 UnknownMarkupDeclaration(Box<str>),
81 UnexpectedXmlVersion(Box<str>),
82 ConflictingEncoding(Encoding, Encoding),
83 UnexpectedTokenBefore(&'static str, char),
84 ExceededConfiguredLimit,
86}
87
88impl fmt::Display for SyntaxError {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 self.to_cow().fmt(f)
91 }
92}
93
94impl SyntaxError {
95 #[inline(never)]
96 #[cold]
97 pub(crate) fn to_cow(&self) -> Cow<'static, str> {
98 match *self {
99 Self::CannotRedefineXmlnsPrefix => "Cannot redefine XMLNS prefix".into(),
100 Self::CannotRedefineXmlPrefix => "Default XMLNS prefix cannot be rebound to another value".into(),
101 Self::EmptyEntity => "Encountered empty entity".into(),
102 Self::EntityTooBig => "Entity too big".into(),
103 Self::NoRootElement => "Unexpected end of stream: no root element found".into(),
104 Self::ProcessingInstructionWithoutName => "Encountered processing instruction without a name".into(),
105 Self::UnbalancedRootElement => "Unexpected end of stream: still inside the root element".into(),
106 Self::UnclosedCdata => "Unclosed <![CDATA[".into(),
107 Self::UnexpectedEof => "Unexpected end of stream".into(),
108 Self::UnexpectedOpeningTag => "'<' is not allowed in attributes".into(),
109 Self::CannotUndefinePrefix(ref ln) => format!("Cannot undefine prefix '{ln}'").into(),
110 Self::ConflictingEncoding(a, b) => format!("Declared encoding {a}, but uses {b}").into(),
111 Self::InvalidCharacterEntity(num) => format!("Invalid character U+{num:04X}").into(),
112 Self::InvalidDefaultNamespace(ref name) => format!("Namespace '{name}' cannot be default").into(),
113 Self::InvalidNamePrefix(ref prefix) => format!("'{prefix}' cannot be an element name prefix").into(),
114 Self::InvalidNumericEntity(ref v) => format!("Invalid numeric entity: {v}").into(),
115 Self::InvalidQualifiedName(ref e) => format!("Qualified name is invalid: {e}").into(),
116 Self::InvalidStandaloneDeclaration(ref value) => format!("Invalid standalone declaration value: {value}").into(),
117 Self::InvalidXmlProcessingInstruction(ref name) => 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(),
118 Self::RedefinedAttribute(ref name) => format!("Attribute '{name}' is redefined").into(),
119 Self::UnboundAttribute(ref name) => format!("Attribute {name} prefix is unbound").into(),
120 Self::UnboundElementPrefix(ref name) => format!("Element {name} prefix is unbound").into(),
121 Self::UndefinedEntity(ref v) => format!("Undefined entity: {v}").into(),
122 Self::UnexpectedClosingTag(ref expected_got) => format!("Unexpected closing tag: {expected_got}").into(),
123 Self::UnexpectedEntity(ref name) => format!("Unexpected entity: {name}").into(),
124 Self::UnexpectedName(ref name) => format!("Unexpected name: {name}").into(),
125 Self::UnexpectedNameInsideXml(ref name) => format!("Unexpected name inside XML declaration: {name}").into(),
126 Self::UnexpectedProcessingInstruction(ref buf, token) => format!("Unexpected token inside processing instruction: <?{buf}{token}").into(),
127 Self::UnexpectedQualifiedName(e) => format!("Unexpected token inside qualified name: {e}").into(),
128 Self::UnexpectedToken(token) => format!("Unexpected token: {token}").into(),
129 Self::UnexpectedTokenBefore(before, c) => format!("Unexpected token '{before}' before '{c}'").into(),
130 Self::UnexpectedTokenInClosingTag(token) => format!("Unexpected token inside closing tag: {token}").into(),
131 Self::UnexpectedTokenInEntity(token) => format!("Unexpected token inside entity: {token}").into(),
132 Self::UnexpectedTokenInOpeningTag(token) => format!("Unexpected token inside opening tag: {token}").into(),
133 Self::UnexpectedTokenOutsideRoot(token) => format!("Unexpected characters outside the root element: {token}").into(),
134 Self::UnexpectedXmlVersion(ref version) => format!("Invalid XML version: {version}").into(),
135 Self::UnknownMarkupDeclaration(ref v) => format!("Unknown markup declaration: {v}").into(),
136 Self::UnsupportedEncoding(ref v) => format!("Unsupported encoding: {v}").into(),
137 Self::ExceededConfiguredLimit => "This document is larger/more complex than allowed by the parser's configuration".into(),
138 }
139 }
140}
141
142#[derive(Clone, PartialEq, Eq, Debug)]
146pub struct Error {
147 pub(crate) pos: TextPosition,
148 pub(crate) kind: ErrorKind,
149}
150
151impl fmt::Display for Error {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 use self::ErrorKind::{EmitterError, Io, Syntax, UnexpectedEof, Utf8};
154
155 write!(f, "{} ", self.pos)?;
156 match &self.kind {
157 Io(io_error) => io_error.fmt(f),
158 Utf8(reason) => reason.fmt(f),
159 Syntax(msg) => f.write_str(msg),
160 UnexpectedEof => f.write_str("Unexpected EOF"),
161 EmitterError(e) => e.fmt(f),
162 }
163 }
164}
165
166impl fmt::Display for ImmutableEntitiesError {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 f.write_str(match self {
169 Self::ElementEncountered => "Element encountered",
170 Self::StandaloneDocument => "Standalone XML",
171 })
172 }
173}
174
175impl fmt::Debug for ImmutableEntitiesError {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 fmt::Display::fmt(self, f)
178 }
179}
180
181impl error::Error for ImmutableEntitiesError {
182}
183
184impl Position for Error {
185 #[inline]
186 fn position(&self) -> TextPosition { self.pos }
187}
188
189impl Error {
190 #[doc(hidden)]
191 #[must_use]
192 pub fn msg(&self) -> String {
193 self.to_string()
194 }
195
196 #[must_use]
198 #[inline]
199 pub fn kind(&self) -> &ErrorKind {
200 &self.kind
201 }
202
203 pub(crate) fn syntax(syntax_msg: Cow<'static, str>, pos: TextPosition) -> Self {
204 Self {
205 kind: ErrorKind::Syntax(syntax_msg),
206 pos
207 }
208 }
209}
210
211impl error::Error for Error {
212 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
213 match &self.kind {
214 ErrorKind::Io(e) => e.source(),
215 ErrorKind::Utf8(e) => Some(e),
216 ErrorKind::EmitterError(e) => Some(e),
217 _ => None,
218 }
219 }
220}
221
222impl<'a, P, M> From<(&'a P, M)> for Error where P: Position, M: Into<Cow<'static, str>> {
223 #[cold]
224 fn from(orig: (&'a P, M)) -> Self {
225 Self {
226 pos: orig.0.position(),
227 kind: ErrorKind::Syntax(orig.1.into()),
228 }
229 }
230}
231
232impl From<util::CharReadError> for Error {
233 #[cold]
234 fn from(e: util::CharReadError) -> Self {
235 use crate::util::CharReadError::{Io, UnexpectedEof, Utf8};
236 Self {
237 pos: TextPosition::new(),
238 kind: match e {
239 UnexpectedEof => ErrorKind::UnexpectedEof,
240 Utf8(reason) => ErrorKind::Utf8(reason),
241 Io(io_error) => ErrorKind::Io(io_error),
242 },
243 }
244 }
245}
246
247impl From<io::Error> for Error {
248 #[cold]
249 fn from(e: io::Error) -> Self {
250 Self {
251 pos: TextPosition::new(),
252 kind: ErrorKind::Io(e),
253 }
254 }
255}
256
257impl From<EmitterError> for Error {
258 #[cold]
259 fn from(e: EmitterError) -> Self {
260 Self {
261 pos: TextPosition::new(),
262 kind: ErrorKind::EmitterError(Box::new(e)),
263 }
264 }
265}
266
267impl From<ImmutableEntitiesError> for Error {
268 #[cold]
269 fn from(e: ImmutableEntitiesError) -> Self {
270 Self {
271 pos: TextPosition::new(),
272 kind: ErrorKind::Io(io::Error::new(io::ErrorKind::Other, e)),
273 }
274 }
275}
276
277impl From<ErrorKind> for Error {
278 fn from(kind: ErrorKind) -> Self {
279 Self { kind, pos: TextPosition::new() }
280 }
281}
282
283impl Clone for ErrorKind {
284 #[cold]
285 fn clone(&self) -> Self {
286 use self::ErrorKind::{EmitterError, Io, Syntax, UnexpectedEof, Utf8};
287 match self {
288 UnexpectedEof => UnexpectedEof,
289 Utf8(reason) => Utf8(*reason),
290 Io(io_error) => Io(io::Error::new(io_error.kind(), io_error.to_string())),
291 Syntax(msg) => Syntax(msg.clone()),
292 EmitterError(e) => EmitterError(e.clone()),
293 }
294 }
295}
296
297impl PartialEq for ErrorKind {
298 #[allow(deprecated)]
299 fn eq(&self, other: &Self) -> bool {
300 use self::ErrorKind::{Io, Syntax, UnexpectedEof, Utf8};
301 match (self, other) {
302 (UnexpectedEof, UnexpectedEof) => true,
303 (Utf8(left), Utf8(right)) => left == right,
304 (Io(left), Io(right)) =>
305 left.kind() == right.kind() &&
306 left.description() == right.description(),
307 (Syntax(left), Syntax(right)) =>
308 left == right,
309 (_, _) => false,
310 }
311 }
312}
313impl Eq for ErrorKind {}
314
315#[test]
316fn err_size() {
317 assert!(std::mem::size_of::<SyntaxError>() <= 24);
318}