zip/extra_fields/extended_timestamp.rs
1use crate::result::{ZipError, ZipResult};
2use crate::unstable::LittleEndianReadExt;
3use std::io::Read;
4
5/// extended timestamp, as described in <https://libzip.org/specifications/extrafld.txt>
6
7#[derive(Debug, Clone)]
8pub struct ExtendedTimestamp {
9 mod_time: Option<u32>,
10 ac_time: Option<u32>,
11 cr_time: Option<u32>,
12}
13
14impl ExtendedTimestamp {
15 /// creates an extended timestamp struct by reading the required bytes from the reader.
16 ///
17 /// This method assumes that the length has already been read, therefore
18 /// it must be passed as an argument
19 pub fn try_from_reader<R>(reader: &mut R, len: u16) -> ZipResult<Self>
20 where
21 R: Read,
22 {
23 let mut flags = [0u8];
24 reader.read_exact(&mut flags)?;
25 let flags = flags[0];
26
27 // the `flags` field refers to the local headers and might not correspond
28 // to the len field. If the length field is 1+4, we assume that only
29 // the modification time has been set
30
31 // > Those times that are present will appear in the order indicated, but
32 // > any combination of times may be omitted. (Creation time may be
33 // > present without access time, for example.) TSize should equal
34 // > (1 + 4*(number of set bits in Flags)), as the block is currently
35 // > defined.
36 if len != 5 && len as u32 != 1 + 4 * flags.count_ones() {
37 //panic!("found len {len} and flags {flags:08b}");
38 return Err(ZipError::UnsupportedArchive(
39 "flags and len don't match in extended timestamp field",
40 ));
41 }
42
43 if flags & 0b11111000 != 0 {
44 return Err(ZipError::UnsupportedArchive(
45 "found unsupported timestamps in the extended timestamp header",
46 ));
47 }
48
49 let mod_time = if (flags & 0b00000001u8 == 0b00000001u8) || len == 5 {
50 Some(reader.read_u32_le()?)
51 } else {
52 None
53 };
54
55 let ac_time = if flags & 0b00000010u8 == 0b00000010u8 && len > 5 {
56 Some(reader.read_u32_le()?)
57 } else {
58 None
59 };
60
61 let cr_time = if flags & 0b00000100u8 == 0b00000100u8 && len > 5 {
62 Some(reader.read_u32_le()?)
63 } else {
64 None
65 };
66 Ok(Self {
67 mod_time,
68 ac_time,
69 cr_time,
70 })
71 }
72
73 /// returns the last modification timestamp, if defined, as UNIX epoch seconds
74 pub fn mod_time(&self) -> Option<u32> {
75 self.mod_time
76 }
77
78 /// returns the last access timestamp, if defined, as UNIX epoch seconds
79 pub fn ac_time(&self) -> Option<u32> {
80 self.ac_time
81 }
82
83 /// returns the creation timestamp, if defined, as UNIX epoch seconds
84 pub fn cr_time(&self) -> Option<u32> {
85 self.cr_time
86 }
87}