Switch bionic over to using libcore's copy of libcore.util.ZoneInfo.

Bug: 7012465
Change-Id: I1225494c5d77a20fd48be1e904d8695ef95860e3
diff --git a/libc/tools/zoneinfo/ZoneCompactor.java b/libc/tools/zoneinfo/ZoneCompactor.java
index b657748..814ef5b 100644
--- a/libc/tools/zoneinfo/ZoneCompactor.java
+++ b/libc/tools/zoneinfo/ZoneCompactor.java
@@ -1,6 +1,9 @@
 
 import java.io.*;
+import java.nio.ByteOrder;
 import java.util.*;
+import libcore.io.BufferIterator;
+import libcore.util.ZoneInfo;
 
 // usage: java ZoneCompiler <setup file> <top-level directory>
 //
@@ -30,27 +33,66 @@
 //     <produces zoneinfo.dat and zoneinfo.idx>
 
 public class ZoneCompactor {
+    public static class ByteArrayBufferIteratorBE extends BufferIterator {
+        private final byte[] bytes;
+        private int offset = 0;
 
-    // Zone name synonyms
-    Map<String,String> links = new HashMap<String,String>();
+        public ByteArrayBufferIteratorBE(byte[] bytes) {
+            this.bytes = bytes;
+            this.offset = 0;
+        }
 
-    // File starting bytes by zone name
-    Map<String,Integer> starts = new HashMap<String,Integer>();
+        public void seek(int offset) {
+            this.offset = offset;
+        }
 
-    // File lengths by zone name
-    Map<String,Integer> lengths = new HashMap<String,Integer>();
+        public void skip(int byteCount) {
+            this.offset += byteCount;
+        }
 
-    // Raw GMT offsets by zone name
-    Map<String,Integer> offsets = new HashMap<String,Integer>();
-    int start = 0;
+        public void readByteArray(byte[] dst, int dstOffset, int byteCount) {
+            System.arraycopy(bytes, offset, dst, dstOffset, byteCount);
+            offset += byteCount;
+        }
+
+        public byte readByte() {
+            return bytes[offset++];
+        }
+
+        public int readInt() {
+            return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff);
+        }
+
+        public void readIntArray(int[] dst, int dstOffset, int intCount) {
+            for (int i = 0; i < intCount; ++i) {
+                dst[dstOffset++] = readInt();
+            }
+        }
+
+        public short readShort() {
+            throw new UnsupportedOperationException();
+        }
+    }
 
     // Maximum number of characters in a zone name, including '\0' terminator
     private static final int MAXNAME = 40;
 
+    // Zone name synonyms
+    private Map<String,String> links = new HashMap<String,String>();
+
+    // File starting bytes by zone name
+    private Map<String,Integer> starts = new HashMap<String,Integer>();
+
+    // File lengths by zone name
+    private Map<String,Integer> lengths = new HashMap<String,Integer>();
+
+    // Raw GMT offsets by zone name
+    private Map<String,Integer> offsets = new HashMap<String,Integer>();
+    private int start = 0;
+
     // Concatenate the contents of 'inFile' onto 'out'
     // and return the contents as a byte array.
-    private static byte[] copyFile(File inFile, OutputStream out)
-        throws Exception {
+    private static byte[] copyFile(File inFile, OutputStream out) throws Exception {
         byte[] ret = new byte[0];
 
         InputStream in = new FileInputStream(inFile);
@@ -70,7 +112,7 @@
         out.flush();
         return ret;
     }
-    
+
     // Write a 32-bit integer in network byte order
     private void writeInt(OutputStream os, int x) throws IOException {
         os.write((x >> 24) & 0xff);
@@ -79,14 +121,13 @@
         os.write( x        & 0xff);
     }
 
-    public ZoneCompactor(String setupFilename, String dirName)
-        throws Exception {
+    public ZoneCompactor(String setupFilename, String dirName) throws Exception {
         File zoneInfoFile = new File("zoneinfo.dat");
         zoneInfoFile.delete();
         OutputStream zoneInfo = new FileOutputStream(zoneInfoFile);
 
         BufferedReader rdr = new BufferedReader(new FileReader(setupFilename));
-    
+
         String s;
         while ((s = rdr.readLine()) != null) {
             s = s.trim();
@@ -107,7 +148,8 @@
                     start += length;
                     byte[] data = copyFile(f, zoneInfo);
 
-                    TimeZone tz = ZoneInfo.make(s, data);
+                    BufferIterator it = new ByteArrayBufferIteratorBE(data);
+                    TimeZone tz = ZoneInfo.makeTimeZone(s, it);
                     int gmtOffset = tz.getRawOffset();
                     offsets.put(s, new Integer(gmtOffset));
                 }
@@ -162,5 +204,4 @@
         }
         new ZoneCompactor(args[0], args[1]);
     }
-
 }
diff --git a/libc/tools/zoneinfo/ZoneInfo.java b/libc/tools/zoneinfo/ZoneInfo.java
deleted file mode 100644
index 99507ae..0000000
--- a/libc/tools/zoneinfo/ZoneInfo.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.TimeZone;
-
-/**
- * Copied from ZoneInfo and ZoneInfoDB in dalvik.
- * {@hide}
- */
-public class ZoneInfo extends TimeZone {
-
-    private static final long MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
-    private static final long MILLISECONDS_PER_400_YEARS =
-        MILLISECONDS_PER_DAY * (400 * 365 + 100 - 3);
-
-    private static final long UNIX_OFFSET = 62167219200000L;
-
-    private static final int[] NORMAL = new int[] {
-        0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
-    };
-
-    private static final int[] LEAP = new int[] {
-        0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335,
-    };
-
-    private static String nullName(byte[] data, int where, int off) {
-        if (off < 0)
-            return null;
-
-        int end = where + off;
-        while (end < data.length && data[end] != '\0')
-            end++;
-
-        return new String(data, where + off, end - (where + off));
-    }
-
-    public static ZoneInfo make(String name, byte[] data) {
-        int ntransition = read4(data, 32);
-        int ngmtoff = read4(data, 36);
-        int base = 44;
-
-        int[] transitions = new int[ntransition];
-        for (int i = 0; i < ntransition; i++)
-            transitions[i] = read4(data, base + 4 * i);
-        base += 4 * ntransition;
-
-        byte[] type = new byte[ntransition];
-        for (int i = 0; i < ntransition; i++)
-            type[i] = data[base + i];
-        base += ntransition;
-
-        int[] gmtoff = new int[ngmtoff];
-        byte[] isdst = new byte[ngmtoff];
-        byte[] abbrev = new byte[ngmtoff];
-        for (int i = 0; i < ngmtoff; i++) {
-            gmtoff[i] = read4(data, base + 6 * i);
-            isdst[i] = data[base + 6 * i + 4];
-            abbrev[i] = data[base + 6 * i + 5];
-        }
-
-        base += 6 * ngmtoff;
-
-        return new ZoneInfo(name, transitions, type, gmtoff, isdst, abbrev, data, base);
-    }
-
-    private static int read4(byte[] data, int off) {
-        return ((data[off    ] & 0xFF) << 24) |
-               ((data[off + 1] & 0xFF) << 16) |
-               ((data[off + 2] & 0xFF) <<  8) |
-               ((data[off + 3] & 0xFF) <<  0);
-    }
-
-    /*package*/ ZoneInfo(String name, int[] transitions, byte[] type,
-                     int[] gmtoff, byte[] isdst, byte[] abbrev,
-                     byte[] data, int abbrevoff) {
-        mTransitions = transitions;
-        mTypes = type;
-        mGmtOffs = gmtoff;
-        mIsDsts = isdst;
-        mUseDst = false;
-        setID(name);
-
-        // Find the latest GMT and non-GMT offsets for their abbreviations
-
-        int lastdst;
-        for (lastdst = mTransitions.length - 1; lastdst >= 0; lastdst--) {
-            if (mIsDsts[mTypes[lastdst] & 0xFF] != 0)
-                break;
-        }
-
-        int laststd;
-        for (laststd = mTransitions.length - 1; laststd >= 0; laststd--) {
-            if (mIsDsts[mTypes[laststd] & 0xFF] == 0)
-                break;
-        }
-
-        if (lastdst >= 0) {
-            mDaylightName = nullName(data, abbrevoff,
-                                     abbrev[mTypes[lastdst] & 0xFF]);
-        }
-        if (laststd >= 0) {
-            mStandardName = nullName(data, abbrevoff,
-                                     abbrev[mTypes[laststd] & 0xFF]);
-        }
-
-        // Use the latest non-DST offset if any as the raw offset
-
-        if (laststd < 0) {
-            laststd = 0;
-        }
-
-        if (laststd >= mTypes.length) {
-            mRawOffset = mGmtOffs[0];
-        } else {
-            mRawOffset = mGmtOffs[mTypes[laststd] & 0xFF];
-        }
-
-        // Subtract the raw offset from all offsets so it can be changed
-        // and affect them too.
-        // Find whether there exist any observances of DST.
-
-        for (int i = 0; i < mGmtOffs.length; i++) {
-            mGmtOffs[i] -= mRawOffset;
-
-            if (mIsDsts[i] != 0) {
-                mUseDst = true;
-            }
-        }
-
-        mRawOffset *= 1000;
-    }
-
-    @Override
-    public int getOffset(@SuppressWarnings("unused") int era,
-        int year, int month, int day,
-        @SuppressWarnings("unused") int dayOfWeek,
-        int millis) {
-        // XXX This assumes Gregorian always; Calendar switches from
-        // Julian to Gregorian in 1582.  What calendar system are the
-        // arguments supposed to come from?
-
-        long calc = (year / 400) * MILLISECONDS_PER_400_YEARS;
-        year %= 400;
-
-        calc += year * (365 * MILLISECONDS_PER_DAY);
-        calc += ((year + 3) / 4) * MILLISECONDS_PER_DAY;
-
-        if (year > 0)
-            calc -= ((year - 1) / 100) * MILLISECONDS_PER_DAY;
-
-        boolean isLeap = (year == 0 || (year % 4 == 0 && year % 100 != 0));
-        int[] mlen = isLeap ? LEAP : NORMAL;
-
-        calc += mlen[month] * MILLISECONDS_PER_DAY;
-        calc += (day - 1) * MILLISECONDS_PER_DAY;
-        calc += millis;
-
-        calc -= mRawOffset;
-        calc -= UNIX_OFFSET;
-
-        return getOffset(calc);
-    }
-
-    @Override
-    public int getOffset(long when) {
-        int unix = (int) (when / 1000);
-        int trans = Arrays.binarySearch(mTransitions, unix);
-
-        if (trans == ~0) {
-            return mGmtOffs[0] * 1000 + mRawOffset;
-        }
-        if (trans < 0) {
-            trans = ~trans - 1;
-        }
-
-        return mGmtOffs[mTypes[trans] & 0xFF] * 1000 + mRawOffset;
-    }
-
-    @Override
-    public int getRawOffset() {
-        return mRawOffset;
-    }
-
-    @Override
-    public void setRawOffset(int off) {
-        mRawOffset = off;
-    }
-
-    @Override
-    public boolean inDaylightTime(Date when) {
-        int unix = (int) (when.getTime() / 1000);
-        int trans = Arrays.binarySearch(mTransitions, unix);
-
-        if (trans == ~0) {
-            return mIsDsts[0] != 0;
-        }
-        if (trans < 0) {
-            trans = ~trans - 1;
-        }
-
-        return mIsDsts[mTypes[trans] & 0xFF] != 0;
-    }
-
-    @Override
-    public boolean useDaylightTime() {
-        return mUseDst;
-    }
-
-    private int mRawOffset;
-    private int[] mTransitions;
-    private int[] mGmtOffs;
-    private byte[] mTypes;
-    private byte[] mIsDsts;
-    private boolean mUseDst;
-    private String mDaylightName;
-    private String mStandardName;
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof ZoneInfo)) {
-           return false;
-        }
-        ZoneInfo other = (ZoneInfo) obj;
-        return mUseDst == other.mUseDst
-                && (mDaylightName == null ? other.mDaylightName == null :
-                        mDaylightName.equals(other.mDaylightName))
-                && (mStandardName == null ? other.mStandardName == null :
-                        mStandardName.equals(other.mStandardName))
-                && mRawOffset == other.mRawOffset
-                // Arrays.equals returns true if both arrays are null
-                && Arrays.equals(mGmtOffs, other.mGmtOffs)
-                && Arrays.equals(mIsDsts, other.mIsDsts)
-                && Arrays.equals(mTypes, other.mTypes)
-                && Arrays.equals(mTransitions, other.mTransitions);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((mDaylightName == null) ? 0 :
-                mDaylightName.hashCode());
-        result = prime * result + Arrays.hashCode(mGmtOffs);
-        result = prime * result + Arrays.hashCode(mIsDsts);
-        result = prime * result + mRawOffset;
-        result = prime * result + ((mStandardName == null) ? 0 :
-                mStandardName.hashCode());
-        result = prime * result + Arrays.hashCode(mTransitions);
-        result = prime * result + Arrays.hashCode(mTypes);
-        result = prime * result + (mUseDst ? 1231 : 1237);
-        return result;
-    }
-}
diff --git a/libc/tools/zoneinfo/generate b/libc/tools/zoneinfo/generate
index ab2617f..fd4e6d0 100755
--- a/libc/tools/zoneinfo/generate
+++ b/libc/tools/zoneinfo/generate
@@ -89,9 +89,11 @@
   setup.close()
 
   print 'Calling ZoneCompactor...'
+  libcore_src_dir = '%s/../libcore/luni/src/main/java/' % bionic_dir
   subprocess.check_call(['javac', '-d', '.',
                          '%s/ZoneCompactor.java' % bionic_libc_tools_zoneinfo_dir,
-                         '%s/ZoneInfo.java' % bionic_libc_tools_zoneinfo_dir])
+                         '%s/libcore/util/ZoneInfo.java' % libcore_src_dir,
+                         '%s/libcore/io/BufferIterator.java' % libcore_src_dir])
   subprocess.check_call(['java', 'ZoneCompactor', 'setup', 'data'])
 
   print 'Updating bionic from %s to %s...' % (current_tzdata_version(), version)