ebml_iterable/errors.rs
1use std::fmt;
2use std::error::Error;
3
4pub mod tool {
5 use super::fmt;
6 use super::Error;
7
8 use std::string::FromUtf8Error;
9
10 #[derive(Debug)]
11 pub enum ToolError {
12 ReadVintOverflow,
13 WriteVintOverflow(u64),
14 WriteSignedVintOverflow(i64),
15 ReadU64Overflow(Vec<u8>),
16 ReadI64Overflow(Vec<u8>),
17 ReadF64Mismatch(Vec<u8>),
18 FromUtf8Error(Vec<u8>, FromUtf8Error)
19 }
20
21 impl fmt::Display for ToolError {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match self {
24 ToolError::ReadVintOverflow => write!(f, "Unrepresentable Vint size encountered."),
25 ToolError::WriteVintOverflow(val) => write!(f, "Value too large to be written as a vint: {val}"),
26 ToolError::WriteSignedVintOverflow(val) => write!(f, "Value outside range to be written as a vint: {val}"),
27 ToolError::ReadU64Overflow(arr) => write!(f, "Could not read unsigned int from array: {arr:?}"),
28 ToolError::ReadI64Overflow(arr) => write!(f, "Could not read int from array: {arr:?}"),
29 ToolError::ReadF64Mismatch(arr) => write!(f, "Could not read float from array: {arr:?}"),
30 ToolError::FromUtf8Error(arr, _source) => write!(f, "Could not read utf8 data: {arr:?}"),
31 }
32 }
33 }
34
35 impl Error for ToolError {
36 fn source(&self) -> Option<&(dyn Error + 'static)> {
37 match self {
38 ToolError::FromUtf8Error(_arr, source) => Some(source),
39 _ => None,
40 }
41 }
42 }
43}
44
45pub mod tag_iterator {
46 use super::fmt;
47 use super::Error;
48 use super::tool::ToolError;
49 use std::io;
50
51 ///
52 /// Errors that indicate file data is corrupted.
53 ///
54 #[derive(Debug)]
55 pub enum CorruptedFileError {
56
57 ///
58 /// An error indicating the reader found an ebml tag id not defined in the current specification.
59 ///
60 InvalidTagId{
61 ///
62 /// The position of the element.
63 ///
64 position: usize,
65
66 ///
67 /// The id of the tag that was found.
68 ///
69 tag_id: u64,
70 },
71
72 ///
73 /// An error indicating the reader could not parse a valid tag due to corrupted tag data (size/contents).
74 ///
75 InvalidTagData{
76 ///
77 /// The position of the element.
78 ///
79 position: usize,
80
81 ///
82 /// The id of the tag that was found.
83 ///
84 tag_id: u64,
85 },
86
87 ///
88 /// An error indicating the reader found an element outside of its expected hierarchy.
89 ///
90 HierarchyError{
91
92 ///
93 /// The id of the tag that was found.
94 ///
95 found_tag_id: u64,
96
97 ///
98 /// The id of the current "master" element that contains the tag that was found.
99 ///
100 current_parent_id: Option<u64>,
101 },
102
103 ///
104 /// An error indicating the reader found a child element with incorrect sizing.
105 ///
106 OversizedChildElement {
107
108 ///
109 /// The position of the element.
110 ///
111 position: usize,
112
113 ///
114 /// The id of the tag that was found.
115 ///
116 tag_id: u64,
117
118 ///
119 /// The size of the tag that was found.
120 ///
121 size: usize
122 },
123
124 ///
125 /// An error indicating the reader found a tag with an invalid size.
126 ///
127 InvalidTagSize {
128
129 ///
130 /// The position of the element.
131 ///
132 position: usize,
133
134 ///
135 /// The id of the tag that was found.
136 ///
137 tag_id: u64,
138
139 ///
140 /// The size of the tag that was found.
141 ///
142 size: usize
143 },
144 }
145
146 impl fmt::Display for CorruptedFileError {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 match self {
149 CorruptedFileError::InvalidTagId {
150 position,
151 tag_id
152 } => write!(f, "Encountered invalid tag id [0x{tag_id:x?}] at position {position}"),
153 CorruptedFileError::InvalidTagData {
154 position,
155 tag_id
156 } => write!(f, "Encountered invalid tag data for tag id [0x{tag_id:x?}] at position {position}"),
157 CorruptedFileError::HierarchyError {
158 found_tag_id,
159 current_parent_id,
160 } => write!(f, "Found child tag [{found_tag_id:x?}] when processing parent [{current_parent_id:x?}]"),
161 CorruptedFileError::OversizedChildElement {
162 position,
163 tag_id,
164 size : _
165 } => write!(f, "Found an oversized tag [0x{tag_id:x?}] at position {position}"),
166 CorruptedFileError::InvalidTagSize {
167 position,
168 tag_id,
169 size,
170 } => write!(f, "Found an oversized tag [0x{tag_id:x?}] at position {position} with size {size}. Max supported size is 8GB."),
171 }
172 }
173 }
174
175 ///
176 /// Errors that can occur when reading ebml data.
177 ///
178 #[derive(Debug)]
179 pub enum TagIteratorError {
180
181 ///
182 /// An error indicating that data in the file being read is not valid.
183 ///
184 CorruptedFileData(CorruptedFileError),
185
186 ///
187 /// An error indicating that the iterator reached the end of the input stream unexpectedly while reading a tag.
188 ///
189 /// This error will occur if the iterator is expecting more data (either due to expecting a size after reading a tag id or based on a tag size) but nothing is available in the input stream.
190 ///
191 UnexpectedEOF {
192
193 ///
194 /// The start position of the tag that was being read when EOF was reached.
195 ///
196 tag_start: usize,
197
198 ///
199 /// The id of the partially read tag, if available.
200 ///
201 tag_id: Option<u64>,
202
203 ///
204 /// The size of the partially read tag, if available.
205 ///
206 tag_size: Option<usize>,
207
208 ///
209 /// Any available data that was read for the tag before reaching EOF.
210 ///
211 partial_data: Option<Vec<u8>>,
212 },
213
214 ///
215 /// An error indicating that tag data appears to be corrupted.
216 ///
217 /// This error typically occurs if tag data cannot be read as its expected data type (e.g. trying to read `[32,42,8]` as float data, since floats require either 4 or 8 bytes).
218 ///
219 CorruptedTagData {
220
221 ///
222 /// The id of the corrupted tag.
223 ///
224 tag_id: u64,
225
226 ///
227 /// An error describing why the data is corrupted.
228 ///
229 problem: ToolError,
230 },
231
232 ///
233 /// An error that wraps an IO error when reading from the underlying source.
234 ///
235 ReadError {
236
237 ///
238 /// The [`io::Error`] that caused this problem.
239 ///
240 source: io::Error,
241 },
242 }
243
244 impl fmt::Display for TagIteratorError {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 match self {
247 TagIteratorError::CorruptedFileData(err) => write!(f, "Encountered corrupted data. Message: {err}"),
248 TagIteratorError::UnexpectedEOF {
249 tag_start,
250 tag_id,
251 tag_size,
252 partial_data: _
253 } => write!(f, "Reached EOF unexpectedly. Partial tag data: {{tag offset:{tag_start}}} {{id:{tag_id:x?}}} {{size:{tag_size:?}}}"),
254 TagIteratorError::CorruptedTagData {
255 tag_id,
256 problem,
257 } => write!(f, "Error reading data for tag id (0x{tag_id:x?}). {problem}"),
258 TagIteratorError::ReadError { source: _ } => write!(f, "Error reading from source."),
259 }
260 }
261 }
262
263 impl Error for TagIteratorError {
264 fn source(&self) -> Option<&(dyn Error + 'static)> {
265 match self {
266 TagIteratorError::CorruptedFileData(_) => None,
267 TagIteratorError::UnexpectedEOF { tag_start: _, tag_id: _, tag_size: _, partial_data: _ } => None,
268 TagIteratorError::CorruptedTagData { tag_id: _, problem } => problem.source(),
269 TagIteratorError::ReadError { source } => Some(source),
270 }
271 }
272 }
273}
274
275pub mod tag_writer {
276 use super::fmt;
277 use super::Error;
278 use std::io;
279
280 ///
281 /// Errors that can occur when writing ebml data.
282 ///
283 #[derive(Debug)]
284 pub enum TagWriterError {
285
286 ///
287 /// An error indicating the tag to be written doesn't conform to the current specification.
288 ///
289 /// This error occurs if you attempt to write a tag outside of a valid document path. See the [EBML RFC](https://www.rfc-editor.org/rfc/rfc8794.html#section-11.1.6.2) for details on element paths.
290 ///
291 UnexpectedTag {
292 tag_id: u64,
293 current_path: Vec<u64>,
294 },
295
296 ///
297 /// An error with a tag id.
298 ///
299 /// This error should only occur if writing "RawTag" variants, and only if the input id is not a valid vint.
300 ///
301 TagIdError(u64),
302
303 ///
304 /// An error with the size of a tag.
305 ///
306 /// Can occur if the tag size overflows the max value representable by a vint (`2^57 - 1`, or `144,115,188,075,855,871`).
307 ///
308 /// This can also occur if a non-[`Master`][`crate::specs::TagDataType::Master`] tag is sent to be written with an unknown size.
309 ///
310 TagSizeError(String),
311
312 ///
313 /// An error indicating a tag was closed unexpectedly.
314 ///
315 /// Can occur if a [`Master::End`][`crate::specs::Master::End`] variant is passed to the [`TagWriter`][`crate::TagWriter`] but the id doesn't match the currently open tag.
316 ///
317 UnexpectedClosingTag {
318
319 ///
320 /// The id of the tag being closed.
321 ///
322 tag_id: u64,
323
324 ///
325 /// The id of the currently open tag.
326 ///
327 expected_id: Option<u64>,
328 },
329
330 ///
331 /// An error that wraps an IO error when writing to the underlying destination.
332 ///
333 WriteError {
334 source: io::Error,
335 },
336 }
337
338 impl fmt::Display for TagWriterError {
339 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340 match self {
341 TagWriterError::UnexpectedTag { tag_id, current_path } => write!(f, "Unexpected tag 0x{tag_id:x?} when writing to {current_path:x?}"),
342 TagWriterError::TagIdError(id) => write!(f, "Tag id 0x{id:x?} is not a valid vint"),
343 TagWriterError::TagSizeError(message) => write!(f, "Problem writing data tag size. {message}"),
344 TagWriterError::UnexpectedClosingTag { tag_id, expected_id } => match expected_id {
345 Some(expected) => write!(f, "Unexpected closing tag 0x'{tag_id:x?}'. Expected 0x'{expected:x?}'"),
346 None => write!(f, "Unexpected closing tag 0x'{tag_id:x?}'"),
347 },
348 TagWriterError::WriteError { source: _ } => write!(f, "Error writing to destination."),
349 }
350 }
351 }
352
353 impl Error for TagWriterError {
354 fn source(&self) -> Option<&(dyn Error + 'static)> {
355 match self {
356 TagWriterError::UnexpectedTag { tag_id: _, current_path: _ } => None,
357 TagWriterError::TagIdError(_) => None,
358 TagWriterError::TagSizeError(_) => None,
359 TagWriterError::UnexpectedClosingTag { tag_id: _, expected_id: _ } => None,
360 TagWriterError::WriteError { source } => Some(source),
361 }
362 }
363 }
364}