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