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