use crate::{
psi::{
DescriptorsRef,
Psi,
PsiSectionError,
psi_section_length,
},
utils::{
BcdTime,
MjdFrom,
crc32b,
},
};
pub const TOT_PID: u16 = 0x0014;
pub struct TotSectionRef<'a>(&'a [u8]);
impl<'a> TotSectionRef<'a> {
pub fn table_id(&self) -> u8 {
self.0[0]
}
pub fn time(&self) -> u64 {
u64::from_mjd([self.0[3], self.0[4]])
+ u32::from_bcd_time([self.0[5], self.0[6], self.0[7]]) as u64
}
fn descriptors_length(&self) -> usize {
(u16::from_be_bytes([self.0[8], self.0[9]]) & 0x0fff) as usize
}
pub fn descriptors(&self) -> Option<DescriptorsRef<'_>> {
let descriptors_len = self.descriptors_length();
(descriptors_len > 0).then(|| self.0[10 .. 10 + descriptors_len].into())
}
pub fn crc32(&self) -> u32 {
let p = &self.0[self.0.len() - 4 ..];
u32::from_be_bytes([p[0], p[1], p[2], p[3]])
}
}
impl<'a> TryFrom<&'a [u8]> for TotSectionRef<'a> {
type Error = PsiSectionError;
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
if value.len() < 14 {
return Err(PsiSectionError::InvalidSectionLength);
}
if value[0] != 0x73 {
return Err(PsiSectionError::InvalidTableId);
}
let section_length = psi_section_length(value);
if section_length > value.len() {
return Err(PsiSectionError::InvalidSectionLength);
}
let tot = TotSectionRef(&value[.. section_length]);
let checksum = crc32b(&value[.. section_length - 4]);
if checksum != tot.crc32() {
return Err(PsiSectionError::InvalidCrc32);
}
Ok(tot)
}
}
impl<'a> TryFrom<&'a Psi> for TotSectionRef<'a> {
type Error = PsiSectionError;
fn try_from(psi: &'a Psi) -> Result<Self, Self::Error> {
match psi.payload() {
Some(payload) => TotSectionRef::try_from(payload),
None => Err(PsiSectionError::InvalidSectionLength),
}
}
}