| ... | @@ -1,3 +1,6 @@ | ... | @@ -1,3 +1,6 @@ |
| | 1 | //! The Time Zone Information Format (TZif) |
| | 2 | //! https://datatracker.ietf.org/doc/html/rfc8536 |
| | 3 | |
| 1 | const builtin = @import("builtin"); | 4 | const builtin = @import("builtin"); |
| 2 | | 5 | |
| 3 | const std = @import("std.zig"); | 6 | const std = @import("std.zig"); |
| ... | @@ -58,30 +61,26 @@ pub const Tz = struct { | ... | @@ -58,30 +61,26 @@ pub const Tz = struct { |
| 58 | }; | 61 | }; |
| 59 | | 62 | |
| 60 | pub fn parse(allocator: Allocator, reader: *Reader) !Tz { | 63 | pub fn parse(allocator: Allocator, reader: *Reader) !Tz { |
| 61 | var legacy_header = try reader.takeStruct(Header, .little); | 64 | const legacy_header = try reader.takeStruct(Header, .big); |
| 62 | if (!std.mem.eql(u8, &legacy_header.magic, "TZif")) return error.BadHeader; | 65 | if (!std.mem.eql(u8, &legacy_header.magic, "TZif")) return error.BadHeader; |
| 63 | if (legacy_header.version != 0 and legacy_header.version != '2' and legacy_header.version != '3') return error.BadVersion; | 66 | if (legacy_header.version != 0 and legacy_header.version != '2' and legacy_header.version != '3') |
| 64 | | 67 | return error.BadVersion; |
| 65 | if (builtin.target.cpu.arch.endian() != std.builtin.Endian.big) { | | |
| 66 | std.mem.byteSwapAllFields(@TypeOf(legacy_header.counts), &legacy_header.counts); | | |
| 67 | } | | |
| 68 | | 68 | |
| 69 | if (legacy_header.version == 0) { | 69 | if (legacy_header.version == 0) |
| 70 | return parseBlock(allocator, reader, legacy_header, true); | 70 | return parseBlock(allocator, reader, legacy_header, true); |
| 71 | } else { | | |
| 72 | // If the format is modern, just skip over the legacy data | | |
| 73 | const skipv = legacy_header.counts.timecnt * 5 + legacy_header.counts.typecnt * 6 + legacy_header.counts.charcnt + legacy_header.counts.leapcnt * 8 + legacy_header.counts.isstdcnt + legacy_header.counts.isutcnt; | | |
| 74 | try reader.discardAll(skipv); | | |
| 75 | | | |
| 76 | var header = try reader.takeStruct(Header, .little); | | |
| 77 | if (!std.mem.eql(u8, &header.magic, "TZif")) return error.BadHeader; | | |
| 78 | if (header.version != '2' and header.version != '3') return error.BadVersion; | | |
| 79 | if (builtin.target.cpu.arch.endian() != std.builtin.Endian.big) { | | |
| 80 | std.mem.byteSwapAllFields(@TypeOf(header.counts), &header.counts); | | |
| 81 | } | | |
| 82 | | 71 | |
| 83 | return parseBlock(allocator, reader, header, false); | 72 | // If the format is modern, just skip over the legacy data |
| 84 | } | 73 | const skip_n = legacy_header.counts.timecnt * 5 + |
| | 74 | legacy_header.counts.typecnt * 6 + |
| | 75 | legacy_header.counts.charcnt + legacy_header.counts.leapcnt * 8 + |
| | 76 | legacy_header.counts.isstdcnt + legacy_header.counts.isutcnt; |
| | 77 | try reader.discardAll(skip_n); |
| | 78 | |
| | 79 | var header = try reader.takeStruct(Header, .big); |
| | 80 | if (!std.mem.eql(u8, &header.magic, "TZif")) return error.BadHeader; |
| | 81 | if (header.version != '2' and header.version != '3') return error.BadVersion; |
| | 82 | |
| | 83 | return parseBlock(allocator, reader, header, false); |
| 85 | } | 84 | } |
| 86 | | 85 | |
| 87 | fn parseBlock(allocator: Allocator, reader: *Reader, header: Header, legacy: bool) !Tz { | 86 | fn parseBlock(allocator: Allocator, reader: *Reader, header: Header, legacy: bool) !Tz { |