// Copyright 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package tzdata provides an embedded copy of the timezone database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // // This package should normally be imported by a program's main package, // not by a library. Libraries normally shouldn't decide whether to // include the timezone database in a program. // // This package will be automatically imported if you build with // -tags timetzdata. package tzdata // The test for this package is time/tzdata_test.go. import ( "errors" "syscall" _ "unsafe" // for go:linkname ) // registerLoadFromEmbeddedTZData is defined in package time. // //go:linkname registerLoadFromEmbeddedTZData time.registerLoadFromEmbeddedTZData func registerLoadFromEmbeddedTZData(func(string) (string, error)) func init() { registerLoadFromEmbeddedTZData(loadFromEmbeddedTZData) } // get4s returns the little-endian 32-bit value at the start of s. func get4s(s string) int { if len(s) < 4 { return 0 } return int(s[0]) | int(s[1])<<8 | int(s[2])<<16 | int(s[3])<<24 } // get2s returns the little-endian 16-bit value at the start of s. func get2s(s string) int { if len(s) < 2 { return 0 } return int(s[0]) | int(s[1])<<8 } // loadFromEmbeddedTZData returns the contents of the file with the given // name in an uncompressed zip file, where the contents of the file can // be found in embeddedTzdata. // This is similar to time.loadTzinfoFromZip. func loadFromEmbeddedTZData(name string) (string, error) { const ( zecheader = 0x06054b50 zcheader = 0x02014b50 ztailsize = 22 zheadersize = 30 zheader = 0x04034b50 ) // zipdata is provided by zzipdata.go, // which is generated by cmd/dist during make.bash. z := zipdata idx := len(z) - ztailsize n := get2s(z[idx+10:]) idx = get4s(z[idx+16:]) for i := 0; i < n; i++ { // See time.loadTzinfoFromZip for zip entry layout. if get4s(z[idx:]) != zcheader { break } meth := get2s(z[idx+10:]) size := get4s(z[idx+24:]) namelen := get2s(z[idx+28:]) xlen := get2s(z[idx+30:]) fclen := get2s(z[idx+32:]) off := get4s(z[idx+42:]) zname := z[idx+46 : idx+46+namelen] idx += 46 + namelen + xlen + fclen if zname != name { continue } if meth != 0 { return "", errors.New("unsupported compression for " + name + " in embedded tzdata") } // See time.loadTzinfoFromZip for zip per-file header layout. idx = off if get4s(z[idx:]) != zheader || get2s(z[idx+8:]) != meth || get2s(z[idx+26:]) != namelen || z[idx+30:idx+30+namelen] != name { return "", errors.New("corrupt embedded tzdata") } xlen = get2s(z[idx+28:]) idx += 30 + namelen + xlen return z[idx : idx+size], nil } return "", syscall.ENOENT }