blob: 9fb9ceca705b4ab88e240716005751f23023985f [file] [log] [blame]
Elliott Hughesd40e63e2011-02-17 16:20:07 -08001
2import java.io.*;
Elliott Hugheseb061292012-10-19 12:05:24 -07003import java.nio.ByteOrder;
Elliott Hughesd40e63e2011-02-17 16:20:07 -08004import java.util.*;
Elliott Hugheseb061292012-10-19 12:05:24 -07005import libcore.io.BufferIterator;
6import libcore.util.ZoneInfo;
Elliott Hughesd40e63e2011-02-17 16:20:07 -08007
Elliott Hughes328a4842012-10-19 13:03:52 -07008// usage: java ZoneCompiler <setup file> <data directory> <output directory> <tzdata version>
Elliott Hughesd40e63e2011-02-17 16:20:07 -08009//
10// Compile a set of tzfile-formatted files into a single file plus
11// an index file.
12//
13// The compilation is controlled by a setup file, which is provided as a
14// command-line argument. The setup file has the form:
15//
16// Link <toName> <fromName>
17// ...
18// <zone filename>
19// ...
20//
21// Note that the links must be declared prior to the zone names. A
22// zone name is a filename relative to the source directory such as
23// 'GMT', 'Africa/Dakar', or 'America/Argentina/Jujuy'.
24//
25// Use the 'zic' command-line tool to convert from flat files
26// (e.g., 'africa', 'northamerica') into a suitable source directory
27// hierarchy for this tool (e.g., 'data/Africa/Abidjan').
28//
29// Example:
30// zic -d data tz2007h
31// javac ZoneCompactor.java
32// java ZoneCompactor setup data
33// <produces zoneinfo.dat and zoneinfo.idx>
34
35public class ZoneCompactor {
Elliott Hugheseb061292012-10-19 12:05:24 -070036 public static class ByteArrayBufferIteratorBE extends BufferIterator {
37 private final byte[] bytes;
38 private int offset = 0;
Elliott Hughesd40e63e2011-02-17 16:20:07 -080039
Elliott Hugheseb061292012-10-19 12:05:24 -070040 public ByteArrayBufferIteratorBE(byte[] bytes) {
41 this.bytes = bytes;
42 this.offset = 0;
43 }
Elliott Hughesd40e63e2011-02-17 16:20:07 -080044
Elliott Hugheseb061292012-10-19 12:05:24 -070045 public void seek(int offset) {
46 this.offset = offset;
47 }
Elliott Hughesd40e63e2011-02-17 16:20:07 -080048
Elliott Hugheseb061292012-10-19 12:05:24 -070049 public void skip(int byteCount) {
50 this.offset += byteCount;
51 }
Elliott Hughesd40e63e2011-02-17 16:20:07 -080052
Elliott Hugheseb061292012-10-19 12:05:24 -070053 public void readByteArray(byte[] dst, int dstOffset, int byteCount) {
54 System.arraycopy(bytes, offset, dst, dstOffset, byteCount);
55 offset += byteCount;
56 }
57
58 public byte readByte() {
59 return bytes[offset++];
60 }
61
62 public int readInt() {
63 return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff);
64 }
65
66 public void readIntArray(int[] dst, int dstOffset, int intCount) {
67 for (int i = 0; i < intCount; ++i) {
68 dst[dstOffset++] = readInt();
69 }
70 }
71
72 public short readShort() {
73 throw new UnsupportedOperationException();
74 }
75 }
Elliott Hughesd40e63e2011-02-17 16:20:07 -080076
77 // Maximum number of characters in a zone name, including '\0' terminator
78 private static final int MAXNAME = 40;
79
Elliott Hugheseb061292012-10-19 12:05:24 -070080 // Zone name synonyms
81 private Map<String,String> links = new HashMap<String,String>();
82
83 // File starting bytes by zone name
84 private Map<String,Integer> starts = new HashMap<String,Integer>();
85
86 // File lengths by zone name
87 private Map<String,Integer> lengths = new HashMap<String,Integer>();
88
89 // Raw GMT offsets by zone name
90 private Map<String,Integer> offsets = new HashMap<String,Integer>();
91 private int start = 0;
92
Elliott Hughesd40e63e2011-02-17 16:20:07 -080093 // Concatenate the contents of 'inFile' onto 'out'
94 // and return the contents as a byte array.
Elliott Hugheseb061292012-10-19 12:05:24 -070095 private static byte[] copyFile(File inFile, OutputStream out) throws Exception {
Elliott Hughesd40e63e2011-02-17 16:20:07 -080096 byte[] ret = new byte[0];
97
98 InputStream in = new FileInputStream(inFile);
99 byte[] buf = new byte[8192];
100 while (true) {
101 int nbytes = in.read(buf);
102 if (nbytes == -1) {
103 break;
104 }
105 out.write(buf, 0, nbytes);
106
107 byte[] nret = new byte[ret.length + nbytes];
108 System.arraycopy(ret, 0, nret, 0, ret.length);
109 System.arraycopy(buf, 0, nret, ret.length, nbytes);
110 ret = nret;
111 }
112 out.flush();
113 return ret;
114 }
Elliott Hugheseb061292012-10-19 12:05:24 -0700115
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800116 // Write a 32-bit integer in network byte order
117 private void writeInt(OutputStream os, int x) throws IOException {
118 os.write((x >> 24) & 0xff);
119 os.write((x >> 16) & 0xff);
120 os.write((x >> 8) & 0xff);
121 os.write( x & 0xff);
122 }
123
Elliott Hughes328a4842012-10-19 13:03:52 -0700124 public ZoneCompactor(String setupFile, String dataDirectory, String outputDirectory, String version) throws Exception {
125 File zoneInfoFile = new File(outputDirectory, "zoneinfo.dat");
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800126 zoneInfoFile.delete();
127 OutputStream zoneInfo = new FileOutputStream(zoneInfoFile);
128
Elliott Hughes328a4842012-10-19 13:03:52 -0700129 BufferedReader rdr = new BufferedReader(new FileReader(setupFile));
Elliott Hugheseb061292012-10-19 12:05:24 -0700130
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800131 String s;
132 while ((s = rdr.readLine()) != null) {
133 s = s.trim();
134 if (s.startsWith("Link")) {
135 StringTokenizer st = new StringTokenizer(s);
136 st.nextToken();
137 String to = st.nextToken();
138 String from = st.nextToken();
139 links.put(from, to);
140 } else {
141 String link = links.get(s);
142 if (link == null) {
Elliott Hughes328a4842012-10-19 13:03:52 -0700143 File f = new File(dataDirectory, s);
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800144 long length = f.length();
145 starts.put(s, new Integer(start));
146 lengths.put(s, new Integer((int)length));
147
148 start += length;
149 byte[] data = copyFile(f, zoneInfo);
150
Elliott Hugheseb061292012-10-19 12:05:24 -0700151 BufferIterator it = new ByteArrayBufferIteratorBE(data);
152 TimeZone tz = ZoneInfo.makeTimeZone(s, it);
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800153 int gmtOffset = tz.getRawOffset();
154 offsets.put(s, new Integer(gmtOffset));
155 }
156 }
157 }
158 zoneInfo.close();
159
160 // Fill in fields for links
161 Iterator<String> iter = links.keySet().iterator();
162 while (iter.hasNext()) {
163 String from = iter.next();
164 String to = links.get(from);
165
166 starts.put(from, starts.get(to));
167 lengths.put(from, lengths.get(to));
168 offsets.put(from, offsets.get(to));
169 }
170
Elliott Hughes328a4842012-10-19 13:03:52 -0700171 File idxFile = new File(outputDirectory, "zoneinfo.idx");
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800172 idxFile.delete();
173 FileOutputStream idx = new FileOutputStream(idxFile);
174
175 ArrayList<String> l = new ArrayList<String>();
176 l.addAll(starts.keySet());
177 Collections.sort(l);
178 Iterator<String> ziter = l.iterator();
179 while (ziter.hasNext()) {
180 String zname = ziter.next();
181 if (zname.length() >= MAXNAME) {
182 System.err.println("Error - zone filename exceeds " +
183 (MAXNAME - 1) + " characters!");
184 }
185
186 byte[] znameBuf = new byte[MAXNAME];
187 for (int i = 0; i < zname.length(); i++) {
188 znameBuf[i] = (byte)zname.charAt(i);
189 }
190 idx.write(znameBuf);
191 writeInt(idx, starts.get(zname).intValue());
192 writeInt(idx, lengths.get(zname).intValue());
193 writeInt(idx, offsets.get(zname).intValue());
194 }
195 idx.close();
196
Elliott Hughes328a4842012-10-19 13:03:52 -0700197 OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(outputDirectory, "zoneinfo.version")), "US-ASCII");
198 writer.write(version);
199 writer.write('\n');
200 writer.close();
201
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800202 // System.out.println("maxLength = " + maxLength);
203 }
204
205 public static void main(String[] args) throws Exception {
Elliott Hughes328a4842012-10-19 13:03:52 -0700206 if (args.length != 4) {
207 System.err.println("usage: java ZoneCompactor <setup file> <data directory> <output directory> <tzdata version>");
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800208 System.exit(0);
209 }
Elliott Hughes328a4842012-10-19 13:03:52 -0700210 new ZoneCompactor(args[0], args[1], args[2], args[3]);
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800211 }
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800212}