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 * @since 2.3
027 */
028
029 public final class HexUtils
030 {
031 // Code from Ajp11, from Apache's JServ
032
033 // Table for HEX to DEC byte translation
034 static final int[] DEC =
035 {
036 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
037 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
038 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
039 00, 01, 02, 03, 04, 05, 06, 07, 8, 9, -1, -1, -1, -1, -1, -1,
040 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
041 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
042 -1, 10, 11, 12, 13, 14, 15, -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, -1,
044 -1, -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, -1,
046 -1, -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, -1,
048 -1, -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, -1,
050 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
051 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
052 };
053
054 /**
055 * Convert a String of hexadecimal digits into the corresponding
056 * byte array by encoding each two hexadecimal digits as a byte.
057 *
058 * @param digits Hexadecimal digits representation
059 *
060 * @exception IllegalArgumentException if an invalid hexadecimal digit
061 * is found, or the input string contains an odd number of hexadecimal
062 * digits
063 */
064 public static byte[] convert(String digits)
065 {
066
067 ByteArrayOutputStream baos = new ByteArrayOutputStream();
068 for (int i = 0; i < digits.length(); i += 2)
069 {
070 char c1 = digits.charAt(i);
071 if ((i+1) >= digits.length())
072 throw new IllegalArgumentException
073 ("Odd number of hexadecimal digits");
074 char c2 = digits.charAt(i + 1);
075 byte b = 0;
076 if ((c1 >= '0') && (c1 <= '9'))
077 b += (c1 - '0') * 16;
078 else if ((c1 >= 'a') && (c1 <= 'f'))
079 b += (c1 - 'a' + 10) * 16;
080 else if ((c1 >= 'A') && (c1 <= 'F'))
081 b += (c1 - 'A' + 10) * 16;
082 else
083 throw new IllegalArgumentException
084 ("Bad hexadecimal digit");
085 if ((c2 >= '0') && (c2 <= '9'))
086 b += c2 - '0';
087 else if ((c2 >= 'a') && (c2 <= 'f'))
088 b += c2 - 'a' + 10;
089 else if ((c2 >= 'A') && (c2 <= 'F'))
090 b += c2 - 'A' + 10;
091 else
092 throw new IllegalArgumentException
093 ("Bad hexadecimal digit");
094 baos.write(b);
095 }
096 return baos.toByteArray();
097
098 }
099
100
101 /**
102 * Convert a byte array into a printable format containing a
103 * String of hexadecimal digit characters (two per byte).
104 *
105 * @param bytes Byte array representation
106 */
107 public static String convert(byte[] bytes)
108 {
109
110 StringBuffer sb = new StringBuffer(bytes.length * 2);
111 for (int i = 0; i < bytes.length; i++)
112 {
113 sb.append(convertDigit(bytes[i] >> 4));
114 sb.append(convertDigit(bytes[i] & 0x0f));
115 }
116 return sb.toString();
117
118 }
119
120 /**
121 * Convert 4 hex digits to an int, and return the number of converted
122 * bytes.
123 *
124 * @param hex Byte array containing exactly four hexadecimal digits
125 *
126 * @exception IllegalArgumentException if an invalid hexadecimal digit
127 * is included
128 */
129 public static int convert2Int( byte[] hex )
130 {
131 // Code from Ajp11, from Apache's JServ
132
133 // assert b.length==4
134 // assert valid data
135 int len;
136 if(hex.length < 4 ) return 0;
137 if( DEC[hex[0]]<0 )
138 throw new IllegalArgumentException("Bad hexadecimal digit");
139 len = DEC[hex[0]];
140 len = len << 4;
141 if( DEC[hex[1]]<0 )
142 throw new IllegalArgumentException("Bad hexadecimal digit");
143 len += DEC[hex[1]];
144 len = len << 4;
145 if( DEC[hex[2]]<0 )
146 throw new IllegalArgumentException("Bad hexadecimal digit");
147 len += DEC[hex[2]];
148 len = len << 4;
149 if( DEC[hex[3]]<0 )
150 throw new IllegalArgumentException("Bad hexadecimal digit");
151 len += DEC[hex[3]];
152 return len;
153 }
154
155 /**
156 * [Private] Convert the specified value (0 .. 15) to the corresponding
157 * hexadecimal digit.
158 *
159 * @param value Value to be converted
160 */
161 private static char convertDigit(int value)
162 {
163
164 value &= 0x0f;
165 if (value >= 10)
166 {
167 return (char) (value - 10 + 'a');
168 }
169 return (char) (value + '0');
170 }
171
172 }