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