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