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