zoneinfo_android.go 2.0 KB

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