001: /*
002: * $Id: HexConverter.java,v 1.32 2007/03/16 09:54:59 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.common.text;
008:
009: import org.xins.common.MandatoryArgumentChecker;
010:
011: /**
012: * Utility class for converting numbers to unsigned hex strings and vice
013: * versa.
014: *
015: * @version $Revision: 1.32 $ $Date: 2007/03/16 09:54:59 $
016: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
017: *
018: * @since XINS 1.0.0
019: */
020: public class HexConverter {
021:
022: /**
023: * The number of characters written when converting a <code>byte</code> to
024: * an unsigned hex string.
025: */
026: private static final int BYTE_LENGTH = 2;
027:
028: /**
029: * The number of characters written when converting a <code>short</code> to
030: * an unsigned hex string.
031: */
032: private static final int SHORT_LENGTH = 4;
033:
034: /**
035: * The number of characters written when converting a <code>char</code> to
036: * an unsigned hex string.
037: */
038: private static final int CHAR_LENGTH = 4;
039:
040: /**
041: * The number of characters written when converting a <code>int</code> to
042: * an unsigned hex string.
043: */
044: private static final int INT_LENGTH = 8;
045:
046: /**
047: * The number of characters written when converting a <code>long</code> to
048: * an unsigned hex string.
049: */
050: private static final int LONG_LENGTH = 16;
051:
052: /**
053: * The radix when converting (16).
054: */
055: private static final byte RADIX = 16;
056:
057: /**
058: * The radix mask as an <code>int</code>. Equal to {@link #RADIX}<code> -
059: * 1</code>.
060: */
061: private static final int INT_MASK = RADIX - 1;
062:
063: /**
064: * The radix mask as a <code>long</code>. Equal to {@link #RADIX}<code> -
065: * 1L</code>.
066: */
067: private static final long LONG_MASK = RADIX - 1L;
068:
069: /**
070: * Array of 2 zero characters.
071: */
072: private static final char[] TWO_ZEROES = { '0', '0' };
073:
074: /**
075: * Array of 4 zero characters.
076: */
077: private static final char[] FOUR_ZEROES = { '0', '0', '0', '0' };
078:
079: /**
080: * Array of 8 zero characters.
081: */
082: private static final char[] EIGHT_ZEROES = { '0', '0', '0', '0',
083: '0', '0', '0', '0' };
084:
085: /**
086: * Array of 16 zero characters.
087: */
088: private static final char[] SIXTEEN_ZEROES = { '0', '0', '0', '0',
089: '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' };
090:
091: /**
092: * Array that contains the hexadecimal digits, from 0 to 9 and from a to z.
093: */
094: private static final char[] DIGITS = { '0', '1', '2', '3', '4',
095: '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
096:
097: /**
098: * The '0' character.
099: */
100: private static final int CHAR_ZERO = (int) '0';
101:
102: /**
103: * The '9' character.
104: */
105: private static final int CHAR_NINE = (int) '9';
106:
107: /**
108: * The 'a' character.
109: */
110: private static final int CHAR_A = (int) 'a';
111:
112: /**
113: * The 'f' character.
114: */
115: private static final int CHAR_F = (int) 'f';
116:
117: /**
118: * The 'A' character.
119: */
120: private static final int CHAR_UP_A = (int) 'A';
121:
122: /**
123: * The 'f' character.
124: */
125: private static final int CHAR_UP_F = (int) 'F';
126:
127: /**
128: * The 'a' character lowered by 0xA.
129: */
130: private static final int CHAR_A_FACTOR = CHAR_A - 10;
131:
132: /**
133: * The 'A' character lowered by 0xA.
134: */
135: private static final int CHAR_UP_A_FACTOR = CHAR_UP_A - 10;
136:
137: /**
138: * Creates a new <code>HexConverter</code> object.
139: */
140: private HexConverter() {
141: // empty
142: }
143:
144: /**
145: * Checks if the specified character is a hexadecimal digit. The following
146: * ranges of characters are considered hexadecimal digits:
147: *
148: * <ul>
149: * <li><code>'0'</code> to <code>'9'</code>
150: * <li><code>'a'</code> to <code>'f'</code>
151: * <li><code>'A'</code> to <code>'F'</code>
152: * </ul>
153: *
154: * @param c
155: * the character to check.
156: *
157: * @return
158: * <code>true</code> if the specified character is a hexadecimal digit,
159: * <code>false</code> otherwise.
160: */
161: public static final boolean isHexDigit(char c) {
162: return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
163: || (c >= 'A' && c <= 'F');
164: }
165:
166: /**
167: * Converts the specified <code>byte</code> array to an unsigned number hex
168: * string. The number of characters in the returned string will always be
169: * equal to the number of input bytes times 2.
170: *
171: * @param input
172: * the <code>byte[]</code> array to be converted to a hex string.
173: *
174: * @return
175: * the hex string, cannot be <code>null</code>, the length is always 2
176: * times the length of the input array
177: * (i.e. <code><em>return</em>.</code>{@link String#length() length()}<code> == (input.length * 2)</code>).
178: *
179: * @throws IllegalArgumentException
180: * if <code>n == null || n.length < 1</code>.
181: */
182: public static String toHexString(byte[] input)
183: throws IllegalArgumentException {
184:
185: // Check preconditions
186: MandatoryArgumentChecker.check("input", input);
187: if (input.length < 1) {
188: throw new IllegalArgumentException("input.length ("
189: + input.length + ") < 1");
190: }
191:
192: // Construct a new char array to store the hex digits in
193: int length = input.length;
194: char[] chars = new char[length * 2];
195:
196: int pos = 0;
197: for (int i = 0; i < length; i++) {
198:
199: int n = (int) input[i];
200: chars[pos++] = DIGITS[(n & 0x000000f0) >> 4];
201: chars[pos++] = DIGITS[(n & 0x0000000f)];
202: }
203:
204: return new String(chars, 0, length * 2);
205: }
206:
207: /**
208: * Converts the specified <code>byte</code> to an unsigned number hex
209: * string. The returned string will always consist of 2 hex characters,
210: * a zero will be prepended if necessary.
211: *
212: * @param n
213: * the number to be converted to a hex string.
214: *
215: * @return
216: * the hex string, cannot be <code>null</code>, the length is always 2
217: * (i.e. <code><em>return</em>.</code>{@link String#length() length()}<code> == 2</code>).
218: */
219: public static String toHexString(byte n) {
220:
221: // First convert to int, since there are no Java opcodes for bytes
222: byte i = (byte) n;
223:
224: char[] chars = new char[BYTE_LENGTH];
225: chars[0] = DIGITS[(i & 0x000000f0) >> 4];
226: chars[1] = DIGITS[(i & 0x0000000f)];
227:
228: return new String(chars);
229: }
230:
231: /**
232: * Converts the specified <code>short</code> to an unsigned number hex
233: * string. The returned string will always consist of 4 hex characters,
234: * zeroes will be prepended as necessary.
235: *
236: * @param n
237: * the number to be converted to a hex string.
238: *
239: * @return
240: * the hex string, cannot be <code>null</code>, the length is always 4
241: * (i.e. <code><em>return</em>.</code>{@link String#length() length()}<code> == 4</code>).
242: */
243: public static String toHexString(short n) {
244:
245: // First convert to int, since there are no Java opcodes for shorts
246: int i = ((int) n) & 0x0000ffff;
247:
248: char[] chars = new char[SHORT_LENGTH];
249: int pos = SHORT_LENGTH - 1;
250:
251: // Convert the number to a hex string until the remainder is 0
252: for (; i != 0; i >>>= 4) {
253: chars[pos--] = DIGITS[i & INT_MASK];
254: }
255:
256: // Fill the rest with '0' characters
257: for (; pos >= 0; pos--) {
258: chars[pos] = '0';
259: }
260:
261: return new String(chars, 0, SHORT_LENGTH);
262: }
263:
264: /**
265: * Converts the specified <code>char</code> to an unsigned number hex
266: * string. The returned string will always consist of 4 hex characters,
267: * zeroes will be prepended as necessary.
268: *
269: * @param n
270: * the character to be converted to a hex string.
271: *
272: * @return
273: * the hex string, cannot be <code>null</code>, the length is always 4
274: * (i.e. <code><em>return</em>.</code>{@link String#length() length()}<code> == 4</code>).
275: */
276: public static String toHexString(char n) {
277:
278: // First convert to int, since there are no Java opcodes for shorts
279: int i = (int) n;
280:
281: char[] chars = new char[CHAR_LENGTH];
282: int pos = CHAR_LENGTH - 1;
283:
284: // Convert the number to a hex string until the remainder is 0
285: for (; i != 0; i >>>= 4) {
286: chars[pos--] = DIGITS[i & INT_MASK];
287: }
288:
289: // Fill the rest with '0' characters
290: for (; pos >= 0; pos--) {
291: chars[pos] = '0';
292: }
293:
294: return new String(chars, 0, CHAR_LENGTH);
295: }
296:
297: /**
298: * Converts the specified <code>int</code> to an unsigned number hex
299: * string. The returned string will always consist of 8 hex characters,
300: * zeroes will be prepended as necessary.
301: *
302: * @param n
303: * the number to be converted to a hex string.
304: *
305: * @return
306: * the hex string, cannot be <code>null</code>, the length is always 8
307: * (i.e. <code><em>return</em>.</code>{@link String#length() length()}<code> == 8</code>).
308: */
309: public static String toHexString(int n) {
310:
311: char[] chars = new char[INT_LENGTH];
312: int pos = INT_LENGTH - 1;
313:
314: // Convert the int to a hex string until the remainder is 0
315: for (; n != 0; n >>>= 4) {
316: chars[pos--] = DIGITS[n & INT_MASK];
317: }
318:
319: // Fill the rest with '0' characters
320: for (; pos >= 0; pos--) {
321: chars[pos] = '0';
322: }
323:
324: return new String(chars, 0, INT_LENGTH);
325: }
326:
327: /**
328: * Convert the specified <code>long</code> to an unsigned number hex
329: * string. The returned string will always consist of 16 hex characters,
330: * zeroes will be prepended as necessary.
331: *
332: * @param n
333: * the number to be converted to a hex string.
334: *
335: * @return
336: * the hex string, cannot be <code>null</code>, the length is always 16
337: * (i.e. <code><em>return</em>.</code>{@link String#length() length()}<code> == 16</code>).
338: */
339: public static String toHexString(long n) {
340:
341: char[] chars = new char[LONG_LENGTH];
342: int pos = LONG_LENGTH - 1;
343:
344: // Convert the long to a hex string until the remainder is 0
345: for (; n != 0; n >>>= 4) {
346: chars[pos--] = DIGITS[(int) (n & LONG_MASK)];
347: }
348:
349: // Fill the rest with '0' characters
350: for (; pos >= 0; pos--) {
351: chars[pos] = '0';
352: }
353:
354: return new String(chars, 0, LONG_LENGTH);
355: }
356:
357: /**
358: * Converts the specified <code>byte</code> to unsigned number and appends
359: * it to the specified string buffer. Exactly 2 characters will be
360: * appended, both between <code>'0'</code> to <code>'9'</code> or between
361: * <code>'a'</code> and <code>'f'</code>.
362: *
363: * @param buffer
364: * the string buffer to append to, cannot be <code>null</code>.
365: *
366: * @param n
367: * the number to be converted to a hex string.
368: *
369: * @throws IllegalArgumentException
370: * if <code>buffer == null</code>.
371: *
372: * @since XINS 1.3.0
373: * @deprecated since XINS 2.0, use toHexString(byte).
374: */
375: public static void toHexString(FastStringBuffer buffer, byte n)
376: throws IllegalArgumentException {
377:
378: // Check preconditions
379: if (buffer == null) {
380: throw new IllegalArgumentException("buffer == null");
381: }
382:
383: // Store the starting position where the buffer should write the value.
384: int initPos = buffer.getLength();
385:
386: // Append 2 zero characters to the buffer
387: buffer.append(TWO_ZEROES);
388:
389: int pos = initPos + BYTE_LENGTH - 1;
390:
391: // Convert the short to a hex string until the remainder is 0
392: int x = ((int) n) & 0x000000ff;
393: for (; x != 0; x >>>= 4) {
394: buffer.setChar(pos--, DIGITS[x & INT_MASK]);
395: }
396: }
397:
398: /**
399: * Converts the specified <code>short</code> to unsigned number and appends
400: * it to the specified string buffer. Exactly 4 characters will be
401: * appended, all between <code>'0'</code> to <code>'9'</code> or between
402: * <code>'a'</code> and <code>'f'</code>.
403: *
404: * @param buffer
405: * the string buffer to append to, cannot be <code>null</code>.
406: *
407: * @param n
408: * the number to be converted to a hex string.
409: *
410: * @throws IllegalArgumentException
411: * if <code>buffer == null</code>.
412: *
413: * @since XINS 1.3.0
414: * @deprecated since XINS 2.0, use toHexString(short).
415: */
416: public static void toHexString(FastStringBuffer buffer, short n)
417: throws IllegalArgumentException {
418:
419: // Check preconditions
420: if (buffer == null) {
421: throw new IllegalArgumentException("buffer == null");
422: }
423:
424: // Store the starting position where the buffer should write the value.
425: int initPos = buffer.getLength();
426:
427: // Append 4 zero characters to the buffer
428: buffer.append(FOUR_ZEROES);
429:
430: int pos = initPos + SHORT_LENGTH - 1;
431:
432: // Convert the short to a hex string until the remainder is 0
433: int x = ((int) n) & 0x0000ffff;
434: for (; x != 0; x >>>= 4) {
435: buffer.setChar(pos--, DIGITS[x & INT_MASK]);
436: }
437: }
438:
439: /**
440: * Converts the specified <code>char</code> to unsigned number and appends
441: * it to the specified string buffer. Exactly 4 characters will be
442: * appended, all between <code>'0'</code> to <code>'9'</code> or between
443: * <code>'a'</code> and <code>'f'</code>.
444: *
445: * @param buffer
446: * the string buffer to append to, cannot be <code>null</code>.
447: *
448: * @param n
449: * the number to be converted to a hex string.
450: *
451: * @throws IllegalArgumentException
452: * if <code>buffer == null</code>.
453: *
454: * @since XINS 1.3.0
455: * @deprecated since XINS 2.0, use toHexString(char).
456: */
457: public static void toHexString(FastStringBuffer buffer, char n)
458: throws IllegalArgumentException {
459:
460: // Check preconditions
461: if (buffer == null) {
462: throw new IllegalArgumentException("buffer == null");
463: }
464:
465: // Store the starting position where the buffer should write the value.
466: int initPos = buffer.getLength();
467:
468: // Append 4 zero characters to the buffer
469: buffer.append(FOUR_ZEROES);
470:
471: int pos = initPos + SHORT_LENGTH - 1;
472:
473: // Convert the char to a hex string until the remainder is 0
474: int x = ((int) n) & 0x0000ffff;
475: for (; x != 0; x >>>= 4) {
476: buffer.setChar(pos--, DIGITS[x & INT_MASK]);
477: }
478: }
479:
480: /**
481: * Converts the specified <code>int</code> to unsigned number and appends
482: * it to the specified string buffer. Exactly 8 characters will be
483: * appended, all between <code>'0'</code> to <code>'9'</code> or between
484: * <code>'a'</code> and <code>'f'</code>.
485: *
486: * @param buffer
487: * the string buffer to append to, cannot be <code>null</code>.
488: *
489: * @param n
490: * the number to be converted to a hex string.
491: *
492: * @throws IllegalArgumentException
493: * if <code>buffer == null</code>.
494: * @deprecated since XINS 2.0, use toHexString(int).
495: */
496: public static void toHexString(FastStringBuffer buffer, int n)
497: throws IllegalArgumentException {
498:
499: // Check preconditions
500: if (buffer == null) {
501: throw new IllegalArgumentException("buffer == null");
502: }
503:
504: // Store the starting position where the buffer should write the value.
505: int initPos = buffer.getLength();
506:
507: // Append 8 zero characters to the buffer
508: buffer.append(EIGHT_ZEROES);
509:
510: int pos = initPos + INT_LENGTH - 1;
511:
512: // Convert the int to a hex string until the remainder is 0
513: for (; n != 0; n >>>= 4) {
514: buffer.setChar(pos--, DIGITS[n & INT_MASK]);
515: }
516: }
517:
518: /**
519: * Converts the specified <code>long</code> to unsigned number and appends
520: * it to the specified string buffer. Exactly 16 characters will be
521: * appended, all between <code>'0'</code> to <code>'9'</code> or between
522: * <code>'a'</code> and <code>'f'</code>.
523: *
524: * @param buffer
525: * the string buffer to append to, cannot be <code>null</code>.
526: *
527: * @param n
528: * the number to be converted to a hex string.
529: *
530: * @throws IllegalArgumentException
531: * if <code>buffer == null</code>.
532: * @deprecated since XINS 2.0, use toHexString(long).
533: */
534: public static void toHexString(FastStringBuffer buffer, long n)
535: throws IllegalArgumentException {
536:
537: // Check preconditions
538: if (buffer == null) {
539: throw new IllegalArgumentException("buffer == null");
540: }
541:
542: // Store the starting position where the buffer should write the value.
543: int initPos = buffer.getLength();
544:
545: // Append 16 zero characters to the buffer
546: buffer.append(SIXTEEN_ZEROES);
547:
548: int pos = initPos + LONG_LENGTH - 1;
549:
550: // Convert the long to a hex string until the remainder is 0
551: for (; n != 0; n >>>= 4) {
552: buffer.setChar(pos--, DIGITS[(int) (n & LONG_MASK)]);
553: }
554: }
555:
556: /**
557: * Parses the specified string as a set of hex digits and converts it to a
558: * byte array.
559: *
560: * @param s
561: * the hexadecimal string, cannot be <code>null</code>.
562: *
563: * @param index
564: * the starting index in the string, must be >= 0.
565: *
566: * @param length
567: * the number of characters to convert in the string, must be >= 0.
568: *
569: * @return
570: * the value of the parsed unsigned hexadecimal string, as an array of
571: * bytes.
572: *
573: * @throws IllegalArgumentException
574: * if <code>s == null || index < 0 || length < 1 || s.{@link String#length() length()} < index + length</code>).
575: *
576: * @throws NumberFormatException
577: * if any of the characters in the specified range of the string is not
578: * a hex digit (<code>'0'</code> to <code>'9'</code>,
579: * <code>'a'</code> to <code>'f'</code> and
580: * <code>'A'</code> to <code>'F'</code>).
581: */
582: public static byte[] parseHexBytes(String s, int index, int length)
583: throws IllegalArgumentException, NumberFormatException {
584:
585: // Check preconditions
586: if (s == null) {
587: throw new IllegalArgumentException("s == null");
588: } else if (index < 0) {
589: throw new IllegalArgumentException("index (" + index
590: + ") < 0");
591: } else if (length < 1) {
592: throw new IllegalArgumentException("length (" + length
593: + ") < 1");
594: } else if (s.length() < index + length) {
595: throw new IllegalArgumentException("s.length() ("
596: + s.length() + ") < index (" + index
597: + ") + length (" + length + ')');
598: }
599:
600: byte[] bytes = new byte[(length / 2) + (length % 2)];
601:
602: // Loop through all characters
603: int top = index + length;
604: int pos = 0;
605: for (int i = index; i < top; i++) {
606: int c = (int) s.charAt(i);
607:
608: int upper;
609: if (c >= CHAR_ZERO && c <= CHAR_NINE) {
610: upper = (c - CHAR_ZERO);
611: } else if (c >= CHAR_A && c <= CHAR_F) {
612: upper = (c - CHAR_A_FACTOR);
613: } else if (c >= CHAR_UP_A && c <= CHAR_UP_F) {
614: upper = (c - CHAR_UP_A_FACTOR);
615: } else {
616: throw new NumberFormatException("s.charAt(" + i
617: + ") == '" + s.charAt(i) + '\'');
618: }
619:
620: // Proceed to next char, which is the lower nibble of the byte
621: i++;
622:
623: int lower = 0;
624: if (i < top) {
625: c = (int) s.charAt(i);
626:
627: if (c >= CHAR_ZERO && c <= CHAR_NINE) {
628: lower = (c - CHAR_ZERO);
629: } else if (c >= CHAR_A && c <= CHAR_F) {
630: lower = (c - CHAR_A_FACTOR);
631: } else if (c >= CHAR_UP_A && c <= CHAR_UP_F) {
632: lower = (c - CHAR_UP_A_FACTOR);
633: } else {
634: throw new NumberFormatException("s.charAt(" + i
635: + ") == '" + s.charAt(i) + '\'');
636: }
637: }
638:
639: upper <<= 4;
640: bytes[pos++] = (byte) (upper | lower);
641: }
642:
643: return bytes;
644: }
645:
646: /**
647: * Parses the 8-digit unsigned hex number in the specified string.
648: *
649: * @param s
650: * the hexadecimal string, cannot be <code>null</code>.
651: *
652: * @param index
653: * the starting index in the string, must be >= 0.
654: *
655: * @return
656: * the value of the parsed unsigned hexadecimal string.
657: *
658: * @throws IllegalArgumentException
659: * if <code>s == null
660: * || index < 0
661: * || s.{@link String#length() length()} < index + 8</code>).
662: *
663: * @throws NumberFormatException
664: * if any of the characters in the specified range of the string is not
665: * a hex digit (<code>'0'</code> to <code>'9'</code> and
666: * <code>'a'</code> to <code>'f'</code>).
667: */
668: public static int parseHexInt(String s, int index)
669: throws IllegalArgumentException, NumberFormatException {
670:
671: // Check preconditions
672: if (s == null) {
673: throw new IllegalArgumentException("s == null");
674: } else if (s.length() < index + 8) {
675: throw new IllegalArgumentException("s.length() ("
676: + s.length() + ") < index (" + index + ") + 8 ("
677: + (index + 8) + ')');
678: }
679:
680: int n = 0;
681:
682: // Loop through all characters
683: int last = index + 8;
684: for (int i = index; i < last; i++) {
685: int c = (int) s.charAt(i);
686: n <<= 4;
687: if (c >= CHAR_ZERO && c <= CHAR_NINE) {
688: n |= (c - CHAR_ZERO);
689: } else if (c >= CHAR_A && c <= CHAR_F) {
690: n |= (c - CHAR_A_FACTOR);
691: } else if (c >= CHAR_UP_A && c <= CHAR_UP_F) {
692: n |= (c - CHAR_UP_A_FACTOR);
693: } else {
694: throw new NumberFormatException("s.charAt(" + i
695: + ") == '" + s.charAt(i) + '\'');
696: }
697: }
698:
699: return n;
700: }
701:
702: /**
703: * Parses the specified 8-digit unsigned hex string.
704: *
705: * @param s
706: * the hexadecimal string, cannot be <code>null</code> and must have
707: * size 8
708: * (i.e. <code>s.</code>{@link String#length() length()}<code> == 8</code>).
709: *
710: * @return
711: * the value of the parsed unsigned hexadecimal string.
712: *
713: * @throws IllegalArgumentException
714: * if <code>s == null || s.</code>{@link String#length() length()}<code> != 8</code>.
715: *
716: * @throws NumberFormatException
717: * if any of the characters in the specified string is not a hex digit
718: * (<code>'0'</code> to <code>'9'</code> and <code>'a'</code> to
719: * <code>'f'</code>).
720: */
721: public static int parseHexInt(String s)
722: throws IllegalArgumentException, NumberFormatException {
723:
724: // Check preconditions
725: if (s == null) {
726: throw new IllegalArgumentException("s == null");
727: } else if (s.length() != 8) {
728: throw new IllegalArgumentException("s.length() != 8");
729: }
730:
731: return parseHexInt(s, 0);
732: }
733:
734: /**
735: * Parses the 16-digit unsigned hex number in the specified string.
736: *
737: * @param s
738: * the hexadecimal string, cannot be <code>null</code>.
739: *
740: * @param index
741: * the starting index in the string, must be >= 0.
742: *
743: * @return
744: * the value of the parsed unsigned hexadecimal string.
745: *
746: * @throws IllegalArgumentException
747: * if <code>s == null
748: * || index < 0
749: * || s.{@link String#length() length()} < index + 16</code>).
750: *
751: * @throws NumberFormatException
752: * if any of the characters in the specified range of the string is not
753: * a hex digit (<code>'0'</code> to <code>'9'</code> and
754: * <code>'a'</code> to <code>'f'</code>).
755: */
756: public static long parseHexLong(String s, int index)
757: throws IllegalArgumentException, NumberFormatException {
758:
759: // Check preconditions
760: if (s == null) {
761: throw new IllegalArgumentException("s == null");
762: } else if (s.length() < index + 16) {
763: throw new IllegalArgumentException("s.length() ("
764: + s.length() + ") < index (" + index + ") + 16 ("
765: + (index + 16) + ')');
766: }
767:
768: long n = 0L;
769:
770: // Loop through all characters
771: int last = index + 16;
772: for (int i = index; i < last; i++) {
773: int c = (int) s.charAt(i);
774: n <<= 4;
775: if (c >= CHAR_ZERO && c <= CHAR_NINE) {
776: n |= (c - CHAR_ZERO);
777: } else if (c >= CHAR_A && c <= CHAR_F) {
778: n |= (c - CHAR_A_FACTOR);
779: } else if (c >= CHAR_UP_A && c <= CHAR_UP_F) {
780: n |= (c - CHAR_UP_A_FACTOR);
781: } else {
782: throw new NumberFormatException("s.charAt(" + i
783: + ") == '" + s.charAt(i) + '\'');
784: }
785: }
786:
787: return n;
788: }
789:
790: /**
791: * Parses the specified 16-digit unsigned hex string.
792: *
793: * @param s
794: * the hexadecimal string, cannot be <code>null</code> and must have
795: * size 16
796: * (i.e. <code>s.</code>{@link String#length() length()}<code> == 16</code>).
797: *
798: * @return
799: * the value of the parsed unsigned hexadecimal string.
800: *
801: * @throws IllegalArgumentException
802: * if <code>s == null || s.</code>{@link String#length() length()}<code> != 16</code>.
803: *
804: * @throws NumberFormatException
805: * if any of the characters in the specified string is not a hex digit
806: * (<code>'0'</code> to <code>'9'</code> and <code>'a'</code> to
807: * <code>'f'</code>).
808: */
809: public static long parseHexLong(String s)
810: throws IllegalArgumentException, NumberFormatException {
811:
812: // Check preconditions
813: if (s == null) {
814: throw new IllegalArgumentException("s == null");
815: } else if (s.length() != 16) {
816: throw new IllegalArgumentException("s.length() != 16");
817: }
818:
819: return parseHexLong(s, 0);
820: }
821: }
|