001: /*
002: * Licensed under the Apache License, Version 2.0 (the "License");
003: * you may not use this file except in compliance with the License.
004: * You may obtain a copy of the License at
005: *
006: * http://www.apache.org/licenses/LICENSE-2.0
007: *
008: * Unless required by applicable law or agreed to in writing, software
009: * distributed under the License is distributed on an "AS IS" BASIS,
010: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: * See the License for the specific language governing permissions and
012: * limitations under the License.
013: */
014: package org.apache.catalina.util;
015:
016: import java.io.ByteArrayOutputStream;
017:
018: /**
019: * Library of utility methods useful in dealing with converting byte arrays
020: * to and from strings of hexadecimal digits.
021: *
022: * Note: this package has been stripped of its localization capabilities,
023: * to lessen library dependencies and increase portability.
024: * - ARJ, 4/04
025: *
026: * @author Craig R. McClanahan
027: * @since 2.3
028: */
029:
030: public final class HexUtils {
031: // Code from Ajp11, from Apache's JServ
032:
033: // Table for HEX to DEC byte translation
034: static final int[] DEC = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
035: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
036: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
037: -1, -1, -1, -1, -1, -1, -1, -1, 00, 01, 02, 03, 04, 05, 06,
038: 07, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14,
039: 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
040: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12,
041: 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
042: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
043: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
044: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
045: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
046: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
047: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
048: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
049: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
050: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
051: -1, -1, -1, -1, -1, -1, };
052:
053: /**
054: * Convert a String of hexadecimal digits into the corresponding
055: * byte array by encoding each two hexadecimal digits as a byte.
056: *
057: * @param digits Hexadecimal digits representation
058: *
059: * @exception IllegalArgumentException if an invalid hexadecimal digit
060: * is found, or the input string contains an odd number of hexadecimal
061: * digits
062: */
063: public static byte[] convert(String digits) {
064:
065: ByteArrayOutputStream baos = new ByteArrayOutputStream();
066: for (int i = 0; i < digits.length(); i += 2) {
067: char c1 = digits.charAt(i);
068: if ((i + 1) >= digits.length())
069: throw new IllegalArgumentException(
070: "Odd number of hexadecimal digits");
071: char c2 = digits.charAt(i + 1);
072: byte b = 0;
073: if ((c1 >= '0') && (c1 <= '9'))
074: b += (c1 - '0') * 16;
075: else if ((c1 >= 'a') && (c1 <= 'f'))
076: b += (c1 - 'a' + 10) * 16;
077: else if ((c1 >= 'A') && (c1 <= 'F'))
078: b += (c1 - 'A' + 10) * 16;
079: else
080: throw new IllegalArgumentException(
081: "Bad hexadecimal digit");
082: if ((c2 >= '0') && (c2 <= '9'))
083: b += c2 - '0';
084: else if ((c2 >= 'a') && (c2 <= 'f'))
085: b += c2 - 'a' + 10;
086: else if ((c2 >= 'A') && (c2 <= 'F'))
087: b += c2 - 'A' + 10;
088: else
089: throw new IllegalArgumentException(
090: "Bad hexadecimal digit");
091: baos.write(b);
092: }
093: return baos.toByteArray();
094:
095: }
096:
097: /**
098: * Convert a byte array into a printable format containing a
099: * String of hexadecimal digit characters (two per byte).
100: *
101: * @param bytes Byte array representation
102: */
103: public static String convert(byte[] bytes) {
104:
105: StringBuffer sb = new StringBuffer(bytes.length * 2);
106: for (int i = 0; i < bytes.length; i++) {
107: sb.append(convertDigit(bytes[i] >> 4));
108: sb.append(convertDigit(bytes[i] & 0x0f));
109: }
110: return sb.toString();
111:
112: }
113:
114: /**
115: * Convert 4 hex digits to an int, and return the number of converted
116: * bytes.
117: *
118: * @param hex Byte array containing exactly four hexadecimal digits
119: *
120: * @exception IllegalArgumentException if an invalid hexadecimal digit
121: * is included
122: */
123: public static int convert2Int(byte[] hex) {
124: // Code from Ajp11, from Apache's JServ
125:
126: // assert b.length==4
127: // assert valid data
128: int len;
129: if (hex.length < 4)
130: return 0;
131: if (DEC[hex[0]] < 0)
132: throw new IllegalArgumentException("Bad hexadecimal digit");
133: len = DEC[hex[0]];
134: len = len << 4;
135: if (DEC[hex[1]] < 0)
136: throw new IllegalArgumentException("Bad hexadecimal digit");
137: len += DEC[hex[1]];
138: len = len << 4;
139: if (DEC[hex[2]] < 0)
140: throw new IllegalArgumentException("Bad hexadecimal digit");
141: len += DEC[hex[2]];
142: len = len << 4;
143: if (DEC[hex[3]] < 0)
144: throw new IllegalArgumentException("Bad hexadecimal digit");
145: len += DEC[hex[3]];
146: return len;
147: }
148:
149: /**
150: * [Private] Convert the specified value (0 .. 15) to the corresponding
151: * hexadecimal digit.
152: *
153: * @param value Value to be converted
154: */
155: private static char convertDigit(int value) {
156:
157: value &= 0x0f;
158: if (value >= 10) {
159: return (char) (value - 10 + 'a');
160: }
161: return (char) (value + '0');
162: }
163:
164: }
|