use chrono::{DateTime, TimeDelta, Utc};
use crate::LapsError;
pub fn convert_to_uint32(data: &[u8]) -> Result<u32, LapsError> {
if data.len() > 4 {
return Err(LapsError::ConversionError("Input too large".into()));
}
Ok(data
.iter()
.enumerate()
.fold(0, |acc, (idx, n)| acc | ((*n as u32) << (idx * 8) as u32)))
}
const WINDOWS_EPOCH: &str = "1601-01-01T00:00:00-00:00";
pub fn filetime_to_datetime(file_time: i64) -> DateTime<Utc> {
let epoch = DateTime::parse_from_rfc3339(WINDOWS_EPOCH)
.expect("Windows Epoch is a valid times")
.to_utc();
let td = TimeDelta::microseconds(file_time / 10);
epoch
.checked_add_signed(td)
.expect("should still be a valid date")
}
#[cfg(test)]
mod uint_tests {
use super::*;
use rstest::rstest;
#[rstest]
#[case(&[0x0, 0x0, 0x0, 0x0], u32::MIN)]
#[case(&[0x0], u32::MIN)]
#[case(&[0x1, 0x0, 0x0, 0x0], 1)]
#[case(&[0x1, 0x1, 0x0, 0x0], 0x101)]
#[case(&[0x1, 0x1, 0x1, 0x0], 0x10101)]
#[case(&[0x1, 0x1, 0x1, 0x1], 0x1010101)]
#[case(&[0xFF, 0xFF, 0xFF, 0xFF], u32::MAX)]
fn conversion(#[case] input: &[u8], #[case] expected: u32) {
assert_eq!(convert_to_uint32(&input).expect("valid inputs"), expected)
}
#[rstest]
#[case(&[0, 0, 0, 0, 0])]
#[case(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF])]
fn should_err_on_invalid_input(#[case] input: &[u8]) {
let e = convert_to_uint32(&input);
assert!(e.is_err());
}
}
#[cfg(test)]
mod date_tests {
use super::*;
use rstest::rstest;
#[rstest]
#[case(133596792000000000, DateTime::<Utc>::from_timestamp_nanos(1715205600000000000))]
#[case(116444736000000000, DateTime::<Utc>::from_timestamp_nanos(0))]
#[case(103821696000000000, DateTime::<Utc>::from_timestamp_nanos(-1262304000000000000))]
fn conversion(#[case] input: i64, #[case] expected: chrono::DateTime<Utc>) {
assert_eq!(filetime_to_datetime(input), expected)
}
}