diff options
author | Tom Tromey <tromey@gcc.gnu.org> | 2005-07-16 00:31:27 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2005-07-16 00:31:27 +0000 |
commit | 37d375fdc5fd13db547fb60bdd40b73355396587 (patch) | |
tree | ed80c7de91726768a42b235beffbaf622dc2553e /libjava/classpath/vm/reference/java/util | |
parent | f911ba985aa7fe0096c386c5be385ac5825ea527 (diff) | |
download | gcc-37d375fdc5fd13db547fb60bdd40b73355396587.zip gcc-37d375fdc5fd13db547fb60bdd40b73355396587.tar.gz gcc-37d375fdc5fd13db547fb60bdd40b73355396587.tar.bz2 |
Initial revision
From-SVN: r102075
Diffstat (limited to 'libjava/classpath/vm/reference/java/util')
-rw-r--r-- | libjava/classpath/vm/reference/java/util/VMTimeZone.java | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/libjava/classpath/vm/reference/java/util/VMTimeZone.java b/libjava/classpath/vm/reference/java/util/VMTimeZone.java new file mode 100644 index 0000000..86b6258 --- /dev/null +++ b/libjava/classpath/vm/reference/java/util/VMTimeZone.java @@ -0,0 +1,345 @@ +/* java.util.VMTimeZone + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import gnu.classpath.Configuration; + +import java.io.*; + +/** + * + */ +final class VMTimeZone +{ + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javautil"); + } + } + + /** + * This method returns a time zone id string which is in the form + * (standard zone name) or (standard zone name)(GMT offset) or + * (standard zone name)(GMT offset)(daylight time zone name). The + * GMT offset can be in seconds, or where it is evenly divisible by + * 3600, then it can be in hours. The offset must be the time to + * add to the local time to get GMT. If a offset is given and the + * time zone observes daylight saving then the (daylight time zone + * name) must also be given (otherwise it is assumed the time zone + * does not observe any daylight savings). + * <p> + * The result of this method is given to the method + * TimeZone.getDefaultTimeZone(String) which tries to map the time + * zone id to a known TimeZone. See that method on how the returned + * String is mapped to a real TimeZone object. + * <p> + * The reference implementation which is made for GNU/Posix like + * systems calls <code>System.getenv("TZ")</code>, + * <code>readTimeZoneFile("/etc/timezone")</code>, + * <code>readtzFile("/etc/localtime")</code> and finally + * <code>getSystemTimeZoneId()</code> till a supported TimeZone is + * found through <code>TimeZone.getDefaultTimeZone(String)</code>. + * If every method fails <code>null</code> is returned (which means + * the TimeZone code will fall back on GMT as default time zone). + * <p> + * Note that this method is called inside a + * <code>AccessController.doPrivileged()</code> block and runs with + * the priviliges of the java.util system classes. It will only be + * called when the default time zone is not yet set, the system + * property user.timezone isn't set and it is requested for the + * first time. + */ + static TimeZone getDefaultTimeZoneId() + { + TimeZone zone = null; + + // See if TZ environment variable is set and accessible. + String tzid = System.getenv("TZ"); + if (tzid != null && !tzid.equals("")) + zone = TimeZone.getDefaultTimeZone(tzid); + + // Try to parse /etc/timezone. + if (zone == null) + { + tzid = readTimeZoneFile("/etc/timezone"); + if (tzid != null && !tzid.equals("")) + zone = TimeZone.getDefaultTimeZone(tzid); + } + + // Try to parse /etc/localtime + if (zone == null) + { + tzid = readtzFile("/etc/localtime"); + if (tzid != null && !tzid.equals("")) + zone = TimeZone.getDefaultTimeZone(tzid); + } + + // Try some system specific way + if (zone == null) + { + tzid = getSystemTimeZoneId(); + if (tzid != null && !tzid.equals("")) + zone = TimeZone.getDefaultTimeZone(tzid); + } + + return zone; + } + + /** + * Tries to read the time zone name from a file. Only the first + * consecutive letters, digits, slashes, dashes and underscores are + * read from the file. If the file cannot be read or an IOException + * occurs null is returned. + * <p> + * The /etc/timezone file is not standard, but a lot of systems have + * it. If it exist the first line always contains a string + * describing the timezone of the host of domain. Some systems + * contain a /etc/TIMEZONE file which is used to set the TZ + * environment variable (which is checked before /etc/timezone is + * read). + */ + private static String readTimeZoneFile(String file) + { + File f = new File(file); + if (!f.exists()) + return null; + + InputStreamReader isr = null; + try + { + FileInputStream fis = new FileInputStream(f); + BufferedInputStream bis = new BufferedInputStream(fis); + isr = new InputStreamReader(bis); + + StringBuffer sb = new StringBuffer(); + int i = isr.read(); + while (i != -1) + { + char c = (char) i; + if (Character.isLetter(c) || Character.isDigit(c) + || c == '/' || c == '-' || c == '_') + { + sb.append(c); + i = isr.read(); + } + else + break; + } + return sb.toString(); + } + catch (IOException ioe) + { + // Parse error, not a proper tzfile. + return null; + } + finally + { + try + { + if (isr != null) + isr.close(); + } + catch (IOException ioe) + { + // Error while close, nothing we can do. + } + } + } + + /** + * Tries to read a file as a "standard" tzfile and return a time + * zone id string as expected by <code>getDefaultTimeZone(String)</code>. + * If the file doesn't exist, an IOException occurs or it isn't a tzfile + * that can be parsed null is returned. + * <p> + * The tzfile structure (as also used by glibc) is described in the Olson + * tz database archive as can be found at + * <code>ftp://elsie.nci.nih.gov/pub/</code>. + * <p> + * At least the following platforms support the tzdata file format + * and /etc/localtime (GNU/Linux, Darwin, Solaris and FreeBSD at + * least). Some systems (like Darwin) don't start the file with the + * required magic bytes 'TZif', this implementation can handle + * that). + */ + private static String readtzFile(String file) + { + File f = new File(file); + if (!f.exists()) + return null; + + DataInputStream dis = null; + try + { + FileInputStream fis = new FileInputStream(f); + BufferedInputStream bis = new BufferedInputStream(fis); + dis = new DataInputStream(bis); + + // Make sure we are reading a tzfile. + byte[] tzif = new byte[4]; + dis.readFully(tzif); + if (tzif[0] == 'T' && tzif[1] == 'Z' + && tzif[2] == 'i' && tzif[3] == 'f') + // Reserved bytes, ttisgmtcnt, ttisstdcnt and leapcnt + skipFully(dis, 16 + 3 * 4); + else + // Darwin has tzdata files that don't start with the TZif marker + skipFully(dis, 16 + 3 * 4 - 4); + + int timecnt = dis.readInt(); + int typecnt = dis.readInt(); + if (typecnt > 0) + { + int charcnt = dis.readInt(); + // Transition times plus indexed transition times. + skipFully(dis, timecnt * (4 + 1)); + + // Get last gmt_offset and dst/non-dst time zone names. + int abbrind = -1; + int dst_abbrind = -1; + int gmt_offset = 0; + while (typecnt-- > 0) + { + // gmtoff + int offset = dis.readInt(); + int dst = dis.readByte(); + if (dst == 0) + { + abbrind = dis.readByte(); + gmt_offset = offset; + } + else + dst_abbrind = dis.readByte(); + } + + // gmt_offset is the offset you must add to UTC/GMT to + // get the local time, we need the offset to add to + // the local time to get UTC/GMT. + gmt_offset *= -1; + + // Turn into hours if possible. + if (gmt_offset % 3600 == 0) + gmt_offset /= 3600; + + if (abbrind >= 0) + { + byte[] names = new byte[charcnt]; + dis.readFully(names); + int j = abbrind; + while (j < charcnt && names[j] != 0) + j++; + + String zonename = new String(names, abbrind, j - abbrind, + "ASCII"); + + String dst_zonename; + if (dst_abbrind >= 0) + { + j = dst_abbrind; + while (j < charcnt && names[j] != 0) + j++; + dst_zonename = new String(names, dst_abbrind, + j - dst_abbrind, "ASCII"); + } + else + dst_zonename = ""; + + // Only use gmt offset when necessary. + // Also special case GMT+/- timezones. + String offset_string; + if ("".equals(dst_zonename) + && (gmt_offset == 0 + || zonename.startsWith("GMT+") + || zonename.startsWith("GMT-"))) + offset_string = ""; + else + offset_string = Integer.toString(gmt_offset); + + String id = zonename + offset_string + dst_zonename; + + return id; + } + } + + // Something didn't match while reading the file. + return null; + } + catch (IOException ioe) + { + // Parse error, not a proper tzfile. + return null; + } + finally + { + try + { + if (dis != null) + dis.close(); + } + catch(IOException ioe) + { + // Error while close, nothing we can do. + } + } + } + + /** + * Skips the requested number of bytes in the given InputStream. + * Throws EOFException if not enough bytes could be skipped. + * Negative numbers of bytes to skip are ignored. + */ + private static void skipFully(InputStream is, long l) throws IOException + { + while (l > 0) + { + long k = is.skip(l); + if (k <= 0) + throw new EOFException(); + l -= k; + } + } + + /** + * Tries to get the system time zone id through native code. + */ + private static native String getSystemTimeZoneId(); +} |