KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mortbay > util > B64Code


1 // ========================================================================
2
// $Id: B64Code.java,v 1.8 2005/03/15 10:04:25 gregwilkins Exp $
3
// Copyright 1999-2004 Mort Bay Consulting Pty. Ltd.
4
// ------------------------------------------------------------------------
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
// ========================================================================
15

16 package org.mortbay.util;
17
18 import java.io.UnsupportedEncodingException JavaDoc;
19
20 /* ------------------------------------------------------------ */
21
22 /** Fast B64 Encoder/Decoder as described in RFC 1421.
23  * <p>Does not insert or interpret whitespace as described in RFC
24  * 1521. If you require this you must pre/post process your data.
25  * <p> Note that in a web context the usual case is to not want
26  * linebreaks or other white space in the encoded output.
27  *
28  * @version $Revision: 1.8 $
29  * @author Brett Sealey (bretts)
30  * @author Greg Wilkins (gregw)
31  */

32 public class B64Code
33 {
34     // ------------------------------------------------------------------
35
static final char pad='=';
36     static final char[] nibble2code=
37             {
38                 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
39                 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
40                 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
41                 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
42             };
43
44     static byte[] code2nibble=null;
45
46     static
47     {
48         code2nibble=new byte[256];
49         for (int i=0;i<256;i++)
50             code2nibble[i]=-1;
51         for (byte b=0;b<64;b++)
52             code2nibble[(byte)nibble2code[b]]=b;
53         code2nibble[(byte)pad]=0;
54     }
55
56     // ------------------------------------------------------------------
57
/**
58      * Base 64 encode as described in RFC 1421.
59      * <p>Does not insert whitespace as described in RFC 1521.
60      * @param s String to encode.
61      * @return String containing the encoded form of the input.
62      */

63     static public String JavaDoc encode(String JavaDoc s)
64     {
65         try
66         {
67             return encode(s,null);
68         }
69         catch (UnsupportedEncodingException JavaDoc e)
70         {
71             throw new IllegalArgumentException JavaDoc(e.toString());
72         }
73     }
74
75     // ------------------------------------------------------------------
76
/**
77      * Base 64 encode as described in RFC 1421.
78      * <p>Does not insert whitespace as described in RFC 1521.
79      * @param s String to encode.
80      * @param charEncoding String representing the name of
81      * the character encoding of the provided input String.
82      * @return String containing the encoded form of the input.
83      */

84     static public String JavaDoc encode(String JavaDoc s,String JavaDoc charEncoding)
85             throws UnsupportedEncodingException JavaDoc
86     {
87         byte[] bytes;
88         if (charEncoding==null)
89             bytes=s.getBytes(StringUtil.__ISO_8859_1);
90         else
91             bytes=s.getBytes(charEncoding);
92
93         return new String JavaDoc(encode(bytes));
94     }
95
96     // ------------------------------------------------------------------
97
/**
98      * Fast Base 64 encode as described in RFC 1421.
99      * <p>Does not insert whitespace as described in RFC 1521.
100      * <p> Avoids creating extra copies of the input/output.
101      * @param b byte array to encode.
102      * @return char array containing the encoded form of the input.
103      */

104     static public char[] encode(byte[] b)
105     {
106         if (b==null)
107             return null;
108
109         int bLen=b.length;
110         char r[]=new char[((bLen+2)/3)*4];
111         int ri=0;
112         int bi=0;
113         byte b0, b1, b2;
114         int stop=(bLen/3)*3;
115         while (bi<stop)
116         {
117             b0=b[bi++];
118             b1=b[bi++];
119             b2=b[bi++];
120             r[ri++]=nibble2code[(b0>>>2)&0x3f];
121             r[ri++]=nibble2code[(b0<<4)&0x3f|(b1>>>4)&0x0f];
122             r[ri++]=nibble2code[(b1<<2)&0x3f|(b2>>>6)&0x03];
123             r[ri++]=nibble2code[b2&077];
124         }
125
126         if (bLen!=bi)
127         {
128             switch (bLen%3)
129             {
130                 case 2:
131                     b0=b[bi++];
132                     b1=b[bi++];
133                     r[ri++]=nibble2code[(b0>>>2)&0x3f];
134                     r[ri++]=nibble2code[(b0<<4)&0x3f|(b1>>>4)&0x0f];
135                     r[ri++]=nibble2code[(b1<<2)&0x3f];
136                     r[ri++]=pad;
137                     break;
138
139                 case 1:
140                     b0=b[bi++];
141                     r[ri++]=nibble2code[(b0>>>2)&0x3f];
142                     r[ri++]=nibble2code[(b0<<4)&0x3f];
143                     r[ri++]=pad;
144                     r[ri++]=pad;
145                     break;
146
147                 default:
148                     break;
149             }
150         }
151
152         return r;
153     }
154
155     // ------------------------------------------------------------------
156
/**
157      * Base 64 decode as described in RFC 1421.
158      * <p>Does not attempt to cope with extra whitespace
159      * as described in RFC 1521.
160      * @param s String to decode
161      * @return String decoded byte array.
162      */

163     static public String JavaDoc decode(String JavaDoc s)
164     {
165         try
166         {
167             return decode(s,StringUtil.__ISO_8859_1);
168         }
169         catch (UnsupportedEncodingException JavaDoc e)
170         {
171             throw new IllegalArgumentException JavaDoc(e.toString());
172         }
173     }
174
175     // ------------------------------------------------------------------
176
/**
177      * Base 64 decode as described in RFC 1421.
178      * <p>Does not attempt to cope with extra whitespace
179      * as described in RFC 1521.
180      * @param s String to decode
181      * @param charEncoding String representing the character encoding
182      * used to map the decoded bytes into a String.
183      * @return String decoded byte array.
184      */

185     static public String JavaDoc decode(String JavaDoc s,String JavaDoc charEncoding)
186             throws UnsupportedEncodingException JavaDoc
187     {
188         byte[] decoded=decode(s.toCharArray());
189
190         if (charEncoding==null)
191             return new String JavaDoc(decoded);
192         return new String JavaDoc(decoded,charEncoding);
193     }
194
195     /* ------------------------------------------------------------ */
196     /**
197      * Fast Base 64 decode as described in RFC 1421.
198      * <p>Does not attempt to cope with extra whitespace
199      * as described in RFC 1521.
200      * <p> Avoids creating extra copies of the input/output.
201      * <p> Note this code has been flattened for performance.
202      * @param b char array to decode.
203      * @return byte array containing the decoded form of the input.
204      * @throws IllegalArgumentException if the input is not a valid
205      * B64 encoding.
206      */

207     static public byte[] decode(char[] b)
208     {
209         if (b==null)
210             return null;
211
212         int bLen=b.length;
213         if (bLen%4!=0)
214             throw new IllegalArgumentException JavaDoc("Input block size is not 4");
215
216         int li=bLen-1;
217         while (li>=0 && b[li]==(byte)pad)
218             li--;
219
220         if (li<0)
221             return new byte[0];
222
223         // Create result array of exact required size.
224
int rLen=((li+1)*3)/4;
225         byte r[]=new byte[rLen];
226         int ri=0;
227         int bi=0;
228         int stop=(rLen/3)*3;
229         byte b0,b1,b2,b3;
230         try
231         {
232             while (ri<stop)
233             {
234                 b0=code2nibble[b[bi++]];
235                 b1=code2nibble[b[bi++]];
236                 b2=code2nibble[b[bi++]];
237                 b3=code2nibble[b[bi++]];
238                 if (b0<0 || b1<0 || b2<0 || b3<0)
239                     throw new IllegalArgumentException JavaDoc("Not B64 encoded");
240
241                 r[ri++]=(byte)(b0<<2|b1>>>4);
242                 r[ri++]=(byte)(b1<<4|b2>>>2);
243                 r[ri++]=(byte)(b2<<6|b3);
244             }
245
246             if (rLen!=ri)
247             {
248                 switch (rLen%3)
249                 {
250                     case 2:
251                         b0=code2nibble[b[bi++]];
252                         b1=code2nibble[b[bi++]];
253                         b2=code2nibble[b[bi++]];
254                         if (b0<0 || b1<0 || b2<0)
255                             throw new IllegalArgumentException JavaDoc("Not B64 encoded");
256                         r[ri++]=(byte)(b0<<2|b1>>>4);
257                         r[ri++]=(byte)(b1<<4|b2>>>2);
258                         break;
259
260                     case 1:
261                         b0=code2nibble[b[bi++]];
262                         b1=code2nibble[b[bi++]];
263                         if (b0<0 || b1<0)
264                             throw new IllegalArgumentException JavaDoc("Not B64 encoded");
265                         r[ri++]=(byte)(b0<<2|b1>>>4);
266                         break;
267
268                     default:
269                         break;
270                 }
271             }
272         }
273         catch (IndexOutOfBoundsException JavaDoc e)
274         {
275             throw new IllegalArgumentException JavaDoc("char "+bi
276                     +" was not B64 encoded");
277         }
278
279         return r;
280     }
281 }
282
Popular Tags