• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 import java.io.*;
3 import java.util.*;
4 
5 // usage: java ZoneCompiler <setup file> <top-level directory>
6 //
7 // Compile a set of tzfile-formatted files into a single file plus
8 // an index file.
9 //
10 // The compilation is controlled by a setup file, which is provided as a
11 // command-line argument.  The setup file has the form:
12 //
13 // Link <toName> <fromName>
14 // ...
15 // <zone filename>
16 // ...
17 //
18 // Note that the links must be declared prior to the zone names.  A
19 // zone name is a filename relative to the source directory such as
20 // 'GMT', 'Africa/Dakar', or 'America/Argentina/Jujuy'.
21 //
22 // Use the 'zic' command-line tool to convert from flat files
23 // (e.g., 'africa', 'northamerica') into a suitable source directory
24 // hierarchy for this tool (e.g., 'data/Africa/Abidjan').
25 //
26 // Example:
27 //     zic -d data tz2007h
28 //     javac ZoneCompactor.java
29 //     java ZoneCompactor setup data
30 //     <produces zoneinfo.dat and zoneinfo.idx>
31 
32 public class ZoneCompactor {
33 
34     // Zone name synonyms
35     Map<String,String> links = new HashMap<String,String>();
36 
37     // File starting bytes by zone name
38     Map<String,Integer> starts = new HashMap<String,Integer>();
39 
40     // File lengths by zone name
41     Map<String,Integer> lengths = new HashMap<String,Integer>();
42 
43     // Raw GMT offsets by zone name
44     Map<String,Integer> offsets = new HashMap<String,Integer>();
45     int start = 0;
46 
47     // Maximum number of characters in a zone name, including '\0' terminator
48     private static final int MAXNAME = 40;
49 
50     // Concatenate the contents of 'inFile' onto 'out'
51     // and return the contents as a byte array.
copyFile(File inFile, OutputStream out)52     private static byte[] copyFile(File inFile, OutputStream out)
53         throws Exception {
54         byte[] ret = new byte[0];
55 
56         InputStream in = new FileInputStream(inFile);
57         byte[] buf = new byte[8192];
58         while (true) {
59             int nbytes = in.read(buf);
60             if (nbytes == -1) {
61                 break;
62             }
63             out.write(buf, 0, nbytes);
64 
65             byte[] nret = new byte[ret.length + nbytes];
66             System.arraycopy(ret, 0, nret, 0, ret.length);
67             System.arraycopy(buf, 0, nret, ret.length, nbytes);
68             ret = nret;
69         }
70         out.flush();
71         return ret;
72     }
73 
74     // Write a 32-bit integer in network byte order
writeInt(OutputStream os, int x)75     private void writeInt(OutputStream os, int x) throws IOException {
76         os.write((x >> 24) & 0xff);
77         os.write((x >> 16) & 0xff);
78         os.write((x >>  8) & 0xff);
79         os.write( x        & 0xff);
80     }
81 
ZoneCompactor(String setupFilename, String dirName)82     public ZoneCompactor(String setupFilename, String dirName)
83         throws Exception {
84         File zoneInfoFile = new File("zoneinfo.dat");
85         zoneInfoFile.delete();
86         OutputStream zoneInfo = new FileOutputStream(zoneInfoFile);
87 
88         BufferedReader rdr = new BufferedReader(new FileReader(setupFilename));
89 
90         String s;
91         while ((s = rdr.readLine()) != null) {
92             s = s.trim();
93             if (s.startsWith("Link")) {
94                 StringTokenizer st = new StringTokenizer(s);
95                 st.nextToken();
96                 String to = st.nextToken();
97                 String from = st.nextToken();
98                 links.put(from, to);
99             } else {
100                 String link = links.get(s);
101                 if (link == null) {
102                     File f = new File(dirName, s);
103                     long length = f.length();
104                     starts.put(s, new Integer(start));
105                     lengths.put(s, new Integer((int)length));
106 
107                     start += length;
108                     byte[] data = copyFile(f, zoneInfo);
109 
110                     TimeZone tz = ZoneInfo.make(s, data);
111                     int gmtOffset = tz.getRawOffset();
112                     offsets.put(s, new Integer(gmtOffset));
113                 }
114             }
115         }
116         zoneInfo.close();
117 
118         // Fill in fields for links
119         Iterator<String> iter = links.keySet().iterator();
120         while (iter.hasNext()) {
121             String from = iter.next();
122             String to = links.get(from);
123 
124             starts.put(from, starts.get(to));
125             lengths.put(from, lengths.get(to));
126             offsets.put(from, offsets.get(to));
127         }
128 
129         File idxFile = new File("zoneinfo.idx");
130         idxFile.delete();
131         FileOutputStream idx = new FileOutputStream(idxFile);
132 
133         ArrayList<String> l = new ArrayList<String>();
134         l.addAll(starts.keySet());
135         Collections.sort(l);
136         Iterator<String> ziter = l.iterator();
137         while (ziter.hasNext()) {
138             String zname = ziter.next();
139             if (zname.length() >= MAXNAME) {
140                 System.err.println("Error - zone filename exceeds " +
141                                    (MAXNAME - 1) + " characters!");
142             }
143 
144             byte[] znameBuf = new byte[MAXNAME];
145             for (int i = 0; i < zname.length(); i++) {
146                 znameBuf[i] = (byte)zname.charAt(i);
147             }
148             idx.write(znameBuf);
149             writeInt(idx, starts.get(zname).intValue());
150             writeInt(idx, lengths.get(zname).intValue());
151             writeInt(idx, offsets.get(zname).intValue());
152         }
153         idx.close();
154 
155         // System.out.println("maxLength = " + maxLength);
156     }
157 
main(String[] args)158     public static void main(String[] args) throws Exception {
159         if (args.length != 2) {
160             System.err.println("usage: java ZoneCompactor <setup> <data dir>");
161             System.exit(0);
162         }
163         new ZoneCompactor(args[0], args[1]);
164     }
165 
166 }
167