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    package org.apache.geronimo.mail.util;
021    
022    import java.io.IOException;
023    import java.io.OutputStream;
024    
025    /**
026     * @version $Rev: 467553 $ $Date: 2006-10-25 06:01:51 +0200 (Mi, 25. Okt 2006) $
027     */
028    public class HexEncoder
029        implements Encoder
030    {
031        protected final byte[] encodingTable =
032            {
033                (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
034                (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
035            };
036    
037        /*
038         * set up the decoding table.
039         */
040        protected final byte[] decodingTable = new byte[128];
041    
042        protected void initialiseDecodingTable()
043        {
044            for (int i = 0; i < encodingTable.length; i++)
045            {
046                decodingTable[encodingTable[i]] = (byte)i;
047            }
048    
049            decodingTable['A'] = decodingTable['a'];
050            decodingTable['B'] = decodingTable['b'];
051            decodingTable['C'] = decodingTable['c'];
052            decodingTable['D'] = decodingTable['d'];
053            decodingTable['E'] = decodingTable['e'];
054            decodingTable['F'] = decodingTable['f'];
055        }
056    
057        public HexEncoder()
058        {
059            initialiseDecodingTable();
060        }
061    
062        /**
063         * encode the input data producing a Hex output stream.
064         *
065         * @return the number of bytes produced.
066         */
067        public int encode(
068            byte[]                data,
069            int                    off,
070            int                    length,
071            OutputStream    out)
072            throws IOException
073        {
074            for (int i = off; i < (off + length); i++)
075            {
076                int    v = data[i] & 0xff;
077    
078                out.write(encodingTable[(v >>> 4)]);
079                out.write(encodingTable[v & 0xf]);
080            }
081    
082            return length * 2;
083        }
084    
085        private boolean ignore(
086            char    c)
087        {
088            return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
089        }
090    
091        /**
092         * decode the Hex encoded byte data writing it to the given output stream,
093         * whitespace characters will be ignored.
094         *
095         * @return the number of bytes produced.
096         */
097        public int decode(
098            byte[]                data,
099            int                    off,
100            int                    length,
101            OutputStream    out)
102            throws IOException
103        {
104            byte[]    bytes;
105            byte    b1, b2;
106            int        outLen = 0;
107    
108            int        end = off + length;
109    
110            while (end > 0)
111            {
112                if (!ignore((char)data[end - 1]))
113                {
114                    break;
115                }
116    
117                end--;
118            }
119    
120            int i = off;
121            while (i < end)
122            {
123                while (i < end && ignore((char)data[i]))
124                {
125                    i++;
126                }
127    
128                b1 = decodingTable[data[i++]];
129    
130                while (i < end && ignore((char)data[i]))
131                {
132                    i++;
133                }
134    
135                b2 = decodingTable[data[i++]];
136    
137                out.write((b1 << 4) | b2);
138    
139                outLen++;
140            }
141    
142            return outLen;
143        }
144    
145        /**
146         * decode the Hex encoded String data writing it to the given output stream,
147         * whitespace characters will be ignored.
148         *
149         * @return the number of bytes produced.
150         */
151        public int decode(
152            String                data,
153            OutputStream    out)
154            throws IOException
155        {
156            byte[]    bytes;
157            byte    b1, b2, b3, b4;
158            int        length = 0;
159    
160            int        end = data.length();
161    
162            while (end > 0)
163            {
164                if (!ignore(data.charAt(end - 1)))
165                {
166                    break;
167                }
168    
169                end--;
170            }
171    
172            int i = 0;
173            while (i < end)
174            {
175                while (i < end && ignore(data.charAt(i)))
176                {
177                    i++;
178                }
179    
180                b1 = decodingTable[data.charAt(i++)];
181    
182                while (i < end && ignore(data.charAt(i)))
183                {
184                    i++;
185                }
186    
187                b2 = decodingTable[data.charAt(i++)];
188    
189                out.write((b1 << 4) | b2);
190    
191                length++;
192            }
193    
194            return length;
195        }
196    }