KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > util > Convert


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2007 William N. Dortch <bill.dortch@gmail.com>
15  *
16  * Alternatively, the contents of this file may be used under the terms of
17  * either of the GNU General Public License Version 2 or later (the "GPL"),
18  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19  * in which case the provisions of the GPL or the LGPL are applicable instead
20  * of those above. If you wish to allow use of your version of this file only
21  * under the terms of either the GPL or the LGPL, and not to allow others to
22  * use your version of this file under the terms of the CPL, indicate your
23  * decision by deleting the provisions above and replace them with the notice
24  * and other provisions required by the GPL or the LGPL. If you do not delete
25  * the provisions above, a recipient may use your version of this file under
26  * the terms of any one of the CPL, the GPL or the LGPL.
27  ***** END LICENSE BLOCK *****/

28 package org.jruby.util;
29 import java.math.BigInteger JavaDoc;
30
31 import org.jruby.RubyNumeric.InvalidIntegerException;
32 import org.jruby.RubyNumeric.NumberTooLargeException;
33
34 /**
35  * @author Bill Dortch
36  *
37  * Primitive conversions adapted from java.lang.Integer/Long (C) Sun Microsystems, Inc.
38  *
39  */

40 public class Convert {
41
42     /**
43      * Returns a <code>ByteList</code> object representing the
44      * specified integer. The argument is converted to signed decimal
45      * representation and returned as a ByteList.
46      *
47      * @param i an integer to be converted.
48      * @return a ByteList representation of the argument in base&nbsp;10.
49      */

50     public static final ByteList intToByteList(int i) {
51         if (i == Integer.MIN_VALUE)
52             return new ByteList((byte[])MIN_INT_BYTE_ARRAY.clone(),false);
53         int size = (i < 0) ? arraySize(-i) + 1 : arraySize(i);
54         byte[] buf = new byte[size];
55         getCharBytes(i, size, buf);
56         return new ByteList(buf,false);
57     }
58
59     /**
60      * Returns a <code>ByteList</code> object representing the
61      * specified integer, using the specified radix. The argument is
62      * converted to signed decimal representation and returned as a ByteList.
63      *
64      * @param i an integer to be converted.
65      * @param radix the radix to use in the ByteList representation.
66      * @return a ByteList representation of the argument in the specified radix.
67      */

68     public static final ByteList intToByteList(int i, int radix) {
69         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
70             radix = 10;
71         if (radix == 10)
72             return intToByteList(i); // much faster for base 10
73
byte buf[] = new byte[33];
74         boolean negative = (i < 0);
75         int charPos = 32;
76         if (!negative) {
77             i = -i;
78         }
79         while (i <= -radix) {
80             buf[charPos--] = digits[-(i % radix)];
81             i = i / radix;
82         }
83         buf[charPos] = digits[-i];
84         if (negative) {
85             buf[--charPos] = '-';
86         }
87         return new ByteList(buf, charPos, (33 - charPos));
88     }
89
90     /**
91      * Returns a <code>ByteList</code> object representing the specified
92      * <code>long</code>. The argument is converted to signed decimal
93      * representation and returned as a ByteList.
94      *
95      * @param i a <code>long</code> to be converted.
96      * @return a ByteList representation of the argument in base&nbsp;10.
97      */

98     public static final ByteList longToByteList(long i) {
99         if (i == Long.MIN_VALUE)
100             return new ByteList((byte[])MIN_LONG_BYTE_ARRAY.clone(),false);
101         // int version is slightly faster, use if possible
102
if (i <= Integer.MAX_VALUE && i >= Integer.MIN_VALUE)
103             return intToByteList((int)i);
104         int size = (i < 0) ? arraySize(-i) + 1 : arraySize(i);
105         byte[] buf = new byte[size];
106         getCharBytes(i, size, buf);
107         return new ByteList(buf,false);
108     }
109    
110     public static final ByteList longToByteList(long i, int radix) {
111         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
112             radix = 10;
113         if (radix == 10)
114             return longToByteList(i); // much faster for base 10
115
byte[] buf = new byte[65];
116         int charPos = 64;
117         boolean negative = (i < 0);
118         if (!negative) {
119             i = -i;
120         }
121         while (i <= -radix) {
122             buf[charPos--] = digits[(int)(-(i % radix))];
123             i = i / radix;
124         }
125         buf[charPos] = digits[(int)(-i)];
126         if (negative) {
127             buf[--charPos] = '-';
128         }
129         return new ByteList(buf, charPos, (65 - charPos));
130     }
131
132     public static final byte[] intToCharBytes(int i) {
133         if (i == Integer.MIN_VALUE)
134             return (byte[])MIN_INT_BYTE_ARRAY.clone();
135         int size = (i < 0) ? arraySize(-i) + 1 : arraySize(i);
136         byte[] buf = new byte[size];
137         getCharBytes(i, size, buf);
138         return buf;
139     }
140
141     public static final byte[] longToCharBytes(long i) {
142 // if (i == Long.MIN_VALUE)
143
// return (byte[])MIN_LONG_BYTE_ARRAY.clone();
144
int size = (i < 0) ? arraySize(-i) + 1 : arraySize(i);
145         byte[] buf = new byte[size];
146         getCharBytes(i, size, buf);
147         return buf;
148     }
149     public static final char[] longToChars(long i) {
150 // if (i == Long.MIN_VALUE)
151
// return (byte[])MIN_LONG_BYTE_ARRAY.clone();
152
int size = (i < 0) ? arraySize(-i) + 1 : arraySize(i);
153         char[] buf = new char[size];
154         getChars(i, size, buf);
155         return buf;
156     }
157     
158     /**
159      * Places characters representing the integer i into the
160      * character array buf. The characters are placed into
161      * the buffer backwards starting with the least significant
162      * digit at the specified index (exclusive), and working
163      * backwards from there.
164      *
165      * Will fail if i == Integer.MIN_VALUE
166      */

167     public static final void getCharBytes(int i, int index, byte[] buf) {
168         int q, r;
169         int charPos = index;
170         byte sign = 0;
171
172         if (i < 0) {
173             sign = '-';
174             i = -i;
175         }
176
177         // Generate two digits per iteration
178
while (i >= 65536) {
179             q = i / 100;
180         // really: r = i - (q * 100);
181
r = i - ((q << 6) + (q << 5) + (q << 2));
182             i = q;
183             buf [--charPos] = DigitOnes[r];
184             buf [--charPos] = DigitTens[r];
185         }
186
187         // Fall thru to fast mode for smaller numbers
188
// assert(i <= 65536, i);
189
for (;;) {
190             q = (i * 52429) >>> (16+3);
191             r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
192
buf [--charPos] = digits[r];
193             i = q;
194             if (i == 0) break;
195         }
196         if (sign != 0) {
197             buf [--charPos] = sign;
198         }
199     }
200
201     /**
202      * Places characters representing the integer i into the
203      * character array buf. The characters are placed into
204      * the buffer backwards starting with the least significant
205      * digit at the specified index (exclusive), and working
206      * backwards from there.
207      *
208      * Will fail if i == Long.MIN_VALUE
209      */

210     public static final void getCharBytes(long i, int index, byte[] buf) {
211         long q;
212         int r;
213         int charPos = index;
214         byte sign = 0;
215
216         if (i < 0) {
217             sign = '-';
218             i = -i;
219         }
220
221         // Get 2 digits/iteration using longs until quotient fits into an int
222
while (i > Integer.MAX_VALUE) {
223             q = i / 100;
224             // really: r = i - (q * 100);
225
r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
226             i = q;
227             buf[--charPos] = DigitOnes[r];
228             buf[--charPos] = DigitTens[r];
229         }
230
231         // Get 2 digits/iteration using ints
232
int q2;
233         int i2 = (int)i;
234         while (i2 >= 65536) {
235             q2 = i2 / 100;
236             // really: r = i2 - (q * 100);
237
r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
238             i2 = q2;
239             buf[--charPos] = DigitOnes[r];
240             buf[--charPos] = DigitTens[r];
241         }
242
243         // Fall thru to fast mode for smaller numbers
244
// assert(i2 <= 65536, i2);
245
for (;;) {
246             q2 = (i2 * 52429) >>> (16+3);
247             r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
248
buf[--charPos] = digits[r];
249             i2 = q2;
250             if (i2 == 0) break;
251         }
252         if (sign != 0) {
253             buf[--charPos] = sign;
254         }
255     }
256     public static final void getChars(long i, int index, char[] buf) {
257         long q;
258         int r;
259         int charPos = index;
260         char sign = 0;
261
262         if (i < 0) {
263             sign = '-';
264             i = -i;
265         }
266
267         // Get 2 digits/iteration using longs until quotient fits into an int
268
while (i > Integer.MAX_VALUE) {
269             q = i / 100;
270             // really: r = i - (q * 100);
271
r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
272             i = q;
273             buf[--charPos] = cDigitOnes[r];
274             buf[--charPos] = cDigitTens[r];
275         }
276
277         // Get 2 digits/iteration using ints
278
int q2;
279         int i2 = (int)i;
280         while (i2 >= 65536) {
281             q2 = i2 / 100;
282             // really: r = i2 - (q * 100);
283
r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
284             i2 = q2;
285             buf[--charPos] = cDigitOnes[r];
286             buf[--charPos] = cDigitTens[r];
287         }
288
289         // Fall thru to fast mode for smaller numbers
290
// assert(i2 <= 65536, i2);
291
for (;;) {
292             q2 = (i2 * 52429) >>> (16+3);
293             r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
294
buf[--charPos] = cdigits[r];
295             i2 = q2;
296             if (i2 == 0) break;
297         }
298         if (sign != 0) {
299             buf[--charPos] = sign;
300         }
301     }
302
303     
304     /**
305      * Requires positive x.
306      * For negative numbers, reverse the sign before calling and add one to
307      * the result (for the '-' sign).
308      */

309     public static final int arraySize(long x) {
310         long p = 10;
311         for (int i=1; i<19; i++) {
312             if (x < p)
313                 return i;
314             p = 10*p;
315         }
316         return 19;
317     }
318     /**
319      * Requires positive x.
320      * For negative numbers, reverse the sign before calling and add one to
321      * the result (for the '-' sign).
322      */

323     public static final int arraySize(int x) {
324         for (int i=0; ; i++)
325             if (x <= sizeTable[i])
326                 return i+1;
327     }
328     // the following group of conversions to binary/octal/hex
329
// is mostly for use by the new sprintf code
330
public static final byte[] intToBinaryBytes(int i) {
331         return intToUnsignedBytes(i, 1);
332     }
333     public static final byte[] intToOctalBytes(int i) {
334         return intToUnsignedBytes(i, 3);
335     }
336     public static final byte[] intToHexBytes(int i) {
337         return intToUnsignedBytes(i, 4);
338     }
339
340     public static final ByteList intToBinaryByteList(int i) {
341         return new ByteList(intToUnsignedBytes(i, 1));
342     }
343     public static final ByteList intToOctalByteList(int i) {
344         return new ByteList(intToUnsignedBytes(i, 3));
345     }
346     public static final ByteList intToHexByteList(int i) {
347         return new ByteList(intToUnsignedBytes(i, 4));
348     }
349
350     public static final byte[] longToBinaryBytes(long i) {
351         return longToUnsignedBytes(i, 1);
352     }
353     public static final byte[] longToOctalBytes(long i) {
354         return longToUnsignedBytes(i, 3);
355     }
356     public static final byte[] longToHexBytes(long i) {
357         return longToUnsignedBytes(i, 4);
358     }
359
360     public static final ByteList longToBinaryByteList(long i) {
361         return new ByteList(longToUnsignedBytes(i, 1));
362     }
363     public static final ByteList longToOctalByteList(long i) {
364         return new ByteList(longToUnsignedBytes(i, 3));
365     }
366     public static final ByteList longToHexByteList(long i) {
367         return new ByteList(longToUnsignedBytes(i, 4));
368     }
369     /**
370      * Convert the integer to an unsigned number.
371      * The character bytes are right-aligned in the 32-byte result.
372      */

373     public static final byte[] intToRawUnsignedBytes(int i, int shift) {
374         byte[] buf = new byte[32];
375         int charPos = 32;
376         int radix = 1 << shift;
377         int mask = radix - 1;
378         do {
379             buf[--charPos] = digits[i & mask];
380             i >>>= shift;
381         } while (i != 0);
382         return buf;
383     }
384     /**
385      * Convert the integer to an unsigned number.
386      * The result array is sized to fit the actual character length.
387      */

388     public static final byte[] intToUnsignedBytes(int i, int shift) {
389         byte[] buf = new byte[32];
390         int charPos = 32;
391         int radix = 1 << shift;
392         int mask = radix - 1;
393         do {
394             buf[--charPos] = digits[i & mask];
395             i >>>= shift;
396         } while (i != 0);
397         int length = 32 - charPos;
398         byte[] result = new byte[length];
399         System.arraycopy(buf,charPos,result,0,length);
400         return result;
401     }
402
403     /**
404      * Convert the long to an unsigned number.
405      * The character bytes are right-aligned in the 64-byte result.
406      */

407     public static final byte[] longToRawUnsignedBytes(long i, int shift) {
408         byte[] buf = new byte[64];
409         int charPos = 64;
410         int radix = 1 << shift;
411         long mask = radix - 1;
412         do {
413             buf[--charPos] = digits[(int)(i & mask)];
414             i >>>= shift;
415         } while (i != 0);
416         return buf;
417     }
418     /**
419      * Convert the long to an unsigned number.
420      * The result array is sized to fit the actual character length.
421      */

422     public static final byte[] longToUnsignedBytes(long i, int shift) {
423         byte[] buf = new byte[64];
424         int charPos = 64;
425         int radix = 1 << shift;
426         long mask = radix - 1;
427         do {
428             buf[--charPos] = digits[(int)(i & mask)];
429             i >>>= shift;
430         } while (i != 0);
431         int length = 64 - charPos;
432         byte[] result = new byte[length];
433         System.arraycopy(buf,charPos,result,0,length);
434         return result;
435     }
436
437     /**
438      * Converts a ByteList to a primitive long value, using the specified
439      * base. If base is zero, defaults to 10 unless a base specifier is encountered
440      * (e.g., '0x'). Follows Ruby rules for converting Strings to Integers. Will fail
441      * with NumberFormatException if the number is too large for a long. If the
442      * raise flag is set, will also fail on certain formatting errors (zero-length
443      * array; zero-length excluding sign; no valid digits).
444      *
445      * @param bytes
446      * @param buflen the effective length of the array (may be less than bytes.length)
447      * @param base
448      * @param raise
449      * @return
450      * @throws NumberFormatException
451      */

452     public static final long byteListToLong(ByteList bytes, int base, boolean raise) {
453         return byteArrayToLong(bytes.unsafeBytes(),bytes.length(),base,raise);
454     }
455     public static final long byteListToLong(ByteList bytes, int base) {
456         return byteArrayToLong(bytes.unsafeBytes(),bytes.length(),base,false);
457     }
458     // for base 10 ByteList
459
public static final long byteListToLong(ByteList bytes) {
460         return byteArrayToLong(bytes.unsafeBytes(),bytes.length(),10,false);
461     }
462     /**
463      * Converts a ByteList to a BigInteger value, using the specified base.
464      * If base is zero, defaults to 10 unless a base specifier is encountered
465      * (e.g., '0x'). Follows Ruby rules for converting Strings to Integers. Will
466      * fail with NumberFormatException on certain formatting errors (zero-length
467      * array; zero-length excluding sign; no valid digits).
468      * <p>
469      * Intended to be called after byteListToLong if that method fails.
470      *
471      * @param bytes
472      * @param buflen the effective length of the array (may be less than bytes.length)
473      * @param base
474      * @return
475      * @throws NumberFormatException, IllegalArgumentException
476      */

477     public static final BigInteger JavaDoc byteListToBigInteger(ByteList bytes, int base, boolean raise) {
478         return byteArrayToBigInteger(bytes.unsafeBytes(),bytes.length(),base,raise);
479     }
480     public static final BigInteger JavaDoc byteListToBigInteger(ByteList bytes, int base) {
481         return byteArrayToBigInteger(bytes.unsafeBytes(),bytes.length(),base,false);
482     }
483     // for base 10 ByteList
484
public static final BigInteger JavaDoc byteListToBigInteger(ByteList bytes) {
485         return byteArrayToBigInteger(bytes.unsafeBytes(),bytes.length(),10,false);
486     }
487    /**
488      * Converts a byte array to a primitive long value, using the specified
489      * base. If base is zero, defaults to 10 unless a base specifier is encountered
490      * (e.g., '0x'). Follows Ruby rules for converting Strings to Integers. Will fail
491      * with NumberFormatException if the number is too large for a long. If the
492      * raise flag is set, will also fail on certain formatting errors (zero-length
493      * array; zero-length excluding sign; no valid digits).
494      *
495      * @param bytes
496      * @param buflen the effective length of the array (may be less than bytes.length)
497      * @param base
498      * @param strict
499      * @return
500      * @throws NumberFormatException, IllegalArgumentException
501      */

502     public static final long byteArrayToLong(byte[] bytes, int buflen, int base, boolean strict) {
503         final int SCOMPLETE = 0;
504         final int SBEGIN = 1;
505         final int SSIGN = 2;
506         final int SZERO = 3;
507         final int SPOST_SIGN = 4;
508         final int SDIGITS = 5;
509         final int SDIGIT = 6;
510         final int SDIGIT_STRICT = 7;
511         final int SDIGIT_USC = 8;
512         final int SEOD_STRICT = 13;
513         final int SEOF = 14;
514         final int SERR_NOT_STRICT = 17;
515         final int SERR_TOO_BIG = 18;
516         final int FLAG_NEGATIVE = 1 << 0;
517         final int FLAG_DIGIT = 1 << 1;
518         final int FLAG_UNDERSCORE = 1 << 2;
519         final int FLAG_WHITESPACE = 1 << 3;
520       
521         if (bytes == null) {
522             throw new IllegalArgumentException JavaDoc("null bytes");
523         }
524         if (buflen < 0 || buflen > bytes.length) {
525             throw new IllegalArgumentException JavaDoc("invalid buflen specified");
526         }
527         int radix = base == 0 ? 10 : base;
528         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
529             throw new IllegalArgumentException JavaDoc("illegal radix " + radix);
530         }
531         if (buflen == 0) {
532             throw new InvalidIntegerException();
533         }
534         int i = 0;
535         byte ival;
536         int flags = 0;
537         long limit = -Long.MAX_VALUE;
538         long result = 0;
539         long multmin = 0;
540         int digit;
541         int state = SBEGIN;
542         while (state != SCOMPLETE) {
543             states:
544             switch(state) {
545             case SBEGIN:
546                 if (strict) {
547                     for (; i < buflen && bytes[i] <= ' '; i++) ;
548                 } else {
549                     for (; i < buflen && ((ival = bytes[i]) <= ' ' || ival == '_'); i++) ;
550                 }
551                 state = i < buflen ? SSIGN : SEOF;
552                 break;
553             case SSIGN:
554                 switch(bytes[i]) {
555                 case '-':
556                     flags |= FLAG_NEGATIVE;
557                     limit = Long.MIN_VALUE;
558                 case '+':
559                     if (++i >= buflen) {
560                         state = SEOF;
561                     } else if (bytes[i] == '0') {
562                         state = SZERO;
563                     } else {
564                         state = SPOST_SIGN;
565                     }
566                     break states;
567                 case '0':
568                     state = SZERO;
569                     break states;
570                 default:
571                     state = SDIGITS;
572                     break states;
573                 }
574             case SZERO:
575                 if (++i >= buflen) {
576                     state = SCOMPLETE;
577                     break;
578                 }
579                 switch (bytes[i]) {
580                 case 'x':
581                 case 'X':
582                     if (base == 0 || base == 16) {
583                         radix = 16;
584                         state = ++i >= buflen ? SEOF : SPOST_SIGN;
585                     } else {
586                         state = SDIGITS;
587                     }
588                     break states;
589                 case 'b':
590                 case 'B':
591                     if (base == 0 || base == 2) {
592                         radix = 2;
593                         state = ++i >= buflen ? SEOF : SPOST_SIGN;
594                     } else {
595                         state = SDIGITS;
596                     }
597                     break states;
598                 default:
599                     if (base == 0 || base == 8) {
600                         radix = 8;
601                     }
602                     flags |= FLAG_DIGIT;
603                     state = SDIGITS;
604                     break states;
605                 }
606             case SPOST_SIGN:
607                 if (strict) {
608                     int ibefore = i;
609                     for (; i < buflen && bytes[i] <= ' '; i++) ;
610                     if (ibefore != i) {
611                         // set this to enforce no-underscore rule (though I think
612
// it's an MRI bug)
613
flags |= FLAG_WHITESPACE;
614                     }
615                 } else {
616                     for ( ; i < buflen && ((ival = bytes[i]) <= ' ' || ival == '_'); i++) {
617                         if (ival == '_') {
618                             if ((flags & FLAG_WHITESPACE) != 0) {
619                                 throw new InvalidIntegerException();
620                             }
621                             flags |= FLAG_UNDERSCORE;
622                         } else {
623                             if ((flags & FLAG_UNDERSCORE) != 0) {
624                                 throw new InvalidIntegerException();
625                             }
626                             flags |= FLAG_WHITESPACE;
627                         }
628                     }
629                 }
630                 state = i < buflen ? SDIGITS : SEOF;
631                 break;
632             case SDIGITS:
633                 digit = Character.digit((char) bytes[i],radix);
634                 if (digit < 0) {
635                     state = strict ? SEOD_STRICT : SEOF;
636                     break;
637                 }
638                 result = -digit;
639                 if (++i >= buflen) {
640                     state = SCOMPLETE;
641                     break;
642                 }
643                 multmin = limit / radix;
644                 flags = (flags | FLAG_DIGIT) & ~FLAG_UNDERSCORE;
645                 state = strict ? SDIGIT_STRICT : SDIGIT;
646                 break;
647
648             case SDIGIT:
649                 while ((digit = Character.digit((char) bytes[i],radix)) >= 0) {
650                     if (result < multmin || ((result *= radix) < limit + digit)) {
651                         state = SERR_TOO_BIG;
652                         break states;
653                     }
654                     result -= digit;
655                     if (++i >= buflen) {
656                         state = SCOMPLETE;
657                         break states;
658                     }
659                 }
660                 state = bytes[i++] == '_' ? SDIGIT_USC : SEOF;
661                 break;
662             case SDIGIT_USC:
663                 for ( ; i < buflen && bytes[i] == '_'; i++) ;
664                 state = i < buflen ? SDIGIT : SEOF;
665                 break;
666                 
667             case SDIGIT_STRICT:
668                 while ((digit = Character.digit((char) bytes[i],radix)) >= 0) {
669                     if (result < multmin || ((result *= radix) < limit + digit)) {
670                         state = SERR_TOO_BIG;
671                         break states;
672                     }
673                     result -= digit;
674                     if (++i >= buflen) {
675                         state = SCOMPLETE;
676                         break states;
677                     }
678                     flags &= ~FLAG_UNDERSCORE;
679                 }
680                 if (bytes[i] == '_') {
681                     if ((flags & (FLAG_UNDERSCORE | FLAG_WHITESPACE)) != 0) {
682                         state = SERR_NOT_STRICT;
683                         break;
684                     }
685                     flags |= FLAG_UNDERSCORE;
686                     state = ++i >= buflen ? SEOD_STRICT : SDIGIT_STRICT;
687                 } else {
688                     state = SEOD_STRICT;
689                 }
690                 break;
691
692             case SEOD_STRICT:
693                 if ((flags & FLAG_UNDERSCORE)!= 0) {
694                     state = SERR_NOT_STRICT;
695                     break;
696                 }
697                 for ( ; i < buflen && bytes[i] <= ' '; i++ );
698                 state = i < buflen ? SERR_NOT_STRICT : SCOMPLETE;
699                 break;
700                 
701             case SEOF:
702                 if ((flags & FLAG_DIGIT) == 0) {
703                     throw new InvalidIntegerException("no digits supplied");
704                 }
705                 state = SCOMPLETE;
706                 break;
707
708             case SERR_TOO_BIG:
709                 throw new NumberTooLargeException("can't convert to long");
710
711             case SERR_NOT_STRICT:
712                 throw new InvalidIntegerException("does not meet strict criteria");
713                 
714             } // switch
715
} //while
716
if ((flags & FLAG_NEGATIVE) == 0) {
717             return -result;
718         } else {
719             return result;
720         }
721     }
722     
723     /**
724      * Converts a byte array to a BigInteger value, using the specified base.
725      * If base is zero, defaults to 10 unless a base specifier is encountered
726      * (e.g., '0x'). Follows Ruby rules for converting Strings to Integers. Will
727      * fail with NumberFormatException on certain formatting errors (zero-length
728      * array; zero-length excluding sign; no valid digits).
729      * <p>
730      * Intended to be called after byteArrayToLong if that method fails.
731      *
732      * @param bytes
733      * @param buflen the effective length of the array (may be less than bytes.length)
734      * @param base
735      * @return
736      * @throws NumberFormatException, IllegalArgumentException
737      */

738     public static final BigInteger JavaDoc byteArrayToBigInteger(byte[] bytes, int buflen, int base, boolean strict) {
739         final int SCOMPLETE = 0;
740         final int SBEGIN = 1;
741         final int SSIGN = 2;
742         final int SZERO = 3;
743         final int SPOST_SIGN = 4;
744         final int SDIGITS = 5;
745         final int SDIGIT = 6;
746         final int SDIGIT_STRICT = 7;
747         final int SDIGIT_USC = 8;
748         final int SEOD_STRICT = 13;
749         final int SEOF = 14;
750         final int SERR_NOT_STRICT = 17;
751         final int FLAG_NEGATIVE = 1 << 0;
752         final int FLAG_DIGIT = 1 << 1;
753         final int FLAG_UNDERSCORE = 1 << 2;
754         final int FLAG_WHITESPACE = 1 << 3;
755       
756         if (bytes == null) {
757             throw new IllegalArgumentException JavaDoc("null bytes");
758         }
759         if (buflen < 0 || buflen > bytes.length) {
760             throw new IllegalArgumentException JavaDoc("invalid buflen specified");
761         }
762         int radix = base == 0 ? 10 : base;
763         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
764             throw new IllegalArgumentException JavaDoc("illegal radix " + radix);
765         }
766         if (buflen == 0) {
767             throw new InvalidIntegerException();
768         }
769         int i = 0;
770         byte ival;
771         int flags = 0;
772         int digit;
773         int offset = 0;
774         char[] chars = null;
775         int state = SBEGIN;
776         while (state != SCOMPLETE) {
777             states:
778             switch(state) {
779             case SBEGIN:
780                 if (strict) {
781                     for (; i < buflen && bytes[i] <= ' '; i++) ;
782                 } else {
783                     for (; i < buflen && ((ival = bytes[i]) <= ' ' || ival == '_'); i++) ;
784                 }
785                 state = i < buflen ? SSIGN : SEOF;
786                 break;
787             case SSIGN:
788                 switch(bytes[i]) {
789                 case '-':
790                     flags |= FLAG_NEGATIVE;
791                 case '+':
792                     if (++i >= buflen) {
793                         state = SEOF;
794                     } else if (bytes[i] == '0') {
795                         state = SZERO;
796                     } else {
797                         state = SPOST_SIGN;
798                     }
799                     break states;
800                 case '0':
801                     state = SZERO;
802                     break states;
803                 default:
804                     state = SDIGITS;
805                     break states;
806                 }
807             case SZERO:
808                 if (++i >= buflen) {
809                     state = SCOMPLETE;
810                     break;
811                 }
812                 switch (bytes[i]) {
813                 case 'x':
814                 case 'X':
815                     if (base == 0 || base == 16) {
816                         radix = 16;
817                         state = ++i >= buflen ? SEOF : SPOST_SIGN;
818                     } else {
819                         state = SDIGITS;
820                     }
821                     break states;
822                 case 'b':
823                 case 'B':
824                     if (base == 0 || base == 2) {
825                         radix = 2;
826                         state = ++i >= buflen ? SEOF : SPOST_SIGN;
827                     } else {
828                         state = SDIGITS;
829                     }
830                     break states;
831                 default:
832                     if (base == 0 || base == 8) {
833                         radix = 8;
834                     }
835                     flags |= FLAG_DIGIT;
836                     state = SDIGITS;
837                     break states;
838                 }
839             case SPOST_SIGN:
840                 if (strict) {
841                     int ibefore = i;
842                     for (; i < buflen && bytes[i] <= ' '; i++) ;
843                     if (ibefore != i) {
844                         // set this to enforce no-underscore rule (though I think
845
// it's an MRI bug)
846
flags |= FLAG_WHITESPACE;
847                     }
848                 } else {
849                     for ( ; i < buflen && ((ival = bytes[i]) <= ' ' || ival == '_'); i++) {
850                         if (ival == '_') {
851                             if ((flags & FLAG_WHITESPACE) != 0) {
852                                 throw new InvalidIntegerException();
853                             }
854                             flags |= FLAG_UNDERSCORE;
855                         } else {
856                             if ((flags & FLAG_UNDERSCORE) != 0) {
857                                 throw new InvalidIntegerException();
858                             }
859                             flags |= FLAG_WHITESPACE;
860                         }
861                     }
862                 }
863                 state = i < buflen ? SDIGITS : SEOF;
864                 break;
865             case SDIGITS:
866                 digit = Character.digit((char) bytes[i],radix);
867                 if (digit < 0) {
868                     state = strict ? SEOD_STRICT : SEOF;
869                     break;
870                 }
871                 if ((flags & FLAG_NEGATIVE) == 0) {
872                     chars = new char[buflen - i];
873                     chars[0] = (char)bytes[i];
874                     offset = 1;
875                 } else {
876                     chars = new char[buflen - i + 1];
877                     chars[0] = '-';
878                     chars[1] = (char)bytes[i];
879                     offset = 2;
880                 }
881                 if (++i >= buflen) {
882                     state = SCOMPLETE;
883                     break;
884                 }
885                 flags = (flags | FLAG_DIGIT) & ~FLAG_UNDERSCORE;
886                 state = strict ? SDIGIT_STRICT : SDIGIT;
887                 break;
888
889             case SDIGIT:
890                 while ((digit = Character.digit((char) bytes[i],radix)) >= 0) {
891                     chars[offset++] = (char)bytes[i];
892                     if (++i >= buflen) {
893                         state = SCOMPLETE;
894                         break states;
895                     }
896                 }
897                 state = bytes[i++] == '_' ? SDIGIT_USC : SEOF;
898                 break;
899             case SDIGIT_USC:
900                 for ( ; i < buflen && bytes[i] == '_'; i++) ;
901                 state = i < buflen ? SDIGIT : SEOF;
902                 break;
903                 
904             case SDIGIT_STRICT:
905                 while ((digit = Character.digit((char)bytes[i],radix)) >= 0) {
906                     chars[offset++] = (char)bytes[i];
907                     if (++i >= buflen) {
908                         state = SCOMPLETE;
909                         break states;
910                     }
911                     flags &= ~FLAG_UNDERSCORE;
912                 }
913                 if (bytes[i] == '_') {
914                     if ((flags & (FLAG_UNDERSCORE | FLAG_WHITESPACE)) != 0) {
915                         state = SERR_NOT_STRICT;
916                         break;
917                     }
918                     flags |= FLAG_UNDERSCORE;
919                     state = ++i >= buflen ? SEOD_STRICT : SDIGIT_STRICT;
920                 } else {
921                     state = SEOD_STRICT;
922                 }
923                 break;
924
925             case SEOD_STRICT:
926                 if ((flags & FLAG_UNDERSCORE)!= 0) {
927                     state = SERR_NOT_STRICT;
928                     break;
929                 }
930                 for ( ; i < buflen && bytes[i] <= ' '; i++ );
931                 state = i < buflen ? SERR_NOT_STRICT : SCOMPLETE;
932                 break;
933                 
934             case SEOF:
935                 if ((flags & FLAG_DIGIT) == 0) {
936                     throw new InvalidIntegerException("no digits supplied");
937                 }
938                 state = SCOMPLETE;
939                 break;
940
941             case SERR_NOT_STRICT:
942                 throw new InvalidIntegerException("does not meet strict criteria");
943                 
944             } // switch
945
} //while
946
if (chars == null) { // 0, won't happen if byteArrayToLong called first
947
return BIG_INT_ZERO;
948         } else {
949             return new BigInteger JavaDoc(new String JavaDoc(chars,0,offset),radix);
950         }
951     }
952     
953     // The following two methods, used in conjunction, provide the
954
// equivalent of String#trim()
955
public static final int skipLeadingWhitespace(byte[] bytes){
956         int length = bytes.length;
957         int start = 0;
958         for ( ; start < length && bytes[start] <= ' '; start++) ;
959         return start;
960     }
961     public static final int skipTrailingWhitespace(byte[] bytes) {
962         int stop = bytes.length - 1;
963         for ( ; stop >= 0 && bytes[stop] <= ' '; stop-- ) ;
964         return stop + 1;
965     }
966     /**
967      * Trims whitespace (any bytes <= 0x20) from the beginning and end
968      * of the array. This is equivalent to String#trim for byte arrays. If
969      * no bytes are trimmed, the original array is returned.
970      *
971      * @param bytes the array to be trimmed
972      * @return the trimmed array if trimming performed, otherwise the original array
973      */

974     public static final byte[] trim (byte[] bytes) {
975         if (bytes.length == 0)
976             return bytes;
977         int start = skipLeadingWhitespace(bytes);
978         if (start >= bytes.length) {
979             return EMPTY_BYTES;
980         }
981         int stop = skipTrailingWhitespace(bytes);
982         int length = stop - start;
983         if (length == bytes.length)
984             return bytes;
985         byte[] trimmed = new byte[length];
986         System.arraycopy(bytes,0,trimmed,0,length);
987         return trimmed;
988     }
989     /**
990      * Deletes the byte at the specified position, shifting all bytes
991      * to the right of it left by one byte. If the copy flag is set,
992      * a new array (one byte shorter) will be created and the original
993      * will remain unchanged; otherwise, the last byte of the array is
994      * set to zero.
995      *
996      * @param bytes the array to 'delete' a byte from
997      * @param pos the offset of the byte to delete
998      * @param copy if true, a new copy of the array will be created, with
999      * the original preserved
1000     */

1001    public static final byte[] delete(byte[] bytes, int pos, boolean copy) {
1002        int buflen = bytes.length;
1003        int newlen = buflen - 1;
1004        if (pos < 0 || pos > newlen) {
1005            throw new IllegalArgumentException JavaDoc("illegal position for delete");
1006        }
1007        int src = pos + 1;
1008        if (copy) {
1009            if (newlen == 0) {
1010                return EMPTY_BYTES;
1011            }
1012            byte[] newbytes = new byte[newlen];
1013            if (pos == 0) {
1014                System.arraycopy(bytes,1,newbytes,0,newlen);
1015            } else {
1016                System.arraycopy(bytes,0,newbytes,0,pos);
1017                System.arraycopy(bytes,src,newbytes,pos,newlen-pos);
1018            }
1019            return newbytes;
1020        } else {
1021            if (newlen > 0) {
1022                System.arraycopy(bytes,src,bytes,pos,buflen-src);
1023                bytes[newlen] = 0;
1024            } else {
1025                bytes[newlen-1] = 0;
1026            }
1027            return bytes;
1028        }
1029    }
1030    public static final byte[] delete(byte[] bytes, int pos, int length, boolean copy) {
1031        if (length < 0) {
1032            throw new IllegalArgumentException JavaDoc("illegal length for delete");
1033        }
1034        int buflen = bytes.length;
1035        if (length == 0 || buflen == 0 ) {
1036            return bytes;
1037        }
1038        int newlen = buflen - length;
1039        int newpos = pos + length;
1040        if (pos < 0 || newpos > buflen) {
1041            throw new IllegalArgumentException JavaDoc("illegal position for delete");
1042        }
1043        if (copy) {
1044            if (newlen == 0) {
1045                return EMPTY_BYTES;
1046            }
1047            byte[] newbytes = new byte[newlen];
1048            if (pos == 0) {
1049                System.arraycopy(bytes,length,newbytes,0,newlen);
1050            } else if (pos == newlen) {
1051                System.arraycopy(bytes,0,newbytes,0,newlen);
1052            } else {
1053                System.arraycopy(bytes,0,newbytes,0,pos);
1054                System.arraycopy(bytes,newpos,newbytes,pos,buflen-newpos);
1055            }
1056            return newbytes;
1057        } else {
1058            if (newlen > 0) {
1059                System.arraycopy(bytes,newpos,bytes,pos,buflen-newpos);
1060            }
1061            fill(bytes,newlen,buflen-newlen,(byte)0);
1062            return bytes;
1063        }
1064    }
1065    /**
1066     * Inserts a single byte at the specified position. If copy is specified, creates
1067     * a new array one byte longer; otherwise shifts bytes in the existing array by one,
1068     * dropping the last byte.
1069     *
1070     * @param bytes
1071     * @param pos
1072     * @param value
1073     * @param copy
1074     * @return new array if copy was specified, otherwise the original array
1075     */

1076    public static final byte[] insert(byte[] bytes, int pos, byte value, boolean copy) {
1077        int buflen = bytes.length;
1078        if (pos < 0 || pos > buflen) {
1079            throw new IllegalArgumentException JavaDoc("illegal position for insert");
1080        }
1081        if (copy) {
1082            byte[] newbytes = new byte[buflen+1];
1083            if (pos == 0) {
1084                System.arraycopy(bytes,0,newbytes,1,buflen);
1085                newbytes[0] = value;
1086            } else if (pos == buflen) {
1087                System.arraycopy(bytes,0,newbytes,0,buflen);
1088                newbytes[buflen] = value;
1089            } else {
1090                System.arraycopy(bytes,0,newbytes,0,pos);
1091                System.arraycopy(bytes,pos,newbytes,pos+1,buflen-pos);
1092                newbytes[pos] = value;
1093            }
1094            return newbytes;
1095        } else {
1096            if (pos == buflen) {
1097                throw new IllegalArgumentException JavaDoc("illegal position for insert with no copy");
1098            }
1099            if (pos > buflen - 1) {
1100                System.arraycopy(bytes,pos,bytes,pos+1,buflen-pos-1);
1101            }
1102            bytes[pos] = value;
1103            return bytes;
1104        }
1105    }
1106    /**
1107     * Inserts the value array at the specified position. If copy is specified, creates a
1108     * new array, length == bytes.length + value.length. Otherwise, displaces bytes in
1109     * the exisiting array, shifting them right by value.length and dropping value.length
1110     * bytes from the end of the array.
1111     *
1112     * @param bytes
1113     * @param pos
1114     * @param value
1115     * @param copy
1116     * @return new array if copy was specified, otherwise the original array
1117     */

1118    public static final byte[] insert(byte[] bytes, int pos, byte[] value, boolean copy) {
1119        int buflen = bytes.length;
1120        if (pos < 0 || pos > buflen) {
1121            throw new IllegalArgumentException JavaDoc("illegal position for insert");
1122        }
1123        int vlen = value.length;
1124        if (copy) {
1125            int newlen = buflen + vlen;
1126            byte[] newbytes = new byte[newlen];
1127            if (pos == 0) {
1128                System.arraycopy(value,0,newbytes,0,vlen);
1129                System.arraycopy(bytes,0,newbytes,vlen,buflen);
1130            } else if (pos == buflen) {
1131                System.arraycopy(bytes,0,newbytes,0,buflen);
1132                System.arraycopy(value,0,newbytes,buflen,vlen);
1133            } else {
1134                System.arraycopy(bytes,0,newbytes,0,pos);
1135                System.arraycopy(value,0,newbytes,pos,vlen);
1136                System.arraycopy(bytes,pos,newbytes,pos+vlen,buflen-pos);
1137            }
1138            return newbytes;
1139        } else {
1140            int displace = pos + vlen;
1141            if (displace > buflen) {
1142                throw new IllegalArgumentException JavaDoc("inserted array won't fit in target array");
1143            }
1144            if (pos == 0) {
1145                System.arraycopy(bytes,0,bytes,vlen,buflen-vlen);
1146                System.arraycopy(value,0,bytes,0,vlen);
1147            } else if (displace == buflen) {
1148                System.arraycopy(value,0,bytes,pos,vlen);
1149            } else {
1150                System.arraycopy(bytes,pos,bytes,displace,buflen-displace);
1151                System.arraycopy(value,0,bytes,pos,vlen);
1152            }
1153            return bytes;
1154        }
1155        
1156    }
1157    public static final byte[] append(byte[] bytes, byte value) {
1158        int buflen = bytes.length;
1159        byte[] newbytes = new byte[buflen + 1];
1160        System.arraycopy(bytes,0,newbytes,0,buflen);
1161        bytes[buflen] = value;
1162        return bytes;
1163    }
1164    /**
1165     * Fills the array with the specified value, starting at the specified position,
1166     * for the specified length. No exception is thrown if length is too big; in that
1167     * case the array will be filled to the end.
1168     *
1169     * @param bytes
1170     * @param pos
1171     * @param length
1172     * @param value
1173     * @return
1174     */

1175    public static final byte[] fill(byte[] bytes, int pos, int length, byte value) {
1176        if (length < 0) {
1177            throw new IllegalArgumentException JavaDoc("illegal length for fill");
1178        }
1179        int buflen = bytes.length;
1180        int stop = pos + length;
1181        if (stop > buflen)
1182            stop = buflen;
1183        for ( ; pos < stop; pos++) {
1184            bytes[pos] = value;
1185        }
1186        return bytes;
1187    }
1188    /**
1189     * Returns a copy of the array, or the array itelf if its length == 0.
1190     *
1191     * @param bytes
1192     * @return
1193     */

1194    public static final byte[] copy(byte[] bytes) {
1195        int buflen = bytes.length;
1196        if (buflen == 0)
1197            return bytes;
1198        byte[] newbytes = new byte[buflen];
1199        System.arraycopy(bytes,0,newbytes,0,buflen);
1200        return newbytes;
1201    }
1202    private static final Long JavaDoc LONG_ZERO = new Long JavaDoc(0);
1203    
1204    private static final BigInteger JavaDoc BIG_INT_ZERO = BigInteger.valueOf(0L);
1205    
1206    private static final byte[] EMPTY_BYTES = {};
1207    
1208    private static final byte[] MIN_INT_BYTE_ARRAY = {
1209        '-','2','1','4','7','4','8','3','6','4','8'
1210        };
1211    private static final byte[] MIN_LONG_BYTE_ARRAY = {
1212        '-','9','2','2','3','3','7','2','0','3','6','8','5','4','7','7','5','8','0','8'
1213        };
1214    // Tables from java.lang.Integer, converted to byte (used in java.lang.Long as well)
1215
private static final int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
1216        99999999, 999999999, Integer.MAX_VALUE };
1217
1218    private static final byte[] digits = {
1219        '0' , '1' , '2' , '3' , '4' , '5' ,
1220        '6' , '7' , '8' , '9' , 'a' , 'b' ,
1221        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
1222        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
1223        'o' , 'p' , 'q' , 'r' , 's' , 't' ,
1224        'u' , 'v' , 'w' , 'x' , 'y' , 'z'
1225        };
1226
1227    private static final byte[] DigitTens = {
1228        '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
1229        '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
1230        '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
1231        '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
1232        '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
1233        '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
1234        '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
1235        '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
1236        '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
1237        '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
1238        } ;
1239
1240    private static final byte[] DigitOnes = {
1241        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1242        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1243        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1244        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1245        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1246        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1247        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1248        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1249        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1250        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1251        } ;
1252
1253    
1254    private static final char[] cdigits = {
1255        '0' , '1' , '2' , '3' , '4' , '5' ,
1256        '6' , '7' , '8' , '9' , 'a' , 'b' ,
1257        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
1258        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
1259        'o' , 'p' , 'q' , 'r' , 's' , 't' ,
1260        'u' , 'v' , 'w' , 'x' , 'y' , 'z'
1261        };
1262    private static final char [] cDigitTens = {
1263        '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
1264        '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
1265        '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
1266        '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
1267        '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
1268        '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
1269        '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
1270        '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
1271        '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
1272        '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
1273        } ;
1274
1275    private static final char [] cDigitOnes = {
1276        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1277        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1278        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1279        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1280        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1281        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1282        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1283        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1284        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1285        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1286        } ;
1287
1288}
1289
Popular Tags