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}