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