Showing the changes to java/pkg/sun/util/calendar/ZoneInfoFile.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,1071 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2010, 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 | package sun.util.calendar; | ||
| 27 | |||
| 28 | import java.io.File; | ||
| 29 | import java.io.FileInputStream; | ||
| 30 | import java.io.FileNotFoundException; | ||
| 31 | import java.io.IOException; | ||
| 32 | import java.lang.ref.SoftReference; | ||
| 33 | import java.nio.file.FileSystems; | ||
| 34 | import java.security.AccessController; | ||
| 35 | import java.security.PrivilegedAction; | ||
| 36 | import java.security.PrivilegedActionException; | ||
| 37 | import java.security.PrivilegedExceptionAction; | ||
| 38 | import java.util.ArrayList; | ||
| 39 | import java.util.HashMap; | ||
| 40 | import java.util.List; | ||
| 41 | import java.util.Map; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * <code>ZoneInfoFile</code> reads Zone information files in the | ||
| 45 | * <java.home>/lib/zi directory and provides time zone | ||
| 46 | * information in the form of a {@link ZoneInfo} object. Also, it | ||
| 47 | * reads the ZoneInfoMappings file to obtain time zone IDs information | ||
| 48 | * that is used by the {@link ZoneInfo} class. The directory layout | ||
| 49 | * and data file formats are as follows. | ||
| 50 | * | ||
| 51 | * <p><strong>Directory layout</strong><p> | ||
| 52 | * | ||
| 53 | * All zone data files and ZoneInfoMappings are put under the | ||
| 54 | * <java.home>/lib/zi directory. A path name for a given time | ||
| 55 | * zone ID is a concatenation of <java.home>/lib/zi/ and the | ||
| 56 | * time zone ID. (The file separator is replaced with the platform | ||
| 57 | * dependent value. e.g., '\' for Win32.) An example layout will look | ||
| 58 | * like as follows. | ||
| 59 | * <blockquote> | ||
| 60 | * <pre> | ||
| 61 | * <java.home>/lib/zi/Africa/Addis_Ababa | ||
| 62 | * /Africa/Dakar | ||
| 63 | * /America/Los_Angeles | ||
| 64 | * /Asia/Singapore | ||
| 65 | * /EET | ||
| 66 | * /Europe/Oslo | ||
| 67 | * /GMT | ||
| 68 | * /Pacific/Galapagos | ||
| 69 | * ... | ||
| 70 | * /ZoneInfoMappings | ||
| 71 | * </pre> | ||
| 72 | * </blockquote> | ||
| 73 | * | ||
| 74 | * A zone data file has specific information of each zone. | ||
| 75 | * <code>ZoneInfoMappings</code> has global information of zone IDs so | ||
| 76 | * that the information can be obtained without instantiating all time | ||
| 77 | * zones. | ||
| 78 | * | ||
| 79 | * <p><strong>File format</strong><p> | ||
| 80 | * | ||
| 81 | * Two binary-file formats based on a simple Tag-Length-Value format are used | ||
| 82 | * to describe TimeZone information. The generic format of a data file is: | ||
| 83 | * <blockquote> | ||
| 84 | * <pre> | ||
| 85 | * DataFile { | ||
| 86 | * u1 magic[7]; | ||
| 87 | * u1 version; | ||
| 88 | * data_item data[]; | ||
| 89 | * } | ||
| 90 | * </pre> | ||
| 91 | * </blockquote> | ||
| 92 | * where <code>magic</code> is a magic number identifying a file | ||
| 93 | * format, <code>version</code> is the format version number, and | ||
| 94 | * <code>data</code> is one or more <code>data_item</code>s. The | ||
| 95 | * <code>data_item</code> structure is: | ||
| 96 | * <blockquote> | ||
| 97 | * <pre> | ||
| 98 | * data_item { | ||
| 99 | * u1 tag; | ||
| 100 | * u2 length; | ||
| 101 | * u1 value[length]; | ||
| 102 | * } | ||
| 103 | * </pre> | ||
| 104 | * </blockquote> | ||
| 105 | * where <code>tag</code> indicates the data type of the item, | ||
| 106 | * <code>length</code> is a byte count of the following | ||
| 107 | * <code>value</code> that is the content of item data. | ||
| 108 | * <p> | ||
| 109 | * All data is stored in the big-endian order. There is no boundary | ||
| 110 | * alignment between date items. | ||
| 111 | * | ||
| 112 | * <p><strong>1. ZoneInfo data file</strong><p> | ||
| 113 | * | ||
| 114 | * Each ZoneInfo data file consists of the following members. | ||
| 115 | * <br> | ||
| 116 | * <blockquote> | ||
| 117 | * <pre> | ||
| 118 | * ZoneInfoDataFile { | ||
| 119 | * u1 magic[7]; | ||
| 120 | * u1 version; | ||
| 121 | * SET OF<sup>1</sup> { | ||
| 122 | * transition transitions<sup>2</sup>; | ||
| 123 | * offset_table offsets<sup>2</sup>; | ||
| 124 | * simpletimezone stzparams<sup>2</sup>; | ||
| 125 | * raw_offset rawoffset; | ||
| 126 | * dstsaving dst; | ||
| 127 | * checksum crc32; | ||
| 128 | * gmtoffsetwillchange gmtflag<sup>2</sup>; | ||
| 129 | * } | ||
| 130 | * } | ||
| 131 | * 1: an unordered collection of zero or one occurrences of each item | ||
| 132 | * 2: optional item | ||
| 133 | * </pre> | ||
| 134 | * </blockquote> | ||
| 135 | * <code>magic</code> is a byte-string constant identifying the | ||
| 136 | * ZoneInfo data file. This field must be <code>"javazi\0"</code> | ||
| 137 | * defined as {@link #JAVAZI_LABEL}. | ||
| 138 | * <p> | ||
| 139 | * <code>version</code> is the version number of the file format. This | ||
| 140 | * will be used for compatibility check. This field must be | ||
| 141 | * <code>0x01</code> in this version. | ||
| 142 | * <p> | ||
| 143 | * <code>transition</code>, <code>offset_table</code> and | ||
| 144 | * <code>simpletimezone</code> have information of time transition | ||
| 145 | * from the past to the future. Therefore, these structures don't | ||
| 146 | * exist if the zone didn't change zone names and haven't applied DST in | ||
| 147 | * the past, and haven't planned to apply it. (e.g. Asia/Tokyo zone) | ||
| 148 | * <p> | ||
| 149 | * <code>raw_offset</code>, <code>dstsaving</code> and <code>checksum</code> | ||
| 150 | * exist in every zoneinfo file. They are used by TimeZone.class indirectly. | ||
| 151 | * | ||
| 152 | * <p><strong>1.1 <code>transition</code> structure</strong><p><a name="transition"></a> | ||
| 153 | * <blockquote> | ||
| 154 | * <pre> | ||
| 155 | * transition { | ||
| 156 | * u1 tag; // 0x04 : constant | ||
| 157 | * u2 length; // byte length of whole values | ||
| 158 | * s8 value[length/8]; // transitions in `long' | ||
| 159 | * } | ||
| 160 | * </pre> | ||
| 161 | * </blockquote> | ||
| 162 | * See {@link ZoneInfo#transitions ZoneInfo.transitions} about the value. | ||
| 163 | * | ||
| 164 | * <p><strong>1.2 <code>offset_table</code> structure</strong><p> | ||
| 165 | * <blockquote> | ||
| 166 | * <pre> | ||
| 167 | * offset_table { | ||
| 168 | * u1 tag; // 0x05 : constant | ||
| 169 | * u2 length; // byte length of whole values | ||
| 170 | * s4 value[length/4]; // offset values in `int' | ||
| 171 | * } | ||
| 172 | * </pre> | ||
| 173 | * </blockquote> | ||
| 174 | * | ||
| 175 | * <p><strong>1.3 <code>simpletimezone</code> structure</strong><p> | ||
| 176 | * See {@link ZoneInfo#simpleTimeZoneParams ZoneInfo.simpleTimeZoneParams} | ||
| 177 | * about the value. | ||
| 178 | * <blockquote> | ||
| 179 | * <pre> | ||
| 180 | * simpletimezone { | ||
| 181 | * u1 tag; // 0x06 : constant | ||
| 182 | * u2 length; // byte length of whole values | ||
| 183 | * s4 value[length/4]; // SimpleTimeZone parameters | ||
| 184 | * } | ||
| 185 | * </pre> | ||
| 186 | * </blockquote> | ||
| 187 | * See {@link ZoneInfo#offsets ZoneInfo.offsets} about the value. | ||
| 188 | * | ||
| 189 | * <p><strong>1.4 <code>raw_offset</code> structure</strong><p> | ||
| 190 | * <blockquote> | ||
| 191 | * <pre> | ||
| 192 | * raw_offset { | ||
| 193 | * u1 tag; // 0x01 : constant | ||
| 194 | * u2 length; // must be 4. | ||
| 195 | * s4 value; // raw GMT offset [millisecond] | ||
| 196 | * } | ||
| 197 | * </pre> | ||
| 198 | * </blockquote> | ||
| 199 | * See {@link ZoneInfo#rawOffset ZoneInfo.rawOffset} about the value. | ||
| 200 | * | ||
| 201 | * <p><strong>1.5 <code>dstsaving</code> structure</strong><p> | ||
| 202 | * Value has dstSaving in seconds. | ||
| 203 | * <blockquote> | ||
| 204 | * <pre> | ||
| 205 | * dstsaving { | ||
| 206 | * u1 tag; // 0x02 : constant | ||
| 207 | * u2 length; // must be 2. | ||
| 208 | * s2 value; // DST save value [second] | ||
| 209 | * } | ||
| 210 | * </pre> | ||
| 211 | * </blockquote> | ||
| 212 | * See {@link ZoneInfo#dstSavings ZoneInfo.dstSavings} about value. | ||
| 213 | * | ||
| 214 | * <p><strong>1.6 <code>checksum</code> structure</strong><p> | ||
| 215 | * <blockquote> | ||
| 216 | * <pre> | ||
| 217 | * checksum { | ||
| 218 | * u1 tag; // 0x03 : constant | ||
| 219 | * u2 length; // must be 4. | ||
| 220 | * s4 value; // CRC32 value of transitions | ||
| 221 | * } | ||
| 222 | * </pre> | ||
| 223 | * </blockquote> | ||
| 224 | * See {@link ZoneInfo#checksum ZoneInfo.checksum}. | ||
| 225 | * | ||
| 226 | * <p><strong>1.7 <code>gmtoffsetwillchange</code> structure</strong><p> | ||
| 227 | * This record has a flag value for {@link ZoneInfo#rawOffsetWillChange}. | ||
| 228 | * If this record is not present in a zoneinfo file, 0 is assumed for | ||
| 229 | * the value. | ||
| 230 | * <blockquote> | ||
| 231 | * <pre> | ||
| 232 | * gmtoffsetwillchange { | ||
| 233 | * u1 tag; // 0x07 : constant | ||
| 234 | * u2 length; // must be 1. | ||
| 235 | * u1 value; // 1: if the GMT raw offset will change | ||
| 236 | * // in the future, 0, otherwise. | ||
| 237 | * } | ||
| 238 | * </pre> | ||
| 239 | * </blockquote> | ||
| 240 | * | ||
| 241 | * | ||
| 242 | * <p><strong>2. ZoneInfoMappings file</strong><p> | ||
| 243 | * | ||
| 244 | * The ZoneInfoMappings file consists of the following members. | ||
| 245 | * <br> | ||
| 246 | * <blockquote> | ||
| 247 | * <pre> | ||
| 248 | * ZoneInfoMappings { | ||
| 249 | * u1 magic[7]; | ||
| 250 | * u1 version; | ||
| 251 | * SET OF { | ||
| 252 | * versionName version; | ||
| 253 | * zone_id_table zoneIDs; | ||
| 254 | * raw_offset_table rawoffsets; | ||
| 255 | * raw_offset_index_table rawoffsetindices; | ||
| 256 | * alias_table aliases; | ||
| 257 | * excluded_list excludedList; | ||
| 258 | * } | ||
| 259 | * } | ||
| 260 | * </pre> | ||
| 261 | * </blockquote> | ||
| 262 | * | ||
| 263 | * <code>magic</code> is a byte-string constant which has the file type. | ||
| 264 | * This field must be <code>"javazm\0"</code> defined as {@link #JAVAZM_LABEL}. | ||
| 265 | * <p> | ||
| 266 | * <code>version</code> is the version number of this file | ||
| 267 | * format. This will be used for compatibility check. This field must | ||
| 268 | * be <code>0x01</code> in this version. | ||
| 269 | * <p> | ||
| 270 | * <code>versionName</code> shows which version of Olson's data has been used | ||
| 271 | * to generate this ZoneInfoMappings. (e.g. <code>tzdata2000g</code>) <br> | ||
| 272 | * This field is for trouble-shooting and isn't usually used in runtime. | ||
| 273 | * <p> | ||
| 274 | * <code>zone_id_table</code>, <code>raw_offset_index_table</code> and | ||
| 275 | * <code>alias_table</code> are general information of supported | ||
| 276 | * zones. | ||
| 277 | * | ||
| 278 | * <p><strong>2.1 <code>zone_id_table</code> structure</strong><p> | ||
| 279 | * The list of zone IDs included in the zi database. The list does | ||
| 280 | * <em>not</em> include zone IDs, if any, listed in excludedList. | ||
| 281 | * <br> | ||
| 282 | * <blockquote> | ||
| 283 | * <pre> | ||
| 284 | * zone_id_table { | ||
| 285 | * u1 tag; // 0x40 : constant | ||
| 286 | * u2 length; // byte length of whole values | ||
| 287 | * u2 zone_id_count; | ||
| 288 | * zone_id value[zone_id_count]; | ||
| 289 | * } | ||
| 290 | * | ||
| 291 | * zone_id { | ||
| 292 | * u1 byte_length; // byte length of id | ||
| 293 | * u1 id[byte_length]; // zone name string | ||
| 294 | * } | ||
| 295 | * </pre> | ||
| 296 | * </blockquote> | ||
| 297 | * | ||
| 298 | * <p><strong>2.2 <code>raw_offset_table</code> structure</strong><p> | ||
| 299 | * <br> | ||
| 300 | * <blockquote> | ||
| 301 | * <pre> | ||
| 302 | * raw_offset_table { | ||
| 303 | * u1 tag; // 0x41 : constant | ||
| 304 | * u2 length; // byte length of whole values | ||
| 305 | * s4 value[length/4]; // raw GMT offset in milliseconds | ||
| 306 | * } | ||
| 307 | * </pre> | ||
| 308 | * </blockquote> | ||
| 309 | * | ||
| 310 | * <p><strong>2.3 <code>raw_offset_index_table</code> structure</strong><p> | ||
| 311 | * <br> | ||
| 312 | * <blockquote> | ||
| 313 | * <pre> | ||
| 314 | * raw_offset_index_table { | ||
| 315 | * u1 tag; // 0x42 : constant | ||
| 316 | * u2 length; // byte length of whole values | ||
| 317 | * u1 value[length]; | ||
| 318 | * } | ||
| 319 | * </pre> | ||
| 320 | * </blockquote> | ||
| 321 | * | ||
| 322 | * <p><strong>2.4 <code>alias_table</code> structure</strong><p> | ||
| 323 | * <br> | ||
| 324 | * <blockquote> | ||
| 325 | * <pre> | ||
| 326 | * alias_table { | ||
| 327 | * u1 tag; // 0x43 : constant | ||
| 328 | * u2 length; // byte length of whole values | ||
| 329 | * u2 nentries; // number of id-pairs | ||
| 330 | * id_pair value[nentries]; | ||
| 331 | * } | ||
| 332 | * | ||
| 333 | * id_pair { | ||
| 334 | * zone_id aliasname; | ||
| 335 | * zone_id ID; | ||
| 336 | * } | ||
| 337 | * </pre> | ||
| 338 | * </blockquote> | ||
| 339 | * | ||
| 340 | * <p><strong>2.5 <code>versionName</code> structure</strong><p> | ||
| 341 | * <br> | ||
| 342 | * <blockquote> | ||
| 343 | * <pre> | ||
| 344 | * versionName { | ||
| 345 | * u1 tag; // 0x44 : constant | ||
| 346 | * u2 length; // byte length of whole values | ||
| 347 | * u1 value[length]; | ||
| 348 | * } | ||
| 349 | * </pre> | ||
| 350 | * </blockquote> | ||
| 351 | * | ||
| 352 | * <p><strong>2.6 <code>excludeList</code> structure</strong><p> | ||
| 353 | * The list of zone IDs whose zones will change their GMT offsets | ||
| 354 | * (a.k.a. raw offsets) some time in the future. Those IDs must be | ||
| 355 | * added to the list of zone IDs for getAvailableIDs(). Also they must | ||
| 356 | * be examined for getAvailableIDs(int) to determine the | ||
| 357 | * <em>current</em> GMT offsets. | ||
| 358 | * <br> | ||
| 359 | * <blockquote> | ||
| 360 | * <pre> | ||
| 361 | * excluded_list { | ||
| 362 | * u1 tag; // 0x45 : constant | ||
| 363 | * u2 length; // byte length of whole values | ||
| 364 | * u2 nentries; // number of zone_ids | ||
| 365 | * zone_id value[nentries]; // excluded zone IDs | ||
| 366 | * } | ||
| 367 | * </pre> | ||
| 368 | * </blockquote> | ||
| 369 | * | ||
| 370 | * @since 1.4 | ||
| 371 | */ | ||
| 372 | |||
| 373 | public class ZoneInfoFile { | ||
| 374 | |||
| 375 | /** | ||
| 376 | * The magic number for the ZoneInfo data file format. | ||
| 377 | */ | ||
| 378 | public static final byte[] JAVAZI_LABEL = { | ||
| 379 | (byte)'j', (byte)'a', (byte)'v', (byte)'a', (byte)'z', (byte)'i', (byte)'\0' | ||
| 380 | }; | ||
| 381 | private static final int JAVAZI_LABEL_LENGTH = JAVAZI_LABEL.length; | ||
| 382 | |||
| 383 | /** | ||
| 384 | * The ZoneInfo data file format version number. Must increase | ||
| 385 | * one when any incompatible change has been made. | ||
| 386 | */ | ||
| 387 | public static final byte JAVAZI_VERSION = 0x01; | ||
| 388 | |||
| 389 | /** | ||
| 390 | * Raw offset data item tag. | ||
| 391 | */ | ||
| 392 | public static final byte TAG_RawOffset = 1; | ||
| 393 | |||
| 394 | /** | ||
| 395 | * Known last Daylight Saving Time save value data item tag. | ||
| 396 | */ | ||
| 397 | public static final byte TAG_LastDSTSaving = 2; | ||
| 398 | |||
| 399 | /** | ||
| 400 | * Checksum data item tag. | ||
| 401 | */ | ||
| 402 | public static final byte TAG_CRC32 = 3; | ||
| 403 | |||
| 404 | /** | ||
| 405 | * Transition data item tag. | ||
| 406 | */ | ||
| 407 | public static final byte TAG_Transition = 4; | ||
| 408 | |||
| 409 | /** | ||
| 410 | * Offset table data item tag. | ||
| 411 | */ | ||
| 412 | public static final byte TAG_Offset = 5; | ||
| 413 | |||
| 414 | /** | ||
| 415 | * SimpleTimeZone parameters data item tag. | ||
| 416 | */ | ||
| 417 | public static final byte TAG_SimpleTimeZone = 6; | ||
| 418 | |||
| 419 | /** | ||
| 420 | * Raw GMT offset will change in the future. | ||
| 421 | */ | ||
| 422 | public static final byte TAG_GMTOffsetWillChange = 7; | ||
| 423 | |||
| 424 | |||
| 425 | /** | ||
| 426 | * The ZoneInfoMappings file name. | ||
| 427 | */ | ||
| 428 | public static final String JAVAZM_FILE_NAME = "ZoneInfoMappings"; | ||
| 429 | |||
| 430 | /** | ||
| 431 | * The magic number for the ZoneInfoMappings file format. | ||
| 432 | */ | ||
| 433 | public static final byte[] JAVAZM_LABEL = { | ||
| 434 | (byte)'j', (byte)'a', (byte)'v', (byte)'a', (byte)'z', (byte)'m', (byte)'\0' | ||
| 435 | }; | ||
| 436 | private static final int JAVAZM_LABEL_LENGTH = JAVAZM_LABEL.length; | ||
| 437 | |||
| 438 | /** | ||
| 439 | * The ZoneInfoMappings file format version number. Must increase | ||
| 440 | * one when any incompatible change has been made. | ||
| 441 | */ | ||
| 442 | public static final byte JAVAZM_VERSION = 0x01; | ||
| 443 | |||
| 444 | /** | ||
| 445 | * Time zone IDs data item tag. | ||
| 446 | */ | ||
| 447 | public static final byte TAG_ZoneIDs = 64; | ||
| 448 | |||
| 449 | /** | ||
| 450 | * Raw GMT offsets table data item tag. | ||
| 451 | */ | ||
| 452 | public static final byte TAG_RawOffsets = 65; | ||
| 453 | |||
| 454 | /** | ||
| 455 | * Indices to the raw GMT offset table data item tag. | ||
| 456 | */ | ||
| 457 | public static final byte TAG_RawOffsetIndices = 66; | ||
| 458 | |||
| 459 | /** | ||
| 460 | * Time zone aliases table data item tag. | ||
| 461 | */ | ||
| 462 | public static final byte TAG_ZoneAliases = 67; | ||
| 463 | |||
| 464 | /** | ||
| 465 | * Olson's public zone information version tag. | ||
| 466 | */ | ||
| 467 | public static final byte TAG_TZDataVersion = 68; | ||
| 468 | |||
| 469 | /** | ||
| 470 | * Excluded zones item tag. (Added in Mustang) | ||
| 471 | */ | ||
| 472 | public static final byte TAG_ExcludedZones = 69; | ||
| 473 | |||
| 474 | private static Map<String, ZoneInfo> zoneInfoObjects = null; | ||
| 475 | |||
| 476 | private static final String ziDir = AccessController.doPrivileged( | ||
| 477 | new PrivilegedAction<String>() { | ||
| 478 | public String run() { | ||
| 479 | String zi = System.getProperty("java.home") + | ||
| 480 | File.separator + "lib" + File.separator + "zi"; | ||
| 481 | try { | ||
| 482 | zi = FileSystems.getDefault().getPath(zi).toRealPath().toString(); | ||
| 483 | } catch(Exception e) { | ||
| 484 | } | ||
| 485 | return zi; | ||
| 486 | } | ||
| 487 | }); | ||
| 488 | |||
| 489 | /** | ||
| 490 | * Converts the given time zone ID to a platform dependent path | ||
| 491 | * name. For example, "America/Los_Angeles" is converted to | ||
| 492 | * "America\Los_Angeles" on Win32. | ||
| 493 | * @return a modified ID replacing '/' with {@link | ||
| 494 | * java.io.File#separatorChar File.separatorChar} if needed. | ||
| 495 | */ | ||
| 496 | public static String getFileName(String ID) { | ||
| 497 | if (File.separatorChar == '/') { | ||
| 498 | return ID; | ||
| 499 | } | ||
| 500 | return ID.replace('/', File.separatorChar); | ||
| 501 | } | ||
| 502 | |||
| 503 | /** | ||
| 504 | * Gets a ZoneInfo with the given GMT offset. The object | ||
| 505 | * has its ID in the format of GMT{+|-}hh:mm. | ||
| 506 | * | ||
| 507 | * @param originalId the given custom id (before normalized such as "GMT+9") | ||
| 508 | * @param gmtOffset GMT offset <em>in milliseconds</em> | ||
| 509 | * @return a ZoneInfo constructed with the given GMT offset | ||
| 510 | */ | ||
| 511 | public static ZoneInfo getCustomTimeZone(String originalId, int gmtOffset) { | ||
| 512 | String id = toCustomID(gmtOffset); | ||
| 513 | |||
| 514 | ZoneInfo zi = getFromCache(id); | ||
| 515 | if (zi == null) { | ||
| 516 | zi = new ZoneInfo(id, gmtOffset); | ||
| 517 | zi = addToCache(id, zi); | ||
| 518 | if (!id.equals(originalId)) { | ||
| 519 | zi = addToCache(originalId, zi); | ||
| 520 | } | ||
| 521 | } | ||
| 522 | return (ZoneInfo) zi.clone(); | ||
| 523 | } | ||
| 524 | |||
| 525 | public static String toCustomID(int gmtOffset) { | ||
| 526 | char sign; | ||
| 527 | int offset = gmtOffset / 60000; | ||
| 528 | |||
| 529 | if (offset >= 0) { | ||
| 530 | sign = '+'; | ||
| 531 | } else { | ||
| 532 | sign = '-'; | ||
| 533 | offset = -offset; | ||
| 534 | } | ||
| 535 | int hh = offset / 60; | ||
| 536 | int mm = offset % 60; | ||
| 537 | |||
| 538 | char[] buf = new char[] { 'G', 'M', 'T', sign, '0', '0', ':', '0', '0' }; | ||
| 539 | if (hh >= 10) { | ||
| 540 | buf[4] += hh / 10; | ||
| 541 | } | ||
| 542 | buf[5] += hh % 10; | ||
| 543 | if (mm != 0) { | ||
| 544 | buf[7] += mm / 10; | ||
| 545 | buf[8] += mm % 10; | ||
| 546 | } | ||
| 547 | return new String(buf); | ||
| 548 | } | ||
| 549 | |||
| 550 | /** | ||
| 551 | * @return a ZoneInfo instance created for the specified id, or | ||
| 552 | * null if there is no time zone data file found for the specified | ||
| 553 | * id. | ||
| 554 | */ | ||
| 555 | public static ZoneInfo getZoneInfo(String id) { | ||
| 556 | ZoneInfo zi = getFromCache(id); | ||
| 557 | if (zi == null) { | ||
| 558 | zi = createZoneInfo(id); | ||
| 559 | if (zi == null) { | ||
| 560 | return null; | ||
| 561 | } | ||
| 562 | zi = addToCache(id, zi); | ||
| 563 | } | ||
| 564 | return (ZoneInfo) zi.clone(); | ||
| 565 | } | ||
| 566 | |||
| 567 | synchronized static ZoneInfo getFromCache(String id) { | ||
| 568 | if (zoneInfoObjects == null) { | ||
| 569 | return null; | ||
| 570 | } | ||
| 571 | return zoneInfoObjects.get(id); | ||
| 572 | } | ||
| 573 | |||
| 574 | synchronized static ZoneInfo addToCache(String id, ZoneInfo zi) { | ||
| 575 | if (zoneInfoObjects == null) { | ||
| 576 | zoneInfoObjects = new HashMap<String, ZoneInfo>(); | ||
| 577 | } else { | ||
| 578 | ZoneInfo zone = zoneInfoObjects.get(id); | ||
| 579 | if (zone != null) { | ||
| 580 | return zone; | ||
| 581 | } | ||
| 582 | } | ||
| 583 | zoneInfoObjects.put(id, zi); | ||
| 584 | return zi; | ||
| 585 | } | ||
| 586 | |||
| 587 | private static ZoneInfo createZoneInfo(String id) { | ||
| 588 | byte[] buf = readZoneInfoFile(getFileName(id)); | ||
| 589 | if (buf == null) { | ||
| 590 | return null; | ||
| 591 | } | ||
| 592 | |||
| 593 | int index = 0; | ||
| 594 | int filesize = buf.length; | ||
| 595 | int rawOffset = 0; | ||
| 596 | int dstSavings = 0; | ||
| 597 | int checksum = 0; | ||
| 598 | boolean willGMTOffsetChange = false; | ||
| 599 | long[] transitions = null; | ||
| 600 | int[] offsets = null; | ||
| 601 | int[] simpleTimeZoneParams = null; | ||
| 602 | |||
| 603 | try { | ||
| 604 | for (index = 0; index < JAVAZI_LABEL.length; index++) { | ||
| 605 | if (buf[index] != JAVAZI_LABEL[index]) { | ||
| 606 | System.err.println("ZoneInfo: wrong magic number: " + id); | ||
| 607 | return null; | ||
| 608 | } | ||
| 609 | } | ||
| 610 | if (buf[index++] > JAVAZI_VERSION) { | ||
| 611 | System.err.println("ZoneInfo: incompatible version (" | ||
| 612 | + buf[index - 1] + "): " + id); | ||
| 613 | return null; | ||
| 614 | } | ||
| 615 | |||
| 616 | while (index < filesize) { | ||
| 617 | byte tag = buf[index++]; | ||
| 618 | int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); | ||
| 619 | |||
| 620 | if (filesize < index+len) { | ||
| 621 | break; | ||
| 622 | } | ||
| 623 | |||
| 624 | switch (tag) { | ||
| 625 | case TAG_CRC32: | ||
| 626 | { | ||
| 627 | int val = buf[index++] & 0xff; | ||
| 628 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 629 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 630 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 631 | checksum = val; | ||
| 632 | } | ||
| 633 | break; | ||
| 634 | |||
| 635 | case TAG_LastDSTSaving: | ||
| 636 | { | ||
| 637 | short val = (short)(buf[index++] & 0xff); | ||
| 638 | val = (short)((val << 8) + (buf[index++] & 0xff)); | ||
| 639 | dstSavings = val * 1000; | ||
| 640 | } | ||
| 641 | break; | ||
| 642 | |||
| 643 | case TAG_RawOffset: | ||
| 644 | { | ||
| 645 | int val = buf[index++] & 0xff; | ||
| 646 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 647 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 648 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 649 | rawOffset = val; | ||
| 650 | } | ||
| 651 | break; | ||
| 652 | |||
| 653 | case TAG_Transition: | ||
| 654 | { | ||
| 655 | int n = len / 8; | ||
| 656 | transitions = new long[n]; | ||
| 657 | for (int i = 0; i < n; i ++) { | ||
| 658 | long val = buf[index++] & 0xff; | ||
| 659 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 660 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 661 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 662 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 663 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 664 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 665 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 666 | transitions[i] = val; | ||
| 667 | } | ||
| 668 | } | ||
| 669 | break; | ||
| 670 | |||
| 671 | case TAG_Offset: | ||
| 672 | { | ||
| 673 | int n = len / 4; | ||
| 674 | offsets = new int[n]; | ||
| 675 | for (int i = 0; i < n; i ++) { | ||
| 676 | int val = buf[index++] & 0xff; | ||
| 677 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 678 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 679 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 680 | offsets[i] = val; | ||
| 681 | } | ||
| 682 | } | ||
| 683 | break; | ||
| 684 | |||
| 685 | case TAG_SimpleTimeZone: | ||
| 686 | { | ||
| 687 | if (len != 32 && len != 40) { | ||
| 688 | System.err.println("ZoneInfo: wrong SimpleTimeZone parameter size"); | ||
| 689 | return null; | ||
| 690 | } | ||
| 691 | int n = len / 4; | ||
| 692 | simpleTimeZoneParams = new int[n]; | ||
| 693 | for (int i = 0; i < n; i++) { | ||
| 694 | int val = buf[index++] & 0xff; | ||
| 695 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 696 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 697 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 698 | simpleTimeZoneParams[i] = val; | ||
| 699 | } | ||
| 700 | } | ||
| 701 | break; | ||
| 702 | |||
| 703 | case TAG_GMTOffsetWillChange: | ||
| 704 | { | ||
| 705 | if (len != 1) { | ||
| 706 | System.err.println("ZoneInfo: wrong byte length for TAG_GMTOffsetWillChange"); | ||
| 707 | } | ||
| 708 | willGMTOffsetChange = buf[index++] == 1; | ||
| 709 | } | ||
| 710 | break; | ||
| 711 | |||
| 712 | default: | ||
| 713 | System.err.println("ZoneInfo: unknown tag < " + tag + ">. ignored."); | ||
| 714 | index += len; | ||
| 715 | break; | ||
| 716 | } | ||
| 717 | } | ||
| 718 | } catch (Exception e) { | ||
| 719 | System.err.println("ZoneInfo: corrupted zoneinfo file: " + id); | ||
| 720 | return null; | ||
| 721 | } | ||
| 722 | |||
| 723 | if (index != filesize) { | ||
| 724 | System.err.println("ZoneInfo: wrong file size: " + id); | ||
| 725 | return null; | ||
| 726 | } | ||
| 727 | |||
| 728 | return new ZoneInfo(id, rawOffset, dstSavings, checksum, | ||
| 729 | transitions, offsets, simpleTimeZoneParams, | ||
| 730 | willGMTOffsetChange); | ||
| 731 | } | ||
| 732 | |||
| 733 | private volatile static SoftReference<List<String>> zoneIDs = null; | ||
| 734 | |||
| 735 | static List<String> getZoneIDs() { | ||
| 736 | List<String> ids = null; | ||
| 737 | |||
| 738 | SoftReference<List<String>> cache = zoneIDs; | ||
| 739 | if (cache != null) { | ||
| 740 | ids = cache.get(); | ||
| 741 | if (ids != null) { | ||
| 742 | return ids; | ||
| 743 | } | ||
| 744 | } | ||
| 745 | |||
| 746 | byte[] buf = null; | ||
| 747 | buf = getZoneInfoMappings(); | ||
| 748 | int index = JAVAZM_LABEL_LENGTH + 1; | ||
| 749 | int filesize = buf.length; | ||
| 750 | |||
| 751 | try { | ||
| 752 | loop: | ||
| 753 | while (index < filesize) { | ||
| 754 | byte tag = buf[index++]; | ||
| 755 | int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); | ||
| 756 | |||
| 757 | switch (tag) { | ||
| 758 | case TAG_ZoneIDs: | ||
| 759 | { | ||
| 760 | int n = (buf[index++] << 8) + (buf[index++] & 0xFF); | ||
| 761 | ids = new ArrayList<String>(n); | ||
| 762 | |||
| 763 | for (int i = 0; i < n; i++) { | ||
| 764 | byte m = buf[index++]; | ||
| 765 | ids.add(new String(buf, index, m, "UTF-8")); | ||
| 766 | index += m; | ||
| 767 | } | ||
| 768 | } | ||
| 769 | break loop; | ||
| 770 | |||
| 771 | default: | ||
| 772 | index += len; | ||
| 773 | break; | ||
| 774 | } | ||
| 775 | } | ||
| 776 | } catch (Exception e) { | ||
| 777 | System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); | ||
| 778 | } | ||
| 779 | |||
| 780 | zoneIDs = new SoftReference<List<String>>(ids); | ||
| 781 | return ids; | ||
| 782 | } | ||
| 783 | |||
| 784 | /** | ||
| 785 | * @return an alias table in HashMap where a key is an alias ID | ||
| 786 | * (e.g., "PST") and its value is a real time zone ID (e.g., | ||
| 787 | * "America/Los_Angeles"). | ||
| 788 | */ | ||
| 789 | static Map<String, String> getZoneAliases() { | ||
| 790 | byte[] buf = getZoneInfoMappings(); | ||
| 791 | int index = JAVAZM_LABEL_LENGTH + 1; | ||
| 792 | int filesize = buf.length; | ||
| 793 | Map<String, String> aliases = null; | ||
| 794 | |||
| 795 | try { | ||
| 796 | loop: | ||
| 797 | while (index < filesize) { | ||
| 798 | byte tag = buf[index++]; | ||
| 799 | int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); | ||
| 800 | |||
| 801 | switch (tag) { | ||
| 802 | case TAG_ZoneAliases: | ||
| 803 | { | ||
| 804 | int n = (buf[index++] << 8) + (buf[index++] & 0xFF); | ||
| 805 | aliases = new HashMap<String, String>(n); | ||
| 806 | for (int i = 0; i < n; i++) { | ||
| 807 | byte m = buf[index++]; | ||
| 808 | String name = new String(buf, index, m, "UTF-8"); | ||
| 809 | index += m; | ||
| 810 | m = buf[index++]; | ||
| 811 | String realName = new String(buf, index, m, "UTF-8"); | ||
| 812 | index += m; | ||
| 813 | aliases.put(name, realName); | ||
| 814 | } | ||
| 815 | } | ||
| 816 | break loop; | ||
| 817 | |||
| 818 | default: | ||
| 819 | index += len; | ||
| 820 | break; | ||
| 821 | } | ||
| 822 | } | ||
| 823 | } catch (Exception e) { | ||
| 824 | System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); | ||
| 825 | return null; | ||
| 826 | } | ||
| 827 | return aliases; | ||
| 828 | } | ||
| 829 | |||
| 830 | private volatile static SoftReference<List<String>> excludedIDs = null; | ||
| 831 | private volatile static boolean hasNoExcludeList = false; | ||
| 832 | |||
| 833 | /** | ||
| 834 | * @return a List of zone IDs for zones that will change their GMT | ||
| 835 | * offsets in some future time. | ||
| 836 | * | ||
| 837 | * @since 1.6 | ||
| 838 | */ | ||
| 839 | static List<String> getExcludedZones() { | ||
| 840 | if (hasNoExcludeList) { | ||
| 841 | return null; | ||
| 842 | } | ||
| 843 | |||
| 844 | List<String> excludeList = null; | ||
| 845 | |||
| 846 | SoftReference<List<String>> cache = excludedIDs; | ||
| 847 | if (cache != null) { | ||
| 848 | excludeList = cache.get(); | ||
| 849 | if (excludeList != null) { | ||
| 850 | return excludeList; | ||
| 851 | } | ||
| 852 | } | ||
| 853 | |||
| 854 | byte[] buf = getZoneInfoMappings(); | ||
| 855 | int index = JAVAZM_LABEL_LENGTH + 1; | ||
| 856 | int filesize = buf.length; | ||
| 857 | |||
| 858 | try { | ||
| 859 | loop: | ||
| 860 | while (index < filesize) { | ||
| 861 | byte tag = buf[index++]; | ||
| 862 | int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); | ||
| 863 | |||
| 864 | switch (tag) { | ||
| 865 | case TAG_ExcludedZones: | ||
| 866 | { | ||
| 867 | int n = (buf[index++] << 8) + (buf[index++] & 0xFF); | ||
| 868 | excludeList = new ArrayList<String>(); | ||
| 869 | for (int i = 0; i < n; i++) { | ||
| 870 | byte m = buf[index++]; | ||
| 871 | String name = new String(buf, index, m, "UTF-8"); | ||
| 872 | index += m; | ||
| 873 | excludeList.add(name); | ||
| 874 | } | ||
| 875 | } | ||
| 876 | break loop; | ||
| 877 | |||
| 878 | default: | ||
| 879 | index += len; | ||
| 880 | break; | ||
| 881 | } | ||
| 882 | } | ||
| 883 | } catch (Exception e) { | ||
| 884 | System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); | ||
| 885 | return null; | ||
| 886 | } | ||
| 887 | |||
| 888 | if (excludeList != null) { | ||
| 889 | excludedIDs = new SoftReference<List<String>>(excludeList); | ||
| 890 | } else { | ||
| 891 | hasNoExcludeList = true; | ||
| 892 | } | ||
| 893 | return excludeList; | ||
| 894 | } | ||
| 895 | |||
| 896 | private volatile static SoftReference<byte[]> rawOffsetIndices = null; | ||
| 897 | |||
| 898 | static byte[] getRawOffsetIndices() { | ||
| 899 | byte[] indices = null; | ||
| 900 | |||
| 901 | SoftReference<byte[]> cache = rawOffsetIndices; | ||
| 902 | if (cache != null) { | ||
| 903 | indices = cache.get(); | ||
| 904 | if (indices != null) { | ||
| 905 | return indices; | ||
| 906 | } | ||
| 907 | } | ||
| 908 | |||
| 909 | byte[] buf = getZoneInfoMappings(); | ||
| 910 | int index = JAVAZM_LABEL_LENGTH + 1; | ||
| 911 | int filesize = buf.length; | ||
| 912 | |||
| 913 | try { | ||
| 914 | loop: | ||
| 915 | while (index < filesize) { | ||
| 916 | byte tag = buf[index++]; | ||
| 917 | int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); | ||
| 918 | |||
| 919 | switch (tag) { | ||
| 920 | case TAG_RawOffsetIndices: | ||
| 921 | { | ||
| 922 | indices = new byte[len]; | ||
| 923 | for (int i = 0; i < len; i++) { | ||
| 924 | indices[i] = buf[index++]; | ||
| 925 | } | ||
| 926 | } | ||
| 927 | break loop; | ||
| 928 | |||
| 929 | default: | ||
| 930 | index += len; | ||
| 931 | break; | ||
| 932 | } | ||
| 933 | } | ||
| 934 | } catch (ArrayIndexOutOfBoundsException e) { | ||
| 935 | System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); | ||
| 936 | } | ||
| 937 | |||
| 938 | rawOffsetIndices = new SoftReference<byte[]>(indices); | ||
| 939 | return indices; | ||
| 940 | } | ||
| 941 | |||
| 942 | private volatile static SoftReference<int[]> rawOffsets = null; | ||
| 943 | |||
| 944 | static int[] getRawOffsets() { | ||
| 945 | int[] offsets = null; | ||
| 946 | |||
| 947 | SoftReference<int[]> cache = rawOffsets; | ||
| 948 | if (cache != null) { | ||
| 949 | offsets = cache.get(); | ||
| 950 | if (offsets != null) { | ||
| 951 | return offsets; | ||
| 952 | } | ||
| 953 | } | ||
| 954 | |||
| 955 | byte[] buf = getZoneInfoMappings(); | ||
| 956 | int index = JAVAZM_LABEL_LENGTH + 1; | ||
| 957 | int filesize = buf.length; | ||
| 958 | |||
| 959 | try { | ||
| 960 | loop: | ||
| 961 | while (index < filesize) { | ||
| 962 | byte tag = buf[index++]; | ||
| 963 | int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); | ||
| 964 | |||
| 965 | switch (tag) { | ||
| 966 | case TAG_RawOffsets: | ||
| 967 | { | ||
| 968 | int n = len/4; | ||
| 969 | offsets = new int[n]; | ||
| 970 | for (int i = 0; i < n; i++) { | ||
| 971 | int val = buf[index++] & 0xff; | ||
| 972 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 973 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 974 | val = (val << 8) + (buf[index++] & 0xff); | ||
| 975 | offsets[i] = val; | ||
| 976 | } | ||
| 977 | } | ||
| 978 | break loop; | ||
| 979 | |||
| 980 | default: | ||
| 981 | index += len; | ||
| 982 | break; | ||
| 983 | } | ||
| 984 | } | ||
| 985 | } catch (ArrayIndexOutOfBoundsException e) { | ||
| 986 | System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); | ||
| 987 | } | ||
| 988 | |||
| 989 | rawOffsets = new SoftReference<int[]>(offsets); | ||
| 990 | return offsets; | ||
| 991 | } | ||
| 992 | |||
| 993 | private volatile static SoftReference<byte[]> zoneInfoMappings = null; | ||
| 994 | |||
| 995 | private static byte[] getZoneInfoMappings() { | ||
| 996 | byte[] data; | ||
| 997 | |||
| 998 | SoftReference<byte[]> cache = zoneInfoMappings; | ||
| 999 | if (cache != null) { | ||
| 1000 | data = cache.get(); | ||
| 1001 | if (data != null) { | ||
| 1002 | return data; | ||
| 1003 | } | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | data = readZoneInfoFile(JAVAZM_FILE_NAME); | ||
| 1007 | |||
| 1008 | if (data == null) { | ||
| 1009 | return null; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | int index; | ||
| 1013 | for (index = 0; index < JAVAZM_LABEL.length; index++) { | ||
| 1014 | if (data[index] != JAVAZM_LABEL[index]) { | ||
| 1015 | System.err.println("ZoneInfo: wrong magic number: " + JAVAZM_FILE_NAME); | ||
| 1016 | return null; | ||
| 1017 | } | ||
| 1018 | } | ||
| 1019 | if (data[index++] > JAVAZM_VERSION) { | ||
| 1020 | System.err.println("ZoneInfo: incompatible version (" | ||
| 1021 | + data[index - 1] + "): " + JAVAZM_FILE_NAME); | ||
| 1022 | return null; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | zoneInfoMappings = new SoftReference<byte[]>(data); | ||
| 1026 | return data; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | /** | ||
| 1030 | * Reads the specified file under <java.home>/lib/zi into a buffer. | ||
| 1031 | * @return the buffer, or null if any I/O error occurred. | ||
| 1032 | */ | ||
| 1033 | private static byte[] readZoneInfoFile(final String fileName) { | ||
| 1034 | byte[] buffer = null; | ||
| 1035 | |||
| 1036 | try { | ||
| 1037 | buffer = (byte[]) AccessController.doPrivileged(new PrivilegedExceptionAction() { | ||
| 1038 | public Object run() throws IOException { | ||
| 1039 | File file = new File(ziDir, fileName); | ||
| 1040 | if (!file.exists() || !file.isFile()) { | ||
| 1041 | return null; | ||
| 1042 | } | ||
| 1043 | file = file.getCanonicalFile(); | ||
| 1044 | String path = file.getCanonicalPath(); | ||
| 1045 | byte[] buf = null; | ||
| 1046 | if (path != null && path.startsWith(ziDir)) { | ||
| 1047 | int filesize = (int)file.length(); | ||
| 1048 | if (filesize > 0) { | ||
| 1049 | FileInputStream fis = new FileInputStream(file); | ||
| 1050 | buf = new byte[filesize]; | ||
| 1051 | try { | ||
| 1052 | if (fis.read(buf) != filesize) { | ||
| 1053 | throw new IOException("read error on " + fileName); | ||
| 1054 | } | ||
| 1055 | } finally { | ||
| 1056 | fis.close(); | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | } | ||
| 1060 | return buf; | ||
| 1061 | } | ||
| 1062 | }); | ||
| 1063 | } catch (PrivilegedActionException e) { | ||
| 1064 | Exception ex = e.getException(); | ||
| 1065 | if (!(ex instanceof FileNotFoundException) || JAVAZM_FILE_NAME.equals(fileName)) { | ||
| 1066 | System.err.println("ZoneInfo: " + ex.getMessage()); | ||
| 1067 | } | ||
| 1068 | } | ||
| 1069 | return buffer; | ||
| 1070 | } | ||
| 1071 | } | ||