Back to index

lightning-sunbird  0.9+nobinonly
VersionComparator.java
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Java XPCOM Bindings.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * IBM Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2005
00019  * IBM Corporation. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Javier Pedemonte (jhpedemonte@gmail.com)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 package org.mozilla.xpcom;
00039 
00040 import java.util.Enumeration;
00041 import java.util.StringTokenizer;
00042 
00043 import org.mozilla.interfaces.nsISupports;
00044 import org.mozilla.interfaces.nsIVersionComparator;
00045 
00046 
00076 public class VersionComparator implements nsIVersionComparator {
00077 
00078   public nsISupports queryInterface(String aIID) {
00079     return Mozilla.queryInterface(this, aIID);
00080   }
00081 
00090   public int compare(String A, String B) {
00091     int result;
00092     String a = A, b = B;
00093 
00094     do {
00095       VersionPart va = new VersionPart();
00096       VersionPart vb = new VersionPart();
00097       a = parseVersionPart(a, va);
00098       b = parseVersionPart(b, vb);
00099 
00100       result = compareVersionPart(va, vb);
00101       if (result != 0) {
00102         break;
00103       }
00104     } while (a != null || b != null);
00105 
00106     return result;
00107   }
00108 
00109   private class VersionPart {
00110     int     numA = 0;
00111     String  strB;
00112     int     numC = 0;
00113     String  extraD;
00114   }
00115 
00116   private static String parseVersionPart(String aVersion, VersionPart result) {
00117     if (aVersion == null || aVersion.length() == 0) {
00118       return aVersion;
00119     }
00120 
00121     StringTokenizer tok = new StringTokenizer(aVersion.trim(), ".");
00122     String part = tok.nextToken();
00123 
00124     if (part.equals("*")) {
00125       result.numA = Integer.MAX_VALUE;
00126       result.strB = "";
00127     } else {
00128       VersionPartTokenizer vertok = new VersionPartTokenizer(part);
00129       try {
00130         result.numA = Integer.parseInt(vertok.nextToken());
00131       } catch (NumberFormatException e) {
00132         // parsing error; default to zero like 'strtol' C function
00133         result.numA = 0;
00134       }
00135 
00136       if (vertok.hasMoreElements()) {
00137         String str = vertok.nextToken();
00138 
00139         // if part is of type "<num>+"
00140         if (str.charAt(0) == '+') {
00141           result.numA++;
00142           result.strB = "pre";
00143         } else {
00144           // else if part is of type "<num><alpha>..."
00145           result.strB = str;
00146 
00147           if (vertok.hasMoreTokens()) {
00148             try {
00149               result.numC = Integer.parseInt(vertok.nextToken());
00150             } catch (NumberFormatException e) {
00151               // parsing error; default to zero like 'strtol' C function
00152               result.numC = 0;
00153             }
00154             if (vertok.hasMoreTokens()) {
00155               result.extraD = vertok.getRemainder();
00156             }
00157           }
00158         }
00159       }
00160     }
00161 
00162     if (tok.hasMoreTokens()) {
00163       // return everything after "."
00164       return aVersion.substring(part.length() + 1);
00165     }
00166     return null;
00167   }
00168 
00169   private int compareVersionPart(VersionPart va, VersionPart vb) {
00170     int res = compareInt(va.numA, vb.numA);
00171     if (res != 0) {
00172       return res;
00173     }
00174 
00175     res = compareString(va.strB, vb.strB);
00176     if (res != 0) {
00177       return res;
00178     }
00179 
00180     res = compareInt(va.numC, vb.numC);
00181     if (res != 0) {
00182       return res;
00183     }
00184 
00185     return compareString(va.extraD, vb.extraD);
00186   }
00187 
00188   private int compareInt(int n1, int n2) {
00189     return n1 - n2;
00190   }
00191 
00192   private int compareString(String str1, String str2) {
00193     // any string is *before* no string
00194     if (str1 == null) {
00195       return (str2 != null) ? 1 : 0;
00196     }
00197 
00198     if (str2 == null) {
00199       return -1;
00200     }
00201 
00202     return str1.compareTo(str2);
00203   }
00204 
00205 }
00206 
00213 class VersionPartTokenizer implements Enumeration {
00214 
00215   String part;
00216 
00217   public VersionPartTokenizer(String aPart) {
00218     part = aPart;
00219   }
00220 
00221   public boolean hasMoreElements() {
00222     return part.length() != 0;
00223   }
00224 
00225   public boolean hasMoreTokens() {
00226     return part.length() != 0;
00227   }
00228 
00229   public Object nextElement() {
00230     if (part.matches("[\\+\\-]?[0-9].*")) {
00231       // if string starts with a number...
00232       int index = 0;
00233       if (part.charAt(0) == '+' || part.charAt(0) == '-') {
00234         index = 1;
00235       }
00236 
00237       while (index < part.length() && Character.isDigit(part.charAt(index))) {
00238         index++;
00239       }
00240 
00241       String numPart = part.substring(0, index);
00242       part = part.substring(index);
00243       return numPart;
00244     } else {
00245       // ... or if this is the non-numeric part of version string
00246       int index = 0;
00247       while (index < part.length() && !Character.isDigit(part.charAt(index))) {
00248         index++;
00249       }
00250 
00251       String alphaPart = part.substring(0, index);
00252       part = part.substring(index);
00253       return alphaPart;
00254     }
00255   }
00256 
00257   public String nextToken() {
00258     return (String) nextElement();
00259   }
00260 
00268   public String getRemainder() {
00269     return part;
00270   }
00271 
00272 }
00273