tzdata.mx raw

   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([]byte) ([]byte, 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 []byte) 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 []byte) 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 []byte) ([]byte, 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