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    }