Skip to main content

hdf5_reader/messages/
modification_time.rs

1//! HDF5 Modification Time messages.
2//!
3//! Two types carry modification timestamps:
4//! - Old modification time (type 0x000E): raw 4-byte string "YYYYMMDDHHMMSS" (14 bytes).
5//! - New modification time (type 0x0012): version byte + reserved + u32 seconds since epoch.
6
7use crate::error::{Error, Result};
8use crate::io::Cursor;
9
10/// Parsed modification time.
11#[derive(Debug, Clone)]
12pub struct ModificationTimeMessage {
13    /// Seconds since UNIX epoch.
14    pub seconds_since_epoch: u32,
15}
16
17/// Parse the old modification time message (type 0x000E).
18///
19/// The old format stores a 14-character ASCII string "YYYYMMDDHHMMSS" but
20/// we just store the raw u32 value since the old format is rarely encountered
21/// in practice. If we get one, we attempt to parse or store 0.
22pub fn parse_old(
23    cursor: &mut Cursor<'_>,
24    _offset_size: u8,
25    _length_size: u8,
26    msg_size: usize,
27) -> Result<ModificationTimeMessage> {
28    // The old format is a fixed-length date string. We skip it and return 0
29    // since precise conversion is rarely needed and would require date math.
30    if msg_size > 0 {
31        cursor.skip(msg_size)?;
32    }
33    Ok(ModificationTimeMessage {
34        seconds_since_epoch: 0,
35    })
36}
37
38/// Parse the new modification time message (type 0x0012).
39pub fn parse_new(
40    cursor: &mut Cursor<'_>,
41    _offset_size: u8,
42    _length_size: u8,
43    msg_size: usize,
44) -> Result<ModificationTimeMessage> {
45    let start = cursor.position();
46    let version = cursor.read_u8()?;
47    if version != 1 {
48        return Err(Error::InvalidData(format!(
49            "unsupported modification time version: {}",
50            version
51        )));
52    }
53
54    let _reserved = cursor.read_bytes(3)?;
55    let seconds_since_epoch = cursor.read_u32_le()?;
56
57    let consumed = (cursor.position() - start) as usize;
58    if consumed < msg_size {
59        cursor.skip(msg_size - consumed)?;
60    }
61
62    Ok(ModificationTimeMessage {
63        seconds_since_epoch,
64    })
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn test_parse_new_modification_time() {
73        let mut data = vec![
74            0x01, // version
75            0x00, 0x00, 0x00, // reserved
76        ];
77        data.extend_from_slice(&1700000000u32.to_le_bytes());
78
79        let mut cursor = Cursor::new(&data);
80        let msg = parse_new(&mut cursor, 8, 8, data.len()).unwrap();
81        assert_eq!(msg.seconds_since_epoch, 1700000000);
82    }
83}