Skip to main content

tzcompile/tzif/
header.rs

1//! The 44-octet TZif header (RFC 9636 ยง3.1) and big-endian write helpers.
2//!
3//! Header layout, all integers big-endian ("network byte order"):
4//!
5//! | bytes | field      | meaning                                   |
6//! |-------|------------|-------------------------------------------|
7//! | 0..4  | magic      | ASCII `TZif`                              |
8//! | 4     | version    | `\0`, `'2'`, `'3'`, or `'4'`              |
9//! | 5..20 | reserved   | 15 NUL bytes                              |
10//! | 20..24| isutcnt    | count of UT/local indicators              |
11//! | 24..28| isstdcnt   | count of standard/wall indicators         |
12//! | 28..32| leapcnt    | count of leap-second records              |
13//! | 32..36| timecnt    | count of transition times                 |
14//! | 36..40| typecnt    | count of local-time-type records (>= 1)   |
15//! | 40..44| charcnt    | total bytes of abbreviation string table  |
16
17/// The four magic bytes that begin every TZif file.
18pub const MAGIC: [u8; 4] = *b"TZif";
19
20/// The six count fields of a TZif header, in their on-disk order.
21#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
22pub struct Counts {
23    pub isutcnt: u32,
24    pub isstdcnt: u32,
25    pub leapcnt: u32,
26    pub timecnt: u32,
27    pub typecnt: u32,
28    pub charcnt: u32,
29}
30
31/// Append a 44-byte header for `version` with the given `counts` to `out`.
32pub fn write_header(out: &mut Vec<u8>, version: u8, counts: &Counts) {
33    out.extend_from_slice(&MAGIC);
34    out.push(version);
35    out.extend_from_slice(&[0u8; 15]); // reserved
36    out.extend_from_slice(&counts.isutcnt.to_be_bytes());
37    out.extend_from_slice(&counts.isstdcnt.to_be_bytes());
38    out.extend_from_slice(&counts.leapcnt.to_be_bytes());
39    out.extend_from_slice(&counts.timecnt.to_be_bytes());
40    out.extend_from_slice(&counts.typecnt.to_be_bytes());
41    out.extend_from_slice(&counts.charcnt.to_be_bytes());
42}