001: /*
002: * @(#)Gen.java 1.6 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package sun.tools.javazic;
028:
029: import java.io.IOException;
030: import java.io.File;
031: import java.io.FileOutputStream;
032: import java.io.DataOutputStream;
033: import java.io.RandomAccessFile;
034: import java.util.ArrayList;
035: import java.util.Iterator;
036: import java.util.LinkedList;
037: import java.util.Set;
038: import java.util.TreeMap;
039: import java.util.TreeSet;
040: import sun.util.calendar.ZoneInfoFile;
041:
042: /**
043: * <code>Gen</code> is one of back-end classes of javazic, and generates
044: * ZoneInfoMappings and zone-specific file for each zone.
045: */
046: class Gen extends BackEnd {
047:
048: /**
049: * Generates datafile in binary TLV format for each zone.
050: * Regarding contents of output files, see {@link ZoneInfoFile}.
051: * @param Timezone
052: * @return 0 if no errors, or 1 if error occurred.
053: */
054: int processZoneinfo(Timezone tz) {
055: try {
056: int size;
057: String outputDir = Main.getOutputDir();
058: String zonefile = ZoneInfoFile.getFileName(tz.getName());
059:
060: /* If outputDir doesn't end with file-separator, adds it. */
061: if (!outputDir.endsWith(File.separator)) {
062: outputDir += File.separatorChar;
063: }
064:
065: /* If zonefile includes file-separator, it's treated as part of
066: * pathname. And make directory if necessary.
067: */
068: int index = zonefile.lastIndexOf(File.separatorChar);
069: if (index != -1) {
070: outputDir += zonefile.substring(0, index + 1);
071: }
072: File outD = new File(outputDir);
073: outD.mkdirs();
074:
075: FileOutputStream fos = new FileOutputStream(outputDir
076: + zonefile.substring(index + 1));
077: DataOutputStream dos = new DataOutputStream(fos);
078:
079: /* Output Label */
080: dos.write(ZoneInfoFile.JAVAZI_LABEL, 0,
081: ZoneInfoFile.JAVAZI_LABEL.length);
082:
083: /* Output Version of ZoneInfoFile */
084: dos.writeByte(ZoneInfoFile.JAVAZI_VERSION);
085:
086: ArrayList transitions = tz.getTransitions();
087: if (transitions != null) {
088: ArrayList dstOffsets = tz.getDstOffsets();
089: ArrayList offsets = tz.getOffsets();
090:
091: if ((dstOffsets == null && offsets != null)
092: || (dstOffsets != null && offsets == null)) {
093: Main
094: .panic("Data not exist. (dstOffsets or offsets)");
095: return 1;
096: }
097:
098: /* Output Transition records */
099: dos.writeByte(ZoneInfoFile.TAG_Transition);
100: size = transitions.size();
101: dos.writeShort((size * 8) & 0xFFFF);
102: int dstoffset;
103: for (int i = 0; i < size; i++) {
104: /* if DST offset is 0, this means DST isn't used.
105: * (NOT: offset's index is 0.)
106: */
107: if ((dstoffset = ((Integer) dstOffsets.get(i))
108: .intValue()) == -1) {
109: dstoffset = 0;
110: }
111:
112: dos.writeLong((((Long) transitions.get(i))
113: .longValue() << 12)
114: | (dstoffset << 4)
115: | ((Integer) offsets.get(i)).intValue());
116:
117: }
118:
119: /* Output data for GMTOffset */
120: ArrayList gmtoffset = tz.getGmtOffsets();
121: dos.writeByte(ZoneInfoFile.TAG_Offset);
122: size = gmtoffset.size();
123: dos.writeShort((size * 4) & 0xFFFF);
124: for (int i = 0; i < size; i++) {
125: dos.writeInt(((Integer) gmtoffset.get(i))
126: .intValue());
127: }
128: }
129:
130: /* Output data for SimpleTimeZone */
131: ArrayList stz = tz.getLastRules();
132: if (stz != null) {
133: RuleRec[] rr = new RuleRec[2];
134: boolean wall = true;
135:
136: rr[0] = (RuleRec) stz.get(0);
137: rr[1] = (RuleRec) stz.get(1);
138:
139: dos.writeByte(ZoneInfoFile.TAG_SimpleTimeZone);
140: wall = rr[0].getTime().isWall()
141: && rr[1].getTime().isWall();
142: if (wall) {
143: dos.writeShort(32);
144: } else {
145: dos.writeShort(40);
146: }
147:
148: for (int i = 0; i < 2; i++) {
149: dos.writeInt(rr[i].getMonthNum());
150: dos.writeInt(rr[i].getDay()
151: .getDayForSimpleTimeZone());
152: dos.writeInt(rr[i].getDay()
153: .getDayOfWeekForSimpleTimeZoneInt());
154: dos.writeInt((int) rr[i].getTime().getTime());
155: if (!wall) {
156: dos
157: .writeInt((rr[i].getTime().getType() & 0xFF) - 1);
158: }
159: }
160: }
161:
162: /* Output RawOffset */
163: dos.writeByte(ZoneInfoFile.TAG_RawOffset);
164: dos.writeShort(4);
165: dos.writeInt(tz.getRawOffset());
166:
167: /* Output willGMTOffsetChange flag */
168: if (tz.willGMTOffsetChange()) {
169: dos.writeByte(ZoneInfoFile.TAG_GMTOffsetWillChange);
170: dos.writeShort(1);
171: dos.writeByte(1);
172: }
173:
174: /* Output LastDSTSaving */
175: dos.writeByte(ZoneInfoFile.TAG_LastDSTSaving);
176: dos.writeShort(2);
177: dos.writeShort(tz.getLastDSTSaving() / 1000);
178:
179: /* Output checksum */
180: dos.writeByte(ZoneInfoFile.TAG_CRC32);
181: dos.writeShort(4);
182: dos.writeInt(tz.getCRC32());
183:
184: fos.close();
185: dos.close();
186: } catch (IOException e) {
187: Main.panic("IO error: " + e.getMessage());
188: return 1;
189: }
190:
191: return 0;
192: }
193:
194: /**
195: * Generates ZoneInfoMappings in binary TLV format for each zone.
196: * Regarding contents of output files, see {@link ZoneInfoFile}.
197: * @param Mappings
198: * @return 0 if no errors, or 1 if error occurred.
199: */
200: int generateSrc(Mappings map) {
201: try {
202: int index;
203: int block_size;
204: int roi_size;
205: long fp;
206: Iterator keys;
207: String key;
208: String outputDir = Main.getOutputDir();
209:
210: /* If outputDir doesn't end with file-separator, adds it. */
211: if (!outputDir.endsWith(File.separator)) {
212: outputDir += File.separatorChar;
213: }
214:
215: File outD = new File(outputDir);
216: outD.mkdirs();
217:
218: /* Open ZoneInfoMapping file to write. */
219: RandomAccessFile raf = new RandomAccessFile(outputDir
220: + ZoneInfoFile.JAVAZM_FILE_NAME, "rw");
221:
222: /* Whether rawOffsetIndex list exists or not. */
223: LinkedList roi = map.getRawOffsetsIndex();
224: if (roi == null) {
225: Main.panic("Data not exist. (rawOffsetsIndex)");
226: return 1;
227: }
228: roi_size = roi.size();
229:
230: /* Whether rawOffsetIndexTable list exists or not. */
231: LinkedList roit = map.getRawOffsetsIndexTable();
232: if (roit == null || roit.size() != roi_size) {
233: Main
234: .panic("Data not exist. (rawOffsetsIndexTable) Otherwise, Invalid size");
235: return 1;
236: }
237:
238: /* Output Label */
239: raf.write(ZoneInfoFile.JAVAZM_LABEL, 0,
240: ZoneInfoFile.JAVAZM_LABEL.length);
241:
242: /* Output Version */
243: raf.writeByte(ZoneInfoFile.JAVAZM_VERSION);
244:
245: index = ZoneInfoFile.JAVAZM_LABEL.length + 2;
246:
247: /* Output Version of Olson's tzdata */
248: byte[] b = Main.getVersionName().getBytes();
249: raf.writeByte(ZoneInfoFile.TAG_TZDataVersion);
250: raf.writeShort((b.length + 1) & 0xFFFF);
251: raf.write(b);
252: raf.writeByte(0x00);
253: index += b.length + 4;
254:
255: /* Output ID list. */
256: raf.writeByte(ZoneInfoFile.TAG_ZoneIDs);
257: block_size = 2;
258: raf.writeShort(block_size & 0xFFFF);
259: short nID = 0;
260: raf.writeShort(nID & 0xFFFF);
261: for (int i = 0; i < roi_size; i++) {
262: TreeSet perRO = (TreeSet) roit.get(i);
263: keys = perRO.iterator();
264:
265: while (keys.hasNext()) {
266: key = (String) keys.next();
267: byte size = (byte) key.getBytes().length;
268: raf.writeByte(size & 0xFF);
269: raf.write(key.getBytes(), 0, size);
270: block_size += 1 + size;
271: nID++;
272: }
273: }
274: fp = raf.getFilePointer();
275: raf.seek(index);
276: raf.writeShort((block_size) & 0xFFFF);
277: raf.writeShort(nID & 0xFFFF);
278: raf.seek(fp);
279:
280: /* Output sorted rawOffset list. */
281: raf.writeByte(ZoneInfoFile.TAG_RawOffsets);
282: index += 3 + block_size;
283: block_size = roi_size * 4;
284: raf.writeShort(block_size & 0xFFFF);
285: for (int i = 0; i < roi_size; i++) {
286: raf.writeInt(Integer.parseInt(roi.get(i).toString()));
287: }
288:
289: /* Output sorted rawOffsetIndex list. */
290: raf.writeByte(ZoneInfoFile.TAG_RawOffsetIndices);
291: index += 3 + block_size;
292: block_size = 0;
293: raf.writeShort(block_size & 0xFFFF);
294: int num;
295: for (int i = 0; i < roi_size; i++) {
296: num = ((TreeSet) (roit.get(i))).size();
297: block_size += num;
298: for (int j = 0; j < num; j++) {
299: raf.writeByte(i);
300: }
301: }
302: fp = raf.getFilePointer();
303: raf.seek(index);
304: raf.writeShort((block_size) & 0xFFFF);
305: raf.seek(fp);
306:
307: /* Whether alias list exists or not. */
308: TreeMap a = map.getAliases();
309: if (a == null) {
310: Main.panic("Data not exist. (aliases)");
311: return 0;
312: }
313:
314: /* Output ID list. */
315: Set s = a.keySet();
316: keys = s.iterator();
317: raf.writeByte(ZoneInfoFile.TAG_ZoneAliases);
318: index += 3 + block_size;
319: block_size = 2;
320: raf.writeShort(block_size & 0xFFFF);
321: raf.writeShort(a.size() & 0xFFFF);
322: while (keys.hasNext()) {
323: key = (String) keys.next();
324: String alias = (String) a.get(key);
325: byte key_size = (byte) key.length();
326: byte alias_size = (byte) alias.length();
327: raf.writeByte(key_size & 0xFF);
328: raf.write(key.getBytes(), 0, key_size);
329: raf.writeByte(alias_size & 0xFF);
330: raf.write(alias.getBytes(), 0, alias_size);
331: block_size += 2 + key_size + alias_size;
332: }
333: fp = raf.getFilePointer();
334: raf.seek(index);
335: raf.writeShort((block_size) & 0xFFFF);
336: raf.seek(fp);
337:
338: /* Close ZoneInfoMapping file. */
339: raf.close();
340: } catch (IOException e) {
341: Main.panic("IO error: " + e.getMessage());
342: return 1;
343: }
344:
345: return 0;
346: }
347: }
|