KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > mail > util > BASE64EncoderStream


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)BASE64EncoderStream.java 1.8 05/08/29
24  *
25  * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package com.sun.mail.util;
29
30 import java.io.*;
31
32 /**
33  * This class implements a BASE64 Encoder. It is implemented as
34  * a FilterOutputStream, so one can just wrap this class around
35  * any output stream and write bytes into this filter. The Encoding
36  * is done as the bytes are written out.
37  *
38  * @author John Mani
39  * @author Bill Shannon
40  */

41
42 public class BASE64EncoderStream extends FilterOutputStream {
43     private byte[] buffer; // cache of bytes that are yet to be encoded
44
private int bufsize = 0; // size of the cache
45
private int count = 0; // number of bytes that have been output
46
private int bytesPerLine; // number of bytes per line
47
private int lineLimit; // number of input bytes to output bytesPerLine
48
private boolean noCRLF = false;
49
50     private static byte[] newline = new byte[] { '\r', '\n' };
51
52     /**
53      * Create a BASE64 encoder that encodes the specified input stream
54      * @param out the output stream
55      * @param bytesPerLine number of bytes per line. The encoder inserts
56      * a CRLF sequence after the specified number of bytes,
57      * unless bytesPerLine is Integer.MAX_VALUE, in which
58      * case no CRLF is inserted. bytesPerLine is rounded
59      * down to a multiple of 4.
60      */

61     public BASE64EncoderStream(OutputStream out, int bytesPerLine) {
62     super(out);
63     buffer = new byte[3];
64     if (bytesPerLine == Integer.MAX_VALUE || bytesPerLine < 4) {
65         noCRLF = true;
66         bytesPerLine = 76;
67     }
68     this.bytesPerLine = (bytesPerLine / 4) * 4; // Rounded down to 4n
69
lineLimit = bytesPerLine / 4 * 3;
70     }
71
72     /**
73      * Create a BASE64 encoder that encodes the specified input stream.
74      * Inserts the CRLF sequence after outputting 76 bytes.
75      * @param out the output stream
76      */

77     public BASE64EncoderStream(OutputStream out) {
78     this(out, 76);
79     }
80
81     /**
82      * Encodes <code>len</code> bytes from the specified
83      * <code>byte</code> array starting at offset <code>off</code> to
84      * this output stream.
85      *
86      * @param b the data.
87      * @param off the start offset in the data.
88      * @param len the number of bytes to write.
89      * @exception IOException if an I/O error occurs.
90      */

91     public void write(byte[] b, int off, int len) throws IOException {
92     int inx;
93
94     // finish off incomplete coding unit, and incomplete line
95
while ((bufsize != 0 || count != 0) && len > 0) {
96         write(b[off++]);
97         len--;
98     }
99
100     // do bulk encoding a line at a time.
101
// reuse a single output buffer.
102
byte[] outbuf;
103     if (noCRLF) {
104         outbuf = new byte[bytesPerLine];
105     } else {
106         outbuf = new byte[bytesPerLine + 2];
107         outbuf[bytesPerLine] = (byte)'\r';
108         outbuf[bytesPerLine + 1] = (byte)'\n';
109     }
110     for (inx = 0; inx + lineLimit < len; inx += lineLimit)
111         out.write(encode(b, off + inx, lineLimit, outbuf));
112
113     // handle remaining partial line
114
for (; inx < len; inx++)
115         write(b[off + inx]);
116     }
117
118     /**
119      * Encodes <code>b.length</code> bytes to this output stream.
120      * @param b the data to be written.
121      * @exception IOException if an I/O error occurs.
122      */

123     public void write(byte[] b) throws IOException {
124     write(b, 0, b.length);
125     }
126
127     /**
128      * Encodes the specified <code>byte</code> to this output stream.
129      * @param c the <code>byte</code>.
130      * @exception IOException if an I/O error occurs.
131      */

132     public void write(int c) throws IOException {
133     buffer[bufsize++] = (byte)c;
134     if (bufsize == 3) { // Encoding unit = 3 bytes
135
encode();
136         bufsize = 0;
137     }
138     }
139
140     /**
141      * Flushes this output stream and forces any buffered output bytes
142      * to be encoded out to the stream.
143      * @exception IOException if an I/O error occurs.
144      */

145     public void flush() throws IOException {
146     if (bufsize > 0) { // If there's unencoded characters in the buffer ..
147
encode(); // .. encode them
148
bufsize = 0;
149     }
150     out.flush();
151     }
152
153     /**
154      * Forces any buffered output bytes to be encoded out to the stream
155      * and closes this output stream
156      */

157     public void close() throws IOException {
158     flush();
159     out.close();
160     }
161
162     /** This array maps the characters to their 6 bit values */
163     private final static char pem_array[] = {
164     'A','B','C','D','E','F','G','H', // 0
165
'I','J','K','L','M','N','O','P', // 1
166
'Q','R','S','T','U','V','W','X', // 2
167
'Y','Z','a','b','c','d','e','f', // 3
168
'g','h','i','j','k','l','m','n', // 4
169
'o','p','q','r','s','t','u','v', // 5
170
'w','x','y','z','0','1','2','3', // 6
171
'4','5','6','7','8','9','+','/' // 7
172
};
173
174     private void encode() throws IOException {
175     // If writing out this encoded unit will cause overflow,
176
// start a new line.
177
if (count + 4 > bytesPerLine) {
178         if (!noCRLF)
179         out.write(newline);
180         count = 0;
181     }
182     out.write(encode(buffer, 0, bufsize, null));
183     // increment count
184
count += 4;
185     }
186
187     /**
188      * Base64 encode a byte array. No line breaks are inserted.
189      * This method is suitable for short strings, such as those
190      * in the IMAP AUTHENTICATE protocol, but not to encode the
191      * entire content of a MIME part.
192      */

193     public static byte[] encode(byte[] inbuf) {
194     if (inbuf.length == 0)
195         return inbuf;
196     return encode(inbuf, 0, inbuf.length, null);
197     }
198
199     /**
200      * Internal use only version of encode. Allow specifying which
201      * part of the input buffer to encode. If outbuf is non-null,
202      * it's used as is. Otherwise, a new output buffer is allocated.
203      */

204     private static byte[] encode(byte[] inbuf, int off, int size,
205                 byte[] outbuf) {
206     if (outbuf == null)
207         outbuf = new byte[((size + 2) / 3) * 4];
208     int inpos, outpos;
209     int val;
210     for (inpos = off, outpos = 0; size >= 3; size -= 3, outpos += 4) {
211         val = inbuf[inpos++] & 0xff;
212         val <<= 8;
213         val |= inbuf[inpos++] & 0xff;
214         val <<= 8;
215         val |= inbuf[inpos++] & 0xff;
216         outbuf[outpos+3] = (byte)pem_array[val & 0x3f];
217         val >>= 6;
218         outbuf[outpos+2] = (byte)pem_array[val & 0x3f];
219         val >>= 6;
220         outbuf[outpos+1] = (byte)pem_array[val & 0x3f];
221         val >>= 6;
222         outbuf[outpos+0] = (byte)pem_array[val & 0x3f];
223     }
224     // done with groups of three, finish up any odd bytes left
225
if (size == 1) {
226         val = inbuf[inpos++] & 0xff;
227         val <<= 4;
228         outbuf[outpos+3] = (byte)'='; // pad character;
229
outbuf[outpos+2] = (byte)'='; // pad character;
230
outbuf[outpos+1] = (byte)pem_array[val & 0x3f];
231         val >>= 6;
232         outbuf[outpos+0] = (byte)pem_array[val & 0x3f];
233     } else if (size == 2) {
234         val = inbuf[inpos++] & 0xff;
235         val <<= 8;
236         val |= inbuf[inpos++] & 0xff;
237         val <<= 2;
238         outbuf[outpos+3] = (byte)'='; // pad character;
239
outbuf[outpos+2] = (byte)pem_array[val & 0x3f];
240         val >>= 6;
241         outbuf[outpos+1] = (byte)pem_array[val & 0x3f];
242         val >>= 6;
243         outbuf[outpos+0] = (byte)pem_array[val & 0x3f];
244     }
245     return outbuf;
246     }
247
248     /*** begin TEST program
249     public static void main(String argv[]) throws Exception {
250     FileInputStream infile = new FileInputStream(argv[0]);
251     BASE64EncoderStream encoder = new BASE64EncoderStream(System.out);
252     int c;
253
254     while ((c = infile.read()) != -1)
255         encoder.write(c);
256     encoder.close();
257     }
258     *** end TEST program **/

259 }
260
Popular Tags