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