#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
pub struct TpmErrorValue {
pub offset: usize,
pub value: u64,
pub needed: usize,
pub available: usize,
pub limit: usize,
pub actual: usize,
}
impl TpmErrorValue {
#[must_use]
pub const fn new(offset: usize) -> Self {
Self {
offset,
value: 0,
needed: 0,
available: 0,
limit: 0,
actual: 0,
}
}
#[must_use]
pub const fn value(mut self, value: u64) -> Self {
self.value = value;
self
}
#[allow(clippy::cast_possible_truncation)]
#[must_use]
pub const fn value_usize(mut self, value: usize) -> Self {
self.value = value as u64;
self
}
#[must_use]
pub const fn actual(mut self, actual: usize) -> Self {
self.actual = actual;
self
}
#[must_use]
pub const fn size(mut self, needed: usize, available: usize) -> Self {
self.needed = needed;
self.available = available;
self
}
#[must_use]
pub const fn limit(mut self, limit: usize, actual: usize) -> Self {
self.limit = limit;
self.actual = actual;
self
}
#[must_use]
pub fn at(base: &[u8], cursor: &[u8]) -> Self {
Self::new(Self::offset(base, cursor))
}
#[must_use]
pub fn offset(base: &[u8], cursor: &[u8]) -> usize {
let base_addr = base.as_ptr() as usize;
let cursor_addr = cursor.as_ptr() as usize;
cursor_addr.saturating_sub(base_addr).min(base.len())
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum TpmError {
BufferOverflow(TpmErrorValue),
IntegerTooLarge(TpmErrorValue),
InvalidBoolean(TpmErrorValue),
InvalidCc(TpmErrorValue),
InvalidMagicNumber(TpmErrorValue),
InvalidRc(TpmErrorValue),
InvalidTag(TpmErrorValue),
TooManyBytes(TpmErrorValue),
TooManyItems(TpmErrorValue),
TrailingData(TpmErrorValue),
UnexpectedEnd(TpmErrorValue),
VariantNotAvailable(TpmErrorValue),
}
impl TpmError {
#[must_use]
pub const fn value(self) -> TpmErrorValue {
match self {
Self::BufferOverflow(value)
| Self::IntegerTooLarge(value)
| Self::InvalidBoolean(value)
| Self::InvalidCc(value)
| Self::InvalidMagicNumber(value)
| Self::InvalidRc(value)
| Self::InvalidTag(value)
| Self::TooManyBytes(value)
| Self::TooManyItems(value)
| Self::TrailingData(value)
| Self::UnexpectedEnd(value)
| Self::VariantNotAvailable(value) => value,
}
}
}
impl core::fmt::Display for TpmError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let (message, value) = match *self {
Self::BufferOverflow(value) => ("buffer overflow", value),
Self::InvalidBoolean(value) => ("invalid boolean value", value),
Self::InvalidCc(value) => ("invalid command code", value),
Self::InvalidMagicNumber(value) => ("invalid magic number", value),
Self::InvalidRc(value) => ("invalid response code", value),
Self::InvalidTag(value) => ("invalid tag", value),
Self::IntegerTooLarge(value) => ("integer overflow", value),
Self::TooManyBytes(value) => ("buffer capacity surpassed", value),
Self::TooManyItems(value) => ("list capacity surpassed", value),
Self::TrailingData(value) => ("trailing data", value),
Self::UnexpectedEnd(value) => ("unexpected end", value),
Self::VariantNotAvailable(value) => ("enum variant is not available", value),
};
write!(f, "{message} at offset {}", value.offset)?;
if value.value != 0 {
write!(f, ", value=0x{:x}", value.value)?;
}
if value.needed != 0 || value.available != 0 {
write!(
f,
", needed={}, available={}",
value.needed, value.available
)?;
}
if value.limit != 0 || value.actual != 0 {
write!(f, ", limit={}, actual={}", value.limit, value.actual)?;
}
Ok(())
}
}
impl core::error::Error for TpmError {}
pub type TpmResult<T> = Result<T, TpmError>;