use core::time::Duration;
use alloc::format;
use alloc::vec;
use alloc::vec::Vec;
use core::fmt;
use crate::import::bin_reader::{BinReader, ImportError};
const IT_EDIT_HISTORY_ENTRY_SIZE: usize = 8;
#[derive(Default)]
pub struct ItEditHistoryEntry {
fat_date: u16,
fat_time: u16,
run_time: u32,
}
impl fmt::Debug for ItEditHistoryEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let date = self.date();
let time = self.time();
f.debug_struct("ItEditHistoryEntry")
.field(
"datetime",
&format!(
"{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
date.0, date.1, date.2, time.0, time.1, time.2
),
)
.field("duration", &format!("{:?}", self.duration()))
.finish()
}
}
impl ItEditHistoryEntry {
fn read(r: &mut BinReader) -> Result<Self, ImportError> {
let fat_date = r.read_u16_le()?;
let fat_time = r.read_u16_le()?;
let run_time = r.read_u32_le()?;
Ok(Self {
fat_date,
fat_time,
run_time,
})
}
pub fn date(&self) -> (u16, u8, u8) {
let year = (self.fat_date >> 9) + 1980;
let month = ((self.fat_date >> 5) & 0x0F) as u8;
let day = (self.fat_date & 0x1F) as u8;
(year, month, day)
}
pub fn time(&self) -> (u8, u8, u8) {
let hour = ((self.fat_time >> 11) & 0x1F) as u8;
let minute = ((self.fat_time >> 5) & 0x3F) as u8;
let second = ((self.fat_time & 0x1F) * 2) as u8;
(hour, minute, second)
}
pub fn duration(&self) -> Duration {
let scaled = (self.run_time as u64) * 5;
let seconds = scaled / 91;
let remainder = scaled % 91; let nanoseconds = (remainder * 1_000_000_000) / 91;
Duration::new(seconds, nanoseconds as u32)
}
}
#[derive(Debug, Default)]
pub struct ItEditHistory;
impl ItEditHistory {
pub fn load(source: &[u8]) -> Result<(Option<Vec<ItEditHistoryEntry>>, usize), ImportError> {
if source.len() < 2 {
return Err(ImportError::UnexpectedEof);
}
let edit_history_number = u16::from_le_bytes(source[0..2].try_into().unwrap()) as usize;
if edit_history_number == 0 {
return Ok((None, 2));
}
let total_size = IT_EDIT_HISTORY_ENTRY_SIZE * edit_history_number;
if source.len() < 2 + total_size {
return Err(ImportError::UnexpectedEof);
}
let mut r = BinReader::new(&source[2..2 + total_size]);
let mut edit_histories: Vec<ItEditHistoryEntry> = vec![];
for _ in 0..edit_history_number {
edit_histories.push(ItEditHistoryEntry::read(&mut r)?);
}
Ok((Some(edit_histories), 2 + total_size))
}
}