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 Event::__Nonexhaustive => unreachable!(),
190 }
191 }
192 }
193
194 impl fmt::Display for EventKind {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 match self {
197 EventKind::StartArray => "StartArray",
198 EventKind::StartDictionary => "StartDictionary",
199 EventKind::EndCollection => "EndCollection",
200 EventKind::Boolean => "Boolean",
201 EventKind::Data => "Data",
202 EventKind::Date => "Date",
203 EventKind::Integer => "Integer",
204 EventKind::Real => "Real",
205 EventKind::String => "String",
206 EventKind::Uid => "Uid",
207 EventKind::ValueOrStartCollection => "value or start collection",
208 EventKind::DictionaryKeyOrEndCollection => "dictionary key or end collection",
209 }
210 .fmt(f)
211 }
212 }
213
from_io_without_position(err: io::Error) -> Error214 pub(crate) fn from_io_without_position(err: io::Error) -> Error {
215 ErrorKind::Io(err).without_position()
216 }
217
unexpected_event_type(expected: EventKind, found: &Event) -> Error218 pub(crate) fn unexpected_event_type(expected: EventKind, found: &Event) -> Error {
219 let found = EventKind::of_event(&found);
220 ErrorKind::UnexpectedEventType { expected, found }.without_position()
221 }
222