Source file 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  }
   111  

View as plain text