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