github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/time/tzdata/tzdata.go (about) 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 // 450 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 }