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