summaryrefslogtreecommitdiff
path: root/android_icu4j/src/main/java/android/icu/util/VersionInfo.java
blob: 7ba8669bf84a20a89d4042f8482b8438bd0d1e0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
/* GENERATED SOURCE. DO NOT MODIFY. */
/*
 *******************************************************************************
 * Copyright (C) 1996-2015, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 */

package android.icu.util;

import java.util.concurrent.ConcurrentHashMap;

/**
 * Class to store version numbers of the form major.minor.milli.micro.
 * @author synwee
 */
public final class VersionInfo implements Comparable<VersionInfo>
{
    // public data members -------------------------------------------------

    /**
     * Unicode 1.0 version
     */
    public static final VersionInfo UNICODE_1_0;
    /**
     * Unicode 1.0.1 version
     */
    public static final VersionInfo UNICODE_1_0_1;
    /**
     * Unicode 1.1.0 version
     */
    public static final VersionInfo UNICODE_1_1_0;
    /**
     * Unicode 1.1.5 version
     */
    public static final VersionInfo UNICODE_1_1_5;
    /**
     * Unicode 2.0 version
     */
    public static final VersionInfo UNICODE_2_0;
    /**
     * Unicode 2.1.2 version
     */
    public static final VersionInfo UNICODE_2_1_2;
    /**
     * Unicode 2.1.5 version
     */
    public static final VersionInfo UNICODE_2_1_5;
    /**
     * Unicode 2.1.8 version
     */
    public static final VersionInfo UNICODE_2_1_8;
    /**
     * Unicode 2.1.9 version
     */
    public static final VersionInfo UNICODE_2_1_9;
    /**
     * Unicode 3.0 version
     */
    public static final VersionInfo UNICODE_3_0;
    /**
     * Unicode 3.0.1 version
     */
    public static final VersionInfo UNICODE_3_0_1;
    /**
     * Unicode 3.1.0 version
     */
    public static final VersionInfo UNICODE_3_1_0;
    /**
     * Unicode 3.1.1 version
     */
    public static final VersionInfo UNICODE_3_1_1;
    /**
     * Unicode 3.2 version
     */
    public static final VersionInfo UNICODE_3_2;

    /**
     * Unicode 4.0 version
     */
    public static final VersionInfo UNICODE_4_0;

    /**
     * Unicode 4.0.1 version
     */
    public static final VersionInfo UNICODE_4_0_1;

    /**
     * Unicode 4.1 version
     */
    public static final VersionInfo UNICODE_4_1;

    /**
     * Unicode 5.0 version
     */
    public static final VersionInfo UNICODE_5_0;

    /**
     * Unicode 5.1 version
     */
    public static final VersionInfo UNICODE_5_1;

    /**
     * Unicode 5.2 version
     */
    public static final VersionInfo UNICODE_5_2;

    /**
     * Unicode 6.0 version
     */
    public static final VersionInfo UNICODE_6_0;

    /**
     * Unicode 6.1 version
     */
    public static final VersionInfo UNICODE_6_1;

    /**
     * Unicode 6.2 version
     */
    public static final VersionInfo UNICODE_6_2;

    /**
     * Unicode 6.3 version
     */
    public static final VersionInfo UNICODE_6_3;

    /**
     * Unicode 7.0 version
     */
    public static final VersionInfo UNICODE_7_0;

    /**
     * Unicode 8.0 version
     */
    public static final VersionInfo UNICODE_8_0;

    /**
     * ICU4J current release version
     */
    public static final VersionInfo ICU_VERSION;

    /**
     * Data version string for ICU's internal data.
     * Used for appending to data path (e.g. icudt43b)
     * @deprecated This API is ICU internal only.
     * @hide original deprecated declaration
     * @hide draft / provisional / internal are hidden on Android
     */
    @Deprecated
    public static final String ICU_DATA_VERSION_PATH = "56b";
    
    /**
     * Data version in ICU4J.
     * @deprecated This API is ICU internal only.
     * @hide original deprecated declaration
     * @hide draft / provisional / internal are hidden on Android
     */
    @Deprecated
    public static final VersionInfo ICU_DATA_VERSION;

    /**
     * Collation runtime version (sort key generator, string comparisons).
     * If the version is different, sort keys for the same string could be different.
     * This value may change in subsequent releases of ICU.
     */
    public static final VersionInfo UCOL_RUNTIME_VERSION;

    /**
     * Collation builder code version.
     * When this is different, the same tailoring might result
     * in assigning different collation elements to code points.
     * This value may change in subsequent releases of ICU.
     */
    public static final VersionInfo UCOL_BUILDER_VERSION;

    /**
     * Constant version 1.
     * This was intended to be the version of collation tailorings,
     * but instead the tailoring data carries a version number.
     * @deprecated ICU 54
     * @hide original deprecated declaration
     */
    @Deprecated
    public static final VersionInfo UCOL_TAILORINGS_VERSION;


    // public methods ------------------------------------------------------

    /**
     * Returns an instance of VersionInfo with the argument version.
     * @param version version String in the format of "major.minor.milli.micro"
     *                or "major.minor.milli" or "major.minor" or "major",
     *                where major, minor, milli, micro are non-negative numbers
     *                &lt;= 255. If the trailing version numbers are
     *                not specified they are taken as 0s. E.g. Version "3.1" is
     *                equivalent to "3.1.0.0".
     * @return an instance of VersionInfo with the argument version.
     * @exception IllegalArgumentException when the argument version
     *                is not in the right format
     */
    public static VersionInfo getInstance(String version)
    {
        int length  = version.length();
        int array[] = {0, 0, 0, 0};
        int count   = 0;
        int index   = 0;

        while (count < 4 && index < length) {
            char c = version.charAt(index);
            if (c == '.') {
                count ++;
            }
            else {
                c -= '0';
                if (c < 0 || c > 9) {
                    throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
                }
                array[count] *= 10;
                array[count] += c;
            }
            index ++;
        }
        if (index != length) {
            throw new IllegalArgumentException(
                                               "Invalid version number: String '" + version + "' exceeds version format");
        }
        for (int i = 0; i < 4; i ++) {
            if (array[i] < 0 || array[i] > 255) {
                throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
            }
        }

        return getInstance(array[0], array[1], array[2], array[3]);
    }

    /**
     * Returns an instance of VersionInfo with the argument version.
     * @param major major version, non-negative number &lt;= 255.
     * @param minor minor version, non-negative number &lt;= 255.
     * @param milli milli version, non-negative number &lt;= 255.
     * @param micro micro version, non-negative number &lt;= 255.
     * @exception IllegalArgumentException when either arguments are negative or &gt; 255
     */
    public static VersionInfo getInstance(int major, int minor, int milli,
                                          int micro)
    {
        // checks if it is in the hashmap
        // else
        if (major < 0 || major > 255 || minor < 0 || minor > 255 ||
            milli < 0 || milli > 255 || micro < 0 || micro > 255) {
            throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
        }
        int     version = getInt(major, minor, milli, micro);
        Integer key     = Integer.valueOf(version);
        VersionInfo  result  = MAP_.get(key);
        if (result == null) {
            result = new VersionInfo(version);
            VersionInfo tmpvi = MAP_.putIfAbsent(key, result);
            if (tmpvi != null) {
                result = tmpvi;
            }
        }
        return result;
    }

    /**
     * Returns an instance of VersionInfo with the argument version.
     * Equivalent to getInstance(major, minor, milli, 0).
     * @param major major version, non-negative number &lt;= 255.
     * @param minor minor version, non-negative number &lt;= 255.
     * @param milli milli version, non-negative number &lt;= 255.
     * @exception IllegalArgumentException when either arguments are
     *                                     negative or &gt; 255
     */
    public static VersionInfo getInstance(int major, int minor, int milli)
    {
        return getInstance(major, minor, milli, 0);
    }

    /**
     * Returns an instance of VersionInfo with the argument version.
     * Equivalent to getInstance(major, minor, 0, 0).
     * @param major major version, non-negative number &lt;= 255.
     * @param minor minor version, non-negative number &lt;= 255.
     * @exception IllegalArgumentException when either arguments are
     *                                     negative or &gt; 255
     */
    public static VersionInfo getInstance(int major, int minor)
    {
        return getInstance(major, minor, 0, 0);
    }

    /**
     * Returns an instance of VersionInfo with the argument version.
     * Equivalent to getInstance(major, 0, 0, 0).
     * @param major major version, non-negative number &lt;= 255.
     * @exception IllegalArgumentException when either arguments are
     *                                     negative or &gt; 255
     */
    public static VersionInfo getInstance(int major)
    {
        return getInstance(major, 0, 0, 0);
    }

    private static volatile VersionInfo javaVersion;

    /**
     * @deprecated This API is ICU internal only.
     * @hide original deprecated declaration
     * @hide draft / provisional / internal are hidden on Android
     */
    @Deprecated
    public static VersionInfo javaVersion() {
        if (javaVersion == null) {
            synchronized(VersionInfo.class) {
                if (javaVersion == null) {
                    String s = System.getProperty("java.version");
                    // clean string
                    // preserve only digits, separated by single '.'
                    // ignore over 4 digit sequences
                    // does not test < 255, very odd...

                    char[] chars = s.toCharArray();
                    int r = 0, w = 0, count = 0;
                    boolean numeric = false; // ignore leading non-numerics
                    while (r < chars.length) {
                        char c = chars[r++];
                        if (c < '0' || c > '9') {
                            if (numeric) {
                                if (count == 3) {
                                    // only four digit strings allowed
                                    break;
                                }
                                numeric = false;
                                chars[w++] = '.';
                                ++count;
                            }
                        } else {
                            numeric = true;
                            chars[w++] = c;
                        }
                    }
                    while (w > 0 && chars[w-1] == '.') {
                        --w;
                    }

                    String vs = new String(chars, 0, w);

                    javaVersion = VersionInfo.getInstance(vs);
                }
            }
        }
        return javaVersion;
    }

    /**
     * Returns the String representative of VersionInfo in the format of
     * "major.minor.milli.micro"
     * @return String representative of VersionInfo
     */
    public String toString()
    {
        StringBuilder result = new StringBuilder(7);
        result.append(getMajor());
        result.append('.');
        result.append(getMinor());
        result.append('.');
        result.append(getMilli());
        result.append('.');
        result.append(getMicro());
        return result.toString();
    }

    /**
     * Returns the major version number
     * @return the major version number
     */
    public int getMajor()
    {
        return (m_version_ >> 24) & LAST_BYTE_MASK_ ;
    }

    /**
     * Returns the minor version number
     * @return the minor version number
     */
    public int getMinor()
    {
        return (m_version_ >> 16) & LAST_BYTE_MASK_ ;
    }

    /**
     * Returns the milli version number
     * @return the milli version number
     */
    public int getMilli()
    {
        return (m_version_ >> 8) & LAST_BYTE_MASK_ ;
    }

    /**
     * Returns the micro version number
     * @return the micro version number
     */
    public int getMicro()
    {
        return m_version_ & LAST_BYTE_MASK_ ;
    }

    /**
     * Checks if this version information is equals to the argument version
     * @param other object to be compared
     * @return true if other is equals to this object's version information,
     *         false otherwise
     */
    public boolean equals(Object other)
    {
        return other == this;
    }

    /**
     * Compares other with this VersionInfo.
     * @param other VersionInfo to be compared
     * @return 0 if the argument is a VersionInfo object that has version
     *           information equals to this object.
     *           Less than 0 if the argument is a VersionInfo object that has
     *           version information greater than this object.
     *           Greater than 0 if the argument is a VersionInfo object that
     *           has version information less than this object.
     */
    public int compareTo(VersionInfo other)
    {
        return m_version_ - other.m_version_;
    }

    // private data members ----------------------------------------------

    /**
     * Unicode data version used by the current release
     */
    private static final VersionInfo UNICODE_VERSION;

    /**
     * Version number stored as a byte for each of the major, minor, milli and
     * micro numbers in the 32 bit int.
     * Most significant for the major and the least significant contains the
     * micro numbers.
     */
    private int m_version_;
    /**
     * Map of singletons
     */
    private static final ConcurrentHashMap<Integer, VersionInfo> MAP_ = new ConcurrentHashMap<Integer, VersionInfo>();
    /**
     * Last byte mask
     */
    private static final int LAST_BYTE_MASK_ = 0xFF;
    /**
     * Error statement string
     */
    private static final String INVALID_VERSION_NUMBER_ =
        "Invalid version number: Version number may be negative or greater than 255";

    // static declaration ------------------------------------------------

    /**
     * Initialize versions only after MAP_ has been created
     */
    static {
        UNICODE_1_0   = getInstance(1, 0, 0, 0);
        UNICODE_1_0_1 = getInstance(1, 0, 1, 0);
        UNICODE_1_1_0 = getInstance(1, 1, 0, 0);
        UNICODE_1_1_5 = getInstance(1, 1, 5, 0);
        UNICODE_2_0   = getInstance(2, 0, 0, 0);
        UNICODE_2_1_2 = getInstance(2, 1, 2, 0);
        UNICODE_2_1_5 = getInstance(2, 1, 5, 0);
        UNICODE_2_1_8 = getInstance(2, 1, 8, 0);
        UNICODE_2_1_9 = getInstance(2, 1, 9, 0);
        UNICODE_3_0   = getInstance(3, 0, 0, 0);
        UNICODE_3_0_1 = getInstance(3, 0, 1, 0);
        UNICODE_3_1_0 = getInstance(3, 1, 0, 0);
        UNICODE_3_1_1 = getInstance(3, 1, 1, 0);
        UNICODE_3_2   = getInstance(3, 2, 0, 0);
        UNICODE_4_0   = getInstance(4, 0, 0, 0);
        UNICODE_4_0_1 = getInstance(4, 0, 1, 0);
        UNICODE_4_1   = getInstance(4, 1, 0, 0);
        UNICODE_5_0   = getInstance(5, 0, 0, 0);
        UNICODE_5_1   = getInstance(5, 1, 0, 0);
        UNICODE_5_2   = getInstance(5, 2, 0, 0);
        UNICODE_6_0   = getInstance(6, 0, 0, 0);
        UNICODE_6_1   = getInstance(6, 1, 0, 0);
        UNICODE_6_2   = getInstance(6, 2, 0, 0);
        UNICODE_6_3   = getInstance(6, 3, 0, 0);
        UNICODE_7_0   = getInstance(7, 0, 0, 0);
        UNICODE_8_0   = getInstance(8, 0, 0, 0);

        ICU_VERSION   = getInstance(56, 1, 0, 0);
        ICU_DATA_VERSION = getInstance(56, 1, 0, 0);
        UNICODE_VERSION = UNICODE_8_0;

        UCOL_RUNTIME_VERSION = getInstance(9);
        UCOL_BUILDER_VERSION = getInstance(9);
        UCOL_TAILORINGS_VERSION = getInstance(1);
    }

    // private constructor -----------------------------------------------

    /**
     * Constructor with int
     * @param compactversion a 32 bit int with each byte representing a number
     */
    private VersionInfo(int compactversion)
    {
        m_version_ = compactversion;
    }

    /**
     * Gets the int from the version numbers
     * @param major non-negative version number
     * @param minor non-negative version number
     * @param milli non-negative version number
     * @param micro non-negative version number
     */
    private static int getInt(int major, int minor, int milli, int micro)
    {
        return (major << 24) | (minor << 16) | (milli << 8) | micro;
    }
    ///CLOVER:OFF
    /**
     * Main method prints out ICU version information
     * @param args arguments (currently not used)
     */
    public static void main(String[] args) {
        String icuApiVer;

        if (ICU_VERSION.getMajor() <= 4) {
            if (ICU_VERSION.getMinor() % 2 != 0) {
                // Development mile stone
                int major = ICU_VERSION.getMajor();
                int minor = ICU_VERSION.getMinor() + 1;
                if (minor >= 10) {
                    minor -= 10;
                    major++;
                }
                icuApiVer = "" + major + "." + minor + "M" + ICU_VERSION.getMilli();
            } else {
                icuApiVer = ICU_VERSION.getVersionString(2, 2);
            }
        } else {
            if (ICU_VERSION.getMinor() == 0) {
                // Development mile stone
                icuApiVer = "" + ICU_VERSION.getMajor() + "M" + ICU_VERSION.getMilli();
            } else {
                icuApiVer = ICU_VERSION.getVersionString(2, 2);
            }
        }


        System.out.println("International Components for Unicode for Java " + icuApiVer);

        System.out.println("");
        System.out.println("Implementation Version: " + ICU_VERSION.getVersionString(2, 4));
        System.out.println("Unicode Data Version:   " + UNICODE_VERSION.getVersionString(2, 4));
        System.out.println("CLDR Data Version:      " + LocaleData.getCLDRVersion().getVersionString(2, 4));
        System.out.println("Time Zone Data Version: " + getTZDataVersion());
    }

    /**
     * Generate version string separated by dots with
     * the specified digit width.  Version digit 0
     * after <code>minDigits</code> will be trimmed off.
     * @param minDigits Minimum number of version digits
     * @param maxDigits Maximum number of version digits
     * @return A tailored version string
     * @deprecated This API is ICU internal only. (For use in CLDR, etc.)
     * @hide original deprecated declaration
     * @hide draft / provisional / internal are hidden on Android
     */
    @Deprecated
    public String getVersionString(int minDigits, int maxDigits) {
        if (minDigits < 1 || maxDigits < 1
                || minDigits > 4 || maxDigits > 4 || minDigits > maxDigits) {
            throw new IllegalArgumentException("Invalid min/maxDigits range");
        }

        int[] digits = new int[4];
        digits[0] = getMajor();
        digits[1] = getMinor();
        digits[2] = getMilli();
        digits[3] = getMicro();

        int numDigits = maxDigits;
        while (numDigits > minDigits) {
            if (digits[numDigits - 1] != 0) {
                break;
            }
            numDigits--;
        }

        StringBuilder verStr = new StringBuilder(7);
        verStr.append(digits[0]);
        for (int i = 1; i < numDigits; i++) {
            verStr.append(".");
            verStr.append(digits[i]);
        }

        return verStr.toString();
    }
    ///CLOVER:ON


    // Moved from TimeZone class
    private static volatile String TZDATA_VERSION = null;

    static String getTZDataVersion() {
        if (TZDATA_VERSION == null) {
            synchronized (VersionInfo.class) {
                if (TZDATA_VERSION == null) {
                    UResourceBundle tzbundle = UResourceBundle.getBundleInstance("android/icu/impl/data/icudt"
                            + VersionInfo.ICU_DATA_VERSION_PATH, "zoneinfo64");
                    TZDATA_VERSION = tzbundle.getString("TZVersion");
                }
            }
        }
        return TZDATA_VERSION;
    }
}