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
/*!
Errors and Results.
*/

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

/// Errors while parsing the PE binary.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(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,
}

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
	}
}

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			Error::Null => f.write_str("Null address reference"),
			Error::Bounds => f.write_str("Bounds check failed"),
			Error::ZeroFill => f.write_str("Zero filled data reference"),
			Error::Unmapped => f.write_str("Overlay data reference"),
			Error::Misaligned => f.write_str("Address misaligned"),
			Error::BadMagic => f.write_str("Unknown magic number"),
			Error::PeMagic => f.write_str("Retry with the correct parser"),
			Error::Insanity => f.write_str("Data insanity"),
			Error::Invalid => f.write_str("Invalid data"),
			Error::Overflow => f.write_str("Overflow error"),
			Error::Encoding => f.write_str("Encoding error"),
		}
	}
}

impl error::Error for Error {
	fn description(&self) -> &str {
		match self {
			Error::Null => "null address",
			Error::Bounds => "out of bounds",
			Error::ZeroFill => "zero fill",
			Error::Unmapped => "unmapped",
			Error::Misaligned => "misaligned",
			Error::BadMagic => "bad magic",
			Error::PeMagic => "incorrect bitness",
			Error::Insanity => "insanity",
			Error::Invalid => "invalid data",
			Error::Overflow => "overflow error",
			Error::Encoding => "encoding error",
		}
	}
}

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