1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.geronimo.mail.util;
21
22 import java.io.IOException;
23 import java.io.OutputStream;
24
25 public class XTextEncoder
26 implements Encoder
27 {
28 protected final byte[] encodingTable =
29 {
30 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
31 (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F'
32 };
33
34 /*
35 * set up the decoding table.
36 */
37 protected final byte[] decodingTable = new byte[128];
38
39 protected void initialiseDecodingTable()
40 {
41 for (int i = 0; i < encodingTable.length; i++)
42 {
43 decodingTable[encodingTable[i]] = (byte)i;
44 }
45 }
46
47 public XTextEncoder()
48 {
49 initialiseDecodingTable();
50 }
51
52 /**
53 * encode the input data producing an XText output stream.
54 *
55 * @return the number of bytes produced.
56 */
57 public int encode(
58 byte[] data,
59 int off,
60 int length,
61 OutputStream out)
62 throws IOException
63 {
64 int bytesWritten = 0;
65
66 for (int i = off; i < (off + length); i++)
67 {
68 int v = data[i] & 0xff;
69 // character tha must be encoded? Prefix with a '+' and encode in hex.
70 if (v < 33 || v > 126 || v == '+' || v == '+') {
71 out.write((byte)'+');
72 out.write(encodingTable[(v >>> 4)]);
73 out.write(encodingTable[v & 0xf]);
74 bytesWritten += 3;
75 }
76 else {
77 // add unchanged.
78 out.write((byte)v);
79 bytesWritten++;
80 }
81 }
82
83 return bytesWritten;
84 }
85
86
87 /**
88 * decode the xtext encoded byte data writing it to the given output stream
89 *
90 * @return the number of bytes produced.
91 */
92 public int decode(
93 byte[] data,
94 int off,
95 int length,
96 OutputStream out)
97 throws IOException
98 {
99 byte[] bytes;
100 byte b1, b2;
101 int outLen = 0;
102
103 int end = off + length;
104
105 int i = off;
106 while (i < end)
107 {
108 byte v = data[i++];
109 // a plus is a hex character marker, need to decode a hex value.
110 if (v == '+') {
111 b1 = decodingTable[data[i++]];
112 b2 = decodingTable[data[i++]];
113 out.write((b1 << 4) | b2);
114 }
115 else {
116 // copied over unchanged.
117 out.write(v);
118 }
119 // always just one byte added
120 outLen++;
121 }
122
123 return outLen;
124 }
125
126 /**
127 * decode the xtext encoded String data writing it to the given output stream.
128 *
129 * @return the number of bytes produced.
130 */
131 public int decode(
132 String data,
133 OutputStream out)
134 throws IOException
135 {
136 byte[] bytes;
137 byte b1, b2, b3, b4;
138 int length = 0;
139
140 int end = data.length();
141
142 int i = 0;
143 while (i < end)
144 {
145 char v = data.charAt(i++);
146 if (v == '+') {
147 b1 = decodingTable[data.charAt(i++)];
148 b2 = decodingTable[data.charAt(i++)];
149
150 out.write((b1 << 4) | b2);
151 }
152 else {
153 out.write((byte)v);
154 }
155 length++;
156 }
157
158 return length;
159 }
160 }
161