• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4  *******************************************************************************
5  * Copyright (C) 1996-2016, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  *******************************************************************************
8  */
9 
10 package com.ibm.icu.util;
11 
12 import java.util.concurrent.ConcurrentHashMap;
13 
14 /**
15  * Class to store version numbers of the form major.minor.milli.micro.
16  * @author synwee
17  * @stable ICU 2.6
18  */
19 public final class VersionInfo implements Comparable<VersionInfo>
20 {
21     // public data members -------------------------------------------------
22 
23     /**
24      * Unicode 1.0 version
25      * @stable ICU 2.6
26      */
27     public static final VersionInfo UNICODE_1_0;
28     /**
29      * Unicode 1.0.1 version
30      * @stable ICU 2.6
31      */
32     public static final VersionInfo UNICODE_1_0_1;
33     /**
34      * Unicode 1.1.0 version
35      * @stable ICU 2.6
36      */
37     public static final VersionInfo UNICODE_1_1_0;
38     /**
39      * Unicode 1.1.5 version
40      * @stable ICU 2.6
41      */
42     public static final VersionInfo UNICODE_1_1_5;
43     /**
44      * Unicode 2.0 version
45      * @stable ICU 2.6
46      */
47     public static final VersionInfo UNICODE_2_0;
48     /**
49      * Unicode 2.1.2 version
50      * @stable ICU 2.6
51      */
52     public static final VersionInfo UNICODE_2_1_2;
53     /**
54      * Unicode 2.1.5 version
55      * @stable ICU 2.6
56      */
57     public static final VersionInfo UNICODE_2_1_5;
58     /**
59      * Unicode 2.1.8 version
60      * @stable ICU 2.6
61      */
62     public static final VersionInfo UNICODE_2_1_8;
63     /**
64      * Unicode 2.1.9 version
65      * @stable ICU 2.6
66      */
67     public static final VersionInfo UNICODE_2_1_9;
68     /**
69      * Unicode 3.0 version
70      * @stable ICU 2.6
71      */
72     public static final VersionInfo UNICODE_3_0;
73     /**
74      * Unicode 3.0.1 version
75      * @stable ICU 2.6
76      */
77     public static final VersionInfo UNICODE_3_0_1;
78     /**
79      * Unicode 3.1.0 version
80      * @stable ICU 2.6
81      */
82     public static final VersionInfo UNICODE_3_1_0;
83     /**
84      * Unicode 3.1.1 version
85      * @stable ICU 2.6
86      */
87     public static final VersionInfo UNICODE_3_1_1;
88     /**
89      * Unicode 3.2 version
90      * @stable ICU 2.6
91      */
92     public static final VersionInfo UNICODE_3_2;
93 
94     /**
95      * Unicode 4.0 version
96      * @stable ICU 2.6
97      */
98     public static final VersionInfo UNICODE_4_0;
99 
100     /**
101      * Unicode 4.0.1 version
102      * @stable ICU 3.4
103      */
104     public static final VersionInfo UNICODE_4_0_1;
105 
106     /**
107      * Unicode 4.1 version
108      * @stable ICU 3.4
109      */
110     public static final VersionInfo UNICODE_4_1;
111 
112     /**
113      * Unicode 5.0 version
114      * @stable ICU 3.4
115      */
116     public static final VersionInfo UNICODE_5_0;
117 
118     /**
119      * Unicode 5.1 version
120      * @stable ICU 4.2
121      */
122     public static final VersionInfo UNICODE_5_1;
123 
124     /**
125      * Unicode 5.2 version
126      * @stable ICU 4.4
127      */
128     public static final VersionInfo UNICODE_5_2;
129 
130     /**
131      * Unicode 6.0 version
132      * @stable ICU 4.6
133      */
134     public static final VersionInfo UNICODE_6_0;
135 
136     /**
137      * Unicode 6.1 version
138      * @stable ICU 49
139      */
140     public static final VersionInfo UNICODE_6_1;
141 
142     /**
143      * Unicode 6.2 version
144      * @stable ICU 50
145      */
146     public static final VersionInfo UNICODE_6_2;
147 
148     /**
149      * Unicode 6.3 version
150      * @stable ICU 52
151      */
152     public static final VersionInfo UNICODE_6_3;
153 
154     /**
155      * Unicode 7.0 version
156      * @stable ICU 54
157      */
158     public static final VersionInfo UNICODE_7_0;
159 
160     /**
161      * Unicode 8.0 version
162      * @stable ICU 56
163      */
164     public static final VersionInfo UNICODE_8_0;
165 
166     /**
167      * Unicode 9.0 version
168      * @stable ICU 58
169      */
170     public static final VersionInfo UNICODE_9_0;
171 
172     /**
173      * Unicode 10.0 version
174      * @stable ICU 60
175      */
176     public static final VersionInfo UNICODE_10_0;
177 
178     /**
179      * Unicode 11.0 version
180      * @stable ICU 62
181      */
182     public static final VersionInfo UNICODE_11_0;
183 
184     /**
185      * Unicode 12.0 version
186      * @stable ICU 64
187      */
188     public static final VersionInfo UNICODE_12_0;
189 
190     /**
191      * Unicode 12.1 version
192      * @stable ICU 64
193      */
194     public static final VersionInfo UNICODE_12_1;
195 
196     /**
197      * Unicode 13.0 version
198      * @stable ICU 66
199      */
200     public static final VersionInfo UNICODE_13_0;
201 
202     /**
203      * Unicode 14.0 version
204      * @stable ICU 70
205      */
206     public static final VersionInfo UNICODE_14_0;
207 
208     /**
209      * ICU4J current release version
210      * @stable ICU 2.8
211      */
212     public static final VersionInfo ICU_VERSION;
213 
214     /**
215      * Data version string for ICU's internal data.
216      * Used for appending to data path (e.g. icudt43b)
217      * @internal
218      * @deprecated This API is ICU internal only.
219      */
220     @Deprecated
221     public static final String ICU_DATA_VERSION_PATH = "70b";
222 
223     /**
224      * Data version in ICU4J.
225      * @internal
226      * @deprecated This API is ICU internal only.
227      */
228     @Deprecated
229     public static final VersionInfo ICU_DATA_VERSION;
230 
231     /**
232      * Collation runtime version (sort key generator, string comparisons).
233      * If the version is different, sort keys for the same string could be different.
234      * This value may change in subsequent releases of ICU.
235      * @stable ICU 2.8
236      */
237     public static final VersionInfo UCOL_RUNTIME_VERSION;
238 
239     /**
240      * Collation builder code version.
241      * When this is different, the same tailoring might result
242      * in assigning different collation elements to code points.
243      * This value may change in subsequent releases of ICU.
244      * @stable ICU 2.8
245      */
246     public static final VersionInfo UCOL_BUILDER_VERSION;
247 
248     /**
249      * Constant version 1.
250      * This was intended to be the version of collation tailorings,
251      * but instead the tailoring data carries a version number.
252      * @deprecated ICU 54
253      */
254     @Deprecated
255     public static final VersionInfo UCOL_TAILORINGS_VERSION;
256 
257 
258     // public methods ------------------------------------------------------
259 
260     /**
261      * Returns an instance of VersionInfo with the argument version.
262      * @param version version String in the format of "major.minor.milli.micro"
263      *                or "major.minor.milli" or "major.minor" or "major",
264      *                where major, minor, milli, micro are non-negative numbers
265      *                &lt;= 255. If the trailing version numbers are
266      *                not specified they are taken as 0s. E.g. Version "3.1" is
267      *                equivalent to "3.1.0.0".
268      * @return an instance of VersionInfo with the argument version.
269      * @exception IllegalArgumentException when the argument version
270      *                is not in the right format
271      * @stable ICU 2.6
272      */
getInstance(String version)273     public static VersionInfo getInstance(String version)
274     {
275         int length  = version.length();
276         int array[] = {0, 0, 0, 0};
277         int count   = 0;
278         int index   = 0;
279 
280         while (count < 4 && index < length) {
281             char c = version.charAt(index);
282             if (c == '.') {
283                 count ++;
284             }
285             else {
286                 c -= '0';
287                 if (c < 0 || c > 9) {
288                     throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
289                 }
290                 array[count] *= 10;
291                 array[count] += c;
292             }
293             index ++;
294         }
295         if (index != length) {
296             throw new IllegalArgumentException(
297                                                "Invalid version number: String '" + version + "' exceeds version format");
298         }
299         for (int i = 0; i < 4; i ++) {
300             if (array[i] < 0 || array[i] > 255) {
301                 throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
302             }
303         }
304 
305         return getInstance(array[0], array[1], array[2], array[3]);
306     }
307 
308     /**
309      * Returns an instance of VersionInfo with the argument version.
310      * @param major major version, non-negative number &lt;= 255.
311      * @param minor minor version, non-negative number &lt;= 255.
312      * @param milli milli version, non-negative number &lt;= 255.
313      * @param micro micro version, non-negative number &lt;= 255.
314      * @exception IllegalArgumentException when either arguments are negative or &gt; 255
315      * @stable ICU 2.6
316      */
getInstance(int major, int minor, int milli, int micro)317     public static VersionInfo getInstance(int major, int minor, int milli,
318                                           int micro)
319     {
320         // checks if it is in the hashmap
321         // else
322         if (major < 0 || major > 255 || minor < 0 || minor > 255 ||
323             milli < 0 || milli > 255 || micro < 0 || micro > 255) {
324             throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
325         }
326         int     version = getInt(major, minor, milli, micro);
327         Integer key     = Integer.valueOf(version);
328         VersionInfo  result  = MAP_.get(key);
329         if (result == null) {
330             result = new VersionInfo(version);
331             VersionInfo tmpvi = MAP_.putIfAbsent(key, result);
332             if (tmpvi != null) {
333                 result = tmpvi;
334             }
335         }
336         return result;
337     }
338 
339     /**
340      * Returns an instance of VersionInfo with the argument version.
341      * Equivalent to getInstance(major, minor, milli, 0).
342      * @param major major version, non-negative number &lt;= 255.
343      * @param minor minor version, non-negative number &lt;= 255.
344      * @param milli milli version, non-negative number &lt;= 255.
345      * @exception IllegalArgumentException when either arguments are
346      *                                     negative or &gt; 255
347      * @stable ICU 2.6
348      */
getInstance(int major, int minor, int milli)349     public static VersionInfo getInstance(int major, int minor, int milli)
350     {
351         return getInstance(major, minor, milli, 0);
352     }
353 
354     /**
355      * Returns an instance of VersionInfo with the argument version.
356      * Equivalent to getInstance(major, minor, 0, 0).
357      * @param major major version, non-negative number &lt;= 255.
358      * @param minor minor version, non-negative number &lt;= 255.
359      * @exception IllegalArgumentException when either arguments are
360      *                                     negative or &gt; 255
361      * @stable ICU 2.6
362      */
getInstance(int major, int minor)363     public static VersionInfo getInstance(int major, int minor)
364     {
365         return getInstance(major, minor, 0, 0);
366     }
367 
368     /**
369      * Returns an instance of VersionInfo with the argument version.
370      * Equivalent to getInstance(major, 0, 0, 0).
371      * @param major major version, non-negative number &lt;= 255.
372      * @exception IllegalArgumentException when either arguments are
373      *                                     negative or &gt; 255
374      * @stable ICU 2.6
375      */
getInstance(int major)376     public static VersionInfo getInstance(int major)
377     {
378         return getInstance(major, 0, 0, 0);
379     }
380 
381     /**
382      * Returns the String representative of VersionInfo in the format of
383      * "major.minor.milli.micro"
384      * @return String representative of VersionInfo
385      * @stable ICU 2.6
386      */
387     @Override
toString()388     public String toString()
389     {
390         StringBuilder result = new StringBuilder(7);
391         result.append(getMajor());
392         result.append('.');
393         result.append(getMinor());
394         result.append('.');
395         result.append(getMilli());
396         result.append('.');
397         result.append(getMicro());
398         return result.toString();
399     }
400 
401     /**
402      * Returns the major version number
403      * @return the major version number
404      * @stable ICU 2.6
405      */
getMajor()406     public int getMajor()
407     {
408         return (m_version_ >> 24) & LAST_BYTE_MASK_ ;
409     }
410 
411     /**
412      * Returns the minor version number
413      * @return the minor version number
414      * @stable ICU 2.6
415      */
getMinor()416     public int getMinor()
417     {
418         return (m_version_ >> 16) & LAST_BYTE_MASK_ ;
419     }
420 
421     /**
422      * Returns the milli version number
423      * @return the milli version number
424      * @stable ICU 2.6
425      */
getMilli()426     public int getMilli()
427     {
428         return (m_version_ >> 8) & LAST_BYTE_MASK_ ;
429     }
430 
431     /**
432      * Returns the micro version number
433      * @return the micro version number
434      * @stable ICU 2.6
435      */
getMicro()436     public int getMicro()
437     {
438         return m_version_ & LAST_BYTE_MASK_ ;
439     }
440 
441     /**
442      * Checks if this version information is equals to the argument version
443      * @param other object to be compared
444      * @return true if other is equals to this object's version information,
445      *         false otherwise
446      * @stable ICU 2.6
447      */
448     @Override
equals(Object other)449     public boolean equals(Object other)
450     {
451         return other == this;
452     }
453 
454     /**
455      * Returns the hash code value for this set.
456      *
457      * @return the hash code value for this set.
458      * @see java.lang.Object#hashCode()
459      * @stable ICU 2.6
460      */
461     @Override
hashCode()462     public int hashCode() {
463         return m_version_;
464     }
465 
466     /**
467      * Compares other with this VersionInfo.
468      * @param other VersionInfo to be compared
469      * @return 0 if the argument is a VersionInfo object that has version
470      *           information equals to this object.
471      *           Less than 0 if the argument is a VersionInfo object that has
472      *           version information greater than this object.
473      *           Greater than 0 if the argument is a VersionInfo object that
474      *           has version information less than this object.
475      * @stable ICU 2.6
476      */
477     @Override
compareTo(VersionInfo other)478     public int compareTo(VersionInfo other)
479     {
480         // m_version_ is an int, a signed 32-bit integer.
481         // When the major version is >=128, then the version int is negative.
482         // Compare it in two steps to simulate an unsigned-int comparison.
483         // (Alternatively we could turn each int into a long and reset the upper 32 bits.)
484         // Compare the upper bits first, using logical shift right (unsigned).
485         int diff = (m_version_ >>> 1) - (other.m_version_ >>> 1);
486         if (diff != 0) { return diff; }
487         // Compare the remaining bits.
488         return (m_version_ & 1) - (other.m_version_ & 1);
489     }
490 
491     // private data members ----------------------------------------------
492 
493     /**
494      * Unicode data version used by the current release.
495      * Defined here privately for printing by the main() method in this class.
496      * Should be the same as {@link com.ibm.icu.lang.UCharacter#getUnicodeVersion()}
497      * which gets the version number from a data file.
498      * We do not want VersionInfo to have an import dependency on UCharacter.
499      */
500     private static final VersionInfo UNICODE_VERSION;
501 
502     /**
503      * Version number stored as a byte for each of the major, minor, milli and
504      * micro numbers in the 32 bit int.
505      * Most significant for the major and the least significant contains the
506      * micro numbers.
507      */
508     private int m_version_;
509     /**
510      * Map of singletons
511      */
512     private static final ConcurrentHashMap<Integer, VersionInfo> MAP_ = new ConcurrentHashMap<>();
513     /**
514      * Last byte mask
515      */
516     private static final int LAST_BYTE_MASK_ = 0xFF;
517     /**
518      * Error statement string
519      */
520     private static final String INVALID_VERSION_NUMBER_ =
521         "Invalid version number: Version number may be negative or greater than 255";
522 
523     // static declaration ------------------------------------------------
524 
525     /**
526      * Initialize versions only after MAP_ has been created
527      */
528     static {
529         UNICODE_1_0   = getInstance(1, 0, 0, 0);
530         UNICODE_1_0_1 = getInstance(1, 0, 1, 0);
531         UNICODE_1_1_0 = getInstance(1, 1, 0, 0);
532         UNICODE_1_1_5 = getInstance(1, 1, 5, 0);
533         UNICODE_2_0   = getInstance(2, 0, 0, 0);
534         UNICODE_2_1_2 = getInstance(2, 1, 2, 0);
535         UNICODE_2_1_5 = getInstance(2, 1, 5, 0);
536         UNICODE_2_1_8 = getInstance(2, 1, 8, 0);
537         UNICODE_2_1_9 = getInstance(2, 1, 9, 0);
538         UNICODE_3_0   = getInstance(3, 0, 0, 0);
539         UNICODE_3_0_1 = getInstance(3, 0, 1, 0);
540         UNICODE_3_1_0 = getInstance(3, 1, 0, 0);
541         UNICODE_3_1_1 = getInstance(3, 1, 1, 0);
542         UNICODE_3_2   = getInstance(3, 2, 0, 0);
543         UNICODE_4_0   = getInstance(4, 0, 0, 0);
544         UNICODE_4_0_1 = getInstance(4, 0, 1, 0);
545         UNICODE_4_1   = getInstance(4, 1, 0, 0);
546         UNICODE_5_0   = getInstance(5, 0, 0, 0);
547         UNICODE_5_1   = getInstance(5, 1, 0, 0);
548         UNICODE_5_2   = getInstance(5, 2, 0, 0);
549         UNICODE_6_0   = getInstance(6, 0, 0, 0);
550         UNICODE_6_1   = getInstance(6, 1, 0, 0);
551         UNICODE_6_2   = getInstance(6, 2, 0, 0);
552         UNICODE_6_3   = getInstance(6, 3, 0, 0);
553         UNICODE_7_0   = getInstance(7, 0, 0, 0);
554         UNICODE_8_0   = getInstance(8, 0, 0, 0);
555         UNICODE_9_0   = getInstance(9, 0, 0, 0);
556         UNICODE_10_0   = getInstance(10, 0, 0, 0);
557         UNICODE_11_0   = getInstance(11, 0, 0, 0);
558         UNICODE_12_0   = getInstance(12, 0, 0, 0);
559         UNICODE_12_1   = getInstance(12, 1, 0, 0);
560         UNICODE_13_0   = getInstance(13, 0, 0, 0);
561         UNICODE_14_0   = getInstance(14, 0, 0, 0);
562 
563         ICU_VERSION   = getInstance(70, 1, 0, 0);
564         ICU_DATA_VERSION = ICU_VERSION;
565         UNICODE_VERSION = UNICODE_14_0;
566 
567         UCOL_RUNTIME_VERSION = getInstance(9);
568         UCOL_BUILDER_VERSION = getInstance(9);
569         UCOL_TAILORINGS_VERSION = getInstance(1);
570     }
571 
572     // private constructor -----------------------------------------------
573 
574     /**
575      * Constructor with int
576      * @param compactversion a 32 bit int with each byte representing a number
577      */
VersionInfo(int compactversion)578     private VersionInfo(int compactversion)
579     {
580         m_version_ = compactversion;
581     }
582 
583     /**
584      * Gets the int from the version numbers
585      * @param major non-negative version number
586      * @param minor non-negative version number
587      * @param milli non-negative version number
588      * @param micro non-negative version number
589      */
getInt(int major, int minor, int milli, int micro)590     private static int getInt(int major, int minor, int milli, int micro)
591     {
592         return (major << 24) | (minor << 16) | (milli << 8) | micro;
593     }
594     ///CLOVER:OFF
595     /**
596      * Main method prints out ICU version information
597      * @param args arguments (currently not used)
598      * @stable ICU 4.6
599      */
main(String[] args)600     public static void main(String[] args) {
601         String icuApiVer;
602 
603         if (ICU_VERSION.getMajor() <= 4) {
604             if (ICU_VERSION.getMinor() % 2 != 0) {
605                 // Development mile stone
606                 int major = ICU_VERSION.getMajor();
607                 int minor = ICU_VERSION.getMinor() + 1;
608                 if (minor >= 10) {
609                     minor -= 10;
610                     major++;
611                 }
612                 icuApiVer = "" + major + "." + minor + "M" + ICU_VERSION.getMilli();
613             } else {
614                 icuApiVer = ICU_VERSION.getVersionString(2, 2);
615             }
616         } else {
617             if (ICU_VERSION.getMinor() == 0) {
618                 // Development mile stone
619                 icuApiVer = "" + ICU_VERSION.getMajor() + "M" + ICU_VERSION.getMilli();
620             } else {
621                 icuApiVer = ICU_VERSION.getVersionString(2, 2);
622             }
623         }
624 
625 
626         System.out.println("International Components for Unicode for Java " + icuApiVer);
627 
628         System.out.println("");
629         System.out.println("Implementation Version: " + ICU_VERSION.getVersionString(2, 4));
630         System.out.println("Unicode Data Version:   " + UNICODE_VERSION.getVersionString(2, 4));
631         System.out.println("CLDR Data Version:      " + LocaleData.getCLDRVersion().getVersionString(2, 4));
632         System.out.println("Time Zone Data Version: " + getTZDataVersion());
633     }
634 
635     /**
636      * Generate version string separated by dots with
637      * the specified digit width.  Version digit 0
638      * after <code>minDigits</code> will be trimmed off.
639      * @param minDigits Minimum number of version digits
640      * @param maxDigits Maximum number of version digits
641      * @return A tailored version string
642      * @internal
643      * @deprecated This API is ICU internal only. (For use in CLDR, etc.)
644      */
645     @Deprecated
getVersionString(int minDigits, int maxDigits)646     public String getVersionString(int minDigits, int maxDigits) {
647         if (minDigits < 1 || maxDigits < 1
648                 || minDigits > 4 || maxDigits > 4 || minDigits > maxDigits) {
649             throw new IllegalArgumentException("Invalid min/maxDigits range");
650         }
651 
652         int[] digits = new int[4];
653         digits[0] = getMajor();
654         digits[1] = getMinor();
655         digits[2] = getMilli();
656         digits[3] = getMicro();
657 
658         int numDigits = maxDigits;
659         while (numDigits > minDigits) {
660             if (digits[numDigits - 1] != 0) {
661                 break;
662             }
663             numDigits--;
664         }
665 
666         StringBuilder verStr = new StringBuilder(7);
667         verStr.append(digits[0]);
668         for (int i = 1; i < numDigits; i++) {
669             verStr.append(".");
670             verStr.append(digits[i]);
671         }
672 
673         return verStr.toString();
674     }
675     ///CLOVER:ON
676 
677 
678     // Moved from TimeZone class
679     private static volatile String TZDATA_VERSION = null;
680 
getTZDataVersion()681     static String getTZDataVersion() {
682         if (TZDATA_VERSION == null) {
683             synchronized (VersionInfo.class) {
684                 if (TZDATA_VERSION == null) {
685                     UResourceBundle tzbundle = UResourceBundle.getBundleInstance("com/ibm/icu/impl/data/icudt"
686                             + VersionInfo.ICU_DATA_VERSION_PATH, "zoneinfo64");
687                     TZDATA_VERSION = tzbundle.getString("TZVersion");
688                 }
689             }
690         }
691         return TZDATA_VERSION;
692     }
693 }
694