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