swf/
error.rs

1use crate::avm1::opcode::OpCode;
2use crate::tag_code::TagCode;
3use std::{borrow, error, fmt, io};
4
5/// A `Result` from reading SWF data.
6pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Debug)]
9pub enum Error {
10    /// An error occurred while parsing an AVM1 action.
11    /// This can contain sub-errors with further information (`Error::source`)
12    Avm1ParseError {
13        opcode: u8,
14        source: Option<Box<dyn error::Error + Send + Sync + 'static>>,
15    },
16
17    /// Invalid or unknown data was encountered.
18    InvalidData(borrow::Cow<'static, str>),
19
20    /// An error occurred while parsing an SWF tag.
21    /// This can contain sub-errors with further information (`Error::source`)
22    SwfParseError {
23        tag_code: u16,
24        source: Box<dyn error::Error + Send + Sync + 'static>,
25    },
26
27    /// An IO error occurred (probably unexpected EOF).
28    IoError(io::Error),
29
30    /// This SWF requires unsupported features.
31    Unsupported(borrow::Cow<'static, str>),
32}
33
34impl Error {
35    /// Helper method to create `Error::Avm1ParseError`.
36    #[inline]
37    pub fn avm1_parse_error(opcode: u8) -> Self {
38        Self::Avm1ParseError {
39            opcode,
40            source: None,
41        }
42    }
43
44    /// Helper method to create `Error::Avm1ParseError`.
45    #[inline]
46    pub fn avm1_parse_error_with_source(
47        opcode: u8,
48        source: impl error::Error + Send + Sync + 'static,
49    ) -> Self {
50        Self::Avm1ParseError {
51            opcode,
52            source: Some(Box::new(source)),
53        }
54    }
55
56    /// Helper method to create `Error::InvalidData`.
57    #[inline]
58    pub fn invalid_data(message: impl Into<borrow::Cow<'static, str>>) -> Self {
59        Self::InvalidData(message.into())
60    }
61
62    /// Helper method to create `Error::SwfParseError`.
63    #[inline]
64    pub fn swf_parse_error(
65        tag_code: u16,
66        source: impl error::Error + Send + Sync + 'static,
67    ) -> Self {
68        Self::SwfParseError {
69            tag_code,
70            source: Box::new(source),
71        }
72    }
73
74    /// Helper method to create `Error::Unsupported`.
75    #[inline]
76    pub fn unsupported(message: impl Into<borrow::Cow<'static, str>>) -> Self {
77        Self::Unsupported(message.into())
78    }
79}
80
81impl fmt::Display for Error {
82    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83        match self {
84            Self::Avm1ParseError { opcode, source } => {
85                write!(f, "Error parsing AVM1 action {}", OpCode::format(*opcode))?;
86                if let Some(source) = source {
87                    write!(f, ": {source}")?;
88                }
89                Ok(())
90            }
91            Self::SwfParseError { tag_code, source } => {
92                write!(
93                    f,
94                    "Error parsing SWF tag {}: {}",
95                    TagCode::format(*tag_code),
96                    source
97                )
98            }
99            Self::IoError(e) => e.fmt(f),
100            Self::InvalidData(message) => write!(f, "Invalid data: {message}"),
101            Self::Unsupported(message) => write!(f, "Unsupported data: {message}"),
102        }
103    }
104}
105
106impl error::Error for Error {
107    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
108        match self {
109            Self::Avm1ParseError { source, .. } => match source {
110                Some(s) => Some(s.as_ref()),
111                None => None,
112            },
113            Self::IoError(e) => e.source(),
114            Self::InvalidData(_) => None,
115            Self::SwfParseError { source, .. } => Some(source.as_ref()),
116            Self::Unsupported(_) => None,
117        }
118    }
119}
120
121impl From<io::Error> for Error {
122    fn from(error: io::Error) -> Self {
123        Self::IoError(error)
124    }
125}
126
127#[cfg(test)]
128#[test]
129fn test_error_send_sync() {
130    fn assert_send_sync<T: Send + Sync>() {}
131    assert_send_sync::<Error>()
132}