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