liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Copyright 2016 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.
 
// Parse the "tzdata" packed timezone file used on Android.
// The format is lifted from ZoneInfoDB.java and ZoneInfo.java in
// java/libcore/util in the AOSP.
 
package time
 
import (
   "errors"
   "runtime"
   "syscall"
)
 
var zoneSources = []string{
   "/system/usr/share/zoneinfo/tzdata",
   "/data/misc/zoneinfo/current/tzdata",
   runtime.GOROOT() + "/lib/time/zoneinfo.zip",
}
 
func initLocal() {
   // TODO(elias.naur): getprop persist.sys.timezone
   localLoc = *UTC
}
 
func init() {
   loadTzinfoFromTzdata = androidLoadTzinfoFromTzdata
}
 
func androidLoadTzinfoFromTzdata(file, name string) ([]byte, error) {
   const (
       headersize = 12 + 3*4
       namesize   = 40
       entrysize  = namesize + 3*4
   )
   if len(name) > namesize {
       return nil, errors.New(name + " is longer than the maximum zone name length (40 bytes)")
   }
   fd, err := open(file)
   if err != nil {
       return nil, err
   }
   defer closefd(fd)
 
   buf := make([]byte, headersize)
   if err := preadn(fd, buf, 0); err != nil {
       return nil, errors.New("corrupt tzdata file " + file)
   }
   d := dataIO{buf, false}
   if magic := d.read(6); string(magic) != "tzdata" {
       return nil, errors.New("corrupt tzdata file " + file)
   }
   d = dataIO{buf[12:], false}
   indexOff, _ := d.big4()
   dataOff, _ := d.big4()
   indexSize := dataOff - indexOff
   entrycount := indexSize / entrysize
   buf = make([]byte, indexSize)
   if err := preadn(fd, buf, int(indexOff)); err != nil {
       return nil, errors.New("corrupt tzdata file " + file)
   }
   for i := 0; i < int(entrycount); i++ {
       entry := buf[i*entrysize : (i+1)*entrysize]
       // len(name) <= namesize is checked at function entry
       if string(entry[:len(name)]) != name {
           continue
       }
       d := dataIO{entry[namesize:], false}
       off, _ := d.big4()
       size, _ := d.big4()
       buf := make([]byte, size)
       if err := preadn(fd, buf, int(off+dataOff)); err != nil {
           return nil, errors.New("corrupt tzdata file " + file)
       }
       return buf, nil
   }
   return nil, syscall.ENOENT
}