1 use std::{error, fmt, io};
2 
3 use crate::stream::Event;
4 
5 /// This type represents all possible errors that can occur when working with plist data.
6 #[derive(Debug)]
7 pub struct Error {
8     inner: Box<ErrorImpl>,
9 }
10 
11 #[derive(Debug)]
12 pub(crate) struct ErrorImpl {
13     kind: ErrorKind,
14     file_position: Option<FilePosition>,
15 }
16 
17 #[derive(Debug)]
18 pub(crate) enum ErrorKind {
19     UnexpectedEof,
20     UnexpectedEndOfEventStream,
21     UnexpectedEventType {
22         expected: EventKind,
23         found: EventKind,
24     },
25 
26     // Xml format-specific errors
27     UnclosedXmlElement,
28     UnpairedXmlClosingTag,
29     UnexpectedXmlCharactersExpectedElement,
30     UnexpectedXmlOpeningTag,
31     UnknownXmlElement,
32     InvalidXmlSyntax,
33     InvalidXmlUtf8,
34     InvalidDataString,
35     InvalidDateString,
36     InvalidIntegerString,
37     InvalidRealString,
38     UidNotSupportedInXmlPlist,
39 
40     // Binary format-specific errors
41     ObjectTooLarge,
42     InvalidMagic,
43     InvalidTrailerObjectOffsetSize, // the size of byte offsets to objects in the object table
44     InvalidTrailerObjectReferenceSize, // the size of indices into the object table
45     InvalidObjectLength,
46     ObjectReferenceTooLarge,
47     ObjectOffsetTooLarge,
48     RecursiveObject,
49     NullObjectUnimplemented,
50     FillObjectUnimplemented,
51     IntegerOutOfRange,
52     InfiniteOrNanDate,
53     InvalidUtf8String,
54     InvalidUtf16String,
55     UnknownObjectType(u8),
56 
57     Io(io::Error),
58     Serde(String),
59 }
60 
61 #[derive(Debug)]
62 pub(crate) enum FilePosition {
63     LineColumn(u64, u64),
64     Offset(u64),
65 }
66 
67 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
68 pub(crate) enum EventKind {
69     StartArray,
70     StartDictionary,
71     EndCollection,
72     Boolean,
73     Data,
74     Date,
75     Integer,
76     Real,
77     String,
78     Uid,
79 
80     ValueOrStartCollection,
81     DictionaryKeyOrEndCollection,
82 }
83 
84 impl Error {
85     /// Returns true if this error was caused by a failure to read or write bytes on an IO stream.
is_io(&self) -> bool86     pub fn is_io(&self) -> bool {
87         self.as_io().is_some()
88     }
89 
90     /// Returns true if this error was caused by prematurely reaching the end of the input data.
is_eof(&self) -> bool91     pub fn is_eof(&self) -> bool {
92         if let ErrorKind::UnexpectedEof = self.inner.kind {
93             true
94         } else {
95             false
96         }
97     }
98 
99     /// Returns the underlying error if it was caused by a failure to read or write bytes on an IO
100     /// stream.
as_io(&self) -> Option<&io::Error>101     pub fn as_io(&self) -> Option<&io::Error> {
102         if let ErrorKind::Io(err) = &self.inner.kind {
103             Some(err)
104         } else {
105             None
106         }
107     }
108 
109     /// Returns the underlying error if it was caused by a failure to read or write bytes on an IO
110     /// stream or `self` if it was not.
into_io(self) -> Result<io::Error, Self>111     pub fn into_io(self) -> Result<io::Error, Self> {
112         if let ErrorKind::Io(err) = self.inner.kind {
113             Ok(err)
114         } else {
115             Err(self)
116         }
117     }
118 }
119 
120 impl error::Error for Error {
source(&self) -> Option<&(dyn std::error::Error + 'static)>121     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
122         match &self.inner.kind {
123             ErrorKind::Io(err) => Some(err),
124             _ => None,
125         }
126     }
127 }
128 
129 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result130     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131         fmt::Debug::fmt(&self.inner.kind, f)
132     }
133 }
134 
135 impl ErrorKind {
with_byte_offset(self, offset: u64) -> Error136     pub fn with_byte_offset(self, offset: u64) -> Error {
137         self.with_position(FilePosition::Offset(offset))
138     }
139 
with_position(self, pos: FilePosition) -> Error140     pub fn with_position(self, pos: FilePosition) -> Error {
141         Error {
142             inner: Box::new(ErrorImpl {
143                 kind: self,
144                 file_position: Some(pos),
145             }),
146         }
147     }
148 
without_position(self) -> Error149     pub fn without_position(self) -> Error {
150         Error {
151             inner: Box::new(ErrorImpl {
152                 kind: self,
153                 file_position: None,
154             }),
155         }
156     }
157 }
158 
159 impl EventKind {
of_event(event: &Event) -> EventKind160     pub fn of_event(event: &Event) -> EventKind {
161         match event {
162             Event::StartArray(_) => EventKind::StartArray,
163             Event::StartDictionary(_) => EventKind::StartDictionary,
164             Event::EndCollection => EventKind::EndCollection,
165             Event::Boolean(_) => EventKind::Boolean,
166             Event::Data(_) => EventKind::Data,
167             Event::Date(_) => EventKind::Date,
168             Event::Integer(_) => EventKind::Integer,
169             Event::Real(_) => EventKind::Real,
170             Event::String(_) => EventKind::String,
171             Event::Uid(_) => EventKind::Uid,
172             Event::__Nonexhaustive => unreachable!(),
173         }
174     }
175 }
176 
177 impl fmt::Display for EventKind {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result178     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179         match self {
180             EventKind::StartArray => "StartArray",
181             EventKind::StartDictionary => "StartDictionary",
182             EventKind::EndCollection => "EndCollection",
183             EventKind::Boolean => "Boolean",
184             EventKind::Data => "Data",
185             EventKind::Date => "Date",
186             EventKind::Integer => "Integer",
187             EventKind::Real => "Real",
188             EventKind::String => "String",
189             EventKind::Uid => "Uid",
190             EventKind::ValueOrStartCollection => "value or start collection",
191             EventKind::DictionaryKeyOrEndCollection => "dictionary key or end collection",
192         }
193         .fmt(f)
194     }
195 }
196 
from_io_without_position(err: io::Error) -> Error197 pub(crate) fn from_io_without_position(err: io::Error) -> Error {
198     ErrorKind::Io(err).without_position()
199 }
200 
unexpected_event_type(expected: EventKind, found: &Event) -> Error201 pub(crate) fn unexpected_event_type(expected: EventKind, found: &Event) -> Error {
202     let found = EventKind::of_event(&found);
203     ErrorKind::UnexpectedEventType { expected, found }.without_position()
204 }
205