1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*!
Errors and Results.
*/

use std::{fmt, result, str};

#[cfg(feature = "std")]
use std::error;

/// Errors while parsing the PE binary.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
pub enum Error {
	/// Null address.
	Null,
	/// Out of bounds.
	///
	/// Catch-all for bounds check errors.
	Bounds,
	/// Data is not available.
	///
	/// Can happen when referencing data in `PeFile` instances.
	///
	/// Sections can be shorter than stored on disk, the remaining bytes will default to zeroes when loaded by the system.
	/// Since these zeroes would just be a waste of space, they are not present in the binaries on disk.
	/// This error happens when attempting to get a reference to such zero filled data.
	ZeroFill,
	/// Data is not available.
	///
	/// Can happen when referencing data in `PeView` instances.
	///
	/// Sections can have excess in their raw data which won't be mapped when loaded by the system.
	/// This error happens when attempting to get a reference to such unmapped raw data.
	/// Sometimes this kind of excess is called an overlay.
	Unmapped,
	/// Address is misaligned.
	Misaligned,
	/// Expected magic number does not match.
	BadMagic,
	/// Trying to load a PE32 file with a PE32+ parser or vice versa.
	PeMagic,
	/// Sanity check failed.
	///
	/// Some value was so far outside its typical range, while not technically incorrect, probably indicating something went wrong.
	/// If this error is encountered legitimately, create an issue or file a PR to relax the artificial restrictions.
	Insanity,
	/// Invalid data.
	///
	/// Structured data was found which simply isn't valid.
	/// Catch-all for errors which don't fall under other errors.
	Invalid,
	/// Overflow error.
	///
	/// Catch-all for overflow and underflow errors.
	Overflow,
	/// Encoding error.
	///
	/// Catch-all for string related errors such as lacking a nul terminator.
	Encoding,
	/// Aliasing error.
	///
	/// Request cannot be fulfilled because it would alias with an existing borrow.
	Aliasing,
}

impl From<str::Utf8Error> for Error {
	fn from(_err: str::Utf8Error) -> Error {
		Error::Encoding
	}
}

impl Error {
	/// Returns if the error variant is Null.
	///
	/// Useful in match guards where `Null` should be handled as a non-error case.
	///
	/// ```
	/// fn with_default(result: pelite::Result<i32>) -> pelite::Result<i32> {
	/// 	let i = match result {
	/// 		Ok(i) => i,
	/// 		// Avoids a more verbose comparison with pelite::Error::Null
	/// 		Err(err) if err.is_null() => 0,
	/// 		Err(err) => return Err(err),
	/// 	};
	/// 	Ok(i)
	/// }
	///
	/// assert_eq!(with_default(Err(pelite::Error::Null)), Ok(0));
	/// ```
	pub fn is_null(self) -> bool {
		self == Error::Null
	}

	/// Returns a simple string representation of the error.
	pub fn to_str(self) -> &'static str {
		match self {
			Error::Null => "null address reference",
			Error::Bounds => "bounds check failed",
			Error::ZeroFill => "zero filled data reference",
			Error::Unmapped => "overlay data reference",
			Error::Misaligned => "address misaligned",
			Error::BadMagic => "unknown magic number",
			Error::PeMagic => "try again with correct parser",
			Error::Insanity => "data insanity",
			Error::Invalid => "invalid data",
			Error::Overflow => "overflow error",
			Error::Encoding => "encoding error",
			Error::Aliasing => "aliasing error",
		}
	}
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		f.write_str(self.to_str())
	}
}

#[cfg(feature = "std")]
impl error::Error for Error {
	fn description(&self) -> &str {
		self.to_str()
	}
}

/// Specialized `Result` type for PE errors.
pub type Result<T> = result::Result<T, Error>;