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         if let Some(position) = &self.inner.file_position {
132             write!(f, "{:?} ({})", &self.inner.kind, position)
133         } else {
134             fmt::Debug::fmt(&self.inner.kind, f)
135         }
136     }
137 }
138 
139 impl fmt::Display for FilePosition {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result140     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141         match self {
142             FilePosition::LineColumn(line, column) => {
143                 write!(f, "line {}, column {}", line, column)
144             }
145             FilePosition::Offset(offset) => {
146                 write!(f, "offset {}", offset)
147             }
148         }
149     }
150 }
151 
152 impl ErrorKind {
with_byte_offset(self, offset: u64) -> Error153     pub fn with_byte_offset(self, offset: u64) -> Error {
154         self.with_position(FilePosition::Offset(offset))
155     }
156 
with_position(self, pos: FilePosition) -> Error157     pub fn with_position(self, pos: FilePosition) -> Error {
158         Error {
159             inner: Box::new(ErrorImpl {
160                 kind: self,
161                 file_position: Some(pos),
162             }),
163         }
164     }
165 
without_position(self) -> Error166     pub fn without_position(self) -> Error {
167         Error {
168             inner: Box::new(ErrorImpl {
169                 kind: self,
170                 file_position: None,
171             }),
172         }
173     }
174 }
175 
176 impl EventKind {
of_event(event: &Event) -> EventKind177     pub fn of_event(event: &Event) -> EventKind {
178         match event {
179             Event::StartArray(_) => EventKind::StartArray,
180             Event::StartDictionary(_) => EventKind::StartDictionary,
181             Event::EndCollection => EventKind::EndCollection,
182             Event::Boolean(_) => EventKind::Boolean,
183             Event::Data(_) => EventKind::Data,
184             Event::Date(_) => EventKind::Date,
185             Event::Integer(_) => EventKind::Integer,
186             Event::Real(_) => EventKind::Real,
187             Event::String(_) => EventKind::String,
188             Event::Uid(_) => EventKind::Uid,
189         }
190     }
191 }
192 
193 impl fmt::Display for EventKind {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result194     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195         match self {
196             EventKind::StartArray => "StartArray",
197             EventKind::StartDictionary => "StartDictionary",
198             EventKind::EndCollection => "EndCollection",
199             EventKind::Boolean => "Boolean",
200             EventKind::Data => "Data",
201             EventKind::Date => "Date",
202             EventKind::Integer => "Integer",
203             EventKind::Real => "Real",
204             EventKind::String => "String",
205             EventKind::Uid => "Uid",
206             EventKind::ValueOrStartCollection => "value or start collection",
207             EventKind::DictionaryKeyOrEndCollection => "dictionary key or end collection",
208         }
209         .fmt(f)
210     }
211 }
212 
from_io_without_position(err: io::Error) -> Error213 pub(crate) fn from_io_without_position(err: io::Error) -> Error {
214     ErrorKind::Io(err).without_position()
215 }
216 
unexpected_event_type(expected: EventKind, found: &Event) -> Error217 pub(crate) fn unexpected_event_type(expected: EventKind, found: &Event) -> Error {
218     let found = EventKind::of_event(&found);
219     ErrorKind::UnexpectedEventType { expected, found }.without_position()
220 }
221