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 * <= 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 <= 255. 287 * @param minor minor version, non-negative number <= 255. 288 * @param milli milli version, non-negative number <= 255. 289 * @param micro micro version, non-negative number <= 255. 290 * @exception IllegalArgumentException when either arguments are negative or > 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 <= 255. 319 * @param minor minor version, non-negative number <= 255. 320 * @param milli milli version, non-negative number <= 255. 321 * @exception IllegalArgumentException when either arguments are 322 * negative or > 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 <= 255. 334 * @param minor minor version, non-negative number <= 255. 335 * @exception IllegalArgumentException when either arguments are 336 * negative or > 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 <= 255. 348 * @exception IllegalArgumentException when either arguments are 349 * negative or > 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