package org.limewire.util; /** * Compares versions using major, minor, service and revision values. You must * include a major version in the string, however you may omit the other * fields. When applicable, the string version must have a dot between the * major, minor and service, however any-non digit separates service from * revision. * <table> * <tr><td><b>String</b></td> <td><b>Major</b></td><td><b>Minor</b></td><td><b>Service</b></td><td><b>Revision</b></td></tr> * <tr><td>1</td> <td>1</td> <td>0</td> <td>0</td> <td>0</td></tr> * <tr><td>1.2</td> <td>1</td> <td>2</td> <td>0</td> <td>0</td></tr> * <tr><td>1.2.3</td> <td>1</td> <td>2</td> <td>3</td> <td>0</td></tr> * <tr><td>1.2.3_4</td> <td>1</td> <td>2</td> <td>3</td> <td>4</td></tr> * <tr><td>1.2.3a</td> <td>1</td> <td>2</td> <td>3</td> <td>0</td></tr> * <tr><td>1.2.3_4a</td> <td>1</td> <td>2</td> <td>3</td> <td>4</td></tr> * <tr><td>1.2.3 A</td> <td>1</td> <td>2</td> <td>3</td> <td>0</td></tr> * <tr><td>1.2.3a4</td> <td>1</td> <td>2</td> <td>3</td> <td>4</td></tr> * </table> * <p> Unsupported versions include: <i>1a</i>, <i>1.2a</i>, <i>1.a</i>, <i>1.2.a</i>, etc. */ public class Version implements Comparable<Version> { /** * The version string. */ private final String v; /** * The major version. * X in X.Y.Z_r */ private final int major; /** * The minor version. * Y in X.Y.Z_r */ private final int minor; /** * The service version. * Z in X.Y.Z_r */ private final int service; /** * The revision. * r in X.Y.Z_r */ private final int revision; /** * Constructs a new Version. */ public Version(String s) throws VersionFormatException { v = s; int[] nums = parse(s); major = nums[0]; minor = nums[1]; service = nums[2]; revision = nums[3]; } public int getMajor() { return major; } public int getMinor() { return minor; } public int getService() { return service; } public int getRevision() { return revision; } /** * Returns the version. */ public String getVersion() { return v; } /** * Returns the version. */ @Override public String toString() { return getVersion(); } /** * Compares two versions. */ public int compareTo(Version other) { int retVal; if(major == other.major) if(minor == other.minor) if(service == other.service) // if revision == other.revision // return 0; // else retVal = revision - other.revision; else retVal = service - other.service; else retVal = minor - other.minor; else retVal = major - other.major; return retVal; } /** * Equality. */ @Override public boolean equals(Object o) { return compareTo((Version)o) == 0; } /** * Parses a version for major/minor/service & revision. * Only Major is required. If Minor, Service or Revision don't exist, * they are assumed to be 0. */ private int[] parse(String vers) throws VersionFormatException { int major, minor, service, revision; int dot1, dot2, lastNum; dot1 = vers.indexOf("."); if(dot1 != -1) { dot2 = vers.indexOf(".", dot1 + 1); if(dot2 == -1) dot2 = vers.length(); } else { dot1 = vers.length(); dot2 = -1; } try { major = Integer.parseInt(vers.substring(0, dot1)); } catch(NumberFormatException nfe) { throw new VersionFormatException(vers); } minor = 0; service = 0; revision = 0; if(dot2 != -1) { try { minor = Integer.parseInt(vers.substring(dot1 + 1, dot2)); } catch(NumberFormatException nfe) { throw new VersionFormatException(vers); } try { int q = dot2 + 1; // advance to the first digit while(q < vers.length() && Character.isDigit(vers.charAt(q))) q++; lastNum = q; if(q <= vers.length()) service = Integer.parseInt(vers.substring(dot2 + 1, q)); } catch(NumberFormatException nfe) { throw new VersionFormatException(vers); } try { int q = lastNum + 1; // advance to the first digit while (q < vers.length() && !Character.isDigit(vers.charAt(q))) q++; int p = q; // advance to the first non-digit while(p < vers.length() && Character.isDigit(vers.charAt(p))) p++; if(q < vers.length() && p <= vers.length()) revision = Integer.parseInt(vers.substring(q, p)); } catch(NumberFormatException okay) { // not everything will have a revision digit. } } return new int[] { major, minor, service, revision }; } }