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