1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.geronimo.mail.util;
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.io.UnsupportedEncodingException;
26
27 import javax.mail.internet.MimeUtility;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class RFC2231Encoder implements Encoder
50 {
51 protected final byte[] encodingTable =
52 {
53 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
54 (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F'
55 };
56
57 protected String DEFAULT_SPECIALS = " *'%";
58 protected String specials = DEFAULT_SPECIALS;
59
60
61
62
63 protected final byte[] decodingTable = new byte[128];
64
65 protected void initialiseDecodingTable()
66 {
67 for (int i = 0; i < encodingTable.length; i++)
68 {
69 decodingTable[encodingTable[i]] = (byte)i;
70 }
71 }
72
73 public RFC2231Encoder()
74 {
75 this(null);
76 }
77
78 public RFC2231Encoder(String specials)
79 {
80 if (specials != null) {
81 this.specials = DEFAULT_SPECIALS + specials;
82 }
83 initialiseDecodingTable();
84 }
85
86
87
88
89
90
91
92 public int encode(byte[] data, int off, int length, OutputStream out) throws IOException {
93
94 int bytesWritten = 0;
95 for (int i = off; i < (off + length); i++)
96 {
97 int ch = data[i] & 0xff;
98
99 if (ch <= 32 || ch >= 127 || specials.indexOf(ch) != -1) {
100 out.write((byte)'%');
101 out.write(encodingTable[ch >> 4]);
102 out.write(encodingTable[ch & 0xf]);
103 bytesWritten += 3;
104 }
105 else {
106
107 out.write((byte)ch);
108 bytesWritten++;
109 }
110 }
111
112 return bytesWritten;
113 }
114
115
116
117
118
119
120
121 public int decode(byte[] data, int off, int length, OutputStream out) throws IOException {
122 int outLen = 0;
123 int end = off + length;
124
125 int i = off;
126 while (i < end)
127 {
128 byte v = data[i++];
129
130 if (v == '%') {
131 byte b1 = decodingTable[data[i++]];
132 byte b2 = decodingTable[data[i++]];
133 out.write((b1 << 4) | b2);
134 }
135 else {
136
137 out.write(v);
138 }
139
140 outLen++;
141 }
142
143 return outLen;
144 }
145
146
147
148
149
150
151 public int decode(String data, OutputStream out) throws IOException
152 {
153 int length = 0;
154 int end = data.length();
155
156 int i = 0;
157 while (i < end)
158 {
159 char v = data.charAt(i++);
160 if (v == '%') {
161 byte b1 = decodingTable[data.charAt(i++)];
162 byte b2 = decodingTable[data.charAt(i++)];
163
164 out.write((b1 << 4) | b2);
165 }
166 else {
167 out.write((byte)v);
168 }
169 length++;
170 }
171
172 return length;
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186 public String encode(String charset, String language, String data) throws IOException {
187
188 byte[] bytes = null;
189 try {
190
191
192 bytes = data.getBytes(MimeUtility.javaCharset(charset));
193 } catch (UnsupportedEncodingException e) {
194
195 return null;
196 }
197
198 StringBuffer result = new StringBuffer();
199
200
201 if (charset != null) {
202 result.append(charset);
203 }
204
205 result.append("'");
206
207
208 if (language != null) {
209 result.append(language);
210 }
211
212 result.append("'");
213
214
215 OutputStream out = new StringBufferOutputStream(result);
216
217
218 encode(bytes, 0, bytes.length, out);
219
220
221 return result.toString();
222 }
223
224
225
226
227
228
229
230
231
232
233
234 public String decode(String data) throws IOException, UnsupportedEncodingException {
235
236 int charsetEnd = data.indexOf('\'');
237
238 if (charsetEnd == -1) {
239 throw new IOException("Missing charset in RFC2231 encoded value");
240 }
241
242 String charset = data.substring(0, charsetEnd);
243
244
245 int languageEnd = data.indexOf('\'', charsetEnd + 1);
246 if (languageEnd == -1) {
247 throw new IOException("Missing language in RFC2231 encoded value");
248 }
249
250 String language = data.substring(charsetEnd + 1, languageEnd);
251
252 ByteArrayOutputStream out = new ByteArrayOutputStream(data.length());
253
254
255 decode(data.substring(languageEnd + 1), out);
256
257 byte[] bytes = out.toByteArray();
258
259 return new String(bytes, 0, bytes.length, MimeUtility.javaCharset(charset));
260 }
261 }