1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.UnsupportedEncodingException;
23
24
25
26
27
28
29
30
31
32
33 public class B64Code
34 {
35
36 static final char pad='=';
37 static final char[] rfc1421alphabet=
38 {
39 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
40 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
41 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
42 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
43 };
44
45 static final byte[] rfc1421nibbles;
46
47 static
48 {
49 rfc1421nibbles=new byte[256];
50 for (int i=0;i<256;i++)
51 rfc1421nibbles[i]=-1;
52 for (byte b=0;b<64;b++)
53 rfc1421nibbles[(byte)rfc1421alphabet[b]]=b;
54 rfc1421nibbles[(byte)pad]=0;
55 }
56
57
58
59
60
61
62
63
64 static public String encode(String s)
65 {
66 try
67 {
68 return encode(s,null);
69 }
70 catch (UnsupportedEncodingException e)
71 {
72 throw new IllegalArgumentException(e.toString());
73 }
74 }
75
76
77
78
79
80
81
82
83
84
85 static public String encode(String s,String charEncoding)
86 throws UnsupportedEncodingException
87 {
88 byte[] bytes;
89 if (charEncoding==null)
90 bytes=s.getBytes(StringUtil.__ISO_8859_1);
91 else
92 bytes=s.getBytes(charEncoding);
93
94 return new String(encode(bytes));
95 }
96
97
98
99
100
101
102
103
104
105 static public char[] encode(byte[] b)
106 {
107 return encode(b,false);
108 }
109
110
111
112
113
114
115
116
117
118
119 static public char[] encode(byte[] b, boolean rfc2045)
120 {
121 if (b==null)
122 return null;
123
124 int bLen=b.length;
125 int cLen=((bLen+2)/3)*4;
126 if (rfc2045)
127 cLen+=2+2*cLen/76;
128 char c[]=new char[cLen];
129 int ci=0;
130 int bi=0;
131 byte b0, b1, b2;
132 int stop=(bLen/3)*3;
133 int l=0;
134 while (bi<stop)
135 {
136 b0=b[bi++];
137 b1=b[bi++];
138 b2=b[bi++];
139 c[ci++]=rfc1421alphabet[(b0>>>2)&0x3f];
140 c[ci++]=rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
141 c[ci++]=rfc1421alphabet[(b1<<2)&0x3f|(b2>>>6)&0x03];
142 c[ci++]=rfc1421alphabet[b2&077];
143 l+=4;
144 if (rfc2045 && l%76==0)
145 {
146 c[ci++]=13;
147 c[ci++]=10;
148 }
149 }
150
151 if (bLen!=bi)
152 {
153 switch (bLen%3)
154 {
155 case 2:
156 b0=b[bi++];
157 b1=b[bi++];
158 c[ci++]=rfc1421alphabet[(b0>>>2)&0x3f];
159 c[ci++]=rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
160 c[ci++]=rfc1421alphabet[(b1<<2)&0x3f];
161 c[ci++]=pad;
162 break;
163
164 case 1:
165 b0=b[bi++];
166 c[ci++]=rfc1421alphabet[(b0>>>2)&0x3f];
167 c[ci++]=rfc1421alphabet[(b0<<4)&0x3f];
168 c[ci++]=pad;
169 c[ci++]=pad;
170 break;
171
172 default:
173 break;
174 }
175 }
176
177 if (rfc2045)
178 {
179 c[ci++]=13;
180 c[ci++]=10;
181 }
182 return c;
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196
197 static public String decode(String encoded,String charEncoding)
198 throws UnsupportedEncodingException
199 {
200 byte[] decoded=decode(encoded);
201 if (charEncoding==null)
202 return new String(decoded);
203 return new String(decoded,charEncoding);
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 static public byte[] decode(char[] b)
220 {
221 if (b==null)
222 return null;
223
224 int bLen=b.length;
225 if (bLen%4!=0)
226 throw new IllegalArgumentException("Input block size is not 4");
227
228 int li=bLen-1;
229 while (li>=0 && b[li]==(byte)pad)
230 li--;
231
232 if (li<0)
233 return new byte[0];
234
235
236 int rLen=((li+1)*3)/4;
237 byte r[]=new byte[rLen];
238 int ri=0;
239 int bi=0;
240 int stop=(rLen/3)*3;
241 byte b0,b1,b2,b3;
242 try
243 {
244 while (ri<stop)
245 {
246 b0=rfc1421nibbles[b[bi++]];
247 b1=rfc1421nibbles[b[bi++]];
248 b2=rfc1421nibbles[b[bi++]];
249 b3=rfc1421nibbles[b[bi++]];
250 if (b0<0 || b1<0 || b2<0 || b3<0)
251 throw new IllegalArgumentException("Not B64 encoded");
252
253 r[ri++]=(byte)(b0<<2|b1>>>4);
254 r[ri++]=(byte)(b1<<4|b2>>>2);
255 r[ri++]=(byte)(b2<<6|b3);
256 }
257
258 if (rLen!=ri)
259 {
260 switch (rLen%3)
261 {
262 case 2:
263 b0=rfc1421nibbles[b[bi++]];
264 b1=rfc1421nibbles[b[bi++]];
265 b2=rfc1421nibbles[b[bi++]];
266 if (b0<0 || b1<0 || b2<0)
267 throw new IllegalArgumentException("Not B64 encoded");
268 r[ri++]=(byte)(b0<<2|b1>>>4);
269 r[ri++]=(byte)(b1<<4|b2>>>2);
270 break;
271
272 case 1:
273 b0=rfc1421nibbles[b[bi++]];
274 b1=rfc1421nibbles[b[bi++]];
275 if (b0<0 || b1<0)
276 throw new IllegalArgumentException("Not B64 encoded");
277 r[ri++]=(byte)(b0<<2|b1>>>4);
278 break;
279
280 default:
281 break;
282 }
283 }
284 }
285 catch (IndexOutOfBoundsException e)
286 {
287 throw new IllegalArgumentException("char "+bi
288 +" was not B64 encoded");
289 }
290
291 return r;
292 }
293
294
295
296
297
298
299
300
301
302
303 static public byte[] decode(String encoded)
304 {
305 if (encoded==null)
306 return null;
307
308 int ci=0;
309 byte nibbles[] = new byte[4];
310 int s=0;
311 ByteArrayOutputStream bout = new ByteArrayOutputStream(4*encoded.length()/3);
312
313 while (ci<encoded.length())
314 {
315 char c=encoded.charAt(ci++);
316
317 if (c==pad)
318 break;
319
320 if (Character.isWhitespace(c))
321 continue;
322
323 byte nibble=rfc1421nibbles[c];
324 if (nibble<0)
325 throw new IllegalArgumentException("Not B64 encoded");
326
327 nibbles[s++]=rfc1421nibbles[c];
328
329 switch(s)
330 {
331 case 1:
332 break;
333 case 2:
334 bout.write(nibbles[0]<<2|nibbles[1]>>>4);
335 break;
336 case 3:
337 bout.write(nibbles[1]<<4|nibbles[2]>>>2);
338 break;
339 case 4:
340 bout.write(nibbles[2]<<6|nibbles[3]);
341 s=0;
342 break;
343 }
344
345 }
346
347 return bout.toByteArray();
348 }
349 }