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}