001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  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, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    
019    package org.apache.geronimo.util.encoders;
020    
021    import java.io.IOException;
022    import java.io.OutputStream;
023    
024    public class HexEncoder
025        implements Encoder
026    {
027        protected final byte[] encodingTable =
028            {
029                (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
030                (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
031            };
032    
033        /*
034         * set up the decoding table.
035         */
036        protected final byte[] decodingTable = new byte[128];
037    
038        protected void initialiseDecodingTable()
039        {
040            for (int i = 0; i < encodingTable.length; i++)
041            {
042                decodingTable[encodingTable[i]] = (byte)i;
043            }
044    
045            decodingTable['A'] = decodingTable['a'];
046            decodingTable['B'] = decodingTable['b'];
047            decodingTable['C'] = decodingTable['c'];
048            decodingTable['D'] = decodingTable['d'];
049            decodingTable['E'] = decodingTable['e'];
050            decodingTable['F'] = decodingTable['f'];
051        }
052    
053        public HexEncoder()
054        {
055            initialiseDecodingTable();
056        }
057    
058        /**
059         * encode the input data producing a Hex output stream.
060         *
061         * @return the number of bytes produced.
062         */
063        public int encode(
064            byte[]                data,
065            int                    off,
066            int                    length,
067            OutputStream    out)
068            throws IOException
069        {
070            for (int i = off; i < (off + length); i++)
071            {
072                int    v = data[i] & 0xff;
073    
074                out.write(encodingTable[(v >>> 4)]);
075                out.write(encodingTable[v & 0xf]);
076            }
077    
078            return length * 2;
079        }
080    
081        private boolean ignore(
082            char    c)
083        {
084            return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
085        }
086    
087        /**
088         * decode the Hex encoded byte data writing it to the given output stream,
089         * whitespace characters will be ignored.
090         *
091         * @return the number of bytes produced.
092         */
093        public int decode(
094            byte[]                data,
095            int                    off,
096            int                    length,
097            OutputStream    out)
098            throws IOException
099        {
100            byte[]    bytes;
101            byte    b1, b2;
102            int        outLen = 0;
103    
104            int        end = off + length;
105    
106            while (end > 0)
107            {
108                if (!ignore((char)data[end - 1]))
109                {
110                    break;
111                }
112    
113                end--;
114            }
115    
116            int i = off;
117            while (i < end)
118            {
119                while (i < end && ignore((char)data[i]))
120                {
121                    i++;
122                }
123    
124                b1 = decodingTable[data[i++]];
125    
126                while (i < end && ignore((char)data[i]))
127                {
128                    i++;
129                }
130    
131                b2 = decodingTable[data[i++]];
132    
133                out.write((b1 << 4) | b2);
134    
135                outLen++;
136            }
137    
138            return outLen;
139        }
140    
141        /**
142         * decode the Hex encoded String data writing it to the given output stream,
143         * whitespace characters will be ignored.
144         *
145         * @return the number of bytes produced.
146         */
147        public int decode(
148            String                data,
149            OutputStream    out)
150            throws IOException
151        {
152            byte[]    bytes;
153            byte    b1, b2, b3, b4;
154            int        length = 0;
155    
156            int        end = data.length();
157    
158            while (end > 0)
159            {
160                if (!ignore(data.charAt(end - 1)))
161                {
162                    break;
163                }
164    
165                end--;
166            }
167    
168            int i = 0;
169            while (i < end)
170            {
171                while (i < end && ignore(data.charAt(i)))
172                {
173                    i++;
174                }
175    
176                b1 = decodingTable[data.charAt(i++)];
177    
178                while (i < end && ignore(data.charAt(i)))
179                {
180                    i++;
181                }
182    
183                b2 = decodingTable[data.charAt(i++)];
184    
185                out.write((b1 << 4) | b2);
186    
187                length++;
188            }
189    
190            return length;
191        }
192    }