1 /* 2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 import java.io.BufferedReader; 27 import java.io.BufferedWriter; 28 import java.io.File; 29 import java.io.FileReader; 30 import java.io.FileWriter; 31 import java.io.IOException; 32 import java.util.Date; 33 import java.util.HashMap; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Set; 37 import java.util.SortedMap; 38 import java.util.StringTokenizer; 39 import java.util.TreeMap; 40 import java.util.TreeSet; 41 42 /** 43 * <code>GenDoc</code> is one of back-end classes of javazic, and generates 44 * index.html and other html files which prints the detailed time zone 45 * information for each zone. 46 */ 47 class GenDoc extends BackEnd { 48 49 private static final String docDir = "doc"; 50 51 private static final String header1 = 52 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"" + 53 "\"http://www.w3.org/TR/REC-html40/frameset.dtd\">\n" + 54 "<HTML>\n<HEAD>\n<!-- Generated by javazic on "; 55 private static final String header2 = 56 "-->\n<TITLE>\n" + 57 "Java Platform, Standard Edition - TimeZone information based on "; 58 private static final String header3 = 59 "-->\n<TITLE>\n" + 60 "Java Platform, Standard Edition TimeZone - "; 61 private static final String header4 = 62 "</TITLE>\n" + 63 "</HEAD>\n\n"; 64 65 private static final String body1 = 66 "<BODY BGCOLOR=\"white\">\n"; 67 private static final String body2 = 68 "</BODY>\n"; 69 70 private static final String footer = 71 "</HTML>\n"; 72 73 74 // list of time zone name and zonefile name/real time zone name 75 // e.g. 76 // key (String) : value (String) 77 // "America/Denver" : "America/Denver.html" (real time zone) 78 // "America/Shiprock" : "America/Denver" (alias) 79 TreeMap<String,String> timezoneList = new TreeMap<String,String>(); 80 81 // list of time zone's display name and time zone name 82 // e.g. 83 // key (String) : value (String) 84 // "Tokyo, Asia" : "Asia/Tokyo" 85 // "Marengo, Indiana, America" : "America/Indiana/Marengo" 86 // (aliases included) 87 TreeMap<String,String> displayNameList = new TreeMap<String,String>(); 88 89 // list of top level regions 90 // e.g. 91 // key (String) : value (String) 92 // "America" : "America.html" 93 // (including entries in America/Indiana/, America/Kentucky/, ...) 94 TreeMap<String,String> regionList = new TreeMap<String,String>(); 95 96 // mapping list from zone name to latitude & longitude 97 // This list is generated from zone.tab. 98 // e.g. 99 // key (String) : value (LatitudeAndLongitude object) 100 // "Asia/Tokyo" : latitude=35.3916, longitude=13.9444 101 // (aliases not included) 102 HashMap<String,LatitudeAndLongitude> mapList = null; 103 104 // SortedMap of zone IDs sorted by their GMT offsets. If zone's GMT 105 // offset will change in the future, its last known offset is 106 // used. 107 SortedMap<Integer, Set<String>> zonesByOffset = new TreeMap<Integer, Set<String>>(); 108 109 /** 110 * Generates HTML document for each zone. 111 * @param Timezone 112 * @return 0 if no errors, or 1 if error occurred. 113 */ 114 int processZoneinfo(Timezone tz) { 115 try { 116 int size; 117 int index; 118 String outputDir = Main.getOutputDir(); 119 String zonename = tz.getName(); 120 String zonefile = ZoneInfoFile.getFileName(zonename) + ".html"; 121 List<RuleRec> stz = tz.getLastRules(); 122 timezoneList.put(zonename, zonefile); 123 displayNameList.put(transform(zonename), zonename); 124 125 // Populate zonesByOffset. (Zones that will change their 126 // GMT offsets are also added to zonesByOffset here.) 127 int lastKnownOffset = tz.getRawOffset(); 128 Set<String> set = zonesByOffset.get(lastKnownOffset); 129 if (set == null) { 130 set = new TreeSet<String>(); 131 zonesByOffset.put(lastKnownOffset, set); 132 } 133 set.add(zonename); 134 135 /* If outputDir doesn't end with file-separator, adds it. */ 136 if (!outputDir.endsWith(File.separator)) { 137 outputDir += File.separatorChar; 138 } 139 outputDir += docDir + File.separatorChar; 140 141 index = zonename.indexOf('/'); 142 if (index != -1) { 143 regionList.put(zonename.substring(0, index), 144 zonename.substring(0, index) + ".html"); 145 } 146 147 /* If zonefile includes file-separator, it's treated as part of 148 * pathname. And make directory if necessary. 149 */ 150 index = zonefile.lastIndexOf('/'); 151 if (index != -1) { 152 zonefile.replace('/', File.separatorChar); 153 outputDir += zonefile.substring(0, index+1); 154 } 155 File outD = new File(outputDir); 156 outD.mkdirs(); 157 158 /* If mapfile is available, add a link to the appropriate map */ 159 if ((mapList == null) && (Main.getMapFile() != null)) { 160 FileReader fr = new FileReader(Main.getMapFile()); 161 BufferedReader in = new BufferedReader(fr); 162 mapList = new HashMap<String,LatitudeAndLongitude>(); 163 String line; 164 while ((line = in.readLine()) != null) { 165 // skip blank and comment lines 166 if (line.length() == 0 || line.charAt(0) == '#') { 167 continue; 168 } 169 StringTokenizer tokens = new StringTokenizer(line); 170 String token = tokens.nextToken(); /* We don't use the first token. */ 171 token = tokens.nextToken(); 172 LatitudeAndLongitude location = new LatitudeAndLongitude(token); 173 token = tokens.nextToken(); 174 mapList.put(token, location); 175 } 176 in.close(); 177 } 178 179 /* Open zoneinfo file to write. */ 180 FileWriter fw = new FileWriter(outputDir + zonefile.substring(index+1)); 181 BufferedWriter out = new BufferedWriter(fw); 182 183 out.write(header1 + new Date() + header3 + zonename + header4); 184 out.write(body1 + "<FONT size=\"+2\"><B>" + zonename + "</B></FONT>"); 185 LatitudeAndLongitude location = mapList.get(zonename); 186 if (location != null) { 187 int deg, min, sec; 188 189 deg = location.getLatDeg(); 190 min = location.getLatMin(); 191 sec = location.getLatSec(); 192 if (deg < 0) { 193 min = -min; 194 sec = -sec; 195 } else if (min < 0) { 196 sec = -sec; 197 } 198 out.write(" " + 199 "<A HREF=\"http://www.mapquest.com/maps/map.adp?" + 200 "latlongtype=degrees" + 201 "&latdeg=" + deg + 202 "&latmin=" + min + 203 "&latsec=" + sec); 204 205 deg = location.getLongDeg(); 206 min = location.getLongMin(); 207 sec = location.getLongSec(); 208 if (deg < 0) { 209 min = -min; 210 sec = -sec; 211 } else if (min < 0) { 212 sec = -sec; 213 } 214 out.write("&longdeg=" + deg + 215 "&longmin=" + min + 216 "&longsec=" + sec + 217 "\" target=\"_blank\">[map]</A>"); 218 } 219 out.write("\n<P>\n"); 220 221 List<ZoneRec> zone = tz.getZones(); 222 List<RuleRec> rule = tz.getRules(); 223 if (rule != null && zone != null) { 224 out.write("<TABLE BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"1\" CELLSPACING=\"0\">\n" + 225 "<TR>\n" + 226 "<TD BGCOLOR=\"#EEEEFF\" WIDTH=\"50%\" ALIGN=\"CENTER\"><BR>" + 227 "<A HREF=\"#Rules\">Rules</A><BR></TD>\n" + 228 "<TD BGCOLOR=\"#EEEEFF\" WIDTH=\"50%\" ALIGN=\"CENTER\">" + 229 "<A HREF=\"#Zone\"><BR>Zone<BR></A></TD>\n" + 230 "</TR>\n</TABLE>\n"); 231 } 232 233 /* Output Rule records. */ 234 if (rule != null) { 235 size = rule.size(); 236 out.write("<P>\n<A NAME=\"Rules\">" + 237 "<FONT SIZE=\"+1\"><B>Rules</B></FONT></A>\n" + 238 "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" CELLSPACING=\"0\">\n" + 239 "<TR BGCOLOR=\"#CCCCFF\">\n" + 240 "<TD>NAME</TD><TD>FROM</TD><TD>TO</TD><TD>TYPE</TD>" + 241 "<TD>IN</TD><TD>ON</TD><TD>AT</TD><TD>SAVE</TD>" + 242 "<TD>LETTER/S</TD><TD>NOTES</TD>\n</TR>\n"); 243 for (int i = 0; i < size; i++) { 244 out.write("<TR BGCOLOR=\"#FFFFFF\">\n"); 245 StringTokenizer st = new StringTokenizer(rule.get(i).getLine()); 246 String s; 247 if (st.hasMoreTokens()) { /* RULE - truncated */ 248 st.nextToken(); 249 } 250 if (st.hasMoreTokens()) { /* NAME */ 251 out.write("<TD>" + st.nextToken() + "</TD>"); 252 } 253 if (st.hasMoreTokens()) { /* FROM */ 254 out.write("<TD>" + st.nextToken() + "</TD>"); 255 } 256 if (st.hasMoreTokens()) { /* TO */ 257 s = st.nextToken(); 258 if (s.equals("min") || s.equals("max")) { 259 out.write("<TD><FONT COLOR=\"red\">" + s + "</FONT></TD>"); 260 } else { 261 out.write("<TD>" + s + "</TD>"); 262 } 263 } 264 if (st.hasMoreTokens()) { /* TYPE */ 265 out.write("<TD>" + st.nextToken() + "</TD>"); 266 } 267 if (st.hasMoreTokens()) { /* IN */ 268 out.write("<TD>" + st.nextToken() + "</TD>"); 269 } 270 if (st.hasMoreTokens()) { /* ON */ 271 out.write("<TD>" + st.nextToken() + "</TD>"); 272 } 273 if (st.hasMoreTokens()) { /* AT */ 274 out.write("<TD>" + st.nextToken() + "</TD>"); 275 } 276 if (st.hasMoreTokens()) { /* SAVE */ 277 out.write("<TD>" + st.nextToken() + "</TD>"); 278 } 279 if (st.hasMoreTokens()) { /* LETTER/S */ 280 out.write("<TD>" + st.nextToken() + "</TD>"); 281 } 282 if (st.hasMoreTokens()) { /* NOTES */ 283 s = st.nextToken(); 284 while (st.hasMoreTokens()) { 285 s += " " + st.nextToken(); 286 } 287 index = s.indexOf('#'); 288 out.write("<TD>" + s.substring(index+1) + "</TD>\n"); 289 } else { 290 out.write("<TD> </TD>\n"); 291 } 292 out.write("</TR>\n"); 293 } 294 out.write("</TABLE>\n<P> <P>\n"); 295 } 296 297 /* Output Zone records. */ 298 if (zone != null) { 299 size = zone.size(); 300 out.write("<P>\n<A NAME=\"Zone\">" + 301 "<FONT SIZE=\"+1\"><B>Zone</B></FONT></A>\n" + 302 "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" CELLSPACING=\"0\">\n" + 303 "<TR BGCOLOR=\"#CCCCFF\">\n<TD>GMTOFF</TD>" + 304 "<TD>RULES</TD><TD>FORMAT</TD><TD>UNTIL</TD>" + 305 "<TD>NOTES</TD>\n</TR>\n"); 306 for (int i = 0; i < size; i++) { 307 out.write("<TR>\n"); 308 StringTokenizer st = new StringTokenizer(zone.get(i).getLine()); 309 String s = st.nextToken(); 310 if (s.equals("Zone")) { /* NAME */ 311 s = st.nextToken(); 312 s = st.nextToken(); 313 } 314 out.write("<TD>" + s + "</TD>"); /* GMTOFFSET */ 315 if (st.hasMoreTokens()) { /* RULES */ 316 out.write("<TD>" + st.nextToken() + "</TD>"); 317 } 318 if (st.hasMoreTokens()) { /* FORMAT */ 319 s = st.nextToken(); 320 index = s.indexOf('#'); 321 if (index != -1) { 322 if (index != 0) { 323 out.write("<TD>" + s.substring(0, index-1) + 324 "</TD>"); /* FORMAT */ 325 s = s.substring(index+1); 326 } else { 327 out.write("<TD> </TD>"); /* FORMAT */ 328 } 329 while (st.hasMoreTokens()) { 330 s += " " + st.nextToken(); 331 } 332 out.write("<TD> </TD>"); /* UNTIL */ 333 out.write("<TD>" + s + "</TD>\n</TR>\n"); /* NOTES */ 334 continue; 335 } else { 336 out.write("<TD>" + s + "</TD>"); /* FORMAT */ 337 } 338 } 339 340 if (st.hasMoreTokens()) { /* UNTIL */ 341 s = st.nextToken(); 342 while (st.hasMoreTokens()) { 343 s += " " + st.nextToken(); 344 } 345 index = s.indexOf('#'); 346 if (index != -1) { 347 if (index != 0) { 348 out.write("<TD>" + s.substring(0, index-1) + 349 "</TD>"); /* UNTIL */ 350 } else { 351 out.write("<TD> </TD>"); /* UNTIL */ 352 } 353 out.write("<TD>" + s.substring(index+1) + 354 "</TD>\n"); /* NOTES */ 355 } else { 356 out.write("<TD>" + s + "</TD>"); /* UNTIL */ 357 out.write("<TD> </TD>\n"); /* NOTES */ 358 } 359 } else { 360 out.write("<TD> </TD>"); /* UNTIL */ 361 out.write("<TD> </TD>\n"); /* NOTES */ 362 } 363 out.write("</TR>\n"); 364 } 365 out.write("</TABLE>\n"); 366 } 367 out.write(body2 + footer); 368 369 out.close(); 370 fw.close(); 371 } catch(IOException e) { 372 Main.panic("IO error: "+e.getMessage()); 373 return 1; 374 } 375 376 return 0; 377 } 378 379 /** 380 * Generates index.html and other top-level frame files. 381 * @param Mappings 382 * @return 0 if no errors, or 1 if error occurred. 383 */ 384 int generateSrc(Mappings map) { 385 try { 386 int len; 387 Object o[]; 388 String outputDir = Main.getOutputDir(); 389 FileWriter fw1, fw2; 390 BufferedWriter out1, out2; 391 392 /* Whether alias list exists or not. */ 393 Map<String,String> a = map.getAliases(); 394 if (a == null) { 395 Main.panic("Data not exist. (aliases)"); 396 return 1; 397 } 398 399 timezoneList.putAll(a); 400 401 /* If outputDir doesn't end with file-separator, adds it. */ 402 if (!outputDir.endsWith(File.separator)) { 403 outputDir += File.separatorChar; 404 } 405 outputDir += docDir + File.separatorChar; 406 407 File outD = new File(outputDir); 408 outD.mkdirs(); 409 410 /* Creates index.html */ 411 fw1 = new FileWriter(outputDir + "index.html", false); 412 out1 = new BufferedWriter(fw1); 413 414 out1.write(header1 + new Date() + header2 + Main.getVersionName() + 415 header4 + 416 "<FRAMESET cols=\"20%,80%\">\n" + 417 "<FRAMESET rows=\"30%,70%\">\n" + 418 "<FRAME src=\"overview-frame.html\" name=\"TimeZoneListFrame\">\n" + 419 "<FRAME src=\"allTimeZone-frame1.html\" name=\"allTimeZoneFrame\">\n" + 420 "</FRAMESET>" + 421 "<FRAME src=\"overview-summary.html\" name=\"rightFrame\">\n" + 422 "</FRAMESET>\n" + 423 "<NOFRAMES>\n" + 424 "<H2>\nFrame Alert\n</H2>\n\n" + 425 "<P>\n\n" + 426 "This document is designed to be viewed using the frames feature. If you see this\n" + 427 "message, you are using a non-frame-capable web client.\n" + 428 "<BR>\n" + 429 "Link to<A HREF=\"overview-summary.html\">Non-frame version.</A>\n" + 430 "</NOFRAMES>\n" + footer); 431 432 out1.close(); 433 fw1.close(); 434 435 436 /* Creates overview-frame.html */ 437 fw1 = new FileWriter(outputDir + "overview-frame.html", false); 438 out1 = new BufferedWriter(fw1); 439 440 out1.write(header1 + new Date() + header2 + Main.getVersionName() + 441 header4 + body1 + 442 "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n<TR>\n" + 443 "<TD NOWRAP><FONT size=\"+1\">\n" + 444 "<B>Java<sup><font size=-2>TM</font></sup> Platform<br>Standard Ed.</B></FONT></TD>\n" + 445 "</TR>\n</TABLE>\n\n" + 446 "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n<TR>\n<TD NOWRAP>" + 447 "<P>\n<FONT size=\"+1\">\nAll Time Zones Sorted By:</FONT>\n<BR>\n" + 448 " <A HREF=\"allTimeZone-frame1.html\" TARGET=\"allTimeZoneFrame\">GMT offsets</A></FONT>\n<BR>\n" + 449 " <A HREF=\"allTimeZone-frame2.html\" TARGET=\"allTimeZoneFrame\">Zone names</A></FONT>\n<BR>" + 450 " <A HREF=\"allTimeZone-frame3.html\" TARGET=\"allTimeZoneFrame\">City names</A></FONT>\n" + 451 "<P>\n<FONT size=\"+1\">\nContinents and Oceans</FONT>\n<BR>\n"); 452 453 for (String regionKey : regionList.keySet()) { 454 out1.write(" <A HREF=\"" + regionList.get(regionKey) + 455 "\" TARGET=\"allTimeZoneFrame\">" + regionKey + 456 "</A><BR>\n"); 457 458 fw2 = new FileWriter(outputDir + regionList.get(regionKey), 459 false); 460 out2 = new BufferedWriter(fw2); 461 462 out2.write(header1 + new Date() + header3 + regionKey + 463 header4 + body1 + "<FONT size=\"+1\"><B>" + 464 regionKey + "</B></FONT>\n<BR>\n<TABLE>\n<TR>\n<TD>"); 465 466 boolean found = false; 467 for (String timezoneKey : timezoneList.keySet()) { 468 int regionIndex = timezoneKey.indexOf('/'); 469 if (regionIndex == -1 || 470 !regionKey.equals(timezoneKey.substring(0, regionIndex))) { 471 if (found) { 472 break; 473 } else { 474 continue; 475 } 476 } 477 478 found = true; 479 if (a.containsKey(timezoneKey)) { 480 Object realName = a.get(timezoneKey); 481 while (a.containsKey(realName)) { 482 realName = a.get(realName); 483 } 484 out2.write(timezoneKey + 485 " (alias for " + "<A HREF=\"" + 486 timezoneList.get(realName) + 487 "\" TARGET=\"rightFrame\">" + 488 realName + "</A>)"); 489 } else { 490 out2.write("<A HREF=\"" + timezoneList.get(timezoneKey) + 491 "\" TARGET=\"rightFrame\">" + timezoneKey + 492 "</A>"); 493 } 494 out2.write("<BR>\n"); 495 } 496 out2.write("</TD>\n</TR>\n</TABLE>\n" + body2 + footer); 497 498 out2.close(); 499 fw2.close(); 500 } 501 out1.write("</FONT></TD>\n</TR></TABLE>\n" + body2 + footer); 502 503 out1.close(); 504 fw1.close(); 505 506 507 /* Creates allTimeZone-frame1.html (Sorted by GMT offsets) */ 508 fw1 = new FileWriter(outputDir + "allTimeZone-frame1.html", false); 509 out1 = new BufferedWriter(fw1); 510 511 out1.write(header1 + new Date() + header2 + Main.getVersionName() + 512 header4 + body1 + 513 "<FONT size=\"+1\"><B>Sorted by GMT offsets</B></FONT>\n" + 514 "<BR>\n\n" + "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n" + 515 "<TR>\n<TD NOWRAP>\n"); 516 517 List<Integer> roi = map.getRawOffsetsIndex(); 518 List<Set<String>> roit = map.getRawOffsetsIndexTable(); 519 520 int index = 0; 521 for (Integer offset : zonesByOffset.keySet()) { 522 int off = roi.get(index); 523 Set<String> perRO = zonesByOffset.get(offset); 524 if (offset == off) { 525 // Merge aliases into zonesByOffset 526 perRO.addAll(roit.get(index)); 527 } 528 index++; 529 530 for (String timezoneKey : perRO) { 531 out1.write("<TR>\n<TD><FONT SIZE=\"-1\">(" + 532 Time.toGMTFormat(offset.toString()) + 533 ")</FONT></TD>\n<TD>"); 534 535 if (a.containsKey(timezoneKey)) { 536 Object realName = a.get(timezoneKey); 537 while (a.containsKey(realName)) { 538 realName = a.get(realName); 539 } 540 out1.write(timezoneKey + 541 " (alias for " + "<A HREF=\"" + 542 timezoneList.get(realName) + 543 "\" TARGET=\"rightFrame\">" + realName + 544 "</A>)"); 545 } else { 546 out1.write("<A HREF=\"" + timezoneList.get(timezoneKey) + 547 "\" TARGET=\"rightFrame\">" + timezoneKey + 548 "</A>"); 549 } 550 out1.write("</TD>\n</TR>\n"); 551 } 552 } 553 out1.write("</FONT></TD>\n</TR>\n</TABLE>\n" + body2 + footer); 554 555 out1.close(); 556 fw1.close(); 557 558 559 /* Creates allTimeZone-frame2.html (Sorted by zone names) */ 560 fw1 = new FileWriter(outputDir + "allTimeZone-frame2.html", false); 561 out1 = new BufferedWriter(fw1); 562 563 out1.write(header1 + new Date() + header2 + Main.getVersionName() + 564 header4 + body1 + 565 "<FONT size=\"+1\"><B>Sorted by zone names</B></FONT>\n" + 566 "<BR>\n\n" + "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n" + 567 "<TR>\n<TD NOWRAP>\n"); 568 o = timezoneList.keySet().toArray(); 569 len = timezoneList.size(); 570 for (int i = 0; i < len; i++) { 571 Object timezoneKey = o[i]; 572 if (a.containsKey(timezoneKey)) { 573 Object realName = a.get(timezoneKey); 574 while (a.containsKey(realName)) { 575 realName = a.get(realName); 576 } 577 out1.write(timezoneKey + 578 " (alias for " + 579 "<A HREF=\"" + timezoneList.get(realName) + 580 "\" TARGET=\"rightFrame\">" + realName + 581 "</A>)"); 582 } else { 583 out1.write("<A HREF=\"" + timezoneList.get(timezoneKey) + 584 "\" TARGET=\"rightFrame\">" + timezoneKey + 585 "</A>"); 586 } 587 out1.write("<BR> \n"); 588 } 589 out1.write("</FONT></TD>\n</TR>\n</TABLE>\n" + body2 + footer); 590 591 out1.close(); 592 fw1.close(); 593 594 /* Creates allTimeZone-frame3.html (Sorted by city names) */ 595 fw1 = new FileWriter(outputDir + "allTimeZone-frame3.html", false); 596 out1 = new BufferedWriter(fw1); 597 598 out1.write(header1 + new Date() + header2 + Main.getVersionName() + 599 header4 + body1 + 600 "<FONT size=\"+1\"><B>Sorted by city names</B></FONT>\n" + 601 "<BR>\n\n" + "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n" + 602 "<TR>\n<TD NOWRAP>\n"); 603 604 Set<String> aliasSet = a.keySet(); 605 len = aliasSet.size(); 606 String aliasNames[] = aliasSet.toArray(new String[0]); 607 for (int i = 0; i < len; i++) { 608 displayNameList.put(transform(aliasNames[i]), 609 aliasNames[i]); 610 } 611 612 o = displayNameList.keySet().toArray(); 613 len = displayNameList.size(); 614 for (int i = 0; i < len; i++) { 615 Object displayName = o[i]; 616 Object timezoneKey = displayNameList.get(o[i]); 617 if (a.containsKey(timezoneKey)) { 618 Object realName = a.get(timezoneKey); 619 while (a.containsKey(realName)) { 620 realName = a.get(realName); 621 } 622 out1.write(displayName + 623 " (alias for " + 624 "<A HREF=\"" + timezoneList.get(realName) + 625 "\" TARGET=\"rightFrame\">" + realName + 626 "</A>)"); 627 } else { 628 out1.write("<A HREF=\"" + timezoneList.get(timezoneKey) + 629 "\" TARGET=\"rightFrame\">" + displayName + 630 "</A>"); 631 } 632 out1.write("<BR> \n"); 633 } 634 635 out1.write("</FONT></TD>\n</TR>\n</TABLE>\n" + body2 + footer); 636 637 out1.close(); 638 fw1.close(); 639 640 /* Creates overview-summary.html */ 641 fw1 = new FileWriter(outputDir + "overview-summary.html", false); 642 out1 = new BufferedWriter(fw1); 643 644 out1.write(header1 + new Date() + header2 + Main.getVersionName() + 645 header4 + body1 + 646 "<p>This is the list of time zones generated from <B>" + 647 Main.getVersionName() + "</B> for Java Platform, " + 648 "Standard Edition. The source code can be obtained " + 649 "from ftp site <a href=\"ftp://elsie.nci.nih.gov/pub/\">" + 650 "ftp://elsie.nci.nih.gov/pub/</a>. A total of <B>" + 651 len + 652 "</B> time zones and aliases are supported " + 653 "in this edition. For the " + 654 "format of rules and zones, refer to the zic " + 655 "(zoneinfo compiler) man page on " + 656 "Solaris or Linux.</p>\n" + 657 "<p>Note that the time zone data is not " + 658 "a public interface of the Java Platform. No " + 659 "applications should rely on the time zone data of " + 660 "this document. Time zone names and data " + 661 "may change without any prior notice.</p>\n" + 662 body2 + footer); 663 664 out1.close(); 665 fw1.close(); 666 } catch(IOException e) { 667 Main.panic("IO error: "+e.getMessage()); 668 return 1; 669 } 670 671 return 0; 672 } 673 674 String transform(String s) { 675 int index = s.lastIndexOf("/"); 676 677 /* If the string doesn't include any delimiter, return */ 678 if (index == -1) { 679 return s; 680 } 681 682 int lastIndex = index; 683 String str = s.substring(index+1); 684 do { 685 index = s.substring(0, lastIndex).lastIndexOf('/'); 686 str += ", " + s.substring(index+1, lastIndex); 687 lastIndex = index; 688 } while (index > -1); 689 690 return str; 691 } 692 693 static class LatitudeAndLongitude { 694 695 private int latDeg, latMin, latSec, longDeg, longMin, longSec; 696 697 LatitudeAndLongitude(String s) { 698 try { 699 // First of all, check the string has the correct format: 700 // either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS 701 702 if (!s.startsWith("+") && !s.startsWith("-")) { 703 Main.warning("Wrong latitude&longitude data: " + s); 704 return; 705 } 706 int index; 707 if (((index = s.lastIndexOf("+")) <= 0) && 708 ((index = s.lastIndexOf("-")) <= 0)) { 709 Main.warning("Wrong latitude&longitude data: " + s); 710 return; 711 } 712 713 if (index == 5) { 714 latDeg = Integer.parseInt(s.substring(1, 3)); 715 latMin = Integer.parseInt(s.substring(3, 5)); 716 latSec = 0; 717 } else if (index == 7) { 718 latDeg = Integer.parseInt(s.substring(1, 3)); 719 latMin = Integer.parseInt(s.substring(3, 5)); 720 latSec = Integer.parseInt(s.substring(5, 7)); 721 } else { 722 Main.warning("Wrong latitude&longitude data: " + s); 723 return; 724 } 725 if (s.startsWith("-")){ 726 latDeg = -latDeg; 727 latMin = -latMin; 728 latSec = -latSec; 729 } 730 731 int len = s.length(); 732 if (index == 5 && len == 11) { 733 longDeg = Integer.parseInt(s.substring(index+1, index+4)); 734 longMin = Integer.parseInt(s.substring(index+4, index+6)); 735 longSec = 0; 736 } else if (index == 7 && len == 15) { 737 longDeg = Integer.parseInt(s.substring(index+1, index+4)); 738 longMin = Integer.parseInt(s.substring(index+4, index+6)); 739 longSec = Integer.parseInt(s.substring(index+6, index+8)); 740 } else { 741 Main.warning("Wrong latitude&longitude data: " + s); 742 return; 743 } 744 if (s.charAt(index) == '-'){ 745 longDeg = -longDeg; 746 longMin = -longMin; 747 longSec = -longSec; 748 } 749 } catch(Exception e) { 750 Main.warning("LatitudeAndLongitude() Parse error: " + s); 751 } 752 } 753 754 int getLatDeg() { 755 return latDeg; 756 } 757 758 int getLatMin() { 759 return latMin; 760 } 761 762 int getLatSec() { 763 return latSec; 764 } 765 766 int getLongDeg() { 767 return longDeg; 768 } 769 770 int getLongMin() { 771 return longMin; 772 } 773 774 int getLongSec() { 775 return longSec; 776 } 777 } 778 }