• 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      * Unicode 15.0 version
210      * @stable ICU 72
211      */
212     public static final VersionInfo UNICODE_15_0;
213 
214     /**
215      * ICU4J current release version
216      * @stable ICU 2.8
217      */
218     public static final VersionInfo ICU_VERSION;
219 
220     /**
221      * Data version string for ICU's internal data.
222      * Used for appending to data path (e.g. icudt43b)
223      * @internal
224      * @deprecated This API is ICU internal only.
225      */
226     @Deprecated
227     public static final String ICU_DATA_VERSION_PATH = "72b";
228 
229     /**
230      * Data version in ICU4J.
231      * @internal
232      * @deprecated This API is ICU internal only.
233      */
234     @Deprecated
235     public static final VersionInfo ICU_DATA_VERSION;
236 
237     /**
238      * Collation runtime version (sort key generator, string comparisons).
239      * If the version is different, sort keys for the same string could be different.
240      * This value may change in subsequent releases of ICU.
241      * @stable ICU 2.8
242      */
243     public static final VersionInfo UCOL_RUNTIME_VERSION;
244 
245     /**
246      * Collation builder code version.
247      * When this is different, the same tailoring might result
248      * in assigning different collation elements to code points.
249      * This value may change in subsequent releases of ICU.
250      * @stable ICU 2.8
251      */
252     public static final VersionInfo UCOL_BUILDER_VERSION;
253 
254     /**
255      * Constant version 1.
256      * This was intended to be the version of collation tailorings,
257      * but instead the tailoring data carries a version number.
258      * @deprecated ICU 54
259      */
260     @Deprecated
261     public static final VersionInfo UCOL_TAILORINGS_VERSION;
262 
263 
264     // public methods ------------------------------------------------------
265 
266     /**
267      * Returns an instance of VersionInfo with the argument version.
268      * @param version version String in the format of "major.minor.milli.micro"
269      *                or "major.minor.milli" or "major.minor" or "major",
270      *                where major, minor, milli, micro are non-negative numbers
271      *                &lt;= 255. If the trailing version numbers are
272      *                not specified they are taken as 0s. E.g. Version "3.1" is
273      *                equivalent to "3.1.0.0".
274      * @return an instance of VersionInfo with the argument version.
275      * @exception IllegalArgumentException when the argument version
276      *                is not in the right format
277      * @stable ICU 2.6
278      */
getInstance(String version)279     public static VersionInfo getInstance(String version)
280     {
281         int length  = version.length();
282         int array[] = {0, 0, 0, 0};
283         int count   = 0;
284         int index   = 0;
285 
286         while (count < 4 && index < length) {
287             char c = version.charAt(index);
288             if (c == '.') {
289                 count ++;
290             }
291             else {
292                 c -= '0';
293                 if (c < 0 || c > 9) {
294                     throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
295                 }
296                 array[count] *= 10;
297                 array[count] += c;
298             }
299             index ++;
300         }
301         if (index != length) {
302             throw new IllegalArgumentException(
303                                                "Invalid version number: String '" + version + "' exceeds version format");
304         }
305         for (int i = 0; i < 4; i ++) {
306             if (array[i] < 0 || array[i] > 255) {
307                 throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
308             }
309         }
310 
311         return getInstance(array[0], array[1], array[2], array[3]);
312     }
313 
314     /**
315      * Returns an instance of VersionInfo with the argument version.
316      * @param major major version, non-negative number &lt;= 255.
317      * @param minor minor version, non-negative number &lt;= 255.
318      * @param milli milli version, non-negative number &lt;= 255.
319      * @param micro micro version, non-negative number &lt;= 255.
320      * @exception IllegalArgumentException when either arguments are negative or &gt; 255
321      * @stable ICU 2.6
322      */
getInstance(int major, int minor, int milli, int micro)323     public static VersionInfo getInstance(int major, int minor, int milli,
324                                           int micro)
325     {
326         // checks if it is in the hashmap
327         // else
328         if (major < 0 || major > 255 || minor < 0 || minor > 255 ||
329             milli < 0 || milli > 255 || micro < 0 || micro > 255) {
330             throw new IllegalArgumentException(INVALID_VERSION_NUMBER_);
331         }
332         int     version = getInt(major, minor, milli, micro);
333         Integer key     = Integer.valueOf(version);
334         VersionInfo  result  = MAP_.get(key);
335         if (result == null) {
336             result = new VersionInfo(version);
337             VersionInfo tmpvi = MAP_.putIfAbsent(key, result);
338             if (tmpvi != null) {
339                 result = tmpvi;
340             }
341         }
342         return result;
343     }
344 
345     /**
346      * Returns an instance of VersionInfo with the argument version.
347      * Equivalent to getInstance(major, minor, milli, 0).
348      * @param major major version, non-negative number &lt;= 255.
349      * @param minor minor version, non-negative number &lt;= 255.
350      * @param milli milli version, non-negative number &lt;= 255.
351      * @exception IllegalArgumentException when either arguments are
352      *                                     negative or &gt; 255
353      * @stable ICU 2.6
354      */
getInstance(int major, int minor, int milli)355     public static VersionInfo getInstance(int major, int minor, int milli)
356     {
357         return getInstance(major, minor, milli, 0);
358     }
359 
360     /**
361      * Returns an instance of VersionInfo with the argument version.
362      * Equivalent to getInstance(major, minor, 0, 0).
363      * @param major major version, non-negative number &lt;= 255.
364      * @param minor minor version, non-negative number &lt;= 255.
365      * @exception IllegalArgumentException when either arguments are
366      *                                     negative or &gt; 255
367      * @stable ICU 2.6
368      */
getInstance(int major, int minor)369     public static VersionInfo getInstance(int major, int minor)
370     {
371         return getInstance(major, minor, 0, 0);
372     }
373 
374     /**
375      * Returns an instance of VersionInfo with the argument version.
376      * Equivalent to getInstance(major, 0, 0, 0).
377      * @param major major version, non-negative number &lt;= 255.
378      * @exception IllegalArgumentException when either arguments are
379      *                                     negative or &gt; 255
380      * @stable ICU 2.6
381      */
getInstance(int major)382     public static VersionInfo getInstance(int major)
383     {
384         return getInstance(major, 0, 0, 0);
385     }
386 
387     /**
388      * Returns the String representative of VersionInfo in the format of
389      * "major.minor.milli.micro"
390      * @return String representative of VersionInfo
391      * @stable ICU 2.6
392      */
393     @Override
toString()394     public String toString()
395     {
396         StringBuilder result = new StringBuilder(7);
397         result.append(getMajor());
398         result.append('.');
399         result.append(getMinor());
400         result.append('.');
401         result.append(getMilli());
402         result.append('.');
403         result.append(getMicro());
404         return result.toString();
405     }
406 
407     /**
408      * Returns the major version number
409      * @return the major version number
410      * @stable ICU 2.6
411      */
getMajor()412     public int getMajor()
413     {
414         return (m_version_ >> 24) & LAST_BYTE_MASK_ ;
415     }
416 
417     /**
418      * Returns the minor version number
419      * @return the minor version number
420      * @stable ICU 2.6
421      */
getMinor()422     public int getMinor()
423     {
424         return (m_version_ >> 16) & LAST_BYTE_MASK_ ;
425     }
426 
427     /**
428      * Returns the milli version number
429      * @return the milli version number
430      * @stable ICU 2.6
431      */
getMilli()432     public int getMilli()
433     {
434         return (m_version_ >> 8) & LAST_BYTE_MASK_ ;
435     }
436 
437     /**
438      * Returns the micro version number
439      * @return the micro version number
440      * @stable ICU 2.6
441      */
getMicro()442     public int getMicro()
443     {
444         return m_version_ & LAST_BYTE_MASK_ ;
445     }
446 
447     /**
448      * Checks if this version information is equals to the argument version
449      * @param other object to be compared
450      * @return true if other is equals to this object's version information,
451      *         false otherwise
452      * @stable ICU 2.6
453      */
454     @Override
equals(Object other)455     public boolean equals(Object other)
456     {
457         return other == this;
458     }
459 
460     /**
461      * Returns the hash code value for this set.
462      *
463      * @return the hash code value for this set.
464      * @see java.lang.Object#hashCode()
465      * @stable ICU 2.6
466      */
467     @Override
hashCode()468     public int hashCode() {
469         return m_version_;
470     }
471 
472     /**
473      * Compares other with this VersionInfo.
474      * @param other VersionInfo to be compared
475      * @return 0 if the argument is a VersionInfo object that has version
476      *           information equals to this object.
477      *           Less than 0 if the argument is a VersionInfo object that has
478      *           version information greater than this object.
479      *           Greater than 0 if the argument is a VersionInfo object that
480      *           has version information less than this object.
481      * @stable ICU 2.6
482      */
483     @Override
compareTo(VersionInfo other)484     public int compareTo(VersionInfo other)
485     {
486         // m_version_ is an int, a signed 32-bit integer.
487         // When the major version is >=128, then the version int is negative.
488         // Compare it in two steps to simulate an unsigned-int comparison.
489         // (Alternatively we could turn each int into a long and reset the upper 32 bits.)
490         // Compare the upper bits first, using logical shift right (unsigned).
491         int diff = (m_version_ >>> 1) - (other.m_version_ >>> 1);
492         if (diff != 0) { return diff; }
493         // Compare the remaining bits.
494         return (m_version_ & 1) - (other.m_version_ & 1);
495     }
496 
497     // private data members ----------------------------------------------
498 
499     /**
500      * Unicode data version used by the current release.
501      * Defined here privately for printing by the main() method in this class.
502      * Should be the same as {@link com.ibm.icu.lang.UCharacter#getUnicodeVersion()}
503      * which gets the version number from a data file.
504      * We do not want VersionInfo to have an import dependency on UCharacter.
505      */
506     private static final VersionInfo UNICODE_VERSION;
507 
508     /**
509      * Version number stored as a byte for each of the major, minor, milli and
510      * micro numbers in the 32 bit int.
511      * Most significant for the major and the least significant contains the
512      * micro numbers.
513      */
514     private int m_version_;
515     /**
516      * Map of singletons
517      */
518     private static final ConcurrentHashMap<Integer, VersionInfo> MAP_ = new ConcurrentHashMap<>();
519     /**
520      * Last byte mask
521      */
522     private static final int LAST_BYTE_MASK_ = 0xFF;
523     /**
524      * Error statement string
525      */
526     private static final String INVALID_VERSION_NUMBER_ =
527         "Invalid version number: Version number may be negative or greater than 255";
528 
529     // static declaration ------------------------------------------------
530 
531     /**
532      * Initialize versions only after MAP_ has been created
533      */
534     static {
535         UNICODE_1_0   = getInstance(1, 0, 0, 0);
536         UNICODE_1_0_1 = getInstance(1, 0, 1, 0);
537         UNICODE_1_1_0 = getInstance(1, 1, 0, 0);
538         UNICODE_1_1_5 = getInstance(1, 1, 5, 0);
539         UNICODE_2_0   = getInstance(2, 0, 0, 0);
540         UNICODE_2_1_2 = getInstance(2, 1, 2, 0);
541         UNICODE_2_1_5 = getInstance(2, 1, 5, 0);
542         UNICODE_2_1_8 = getInstance(2, 1, 8, 0);
543         UNICODE_2_1_9 = getInstance(2, 1, 9, 0);
544         UNICODE_3_0   = getInstance(3, 0, 0, 0);
545         UNICODE_3_0_1 = getInstance(3, 0, 1, 0);
546         UNICODE_3_1_0 = getInstance(3, 1, 0, 0);
547         UNICODE_3_1_1 = getInstance(3, 1, 1, 0);
548         UNICODE_3_2   = getInstance(3, 2, 0, 0);
549         UNICODE_4_0   = getInstance(4, 0, 0, 0);
550         UNICODE_4_0_1 = getInstance(4, 0, 1, 0);
551         UNICODE_4_1   = getInstance(4, 1, 0, 0);
552         UNICODE_5_0   = getInstance(5, 0, 0, 0);
553         UNICODE_5_1   = getInstance(5, 1, 0, 0);
554         UNICODE_5_2   = getInstance(5, 2, 0, 0);
555         UNICODE_6_0   = getInstance(6, 0, 0, 0);
556         UNICODE_6_1   = getInstance(6, 1, 0, 0);
557         UNICODE_6_2   = getInstance(6, 2, 0, 0);
558         UNICODE_6_3   = getInstance(6, 3, 0, 0);
559         UNICODE_7_0   = getInstance(7, 0, 0, 0);
560         UNICODE_8_0   = getInstance(8, 0, 0, 0);
561         UNICODE_9_0   = getInstance(9, 0, 0, 0);
562         UNICODE_10_0   = getInstance(10, 0, 0, 0);
563         UNICODE_11_0   = getInstance(11, 0, 0, 0);
564         UNICODE_12_0   = getInstance(12, 0, 0, 0);
565         UNICODE_12_1   = getInstance(12, 1, 0, 0);
566         UNICODE_13_0   = getInstance(13, 0, 0, 0);
567         UNICODE_14_0   = getInstance(14, 0, 0, 0);
568         UNICODE_15_0   = getInstance(15, 0, 0, 0);
569 
570         ICU_VERSION   = getInstance(72, 1, 0, 0);
571         ICU_DATA_VERSION = ICU_VERSION;
572         UNICODE_VERSION = UNICODE_15_0;
573 
574         UCOL_RUNTIME_VERSION = getInstance(9);
575         UCOL_BUILDER_VERSION = getInstance(9);
576         UCOL_TAILORINGS_VERSION = getInstance(1);
577     }
578 
579     // private constructor -----------------------------------------------
580 
581     /**
582      * Constructor with int
583      * @param compactversion a 32 bit int with each byte representing a number
584      */
VersionInfo(int compactversion)585     private VersionInfo(int compactversion)
586     {
587         m_version_ = compactversion;
588     }
589 
590     /**
591      * Gets the int from the version numbers
592      * @param major non-negative version number
593      * @param minor non-negative version number
594      * @param milli non-negative version number
595      * @param micro non-negative version number
596      */
getInt(int major, int minor, int milli, int micro)597     private static int getInt(int major, int minor, int milli, int micro)
598     {
599         return (major << 24) | (minor << 16) | (milli << 8) | micro;
600     }
601     ///CLOVER:OFF
602     /**
603      * Main method prints out ICU version information
604      * @param args arguments (currently not used)
605      * @stable ICU 4.6
606      */
main(String[] args)607     public static void main(String[] args) {
608         String icuApiVer;
609 
610         if (ICU_VERSION.getMajor() <= 4) {
611             if (ICU_VERSION.getMinor() % 2 != 0) {
612                 // Development mile stone
613                 int major = ICU_VERSION.getMajor();
614                 int minor = ICU_VERSION.getMinor() + 1;
615                 if (minor >= 10) {
616                     minor -= 10;
617                     major++;
618                 }
619                 icuApiVer = "" + major + "." + minor + "M" + ICU_VERSION.getMilli();
620             } else {
621                 icuApiVer = ICU_VERSION.getVersionString(2, 2);
622             }
623         } else {
624             if (ICU_VERSION.getMinor() == 0) {
625                 // Development mile stone
626                 icuApiVer = "" + ICU_VERSION.getMajor() + "M" + ICU_VERSION.getMilli();
627             } else {
628                 icuApiVer = ICU_VERSION.getVersionString(2, 2);
629             }
630         }
631 
632 
633         System.out.println("International Components for Unicode for Java " + icuApiVer);
634 
635         System.out.println("");
636         System.out.println("Implementation Version: " + ICU_VERSION.getVersionString(2, 4));
637         System.out.println("Unicode Data Version:   " + UNICODE_VERSION.getVersionString(2, 4));
638         System.out.println("CLDR Data Version:      " + LocaleData.getCLDRVersion().getVersionString(2, 4));
639         System.out.println("Time Zone Data Version: " + getTZDataVersion());
640     }
641 
642     /**
643      * Generate version string separated by dots with
644      * the specified digit width.  Version digit 0
645      * after <code>minDigits</code> will be trimmed off.
646      * @param minDigits Minimum number of version digits
647      * @param maxDigits Maximum number of version digits
648      * @return A tailored version string
649      * @internal
650      * @deprecated This API is ICU internal only. (For use in CLDR, etc.)
651      */
652     @Deprecated
getVersionString(int minDigits, int maxDigits)653     public String getVersionString(int minDigits, int maxDigits) {
654         if (minDigits < 1 || maxDigits < 1
655                 || minDigits > 4 || maxDigits > 4 || minDigits > maxDigits) {
656             throw new IllegalArgumentException("Invalid min/maxDigits range");
657         }
658 
659         int[] digits = new int[4];
660         digits[0] = getMajor();
661         digits[1] = getMinor();
662         digits[2] = getMilli();
663         digits[3] = getMicro();
664 
665         int numDigits = maxDigits;
666         while (numDigits > minDigits) {
667             if (digits[numDigits - 1] != 0) {
668                 break;
669             }
670             numDigits--;
671         }
672 
673         StringBuilder verStr = new StringBuilder(7);
674         verStr.append(digits[0]);
675         for (int i = 1; i < numDigits; i++) {
676             verStr.append(".");
677             verStr.append(digits[i]);
678         }
679 
680         return verStr.toString();
681     }
682     ///CLOVER:ON
683 
684 
685     // Moved from TimeZone class
686     private static volatile String TZDATA_VERSION = null;
687 
getTZDataVersion()688     static String getTZDataVersion() {
689         if (TZDATA_VERSION == null) {
690             synchronized (VersionInfo.class) {
691                 if (TZDATA_VERSION == null) {
692                     UResourceBundle tzbundle = UResourceBundle.getBundleInstance("com/ibm/icu/impl/data/icudt"
693                             + VersionInfo.ICU_DATA_VERSION_PATH, "zoneinfo64");
694                     TZDATA_VERSION = tzbundle.getString("TZVersion");
695                 }
696             }
697         }
698         return TZDATA_VERSION;
699     }
700 }
701