use crate::Result;
use crate::errors::PagedbError;
use crate::pager::format::structural_header::{
MAC_LEN, MAGIC_MAIN, MAIN_FIELDS_END, MAIN_FORMAT_VERSION,
};
fn declared_page_size(slot: &[u8]) -> Option<usize> {
if slot.len() < 12 || slot[..8] != MAGIC_MAIN {
return None;
}
match slot[11] {
log2 @ 12..=16 => Some(1usize << log2),
_ => None,
}
}
pub(crate) fn check_page_size(slot_a: &[u8], slot_b: &[u8], supplied: usize) -> Result<()> {
let Some(stored) = declared_page_size(slot_a).or_else(|| declared_page_size(slot_b)) else {
return Ok(());
};
if stored == supplied {
return Ok(());
}
Err(PagedbError::PageSizeMismatch { stored, supplied })
}
fn declared_format_version(slot: &[u8]) -> Option<u16> {
if slot.len() < 10 || slot[..8] != MAGIC_MAIN {
return None;
}
Some(u16::from_le_bytes([slot[8], slot[9]]))
}
pub(crate) fn check_format_version(slot_a: &[u8], slot_b: &[u8]) -> Result<()> {
let Some(stored) = declared_format_version(slot_a).or_else(|| declared_format_version(slot_b))
else {
return Ok(());
};
if stored == MAIN_FORMAT_VERSION {
return Ok(());
}
Err(PagedbError::FormatVersionUnsupported {
stored,
supported: MAIN_FORMAT_VERSION,
})
}
pub(crate) fn unverifiable_header_cause(
slot_a: &[u8],
slot_b: &[u8],
page_size: usize,
) -> PagedbError {
let framed = |slot: &[u8]| -> bool {
slot.len() == page_size
&& slot[..8] == MAGIC_MAIN
&& slot[161..168].iter().all(|byte| *byte == 0)
&& slot[MAIN_FIELDS_END..page_size - MAC_LEN]
.iter()
.all(|byte| *byte == 0)
};
if page_size > MAIN_FIELDS_END + MAC_LEN && (framed(slot_a) || framed(slot_b)) {
PagedbError::KeyMismatch
} else {
PagedbError::corruption(crate::errors::CorruptionDetail::HeaderUnverifiable)
}
}