]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/B64Code.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / util / B64Code.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.util;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.nio.charset.Charset;
24 import java.nio.charset.StandardCharsets;
25 import java.nio.charset.UnsupportedCharsetException;
26
27
28 /** Fast B64 Encoder/Decoder as described in RFC 1421.
29  * <p>Does not insert or interpret whitespace as described in RFC
30  * 1521. If you require this you must pre/post process your data.
31  * <p> Note that in a web context the usual case is to not want
32  * linebreaks or other white space in the encoded output.
33  *
34  */
35 public class B64Code
36 {
37     private static final char __pad='=';
38     private static final char[] __rfc1421alphabet=
39             {
40                 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
41                 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
42                 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
43                 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
44             };
45
46     private static final byte[] __rfc1421nibbles;
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     private B64Code()
58     {
59     }
60
61     /**
62      * Base 64 encode as described in RFC 1421.
63      * <p>Does not insert whitespace as described in RFC 1521.
64      * @param s String to encode.
65      * @return String containing the encoded form of the input.
66      */
67     public static String encode(String s)
68     {
69         return encode(s, (Charset)null);
70     }
71
72     /**
73      * Base 64 encode as described in RFC 1421.
74      * <p>Does not insert whitespace as described in RFC 1521.
75      * @param s String to encode.
76      * @param charEncoding String representing the name of
77      *        the character encoding of the provided input String.
78      * @return String containing the encoded form of the input.
79      */
80     public static String encode(String s,String charEncoding)
81     {
82         byte[] bytes;
83         if (charEncoding==null)
84             bytes=s.getBytes(StandardCharsets.ISO_8859_1);
85         else
86             bytes=s.getBytes(Charset.forName(charEncoding));
87         return new String(encode(bytes));
88     }
89
90     /**
91      * Base 64 encode as described in RFC 1421.
92      * <p>Does not insert whitespace as described in RFC 1521.
93      * @param s String to encode.
94      * @param charEncoding The character encoding of the provided input String.
95      * @return String containing the encoded form of the input.
96      */
97     public static String encode(String s, Charset charEncoding)
98     {
99         byte[] bytes=s.getBytes(charEncoding==null ? StandardCharsets.ISO_8859_1 : charEncoding);
100         return new String(encode(bytes));
101     }
102
103     /**
104      * Fast Base 64 encode as described in RFC 1421.
105      * <p>Does not insert whitespace as described in RFC 1521.
106      * <p> Avoids creating extra copies of the input/output.
107      * @param b byte array to encode.
108      * @return char array containing the encoded form of the input.
109      */
110     public static char[] encode(byte[] b)
111     {
112         if (b==null)
113             return null;
114
115         int bLen=b.length;
116         int cLen=((bLen+2)/3)*4;
117         char c[]=new char[cLen];
118         int ci=0;
119         int bi=0;
120         byte b0, b1, b2;
121         int stop=(bLen/3)*3;
122         while (bi<stop)
123         {
124             b0=b[bi++];
125             b1=b[bi++];
126             b2=b[bi++];
127             c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
128             c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
129             c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f|(b2>>>6)&0x03];
130             c[ci++]=__rfc1421alphabet[b2&0x3f];
131         }
132
133         if (bLen!=bi)
134         {
135             switch (bLen%3)
136             {
137                 case 2:
138                     b0=b[bi++];
139                     b1=b[bi++];
140                     c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
141                     c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
142                     c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f];
143                     c[ci++]=__pad;
144                     break;
145
146                 case 1:
147                     b0=b[bi++];
148                     c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
149                     c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f];
150                     c[ci++]=__pad;
151                     c[ci++]=__pad;
152                     break;
153
154                 default:
155                     break;
156             }
157         }
158
159         return c;
160     }
161
162     /**
163      * Fast Base 64 encode as described in RFC 1421 and RFC2045
164      * <p>Does not insert whitespace as described in RFC 1521, unless rfc2045 is passed as true.
165      * <p> Avoids creating extra copies of the input/output.
166      * @param b byte array to encode.
167      * @param rfc2045 If true, break lines at 76 characters with CRLF
168      * @return char array containing the encoded form of the input.
169      */
170     public static char[] encode(byte[] b, boolean rfc2045)
171     {
172         if (b==null)
173             return null;
174         if (!rfc2045)
175             return encode(b);
176
177         int bLen=b.length;
178         int cLen=((bLen+2)/3)*4;
179         cLen+=2+2*(cLen/76);
180         char c[]=new char[cLen];
181         int ci=0;
182         int bi=0;
183         byte b0, b1, b2;
184         int stop=(bLen/3)*3;
185         int l=0;
186         while (bi<stop)
187         {
188             b0=b[bi++];
189             b1=b[bi++];
190             b2=b[bi++];
191             c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
192             c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
193             c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f|(b2>>>6)&0x03];
194             c[ci++]=__rfc1421alphabet[b2&0x3f];
195             l+=4;
196             if (l%76==0)
197             {
198                 c[ci++]=13;
199                 c[ci++]=10;
200             }
201         }
202
203         if (bLen!=bi)
204         {
205             switch (bLen%3)
206             {
207                 case 2:
208                     b0=b[bi++];
209                     b1=b[bi++];
210                     c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
211                     c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
212                     c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f];
213                     c[ci++]=__pad;
214                     break;
215
216                 case 1:
217                     b0=b[bi++];
218                     c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
219                     c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f];
220                     c[ci++]=__pad;
221                     c[ci++]=__pad;
222                     break;
223
224                 default:
225                     break;
226             }
227         }
228
229         c[ci++]=13;
230         c[ci++]=10;
231         return c;
232     }
233
234     /**
235      * Base 64 decode as described in RFC 2045.
236      * <p>Unlike {@link #decode(char[])}, extra whitespace is ignored.
237      * @param encoded String to decode.
238      * @param charEncoding String representing the character encoding
239      *        used to map the decoded bytes into a String.
240      * @return String decoded byte array.
241      * @throws UnsupportedCharsetException if the encoding is not supported
242      * @throws IllegalArgumentException if the input is not a valid
243      *         B64 encoding.
244      */
245     public static String decode(String encoded,String charEncoding)
246     {
247         byte[] decoded=decode(encoded);
248         if (charEncoding==null)
249             return new String(decoded);
250         return new String(decoded,Charset.forName(charEncoding));
251     }
252
253     /**
254      * Base 64 decode as described in RFC 2045.
255      * <p>Unlike {@link #decode(char[])}, extra whitespace is ignored.
256      * @param encoded String to decode.
257      * @param charEncoding Character encoding
258      *        used to map the decoded bytes into a String.
259      * @return String decoded byte array.
260      * @throws IllegalArgumentException if the input is not a valid
261      *         B64 encoding.
262      */
263     public static String decode(String encoded, Charset charEncoding)
264     {
265         byte[] decoded=decode(encoded);
266         if (charEncoding==null)
267             return new String(decoded);
268         return new String(decoded, charEncoding);
269     }
270
271     /**
272      * Fast Base 64 decode as described in RFC 1421.
273      *
274      * <p>Unlike other decode methods, this does not attempt to
275      * cope with extra whitespace as described in RFC 1521/2045.
276      * <p> Avoids creating extra copies of the input/output.
277      * <p> Note this code has been flattened for performance.
278      * @param b char array to decode.
279      * @return byte array containing the decoded form of the input.
280      * @throws IllegalArgumentException if the input is not a valid
281      *         B64 encoding.
282      */
283     public static byte[] decode(char[] b)
284     {
285         if (b==null)
286             return null;
287
288         int bLen=b.length;
289         if (bLen%4!=0)
290             throw new IllegalArgumentException("Input block size is not 4");
291
292         int li=bLen-1;
293         while (li>=0 && b[li]==(byte)__pad)
294             li--;
295
296         if (li<0)
297             return new byte[0];
298
299         // Create result array of exact required size.
300         int rLen=((li+1)*3)/4;
301         byte r[]=new byte[rLen];
302         int ri=0;
303         int bi=0;
304         int stop=(rLen/3)*3;
305         byte b0,b1,b2,b3;
306         try
307         {
308             while (ri<stop)
309             {
310                 b0=__rfc1421nibbles[b[bi++]];
311                 b1=__rfc1421nibbles[b[bi++]];
312                 b2=__rfc1421nibbles[b[bi++]];
313                 b3=__rfc1421nibbles[b[bi++]];
314                 if (b0<0 || b1<0 || b2<0 || b3<0)
315                     throw new IllegalArgumentException("Not B64 encoded");
316
317                 r[ri++]=(byte)(b0<<2|b1>>>4);
318                 r[ri++]=(byte)(b1<<4|b2>>>2);
319                 r[ri++]=(byte)(b2<<6|b3);
320             }
321
322             if (rLen!=ri)
323             {
324                 switch (rLen%3)
325                 {
326                     case 2:
327                         b0=__rfc1421nibbles[b[bi++]];
328                         b1=__rfc1421nibbles[b[bi++]];
329                         b2=__rfc1421nibbles[b[bi++]];
330                         if (b0<0 || b1<0 || b2<0)
331                             throw new IllegalArgumentException("Not B64 encoded");
332                         r[ri++]=(byte)(b0<<2|b1>>>4);
333                         r[ri++]=(byte)(b1<<4|b2>>>2);
334                         break;
335
336                     case 1:
337                         b0=__rfc1421nibbles[b[bi++]];
338                         b1=__rfc1421nibbles[b[bi++]];
339                         if (b0<0 || b1<0)
340                             throw new IllegalArgumentException("Not B64 encoded");
341                         r[ri++]=(byte)(b0<<2|b1>>>4);
342                         break;
343
344                     default:
345                         break;
346                 }
347             }
348         }
349         catch (IndexOutOfBoundsException e)
350         {
351             throw new IllegalArgumentException("char "+bi
352                     +" was not B64 encoded");
353         }
354
355         return r;
356     }
357
358     /**
359      * Base 64 decode as described in RFC 2045.
360      * <p>Unlike {@link #decode(char[])}, extra whitespace is ignored.
361      * @param encoded String to decode.
362      * @return byte array containing the decoded form of the input.
363      * @throws IllegalArgumentException if the input is not a valid
364      *         B64 encoding.
365      */
366     public static byte[] decode(String encoded)
367     {
368         if (encoded==null)
369             return null;
370
371         ByteArrayOutputStream bout = new ByteArrayOutputStream(4*encoded.length()/3);        
372         decode(encoded, bout);
373         return bout.toByteArray();
374     }
375     
376     /* ------------------------------------------------------------ */
377     /**
378      * Base 64 decode as described in RFC 2045.
379      * <p>Unlike {@link #decode(char[])}, extra whitespace is ignored.
380      * @param encoded String to decode.
381      * @param bout stream for decoded bytes
382      * @throws IllegalArgumentException if the input is not a valid
383      *         B64 encoding.
384      */
385     static public void decode (String encoded, ByteArrayOutputStream bout)
386     {
387         if (encoded==null)
388             return;
389         
390         if (bout == null)
391             throw new IllegalArgumentException("No outputstream for decoded bytes");
392         
393         int ci=0;
394         byte nibbles[] = new byte[4];
395         int s=0;
396   
397         while (ci<encoded.length())
398         {
399             char c=encoded.charAt(ci++);
400
401             if (c==__pad)
402                 break;
403
404             if (Character.isWhitespace(c))
405                 continue;
406
407             byte nibble=__rfc1421nibbles[c];
408             if (nibble<0)
409                 throw new IllegalArgumentException("Not B64 encoded");
410
411             nibbles[s++]=__rfc1421nibbles[c];
412
413             switch(s)
414             {
415                 case 1:
416                     break;
417                 case 2:
418                     bout.write(nibbles[0]<<2|nibbles[1]>>>4);
419                     break;
420                 case 3:
421                     bout.write(nibbles[1]<<4|nibbles[2]>>>2);
422                     break;
423                 case 4:
424                     bout.write(nibbles[2]<<6|nibbles[3]);
425                     s=0;
426                     break;
427             }
428
429         }
430
431         return;
432     }
433     
434
435     public static void encode(int value,Appendable buf) throws IOException
436     {
437         buf.append(__rfc1421alphabet[0x3f&((0xFC000000&value)>>26)]);
438         buf.append(__rfc1421alphabet[0x3f&((0x03F00000&value)>>20)]);
439         buf.append(__rfc1421alphabet[0x3f&((0x000FC000&value)>>14)]);
440         buf.append(__rfc1421alphabet[0x3f&((0x00003F00&value)>>8)]);
441         buf.append(__rfc1421alphabet[0x3f&((0x000000FC&value)>>2)]);
442         buf.append(__rfc1421alphabet[0x3f&((0x00000003&value)<<4)]);
443         buf.append('=');
444     }
445
446     public static void encode(long lvalue,Appendable buf) throws IOException
447     {
448         int value=(int)(0xFFFFFFFC&(lvalue>>32));
449         buf.append(__rfc1421alphabet[0x3f&((0xFC000000&value)>>26)]);
450         buf.append(__rfc1421alphabet[0x3f&((0x03F00000&value)>>20)]);
451         buf.append(__rfc1421alphabet[0x3f&((0x000FC000&value)>>14)]);
452         buf.append(__rfc1421alphabet[0x3f&((0x00003F00&value)>>8)]);
453         buf.append(__rfc1421alphabet[0x3f&((0x000000FC&value)>>2)]);
454
455         buf.append(__rfc1421alphabet[0x3f&((0x00000003&value)<<4) + (0xf&(int)(lvalue>>28))]);
456
457         value=0x0FFFFFFF&(int)lvalue;
458         buf.append(__rfc1421alphabet[0x3f&((0x0FC00000&value)>>22)]);
459         buf.append(__rfc1421alphabet[0x3f&((0x003F0000&value)>>16)]);
460         buf.append(__rfc1421alphabet[0x3f&((0x0000FC00&value)>>10)]);
461         buf.append(__rfc1421alphabet[0x3f&((0x000003F0&value)>>4)]);
462         buf.append(__rfc1421alphabet[0x3f&((0x0000000F&value)<<2)]);
463     }
464 }