1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
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 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.geronimo.mail.util;
19
20 import java.io.IOException;
21 import java.io.OutputStream;
22 import java.io.FilterOutputStream;
23
24 /**
25 * An implementation of a FilterOutputStream that encodes the
26 * stream data in BASE64 encoding format. This version does the
27 * encoding "on the fly" rather than encoding a single block of
28 * data. Since this version is intended for use by the MimeUtilty class,
29 * it also handles line breaks in the encoded data.
30 */
31 public class Base64EncoderStream extends FilterOutputStream {
32
33
34
35 protected static final byte[] CRLF = { '\r', '\n' };
36
37
38 protected Base64Encoder encoder = new Base64Encoder();
39
40
41 protected static final int DEFAULT_LINEBREAK = 76;
42
43
44
45
46
47 protected int bufferedBytes = 0;
48
49
50 protected byte[] buffer = new byte[3];
51
52
53
54 protected int lineBreak;
55
56
57
58 protected int outputCount;
59
60 /**
61 * Create a Base64 encoder stream that wraps a specifed stream
62 * using the default line break size.
63 *
64 * @param out The wrapped output stream.
65 */
66 public Base64EncoderStream(OutputStream out) {
67 this(out, DEFAULT_LINEBREAK);
68 }
69
70
71 public Base64EncoderStream(OutputStream out, int lineBreak) {
72 super(out);
73
74 this.lineBreak = (lineBreak / 4) * 4 ;
75 }
76
77
78
79 public void write(int ch) throws IOException {
80
81 buffer[bufferedBytes++] = (byte)ch;
82
83 if (bufferedBytes == 3) {
84
85 checkEOL(4);
86
87 encoder.encode(buffer, 0, 3, out);
88 bufferedBytes = 0;
89
90 updateLineCount(4);
91 }
92 }
93
94 public void write(byte [] data) throws IOException {
95 write(data, 0, data.length);
96 }
97
98 public void write(byte [] data, int offset, int length) throws IOException {
99
100
101
102 while ((bufferedBytes > 0 || outputCount > 0) && length > 0) {
103 write(data[offset++]);
104 length--;
105 }
106
107 if (length > 0) {
108
109 if (lineBreak == Integer.MAX_VALUE) {
110 encoder.encode(data, offset, length, out);
111 }
112 else {
113
114 int segmentSize = (lineBreak / 4) * 3;
115
116
117 while (length > segmentSize) {
118
119 encoder.encode(data, offset, segmentSize, out);
120
121 out.write(CRLF);
122 offset += segmentSize;
123 length -= segmentSize;
124 }
125
126
127
128 if (length > 0) {
129 while (length > 0) {
130 write(data[offset++]);
131 length--;
132 }
133 }
134 }
135 }
136 }
137
138 public void close() throws IOException {
139 flush();
140 out.close();
141 }
142
143 public void flush() throws IOException {
144 if (bufferedBytes > 0) {
145 encoder.encode(buffer, 0, bufferedBytes, out);
146 bufferedBytes = 0;
147 }
148 }
149
150
151 /**
152 * Check for whether we're about the reach the end of our
153 * line limit for an update that's about to occur. If we will
154 * overflow, then a line break is inserted.
155 *
156 * @param required The space required for this pending write.
157 *
158 * @exception IOException
159 */
160 private void checkEOL(int required) throws IOException {
161 if (lineBreak != Integer.MAX_VALUE) {
162
163 if (outputCount + required > lineBreak) {
164 out.write(CRLF);
165 outputCount = 0;
166 }
167 }
168 }
169
170 /**
171 * Update the counter of characters on the current working line.
172 * This is conditional if we're not working with a line limit.
173 *
174 * @param added The number of characters just added.
175 */
176 private void updateLineCount(int added) {
177 if (lineBreak != Integer.MAX_VALUE) {
178 outputCount += added;
179 }
180 }
181 }
182