/rust/registry/src/index.crates.io-1949cf8c6b5b557f/quick-xml-0.38.4/src/errors.rs
Line | Count | Source |
1 | | //! Error management module |
2 | | |
3 | | use crate::encoding::{Decoder, EncodingError}; |
4 | | use crate::escape::EscapeError; |
5 | | use crate::events::attributes::AttrError; |
6 | | use crate::name::{NamespaceError, QName}; |
7 | | use std::fmt; |
8 | | use std::io::Error as IoError; |
9 | | use std::sync::Arc; |
10 | | |
11 | | /// An error returned if parsed document does not correspond to the XML grammar, |
12 | | /// for example, a tag opened by `<` not closed with `>`. This error does not |
13 | | /// represent invalid XML constructs, for example, tags `<>` and `</>` a well-formed |
14 | | /// from syntax point-of-view. |
15 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
16 | | pub enum SyntaxError { |
17 | | /// The parser started to parse `<!`, but the input ended before it can recognize |
18 | | /// anything. |
19 | | InvalidBangMarkup, |
20 | | /// The parser started to parse processing instruction or XML declaration (`<?`), |
21 | | /// but the input ended before the `?>` sequence was found. |
22 | | UnclosedPIOrXmlDecl, |
23 | | /// The parser started to parse comment (`<!--`) content, but the input ended |
24 | | /// before the `-->` sequence was found. |
25 | | UnclosedComment, |
26 | | /// The parser started to parse DTD (`<!DOCTYPE`) content, but the input ended |
27 | | /// before the closing `>` character was found. |
28 | | UnclosedDoctype, |
29 | | /// The parser started to parse `<![CDATA[` content, but the input ended |
30 | | /// before the `]]>` sequence was found. |
31 | | UnclosedCData, |
32 | | /// The parser started to parse tag content, but the input ended |
33 | | /// before the closing `>` character was found. |
34 | | UnclosedTag, |
35 | | } |
36 | | |
37 | | impl fmt::Display for SyntaxError { |
38 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
39 | 0 | match self { |
40 | 0 | Self::InvalidBangMarkup => f.write_str("unknown or missed symbol in markup"), |
41 | | Self::UnclosedPIOrXmlDecl => { |
42 | 0 | f.write_str("processing instruction or xml declaration not closed: `?>` not found before end of input") |
43 | | } |
44 | | Self::UnclosedComment => { |
45 | 0 | f.write_str("comment not closed: `-->` not found before end of input") |
46 | | } |
47 | | Self::UnclosedDoctype => { |
48 | 0 | f.write_str("DOCTYPE not closed: `>` not found before end of input") |
49 | | } |
50 | | Self::UnclosedCData => { |
51 | 0 | f.write_str("CDATA not closed: `]]>` not found before end of input") |
52 | | } |
53 | 0 | Self::UnclosedTag => f.write_str("tag not closed: `>` not found before end of input"), |
54 | | } |
55 | 0 | } |
56 | | } |
57 | | |
58 | | impl std::error::Error for SyntaxError {} |
59 | | |
60 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
61 | | |
62 | | /// An error returned if parsed document is not [well-formed], for example, |
63 | | /// an opened tag is not closed before end of input. |
64 | | /// |
65 | | /// Those errors are not fatal: after encountering an error you can continue |
66 | | /// parsing the document. |
67 | | /// |
68 | | /// [well-formed]: https://www.w3.org/TR/xml11/#dt-wellformed |
69 | | #[derive(Clone, Debug, PartialEq, Eq)] |
70 | | pub enum IllFormedError { |
71 | | /// A `version` attribute was not found in an XML declaration or is not the |
72 | | /// first attribute. |
73 | | /// |
74 | | /// According to the [specification], the XML declaration (`<?xml ?>`) MUST contain |
75 | | /// a `version` attribute and it MUST be the first attribute. This error indicates, |
76 | | /// that the declaration does not contain attributes at all (if contains `None`) |
77 | | /// or either `version` attribute is not present or not the first attribute in |
78 | | /// the declaration. In the last case it contains the name of the found attribute. |
79 | | /// |
80 | | /// [specification]: https://www.w3.org/TR/xml11/#sec-prolog-dtd |
81 | | MissingDeclVersion(Option<String>), |
82 | | /// A document type definition (DTD) does not contain a name of a root element. |
83 | | /// |
84 | | /// According to the [specification], document type definition (`<!DOCTYPE foo>`) |
85 | | /// MUST contain a name which defines a document type (`foo`). If that name |
86 | | /// is missed, this error is returned. |
87 | | /// |
88 | | /// [specification]: https://www.w3.org/TR/xml11/#NT-doctypedecl |
89 | | MissingDoctypeName, |
90 | | /// The end tag was not found during reading of a sub-tree of elements due to |
91 | | /// encountering an EOF from the underlying reader. This error is returned from |
92 | | /// [`Reader::read_to_end`]. |
93 | | /// |
94 | | /// [`Reader::read_to_end`]: crate::reader::Reader::read_to_end |
95 | | MissingEndTag(String), |
96 | | /// The specified end tag was encountered without corresponding open tag at the |
97 | | /// same level of hierarchy |
98 | | UnmatchedEndTag(String), |
99 | | /// The specified end tag does not match the start tag at that nesting level. |
100 | | MismatchedEndTag { |
101 | | /// Name of open tag, that is expected to be closed |
102 | | expected: String, |
103 | | /// Name of actually closed tag |
104 | | found: String, |
105 | | }, |
106 | | /// A comment contains forbidden double-hyphen (`--`) sequence inside. |
107 | | /// |
108 | | /// According to the [specification], for compatibility, comments MUST NOT contain |
109 | | /// double-hyphen (`--`) sequence, in particular, they cannot end by `--->`. |
110 | | /// |
111 | | /// The quick-xml by default does not check that, because this restriction is |
112 | | /// mostly artificial, but you can enable it in the [configuration]. |
113 | | /// |
114 | | /// [specification]: https://www.w3.org/TR/xml11/#sec-comments |
115 | | /// [configuration]: crate::reader::Config::check_comments |
116 | | DoubleHyphenInComment, |
117 | | /// The parser started to parse entity or character reference (`&...;`) in text, |
118 | | /// but the input ended before the closing `;` character was found. |
119 | | UnclosedReference, |
120 | | } |
121 | | |
122 | | impl fmt::Display for IllFormedError { |
123 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
124 | 0 | match self { |
125 | | Self::MissingDeclVersion(None) => { |
126 | 0 | f.write_str("an XML declaration does not contain `version` attribute") |
127 | | } |
128 | 0 | Self::MissingDeclVersion(Some(attr)) => { |
129 | 0 | write!(f, "an XML declaration must start with `version` attribute, but in starts with `{}`", attr) |
130 | | } |
131 | | Self::MissingDoctypeName => { |
132 | 0 | f.write_str("`<!DOCTYPE>` declaration does not contain a name of a document type") |
133 | | } |
134 | 0 | Self::MissingEndTag(tag) => write!( |
135 | 0 | f, |
136 | 0 | "start tag not closed: `</{}>` not found before end of input", |
137 | | tag, |
138 | | ), |
139 | 0 | Self::UnmatchedEndTag(tag) => { |
140 | 0 | write!(f, "close tag `</{}>` does not match any open tag", tag) |
141 | | } |
142 | 0 | Self::MismatchedEndTag { expected, found } => write!( |
143 | 0 | f, |
144 | 0 | "expected `</{}>`, but `</{}>` was found", |
145 | | expected, found, |
146 | | ), |
147 | | Self::DoubleHyphenInComment => { |
148 | 0 | f.write_str("forbidden string `--` was found in a comment") |
149 | | } |
150 | 0 | Self::UnclosedReference => f.write_str( |
151 | 0 | "entity or character reference not closed: `;` not found before end of input", |
152 | | ), |
153 | | } |
154 | 0 | } |
155 | | } |
156 | | |
157 | | impl std::error::Error for IllFormedError {} |
158 | | |
159 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
160 | | |
161 | | /// The error type used by this crate. |
162 | | #[derive(Clone, Debug)] |
163 | | pub enum Error { |
164 | | /// XML document cannot be read from underlying source. |
165 | | /// |
166 | | /// Contains the reference-counted I/O error to make the error type `Clone`able. |
167 | | Io(Arc<IoError>), |
168 | | /// The document does not corresponds to the XML grammar. |
169 | | Syntax(SyntaxError), |
170 | | /// The document is not [well-formed](https://www.w3.org/TR/xml11/#dt-wellformed). |
171 | | IllFormed(IllFormedError), |
172 | | /// Attribute parsing error |
173 | | InvalidAttr(AttrError), |
174 | | /// Encoding error |
175 | | Encoding(EncodingError), |
176 | | /// Escape error |
177 | | Escape(EscapeError), |
178 | | /// Parsed XML has some namespace-related problems |
179 | | Namespace(NamespaceError), |
180 | | } |
181 | | |
182 | | impl Error { |
183 | 0 | pub(crate) fn missed_end(name: QName, decoder: Decoder) -> Self { |
184 | 0 | match decoder.decode(name.as_ref()) { |
185 | 0 | Ok(name) => IllFormedError::MissingEndTag(name.into()).into(), |
186 | 0 | Err(err) => err.into(), |
187 | | } |
188 | 0 | } |
189 | | } |
190 | | |
191 | | impl From<IoError> for Error { |
192 | | /// Creates a new `Error::Io` from the given error |
193 | | #[inline] |
194 | 0 | fn from(error: IoError) -> Error { |
195 | 0 | Self::Io(Arc::new(error)) |
196 | 0 | } |
197 | | } |
198 | | |
199 | | impl From<SyntaxError> for Error { |
200 | | /// Creates a new `Error::Syntax` from the given error |
201 | | #[inline] |
202 | 0 | fn from(error: SyntaxError) -> Self { |
203 | 0 | Self::Syntax(error) |
204 | 0 | } |
205 | | } |
206 | | |
207 | | impl From<IllFormedError> for Error { |
208 | | /// Creates a new `Error::IllFormed` from the given error |
209 | | #[inline] |
210 | 0 | fn from(error: IllFormedError) -> Self { |
211 | 0 | Self::IllFormed(error) |
212 | 0 | } |
213 | | } |
214 | | |
215 | | impl From<EncodingError> for Error { |
216 | | /// Creates a new `Error::EncodingError` from the given error |
217 | | #[inline] |
218 | 0 | fn from(error: EncodingError) -> Error { |
219 | 0 | Self::Encoding(error) |
220 | 0 | } |
221 | | } |
222 | | |
223 | | impl From<EscapeError> for Error { |
224 | | /// Creates a new `Error::EscapeError` from the given error |
225 | | #[inline] |
226 | 0 | fn from(error: EscapeError) -> Error { |
227 | 0 | Self::Escape(error) |
228 | 0 | } |
229 | | } |
230 | | |
231 | | impl From<AttrError> for Error { |
232 | | #[inline] |
233 | 0 | fn from(error: AttrError) -> Self { |
234 | 0 | Self::InvalidAttr(error) |
235 | 0 | } |
236 | | } |
237 | | |
238 | | impl From<NamespaceError> for Error { |
239 | | #[inline] |
240 | 0 | fn from(error: NamespaceError) -> Self { |
241 | 0 | Self::Namespace(error) |
242 | 0 | } |
243 | | } |
244 | | |
245 | | /// A specialized `Result` type where the error is hard-wired to [`Error`]. |
246 | | pub type Result<T> = std::result::Result<T, Error>; |
247 | | |
248 | | impl fmt::Display for Error { |
249 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
250 | 0 | match self { |
251 | 0 | Self::Io(e) => write!(f, "I/O error: {}", e), |
252 | 0 | Self::Syntax(e) => write!(f, "syntax error: {}", e), |
253 | 0 | Self::IllFormed(e) => write!(f, "ill-formed document: {}", e), |
254 | 0 | Self::InvalidAttr(e) => write!(f, "error while parsing attribute: {}", e), |
255 | 0 | Self::Encoding(e) => e.fmt(f), |
256 | 0 | Self::Escape(e) => e.fmt(f), |
257 | 0 | Self::Namespace(e) => e.fmt(f), |
258 | | } |
259 | 0 | } |
260 | | } |
261 | | |
262 | | impl std::error::Error for Error { |
263 | 0 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
264 | 0 | match self { |
265 | 0 | Self::Io(e) => Some(e), |
266 | 0 | Self::Syntax(e) => Some(e), |
267 | 0 | Self::IllFormed(e) => Some(e), |
268 | 0 | Self::InvalidAttr(e) => Some(e), |
269 | 0 | Self::Encoding(e) => Some(e), |
270 | 0 | Self::Escape(e) => Some(e), |
271 | 0 | Self::Namespace(e) => Some(e), |
272 | | } |
273 | 0 | } |
274 | | } |
275 | | |
276 | | #[cfg(feature = "serialize")] |
277 | | pub mod serialize { |
278 | | //! A module to handle serde (de)serialization errors |
279 | | |
280 | | use super::*; |
281 | | use crate::utils::write_byte_string; |
282 | | use std::borrow::Cow; |
283 | | #[cfg(feature = "overlapped-lists")] |
284 | | use std::num::NonZeroUsize; |
285 | | use std::str::Utf8Error; |
286 | | |
287 | | /// (De)serialization error |
288 | | #[derive(Clone, Debug)] |
289 | | pub enum DeError { |
290 | | /// Serde custom error |
291 | | Custom(String), |
292 | | /// Xml parsing error |
293 | | InvalidXml(Error), |
294 | | /// This error indicates an error in the [`Deserialize`](serde::Deserialize) |
295 | | /// implementation when read a map or a struct: `MapAccess::next_value[_seed]` |
296 | | /// was called before `MapAccess::next_key[_seed]`. |
297 | | /// |
298 | | /// You should check your types, that implements corresponding trait. |
299 | | KeyNotRead, |
300 | | /// Deserializer encounter a start tag with a specified name when it is |
301 | | /// not expecting. This happens when you try to deserialize a primitive |
302 | | /// value (numbers, strings, booleans) from an XML element. |
303 | | UnexpectedStart(Vec<u8>), |
304 | | /// The [`Reader`] produced [`Event::Eof`] when it is not expecting, |
305 | | /// for example, after producing [`Event::Start`] but before corresponding |
306 | | /// [`Event::End`]. |
307 | | /// |
308 | | /// [`Reader`]: crate::reader::Reader |
309 | | /// [`Event::Eof`]: crate::events::Event::Eof |
310 | | /// [`Event::Start`]: crate::events::Event::Start |
311 | | /// [`Event::End`]: crate::events::Event::End |
312 | | UnexpectedEof, |
313 | | /// Too many events were skipped while deserializing a sequence, event limit |
314 | | /// exceeded. The limit was provided as an argument |
315 | | #[cfg(feature = "overlapped-lists")] |
316 | | TooManyEvents(NonZeroUsize), |
317 | | } |
318 | | |
319 | | impl fmt::Display for DeError { |
320 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
321 | 0 | match self { |
322 | 0 | Self::Custom(s) => f.write_str(s), |
323 | 0 | Self::InvalidXml(e) => e.fmt(f), |
324 | 0 | Self::KeyNotRead => f.write_str("invalid `Deserialize` implementation: `MapAccess::next_value[_seed]` was called before `MapAccess::next_key[_seed]`"), |
325 | 0 | Self::UnexpectedStart(e) => { |
326 | 0 | f.write_str("unexpected `Event::Start(")?; |
327 | 0 | write_byte_string(f, e)?; |
328 | 0 | f.write_str(")`") |
329 | | } |
330 | 0 | Self::UnexpectedEof => f.write_str("unexpected `Event::Eof`"), |
331 | | #[cfg(feature = "overlapped-lists")] |
332 | 0 | Self::TooManyEvents(s) => write!(f, "deserializer buffered {} events, limit exceeded", s), |
333 | | } |
334 | 0 | } |
335 | | } |
336 | | |
337 | | impl std::error::Error for DeError { |
338 | 0 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
339 | 0 | match self { |
340 | 0 | Self::InvalidXml(e) => Some(e), |
341 | 0 | _ => None, |
342 | | } |
343 | 0 | } |
344 | | } |
345 | | |
346 | | impl serde::de::Error for DeError { |
347 | 0 | fn custom<T: fmt::Display>(msg: T) -> Self { |
348 | 0 | Self::Custom(msg.to_string()) |
349 | 0 | } |
350 | | } |
351 | | |
352 | | impl From<Error> for DeError { |
353 | | #[inline] |
354 | 0 | fn from(e: Error) -> Self { |
355 | 0 | Self::InvalidXml(e) |
356 | 0 | } |
357 | | } |
358 | | |
359 | | impl From<EscapeError> for DeError { |
360 | | #[inline] |
361 | 0 | fn from(e: EscapeError) -> Self { |
362 | 0 | Self::InvalidXml(e.into()) |
363 | 0 | } |
364 | | } |
365 | | |
366 | | impl From<EncodingError> for DeError { |
367 | | #[inline] |
368 | 0 | fn from(e: EncodingError) -> Self { |
369 | 0 | Self::InvalidXml(e.into()) |
370 | 0 | } |
371 | | } |
372 | | |
373 | | impl From<AttrError> for DeError { |
374 | | #[inline] |
375 | 0 | fn from(e: AttrError) -> Self { |
376 | 0 | Self::InvalidXml(e.into()) |
377 | 0 | } |
378 | | } |
379 | | |
380 | | /// Serialization error |
381 | | #[derive(Clone, Debug)] |
382 | | pub enum SeError { |
383 | | /// Serde custom error |
384 | | Custom(String), |
385 | | /// XML document cannot be written to underlying source. |
386 | | /// |
387 | | /// Contains the reference-counted I/O error to make the error type `Clone`able. |
388 | | Io(Arc<IoError>), |
389 | | /// Some value could not be formatted |
390 | | Fmt(std::fmt::Error), |
391 | | /// Serialized type cannot be represented in an XML due to violation of the |
392 | | /// XML rules in the final XML document. For example, attempt to serialize |
393 | | /// a `HashMap<{integer}, ...>` would cause this error because [XML name] |
394 | | /// cannot start from a digit or a hyphen (minus sign). The same result |
395 | | /// would occur if map key is a complex type that cannot be serialized as |
396 | | /// a primitive type (i.e. string, char, bool, unit struct or unit variant). |
397 | | /// |
398 | | /// [XML name]: https://www.w3.org/TR/xml11/#sec-common-syn |
399 | | Unsupported(Cow<'static, str>), |
400 | | /// Some value could not be turned to UTF-8 |
401 | | NonEncodable(Utf8Error), |
402 | | } |
403 | | |
404 | | impl fmt::Display for SeError { |
405 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
406 | 0 | match self { |
407 | 0 | Self::Custom(s) => f.write_str(s), |
408 | 0 | Self::Io(e) => write!(f, "I/O error: {}", e), |
409 | 0 | Self::Fmt(e) => write!(f, "formatting error: {}", e), |
410 | 0 | Self::Unsupported(s) => write!(f, "unsupported value: {}", s), |
411 | 0 | Self::NonEncodable(e) => write!(f, "malformed UTF-8: {}", e), |
412 | | } |
413 | 0 | } |
414 | | } |
415 | | |
416 | | impl ::std::error::Error for SeError { |
417 | 0 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
418 | 0 | match self { |
419 | 0 | Self::Io(e) => Some(e), |
420 | 0 | _ => None, |
421 | | } |
422 | 0 | } |
423 | | } |
424 | | |
425 | | impl serde::ser::Error for SeError { |
426 | 0 | fn custom<T: fmt::Display>(msg: T) -> Self { |
427 | 0 | Self::Custom(msg.to_string()) |
428 | 0 | } |
429 | | } |
430 | | |
431 | | impl From<IoError> for SeError { |
432 | | #[inline] |
433 | 0 | fn from(e: IoError) -> Self { |
434 | 0 | Self::Io(Arc::new(e)) |
435 | 0 | } |
436 | | } |
437 | | |
438 | | impl From<Utf8Error> for SeError { |
439 | | #[inline] |
440 | 0 | fn from(e: Utf8Error) -> Self { |
441 | 0 | Self::NonEncodable(e) |
442 | 0 | } |
443 | | } |
444 | | |
445 | | impl From<fmt::Error> for SeError { |
446 | | #[inline] |
447 | 0 | fn from(e: fmt::Error) -> Self { |
448 | 0 | Self::Fmt(e) |
449 | 0 | } |
450 | | } |
451 | | } |