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 }