1 |
/* |
/* |
2 |
* $Id$ |
* UTF7imap.java |
3 |
* Copyright (C) 2003 The Free Software Foundation |
* Copyright (C) 2003 The Free Software Foundation |
4 |
* |
* |
5 |
* This file is part of GNU inetlib, a library. |
* This file is part of GNU inetlib, a library. |
46 |
* encoding scheme. |
* encoding scheme. |
47 |
* |
* |
48 |
* @author <a href="mailto:dog@gnu.org">Chris Burdess</a> |
* @author <a href="mailto:dog@gnu.org">Chris Burdess</a> |
|
* @version $Revision$ $Date$ |
|
49 |
*/ |
*/ |
50 |
public final class UTF7imap |
public final class UTF7imap |
51 |
{ |
{ |
77 |
|
|
78 |
} |
} |
79 |
|
|
80 |
private UTF7imap () |
private UTF7imap() |
81 |
{ |
{ |
82 |
} |
} |
83 |
|
|
87 |
* |
* |
88 |
* @param bs the source byte array |
* @param bs the source byte array |
89 |
*/ |
*/ |
90 |
static byte[] encode (byte[] bs) |
static byte[] encode(byte[] bs) |
91 |
{ |
{ |
92 |
int si = 0, ti = 0; // source/target array indices |
int si = 0, ti = 0; // source/target array indices |
93 |
byte[] bt = new byte[(((bs.length + 2) / 3) * 4) -1];// target byte array |
byte[] bt = new byte[(((bs.length + 2) / 3) * 4) -1];// target byte array |
94 |
for (; si < bs.length; si += 3) |
for (; si < bs.length; si += 3) |
95 |
{ |
{ |
96 |
int buflen = bs.length - si; |
int buflen = bs.length - si; |
97 |
if (buflen == 1) |
if (buflen == 1) |
98 |
{ |
{ |
99 |
byte b = bs[si]; |
byte b = bs[si]; |
100 |
int i = 0; |
int i = 0; |
101 |
boolean flag = false; |
boolean flag = false; |
102 |
bt[ti++] = src[b >>> 2 & 0x3f]; |
bt[ti++] = src[b >>> 2 & 0x3f]; |
103 |
bt[ti++] = src[(b << 4 & 0x30) + (i >>> 4 & 0xf)]; |
bt[ti++] = src[(b << 4 & 0x30) + (i >>> 4 & 0xf)]; |
104 |
} |
} |
105 |
else if (buflen == 2) |
else if (buflen == 2) |
106 |
{ |
{ |
107 |
byte b1 = bs[si], b2 = bs[si + 1]; |
byte b1 = bs[si], b2 = bs[si + 1]; |
108 |
int i = 0; |
int i = 0; |
109 |
bt[ti++] = src[b1 >>> 2 & 0x3f]; |
bt[ti++] = src[b1 >>> 2 & 0x3f]; |
110 |
bt[ti++] = src[(b1 << 4 & 0x30) + (b2 >>> 4 & 0xf)]; |
bt[ti++] = src[(b1 << 4 & 0x30) + (b2 >>> 4 & 0xf)]; |
111 |
bt[ti++] = src[(b2 << 2 & 0x3c) + (i >>> 6 & 0x3)]; |
bt[ti++] = src[(b2 << 2 & 0x3c) + (i >>> 6 & 0x3)]; |
112 |
} |
} |
113 |
else if (buflen == 3) |
else if (buflen == 3) |
114 |
{ |
{ |
115 |
byte b1 = bs[si], b2 = bs[si + 1], b3 = bs[si + 2]; |
byte b1 = bs[si], b2 = bs[si + 1], b3 = bs[si + 2]; |
116 |
bt[ti++] = src[b1 >>> 2 & 0x3f]; |
bt[ti++] = src[b1 >>> 2 & 0x3f]; |
117 |
bt[ti++] = src[(b1 << 4 & 0x30) + (b2 >>> 4 & 0xf)]; |
bt[ti++] = src[(b1 << 4 & 0x30) + (b2 >>> 4 & 0xf)]; |
118 |
bt[ti++] = src[(b2 << 2 & 0x3c) + (b3 >>> 6 & 0x3)]; |
bt[ti++] = src[(b2 << 2 & 0x3c) + (b3 >>> 6 & 0x3)]; |
119 |
bt[ti++] = src[b3 & 0x3f]; |
bt[ti++] = src[b3 & 0x3f]; |
120 |
} |
} |
121 |
} |
} |
122 |
return bt; |
return bt; |
123 |
} |
} |
124 |
|
|
125 |
/** |
/** |
126 |
* Decode the specified byte array using the modified BASE64 algorithm |
* Decode the specified byte array using the modified BASE64 algorithm |
128 |
* |
* |
129 |
* @param bs the source byte array |
* @param bs the source byte array |
130 |
*/ |
*/ |
131 |
static int[] decode (byte[] bs) |
static int[] decode(byte[] bs) |
132 |
{ |
{ |
133 |
int[] buffer = new int[bs.length]; |
int[] buffer = new int[bs.length]; |
134 |
int buflen = 0; |
int buflen = 0; |
135 |
int si = 0; |
int si = 0; |
136 |
int len = bs.length - si; |
int len = bs.length - si; |
137 |
while (len > 0) |
while (len > 0) |
138 |
{ |
{ |
139 |
byte b0 = dst[bs[si++] & 0xff]; |
byte b0 = dst[bs[si++] & 0xff]; |
140 |
byte b2 = dst[bs[si++] & 0xff]; |
byte b2 = dst[bs[si++] & 0xff]; |
141 |
buffer[buflen++] = (b0 << 2 & 0xfc | b2 >>> 4 & 0x3); |
buffer[buflen++] = (b0 << 2 & 0xfc | b2 >>> 4 & 0x3); |
142 |
if (len > 2) |
if (len > 2) |
143 |
{ |
{ |
144 |
b0 = b2; |
b0 = b2; |
145 |
b2 = dst[bs[si++] & 0xff]; |
b2 = dst[bs[si++] & 0xff]; |
146 |
buffer[buflen++] = (b0 << 4 & 0xf0 | b2 >>> 2 & 0xf); |
buffer[buflen++] = (b0 << 4 & 0xf0 | b2 >>> 2 & 0xf); |
147 |
if (len > 3) |
if (len > 3) |
148 |
{ |
{ |
149 |
b0 = b2; |
b0 = b2; |
150 |
b2 = dst[bs[si++] & 0xff]; |
b2 = dst[bs[si++] & 0xff]; |
151 |
buffer[buflen++] = (b0 << 6 & 0xc0 | b2 & 0x3f); |
buffer[buflen++] = (b0 << 6 & 0xc0 | b2 & 0x3f); |
152 |
} |
} |
153 |
} |
} |
154 |
len = bs.length - si; |
len = bs.length - si; |
155 |
} |
} |
156 |
int[] bt = new int[buflen]; |
int[] bt = new int[buflen]; |
157 |
System.arraycopy (buffer, 0, bt, 0, buflen); |
System.arraycopy(buffer, 0, bt, 0, buflen); |
158 |
return bt; |
return bt; |
159 |
} |
} |
160 |
|
|
161 |
/** |
/** |
162 |
* Encodes the specified name using the UTF-7.imap encoding. |
* Encodes the specified name using the UTF-7.imap encoding. |
163 |
* See IMAP4rev1 spec, section 5.1.3 |
* See IMAP4rev1 spec, section 5.1.3 |
164 |
*/ |
*/ |
165 |
public static String encode (String name) |
public static String encode(String name) |
166 |
{ |
{ |
167 |
try |
try |
168 |
{ |
{ |
169 |
StringBuffer buffer = null; |
StringBuffer buffer = null; |
170 |
ByteArrayOutputStream encoderSink = null; |
ByteArrayOutputStream encoderSink = null; |
171 |
char[] chars = name.toCharArray (); |
char[] chars = name.toCharArray(); |
172 |
boolean encoding = false; |
boolean encoding = false; |
173 |
for (int i = 0; i < chars.length; i++) |
for (int i = 0; i < chars.length; i++) |
174 |
{ |
{ |
175 |
char c = chars[i]; |
char c = chars[i]; |
176 |
if (c == '&') |
if (c == '&') |
177 |
{ |
{ |
178 |
if (buffer == null) |
if (buffer == null) |
179 |
{ |
{ |
180 |
buffer = new StringBuffer (); |
buffer = new StringBuffer(); |
181 |
for (int j = 0; j < i; j++) |
for (int j = 0; j < i; j++) |
182 |
{ |
{ |
183 |
buffer.append (chars[j]); |
buffer.append(chars[j]); |
184 |
} |
} |
185 |
} |
} |
186 |
buffer.append ('&'); |
buffer.append('&'); |
187 |
buffer.append ('-'); |
buffer.append('-'); |
188 |
} |
} |
189 |
if (c < 0x1f || c > 0x7f) |
if (c < 0x1f || c > 0x7f) |
190 |
{ |
{ |
191 |
// needs encoding |
// needs encoding |
192 |
if (buffer == null) |
if (buffer == null) |
193 |
{ |
{ |
194 |
buffer = new StringBuffer (); |
buffer = new StringBuffer(); |
195 |
for (int j = 0; j < i; j++) |
for (int j = 0; j < i; j++) |
196 |
{ |
{ |
197 |
buffer.append (chars[j]); |
buffer.append(chars[j]); |
198 |
} |
} |
199 |
encoderSink = new ByteArrayOutputStream (); |
encoderSink = new ByteArrayOutputStream(); |
200 |
} |
} |
201 |
if (!encoding) |
if (!encoding) |
202 |
{ |
{ |
203 |
encoderSink.reset (); |
encoderSink.reset(); |
204 |
buffer.append ('&'); |
buffer.append('&'); |
205 |
encoding = true; |
encoding = true; |
206 |
} |
} |
207 |
encoderSink.write (((int) c) / 0x100); |
encoderSink.write(((int) c) / 0x100); |
208 |
encoderSink.write (((int) c) % 0x100); |
encoderSink.write(((int) c) % 0x100); |
209 |
} |
} |
210 |
else if (encoding) |
else if (encoding) |
211 |
{ |
{ |
212 |
encoderSink.flush (); |
encoderSink.flush(); |
213 |
byte[] encoded = encode (encoderSink.toByteArray ()); |
byte[] encoded = encode(encoderSink.toByteArray()); |
214 |
buffer.append (new String (encoded, US_ASCII)); |
buffer.append(new String(encoded, US_ASCII)); |
215 |
buffer.append ('-'); |
buffer.append('-'); |
216 |
encoding = false; |
encoding = false; |
217 |
if (c != '-') |
if (c != '-') |
218 |
{ |
{ |
219 |
buffer.append (c); |
buffer.append(c); |
220 |
} |
} |
221 |
} |
} |
222 |
else if (buffer != null) |
else if (buffer != null) |
223 |
{ |
{ |
224 |
buffer.append (c); |
buffer.append(c); |
225 |
} |
} |
226 |
} |
} |
227 |
if (encoding) |
if (encoding) |
228 |
{ |
{ |
229 |
encoderSink.flush (); |
encoderSink.flush(); |
230 |
byte[] encoded = encode (encoderSink.toByteArray ()); |
byte[] encoded = encode(encoderSink.toByteArray()); |
231 |
buffer.append (new String(encoded, US_ASCII)); |
buffer.append(new String(encoded, US_ASCII)); |
232 |
buffer.append ('-'); |
buffer.append('-'); |
233 |
} |
} |
234 |
if (buffer != null) |
if (buffer != null) |
235 |
{ |
{ |
236 |
return buffer.toString (); |
return buffer.toString(); |
237 |
} |
} |
238 |
} |
} |
239 |
catch (IOException e) |
catch (IOException e) |
240 |
{ |
{ |
241 |
// This should never happen |
// This should never happen |
242 |
throw new RuntimeException (e.getMessage ()); |
throw new RuntimeException(e.getMessage()); |
243 |
} |
} |
244 |
return name; |
return name; |
245 |
} |
} |
246 |
|
|
247 |
/** |
/** |
248 |
* Decodes the specified name using the UTF-7.imap decoding. |
* Decodes the specified name using the UTF-7.imap decoding. |
249 |
* See IMAP4rev1 spec, section 5.1.3 |
* See IMAP4rev1 spec, section 5.1.3 |
250 |
*/ |
*/ |
251 |
public static String decode (String name) |
public static String decode(String name) |
252 |
{ |
{ |
253 |
StringBuffer buffer = null; |
StringBuffer buffer = null; |
254 |
ByteArrayOutputStream decoderSink = null; |
ByteArrayOutputStream decoderSink = null; |
255 |
char[] chars = name.toCharArray (); |
char[] chars = name.toCharArray(); |
256 |
boolean encoded = false; |
boolean encoded = false; |
257 |
for (int i = 0; i < chars.length; i++) |
for (int i = 0; i < chars.length; i++) |
258 |
{ |
{ |
259 |
char c = chars[i]; |
char c = chars[i]; |
260 |
if (c == '&') |
if (c == '&') |
261 |
{ |
{ |
262 |
if (buffer == null) |
if (buffer == null) |
263 |
{ |
{ |
264 |
buffer = new StringBuffer (); |
buffer = new StringBuffer(); |
265 |
decoderSink = new ByteArrayOutputStream (); |
decoderSink = new ByteArrayOutputStream(); |
266 |
for (int j = 0; j < i; j++) |
for (int j = 0; j < i; j++) |
267 |
{ |
{ |
268 |
buffer.append (chars[j]); |
buffer.append(chars[j]); |
269 |
} |
} |
270 |
} |
} |
271 |
decoderSink.reset (); |
decoderSink.reset(); |
272 |
encoded = true; |
encoded = true; |
273 |
} |
} |
274 |
else if (c == '-' && encoded) |
else if (c == '-' && encoded) |
275 |
{ |
{ |
276 |
if (decoderSink.size () == 0) |
if (decoderSink.size() == 0) |
277 |
{ |
{ |
278 |
buffer.append ('&'); |
buffer.append('&'); |
279 |
} |
} |
280 |
else |
else |
281 |
{ |
{ |
282 |
int[] decoded = decode (decoderSink.toByteArray ()); |
int[] decoded = decode(decoderSink.toByteArray()); |
283 |
for (int j = 0; j < decoded.length - 1; j += 2) |
for (int j = 0; j < decoded.length - 1; j += 2) |
284 |
{ |
{ |
285 |
int hibyte = decoded[j]; |
int hibyte = decoded[j]; |
286 |
int lobyte = decoded[j + 1]; |
int lobyte = decoded[j + 1]; |
287 |
int d = (hibyte * 0x100) | lobyte; |
int d = (hibyte * 0x100) | lobyte; |
288 |
buffer.append ((char) d); |
buffer.append((char) d); |
289 |
} |
} |
290 |
} |
} |
291 |
encoded = false; |
encoded = false; |
292 |
} |
} |
293 |
else if (encoded) |
else if (encoded) |
294 |
{ |
{ |
295 |
decoderSink.write ((byte) c); |
decoderSink.write((byte) c); |
296 |
} |
} |
297 |
else if (buffer != null) |
else if (buffer != null) |
298 |
{ |
{ |
299 |
buffer.append (c); |
buffer.append(c); |
300 |
} |
} |
301 |
} |
} |
302 |
if (buffer != null) |
if (buffer != null) |
303 |
{ |
{ |
304 |
return buffer.toString (); |
return buffer.toString(); |
305 |
} |
} |
306 |
return name; |
return name; |
|
} |
|
|
|
|
|
public static void main (String[] args) |
|
|
{ |
|
|
boolean decode = false; |
|
|
for (int i = 0; i < args.length; i++) |
|
|
{ |
|
|
if (args[i].equals ("-d")) |
|
|
{ |
|
|
decode = true; |
|
|
} |
|
|
else |
|
|
{ |
|
|
String ret = decode ? decode (args[i]) : encode (args[i]); |
|
|
StringBuffer buf = new StringBuffer (args[i]); |
|
|
buf.append (" = \""); |
|
|
buf.append (ret); |
|
|
buf.append ("\" ("); |
|
|
for (int j = 0; j < ret.length (); j++) |
|
|
{ |
|
|
if (j > 0) |
|
|
{ |
|
|
buf.append (' '); |
|
|
} |
|
|
int c = (int) (ret.charAt (j)); |
|
|
buf.append (Integer.toString (c, 16)); |
|
|
} |
|
|
buf.append (")"); |
|
|
System.out.println (buf.toString ()); |
|
|
} |
|
|
} |
|
307 |
} |
} |
308 |
|
|
309 |
|
public static void main(String[] args) |
310 |
|
{ |
311 |
|
boolean decode = false; |
312 |
|
for (int i = 0; i < args.length; i++) |
313 |
|
{ |
314 |
|
if (args[i].equals("-d")) |
315 |
|
{ |
316 |
|
decode = true; |
317 |
|
} |
318 |
|
else |
319 |
|
{ |
320 |
|
String ret = decode ? decode(args[i]) : encode(args[i]); |
321 |
|
StringBuffer buf = new StringBuffer(args[i]); |
322 |
|
buf.append(" = \""); |
323 |
|
buf.append(ret); |
324 |
|
buf.append("\"("); |
325 |
|
for (int j = 0; j < ret.length(); j++) |
326 |
|
{ |
327 |
|
if (j > 0) |
328 |
|
{ |
329 |
|
buf.append(' '); |
330 |
|
} |
331 |
|
int c = (int) ret.charAt(j); |
332 |
|
buf.append(Integer.toString(c, 16)); |
333 |
|
} |
334 |
|
buf.append(")"); |
335 |
|
System.out.println(buf.toString()); |
336 |
|
} |
337 |
|
} |
338 |
|
} |
339 |
|
|
340 |
} |
} |
341 |
|
|