110 lines
2.9 KiB
Go
110 lines
2.9 KiB
Go
// 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.
|
|
|
|
//go:generate go run generate_zipdata.go
|
|
|
|
// 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
|
|
// 800 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
|
|
)
|
|
|
|
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
|
|
}
|