Move the zoneinfo generation tool into bionic.
This also incorporates a bunch of changes to the previous script; this one
requires no setup, can be run from anywhere, and leaves no droppings.
Change-Id: I38f299f03e33950d2a64e9336f4ba7cb3c5cf6f0
diff --git a/libc/tools/zoneinfo/ZoneCompactor.java b/libc/tools/zoneinfo/ZoneCompactor.java
new file mode 100644
index 0000000..b657748
--- /dev/null
+++ b/libc/tools/zoneinfo/ZoneCompactor.java
@@ -0,0 +1,166 @@
+
+import java.io.*;
+import java.util.*;
+
+// usage: java ZoneCompiler <setup file> <top-level directory>
+//
+// Compile a set of tzfile-formatted files into a single file plus
+// an index file.
+//
+// The compilation is controlled by a setup file, which is provided as a
+// command-line argument. The setup file has the form:
+//
+// Link <toName> <fromName>
+// ...
+// <zone filename>
+// ...
+//
+// Note that the links must be declared prior to the zone names. A
+// zone name is a filename relative to the source directory such as
+// 'GMT', 'Africa/Dakar', or 'America/Argentina/Jujuy'.
+//
+// Use the 'zic' command-line tool to convert from flat files
+// (e.g., 'africa', 'northamerica') into a suitable source directory
+// hierarchy for this tool (e.g., 'data/Africa/Abidjan').
+//
+// Example:
+// zic -d data tz2007h
+// javac ZoneCompactor.java
+// java ZoneCompactor setup data
+// <produces zoneinfo.dat and zoneinfo.idx>
+
+public class ZoneCompactor {
+
+ // Zone name synonyms
+ Map<String,String> links = new HashMap<String,String>();
+
+ // File starting bytes by zone name
+ Map<String,Integer> starts = new HashMap<String,Integer>();
+
+ // File lengths by zone name
+ Map<String,Integer> lengths = new HashMap<String,Integer>();
+
+ // Raw GMT offsets by zone name
+ Map<String,Integer> offsets = new HashMap<String,Integer>();
+ int start = 0;
+
+ // Maximum number of characters in a zone name, including '\0' terminator
+ private static final int MAXNAME = 40;
+
+ // 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 {
+ byte[] ret = new byte[0];
+
+ InputStream in = new FileInputStream(inFile);
+ byte[] buf = new byte[8192];
+ while (true) {
+ int nbytes = in.read(buf);
+ if (nbytes == -1) {
+ break;
+ }
+ out.write(buf, 0, nbytes);
+
+ byte[] nret = new byte[ret.length + nbytes];
+ System.arraycopy(ret, 0, nret, 0, ret.length);
+ System.arraycopy(buf, 0, nret, ret.length, nbytes);
+ ret = nret;
+ }
+ 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);
+ os.write((x >> 16) & 0xff);
+ os.write((x >> 8) & 0xff);
+ os.write( x & 0xff);
+ }
+
+ 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();
+ if (s.startsWith("Link")) {
+ StringTokenizer st = new StringTokenizer(s);
+ st.nextToken();
+ String to = st.nextToken();
+ String from = st.nextToken();
+ links.put(from, to);
+ } else {
+ String link = links.get(s);
+ if (link == null) {
+ File f = new File(dirName, s);
+ long length = f.length();
+ starts.put(s, new Integer(start));
+ lengths.put(s, new Integer((int)length));
+
+ start += length;
+ byte[] data = copyFile(f, zoneInfo);
+
+ TimeZone tz = ZoneInfo.make(s, data);
+ int gmtOffset = tz.getRawOffset();
+ offsets.put(s, new Integer(gmtOffset));
+ }
+ }
+ }
+ zoneInfo.close();
+
+ // Fill in fields for links
+ Iterator<String> iter = links.keySet().iterator();
+ while (iter.hasNext()) {
+ String from = iter.next();
+ String to = links.get(from);
+
+ starts.put(from, starts.get(to));
+ lengths.put(from, lengths.get(to));
+ offsets.put(from, offsets.get(to));
+ }
+
+ File idxFile = new File("zoneinfo.idx");
+ idxFile.delete();
+ FileOutputStream idx = new FileOutputStream(idxFile);
+
+ ArrayList<String> l = new ArrayList<String>();
+ l.addAll(starts.keySet());
+ Collections.sort(l);
+ Iterator<String> ziter = l.iterator();
+ while (ziter.hasNext()) {
+ String zname = ziter.next();
+ if (zname.length() >= MAXNAME) {
+ System.err.println("Error - zone filename exceeds " +
+ (MAXNAME - 1) + " characters!");
+ }
+
+ byte[] znameBuf = new byte[MAXNAME];
+ for (int i = 0; i < zname.length(); i++) {
+ znameBuf[i] = (byte)zname.charAt(i);
+ }
+ idx.write(znameBuf);
+ writeInt(idx, starts.get(zname).intValue());
+ writeInt(idx, lengths.get(zname).intValue());
+ writeInt(idx, offsets.get(zname).intValue());
+ }
+ idx.close();
+
+ // System.out.println("maxLength = " + maxLength);
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (args.length != 2) {
+ System.err.println("usage: java ZoneCompactor <setup> <data dir>");
+ System.exit(0);
+ }
+ new ZoneCompactor(args[0], args[1]);
+ }
+
+}