]> Cypherpunks.ru repositories - gostls13.git/blob - src/time/tzdata/tzdata.go
time/tzdata: generate zip constant during cmd/dist
[gostls13.git] / src / time / tzdata / tzdata.go
1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package tzdata provides an embedded copy of the timezone database.
6 // If this package is imported anywhere in the program, then if
7 // the time package cannot find tzdata files on the system,
8 // it will use this embedded information.
9 //
10 // Importing this package will increase the size of a program by about
11 // 450 KB.
12 //
13 // This package should normally be imported by a program's main package,
14 // not by a library. Libraries normally shouldn't decide whether to
15 // include the timezone database in a program.
16 //
17 // This package will be automatically imported if you build with
18 // -tags timetzdata.
19 package tzdata
20
21 // The test for this package is time/tzdata_test.go.
22
23 import (
24         "errors"
25         "syscall"
26         _ "unsafe" // for go:linkname
27 )
28
29 // registerLoadFromEmbeddedTZData is defined in package time.
30 //
31 //go:linkname registerLoadFromEmbeddedTZData time.registerLoadFromEmbeddedTZData
32 func registerLoadFromEmbeddedTZData(func(string) (string, error))
33
34 func init() {
35         registerLoadFromEmbeddedTZData(loadFromEmbeddedTZData)
36 }
37
38 // get4s returns the little-endian 32-bit value at the start of s.
39 func get4s(s string) int {
40         if len(s) < 4 {
41                 return 0
42         }
43         return int(s[0]) | int(s[1])<<8 | int(s[2])<<16 | int(s[3])<<24
44 }
45
46 // get2s returns the little-endian 16-bit value at the start of s.
47 func get2s(s string) int {
48         if len(s) < 2 {
49                 return 0
50         }
51         return int(s[0]) | int(s[1])<<8
52 }
53
54 // loadFromEmbeddedTZData returns the contents of the file with the given
55 // name in an uncompressed zip file, where the contents of the file can
56 // be found in embeddedTzdata.
57 // This is similar to time.loadTzinfoFromZip.
58 func loadFromEmbeddedTZData(name string) (string, error) {
59         const (
60                 zecheader = 0x06054b50
61                 zcheader  = 0x02014b50
62                 ztailsize = 22
63
64                 zheadersize = 30
65                 zheader     = 0x04034b50
66         )
67
68         // zipdata is provided by zzipdata.go,
69         // which is generated by cmd/dist during make.bash.
70         z := zipdata
71
72         idx := len(z) - ztailsize
73         n := get2s(z[idx+10:])
74         idx = get4s(z[idx+16:])
75
76         for i := 0; i < n; i++ {
77                 // See time.loadTzinfoFromZip for zip entry layout.
78                 if get4s(z[idx:]) != zcheader {
79                         break
80                 }
81                 meth := get2s(z[idx+10:])
82                 size := get4s(z[idx+24:])
83                 namelen := get2s(z[idx+28:])
84                 xlen := get2s(z[idx+30:])
85                 fclen := get2s(z[idx+32:])
86                 off := get4s(z[idx+42:])
87                 zname := z[idx+46 : idx+46+namelen]
88                 idx += 46 + namelen + xlen + fclen
89                 if zname != name {
90                         continue
91                 }
92                 if meth != 0 {
93                         return "", errors.New("unsupported compression for " + name + " in embedded tzdata")
94                 }
95
96                 // See time.loadTzinfoFromZip for zip per-file header layout.
97                 idx = off
98                 if get4s(z[idx:]) != zheader ||
99                         get2s(z[idx+8:]) != meth ||
100                         get2s(z[idx+26:]) != namelen ||
101                         z[idx+30:idx+30+namelen] != name {
102                         return "", errors.New("corrupt embedded tzdata")
103                 }
104                 xlen = get2s(z[idx+28:])
105                 idx += 30 + namelen + xlen
106                 return z[idx : idx+size], nil
107         }
108
109         return "", syscall.ENOENT
110 }