View Javadoc

1   /* Generated By:JavaCC: Do not edit this line. VersionParser.java */
2   /*
3    *   Copyright (C) Christian Schulte, 2005-206
4    *   All rights reserved.
5    *
6    *   Redistribution and use in source and binary forms, with or without
7    *   modification, are permitted provided that the following conditions
8    *   are met:
9    *
10   *     o Redistributions of source code must retain the above copyright
11   *       notice, this list of conditions and the following disclaimer.
12   *
13   *     o Redistributions in binary form must reproduce the above copyright
14   *       notice, this list of conditions and the following disclaimer in
15   *       the documentation and/or other materials provided with the
16   *       distribution.
17   *
18   *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19   *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20   *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
22   *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23   *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24   *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25   *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26   *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27   *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28   *
29   *   $JOMC: VersionParser.jj 3862 2011-10-12 12:37:40Z schulte2005 $
30   *
31   */
32  package org.jomc.util;
33  
34  import java.io.StringReader;
35  import java.text.MessageFormat;
36  import java.text.NumberFormat;
37  import java.util.List;
38  import java.util.LinkedList;
39  import java.util.Locale;
40  import java.util.ResourceBundle;
41  
42  /**
43   * Parses and compares version identifiers.
44   * <p><blockquote><pre>
45   * Version    ::= Token ( ( &lt;SEPARATOR&gt; )* Token )* &lt;EOF&gt;
46   * Token      ::= &lt;INTEGER&gt;
47   *              | &lt;IDENTIFIER&gt;
48   * </pre></blockquote></p>
49   * <p>
50   * A separator character is defined as<blockquote><pre>
51   * [".","_","-","@","/","\\"," ","\t","\n","\r","\f","\b","\"","\'"]</pre></blockquote>
52   * An integer is a sequence of digits. An identifier is everything else, not
53   * a separator character or an integer.
54   * </p>
55   *
56   * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
57   * @version $JOMC: VersionParser.jj 3862 2011-10-12 12:37:40Z schulte2005 $
58   * @see #compare(String, String)
59   */
60  public final class VersionParser implements VersionParserConstants {
61  
62      /**
63       * Parses the input to produce an array of tokens.
64       *
65       * @return The parsed tokens.
66       *
67       * @throws ParseException if the parse fails.
68       * @throws TokenMgrError for any invalid tokens.
69       */
70      public Token[] parse() throws ParseException, TokenMgrError
71      {
72          return this.Version();
73      }
74  
75      /**
76       * Compares two versions for order.
77       * <p>This method parses the given strings to produce a sequence of tokens and then compares these tokens for
78       * order.</p>
79       *
80       * @param v1 The version to compare with.
81       * @param v2 The version to compare to.
82       *
83       * @return A negative integer, zero, or a positive integer as the first version is less than, equal to, or greater
84       * than the second.
85       *
86       * @throws NullPointerException if {@code v1} or {@code v2} is {@code null}.
87       * @throws ParseException if parsing fails.
88       * @throws TokenMgrError for any invalid tokens.
89       */
90      public static int compare( final String v1, final String v2 ) throws ParseException, TokenMgrError
91      {
92          if ( v1 == null )
93          {
94              throw new NullPointerException( "v1" );
95          }
96          if ( v2 == null )
97          {
98              throw new NullPointerException( "v2" );
99          }
100 
101         try
102         {
103             final NumberFormat format = NumberFormat.getNumberInstance( Locale.ENGLISH );
104             final StringReader v1Reader = new StringReader( v1 );
105             final VersionParser versionParser = new VersionParser( v1Reader );
106             final Token[] c = versionParser.parse();
107             final StringReader v2Reader = new StringReader( v2 );
108             versionParser.ReInit( v2Reader );
109             final Token[] r = versionParser.parse();
110             final int len = Math.max( c.length, r.length );
111             int result = 0;
112 
113             v1Reader.close();
114             v2Reader.close();
115 
116             for ( int i = 0; i < len; i++ )
117             {
118                 final Token current;
119                 final Token spec;
120 
121                 if ( i < c.length )
122                 {
123                     current = c[i];
124                 }
125                 else
126                 {
127                     current = new Token();
128                     current.kind = r[i].kind;
129 
130                     if ( r[i].kind == VersionParserConstants.IDENTIFIER )
131                     {
132                         // If a version has less tokens than another, comparison is stopped
133                         // at the first identifier. Remaining tokens are considered suffices
134                         // less than the shorter version.
135                         result = 1;
136                         break;
137                     }
138                     else if ( r[i].kind == VersionParserConstants.INTEGER )
139                     {
140                         current.image = "0";
141                     }
142                 }
143 
144                 if ( i < r.length )
145                 {
146                     spec = r[i];
147                 }
148                 else
149                 {
150                     spec = new Token();
151                     spec.kind = c[i].kind;
152 
153                     if ( c[i].kind == VersionParserConstants.IDENTIFIER )
154                     {
155                         // If a version has less tokens than another, comparison is stopped
156                         // at the first identifier. Remaining tokens are considered suffices
157                         // less than the shorter version.
158                         result = -1;
159                         break;
160                     }
161                     else if ( c[i].kind == VersionParserConstants.INTEGER )
162                     {
163                         spec.image = "0";
164                     }
165                 }
166 
167                 if ( current.kind != spec.kind )
168                 {
169                     throw new ParseException( getMessage( "cannotCompare", current.image, spec.image, v1, v2 ) );
170                 }
171 
172                 if ( current.kind == VersionParserConstants.IDENTIFIER )
173                 {
174                     result = current.image.compareTo( spec.image );
175                     if ( result != 0 )
176                     {
177                         break;
178                     }
179                 }
180                 else if ( current.kind == VersionParserConstants.INTEGER )
181                 {
182                     final Long m = (Long) format.parse( current.image );
183                     final Long n = (Long) format.parse( spec.image );
184 
185                     result = m.compareTo( n );
186 
187                     if ( result != 0 )
188                     {
189                         break;
190                     }
191                 }
192                 else
193                 {
194                     // Unsupported tokens are compared lexicographically by default.
195                     result = current.image.compareTo( spec.image );
196                     if ( result != 0 )
197                     {
198                         break;
199                     }
200                 }
201             }
202 
203             return result;
204         }
205         catch ( java.text.ParseException e )
206         {
207             throw new ParseException( e.getMessage() );
208         }
209     }
210 
211     private static String getMessage( final String key, final Object... arguments )
212     {
213         return MessageFormat.format( ResourceBundle.getBundle( VersionParser.class.getName().replace( '.', '/' ),
214                                                                Locale.getDefault() ).getString( key ),
215                                      arguments );
216 
217     }
218 
219   final private Token[] Version() throws ParseException {
220     final List tokens = new LinkedList();
221     Token(tokens);
222     label_1:
223     while (true) {
224       switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
225       case INTEGER:
226       case SEPARATOR:
227       case IDENTIFIER:
228         ;
229         break;
230       default:
231         jj_la1[0] = jj_gen;
232         break label_1;
233       }
234       label_2:
235       while (true) {
236         switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
237         case SEPARATOR:
238           ;
239           break;
240         default:
241           jj_la1[1] = jj_gen;
242           break label_2;
243         }
244         jj_consume_token(SEPARATOR);
245       }
246       Token(tokens);
247     }
248     jj_consume_token(0);
249     {if (true) return (Token[]) tokens.toArray(new Token[tokens.size()]);}
250     throw new Error("Missing return statement in function");
251   }
252 
253   final private void Token(final List tokens) throws ParseException {
254     Token part;
255     switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
256     case INTEGER:
257       part = jj_consume_token(INTEGER);
258                      tokens.add ( part );
259       break;
260     case IDENTIFIER:
261       part = jj_consume_token(IDENTIFIER);
262                         tokens.add( part );
263       break;
264     default:
265       jj_la1[2] = jj_gen;
266       jj_consume_token(-1);
267       throw new ParseException();
268     }
269   }
270 
271   /** Generated Token Manager. */
272   public VersionParserTokenManager token_source;
273   SimpleCharStream jj_input_stream;
274   /** Current token. */
275   public Token token;
276   /** Next token. */
277   public Token jj_nt;
278   private int jj_ntk;
279   private int jj_gen;
280   final private int[] jj_la1 = new int[3];
281   static private int[] jj_la1_0;
282   static {
283       jj_la1_init_0();
284    }
285    private static void jj_la1_init_0() {
286       jj_la1_0 = new int[] {0xe,0x4,0xa,};
287    }
288 
289   /** Constructor with InputStream. */
290   public VersionParser(java.io.InputStream stream) {
291      this(stream, null);
292   }
293   /** Constructor with InputStream and supplied encoding */
294   public VersionParser(java.io.InputStream stream, String encoding) {
295     try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
296     token_source = new VersionParserTokenManager(jj_input_stream);
297     token = new Token();
298     jj_ntk = -1;
299     jj_gen = 0;
300     for (int i = 0; i < 3; i++) jj_la1[i] = -1;
301   }
302 
303   /** Reinitialise. */
304   public void ReInit(java.io.InputStream stream) {
305      ReInit(stream, null);
306   }
307   /** Reinitialise. */
308   public void ReInit(java.io.InputStream stream, String encoding) {
309     try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
310     token_source.ReInit(jj_input_stream);
311     token = new Token();
312     jj_ntk = -1;
313     jj_gen = 0;
314     for (int i = 0; i < 3; i++) jj_la1[i] = -1;
315   }
316 
317   /** Constructor. */
318   public VersionParser(java.io.Reader stream) {
319     jj_input_stream = new SimpleCharStream(stream, 1, 1);
320     token_source = new VersionParserTokenManager(jj_input_stream);
321     token = new Token();
322     jj_ntk = -1;
323     jj_gen = 0;
324     for (int i = 0; i < 3; i++) jj_la1[i] = -1;
325   }
326 
327   /** Reinitialise. */
328   public void ReInit(java.io.Reader stream) {
329     jj_input_stream.ReInit(stream, 1, 1);
330     token_source.ReInit(jj_input_stream);
331     token = new Token();
332     jj_ntk = -1;
333     jj_gen = 0;
334     for (int i = 0; i < 3; i++) jj_la1[i] = -1;
335   }
336 
337   /** Constructor with generated Token Manager. */
338   public VersionParser(VersionParserTokenManager tm) {
339     token_source = tm;
340     token = new Token();
341     jj_ntk = -1;
342     jj_gen = 0;
343     for (int i = 0; i < 3; i++) jj_la1[i] = -1;
344   }
345 
346   /** Reinitialise. */
347   public void ReInit(VersionParserTokenManager tm) {
348     token_source = tm;
349     token = new Token();
350     jj_ntk = -1;
351     jj_gen = 0;
352     for (int i = 0; i < 3; i++) jj_la1[i] = -1;
353   }
354 
355   private Token jj_consume_token(int kind) throws ParseException {
356     Token oldToken;
357     if ((oldToken = token).next != null) token = token.next;
358     else token = token.next = token_source.getNextToken();
359     jj_ntk = -1;
360     if (token.kind == kind) {
361       jj_gen++;
362       return token;
363     }
364     token = oldToken;
365     jj_kind = kind;
366     throw generateParseException();
367   }
368 
369 
370 /** Get the next Token. */
371   final public Token getNextToken() {
372     if (token.next != null) token = token.next;
373     else token = token.next = token_source.getNextToken();
374     jj_ntk = -1;
375     jj_gen++;
376     return token;
377   }
378 
379 /** Get the specific Token. */
380   final public Token getToken(int index) {
381     Token t = token;
382     for (int i = 0; i < index; i++) {
383       if (t.next != null) t = t.next;
384       else t = t.next = token_source.getNextToken();
385     }
386     return t;
387   }
388 
389   private int jj_ntk() {
390     if ((jj_nt=token.next) == null)
391       return (jj_ntk = (token.next=token_source.getNextToken()).kind);
392     else
393       return (jj_ntk = jj_nt.kind);
394   }
395 
396   private java.util.List jj_expentries = new java.util.ArrayList();
397   private int[] jj_expentry;
398   private int jj_kind = -1;
399 
400   /** Generate ParseException. */
401   public ParseException generateParseException() {
402     jj_expentries.clear();
403     boolean[] la1tokens = new boolean[4];
404     if (jj_kind >= 0) {
405       la1tokens[jj_kind] = true;
406       jj_kind = -1;
407     }
408     for (int i = 0; i < 3; i++) {
409       if (jj_la1[i] == jj_gen) {
410         for (int j = 0; j < 32; j++) {
411           if ((jj_la1_0[i] & (1<<j)) != 0) {
412             la1tokens[j] = true;
413           }
414         }
415       }
416     }
417     for (int i = 0; i < 4; i++) {
418       if (la1tokens[i]) {
419         jj_expentry = new int[1];
420         jj_expentry[0] = i;
421         jj_expentries.add(jj_expentry);
422       }
423     }
424     int[][] exptokseq = new int[jj_expentries.size()][];
425     for (int i = 0; i < jj_expentries.size(); i++) {
426       exptokseq[i] = (int[])jj_expentries.get(i);
427     }
428     return new ParseException(token, exptokseq, tokenImage);
429   }
430 
431   /** Enable tracing. */
432   final public void enable_tracing() {
433   }
434 
435   /** Disable tracing. */
436   final public void disable_tracing() {
437   }
438 
439 }