001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    
021    package org.apache.directory.shared.asn1.codec.binary;
022    
023    
024    import org.apache.directory.shared.asn1.codec.BinaryDecoder;
025    import org.apache.directory.shared.asn1.codec.BinaryEncoder;
026    import org.apache.directory.shared.asn1.codec.DecoderException;
027    import org.apache.directory.shared.asn1.codec.EncoderException;
028    import org.apache.directory.shared.i18n.I18n;
029    
030    
031    /**
032     * Hex encoder and decoder.
033     * 
034     * @since 1.1
035     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
036     * @version $Id: Hex.java 912399 2010-02-21 20:52:31Z felixk $
037     */
038    public class Hex implements BinaryEncoder, BinaryDecoder
039    {
040    
041        /**
042         * Used to build output as Hex
043         */
044        private static final char[] DIGITS =
045            { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
046    
047    
048        /**
049         * Converts an array of characters representing hexidecimal values into an
050         * array of bytes of those same values. The returned array will be half the
051         * length of the passed array, as it takes two characters to represent any
052         * given byte. An exception is thrown if the passed char array has an odd
053         * number of elements.
054         * 
055         * @param data
056         *            An array of characters containing hexidecimal digits
057         * @return A byte array containing binary data decoded from the supplied
058         *         char array.
059         * @throws DecoderException
060         *             Thrown if an odd number or illegal of characters is supplied
061         */
062        public static byte[] decodeHex( char[] data ) throws DecoderException
063        {
064    
065            int len = data.length;
066    
067            if ( ( len & 0x01 ) != 0 )
068            {
069                throw new DecoderException( I18n.err( I18n.ERR_00013 ) );
070            }
071    
072            byte[] out = new byte[len >> 1];
073    
074            // two characters form the hex value.
075            for ( int i = 0, j = 0; j < len; i++ )
076            {
077                int f = toDigit( data[j], j ) << 4;
078                j++;
079                f |= toDigit( data[j], j );
080                j++;
081                out[i] = ( byte ) ( f & 0xFF );
082            }
083    
084            return out;
085        }
086    
087    
088        /**
089         * Converts a hexadecimal character to an integer.
090         * 
091         * @param ch
092         *            A character to convert to an integer digit
093         * @param index
094         *            The index of the character in the source
095         * @return An integer
096         * @throws DecoderException
097         *             Thrown if ch is an illegal hex character
098         */
099        protected static int toDigit( char ch, int index ) throws DecoderException
100        {
101            int digit = Character.digit( ch, 16 );
102            if ( digit == -1 )
103            {
104                throw new DecoderException( I18n.err( I18n.ERR_00014, ch, index ) );
105            }
106            return digit;
107        }
108    
109    
110        /**
111         * Converts an array of bytes into an array of characters representing the
112         * hexidecimal values of each byte in order. The returned array will be
113         * double the length of the passed array, as it takes two characters to
114         * represent any given byte.
115         * 
116         * @param data
117         *            a byte[] to convert to Hex characters
118         * @return A char[] containing hexidecimal characters
119         */
120        public static char[] encodeHex( byte[] data )
121        {
122    
123            int l = data.length;
124    
125            char[] out = new char[l << 1];
126    
127            // two characters form the hex value.
128            for ( int i = 0, j = 0; i < l; i++ )
129            {
130                out[j++] = DIGITS[( 0xF0 & data[i] ) >>> 4];
131                out[j++] = DIGITS[0x0F & data[i]];
132            }
133    
134            return out;
135        }
136    
137    
138        /**
139         * Converts an array of character bytes representing hexidecimal values into
140         * an array of bytes of those same values. The returned array will be half
141         * the length of the passed array, as it takes two characters to represent
142         * any given byte. An exception is thrown if the passed char array has an
143         * odd number of elements.
144         * 
145         * @param array
146         *            An array of character bytes containing hexidecimal digits
147         * @return A byte array containing binary data decoded from the supplied
148         *         byte array (representing characters).
149         * @throws DecoderException
150         *             Thrown if an odd number of characters is supplied to this
151         *             function
152         * @see #decodeHex(char[])
153         */
154        public byte[] decode( byte[] array ) throws DecoderException
155        {
156            return decodeHex( new String( array ).toCharArray() );
157        }
158    
159    
160        /**
161         * Converts a String or an array of character bytes representing hexidecimal
162         * values into an array of bytes of those same values. The returned array
163         * will be half the length of the passed String or array, as it takes two
164         * characters to represent any given byte. An exception is thrown if the
165         * passed char array has an odd number of elements.
166         * 
167         * @param object
168         *            A String or, an array of character bytes containing
169         *            hexidecimal digits
170         * @return A byte array containing binary data decoded from the supplied
171         *         byte array (representing characters).
172         * @throws DecoderException
173         *             Thrown if an odd number of characters is supplied to this
174         *             function or the object is not a String or char[]
175         * @see #decodeHex(char[])
176         */
177        public Object decode( Object object ) throws DecoderException
178        {
179            try
180            {
181                char[] charArray = object instanceof String ? ( ( String ) object ).toCharArray() : ( char[] ) object;
182                return decodeHex( charArray );
183            }
184            catch ( ClassCastException e )
185            {
186                throw new DecoderException( e.getMessage() );
187            }
188        }
189    
190    
191        /**
192         * Converts an array of bytes into an array of bytes for the characters
193         * representing the hexidecimal values of each byte in order. The returned
194         * array will be double the length of the passed array, as it takes two
195         * characters to represent any given byte.
196         * 
197         * @param array
198         *            a byte[] to convert to Hex characters
199         * @return A byte[] containing the bytes of the hexidecimal characters
200         * @see #encodeHex(byte[])
201         */
202        public byte[] encode( byte[] array )
203        {
204            return new String( encodeHex( array ) ).getBytes();
205        }
206    
207    
208        /**
209         * Converts a String or an array of bytes into an array of characters
210         * representing the hexidecimal values of each byte in order. The returned
211         * array will be double the length of the passed String or array, as it
212         * takes two characters to represent any given byte.
213         * 
214         * @param object
215         *            a String, or byte[] to convert to Hex characters
216         * @return A char[] containing hexidecimal characters
217         * @throws EncoderException
218         *             Thrown if the given object is not a String or byte[]
219         * @see #encodeHex(byte[])
220         */
221        public Object encode( Object object ) throws EncoderException
222        {
223            try
224            {
225                byte[] byteArray = object instanceof String ? ( ( String ) object ).getBytes() : ( byte[] ) object;
226                return encodeHex( byteArray );
227            }
228            catch ( ClassCastException e )
229            {
230                throw new EncoderException( e.getMessage() );
231            }
232        }
233    
234    }