...
Run Format

Source file src/time/zoneinfo_android.go

Documentation: time

  // 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"
  )
  
  var tzdataPaths = []string{
  	"/system/usr/share/zoneinfo/tzdata",
  	"/data/misc/zoneinfo/current/tzdata",
  	runtime.GOROOT() + "/lib/time/zoneinfo.zip",
  }
  
  var origTzdataPaths = tzdataPaths
  
  func forceZipFileForTesting(zipOnly bool) {
  	tzdataPaths = make([]string, len(origTzdataPaths))
  	copy(tzdataPaths, origTzdataPaths)
  	if zipOnly {
  		for i := 0; i < len(tzdataPaths)-1; i++ {
  			tzdataPaths[i] = "/XXXNOEXIST"
  		}
  	}
  }
  
  func initTestingZone() {
  	z, err := loadLocation("America/Los_Angeles")
  	if err != nil {
  		panic("cannot load America/Los_Angeles for testing: " + err.Error())
  	}
  	z.name = "Local"
  	localLoc = *z
  }
  
  func initLocal() {
  	// TODO(elias.naur): getprop persist.sys.timezone
  	localLoc = *UTC
  }
  
  func loadLocation(name string) (*Location, error) {
  	var firstErr error
  	for _, path := range tzdataPaths {
  		var z *Location
  		var err error
  		if len(path) > 4 && path[len(path)-4:] == ".zip" {
  			z, err = loadZoneZip(path, name)
  		} else {
  			z, err = loadTzdataFile(path, name)
  		}
  		if err == nil {
  			z.name = name
  			return z, nil
  		} else if firstErr == nil && !isNotExist(err) {
  			firstErr = err
  		}
  	}
  	if firstErr != nil {
  		return nil, firstErr
  	}
  	return nil, errors.New("unknown time zone " + name)
  }
  
  func loadTzdataFile(file, name string) (*Location, 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 := data{buf, false}
  	if magic := d.read(6); string(magic) != "tzdata" {
  		return nil, errors.New("corrupt tzdata file " + file)
  	}
  	d = data{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 := data{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 loadZoneData(buf)
  	}
  	return nil, errors.New("cannot find " + name + " in tzdata file " + file)
  }
  

View as plain text