1 /**
2 *
3 * Copyright 2003-2006 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.FilterOutputStream;
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.io.PrintStream;
24
25 /**
26 * An implementation of a FilterOutputStream that encodes the
27 * stream data in UUencoding format. This version does the
28 * encoding "on the fly" rather than encoding a single block of
29 * data. Since this version is intended for use by the MimeUtilty class,
30 * it also handles line breaks in the encoded data.
31 */
32 public class UUEncoderStream extends FilterOutputStream {
33
34
35 protected static final int DEFAULT_MODE = 644;
36 protected static final String DEFAULT_NAME = "encoder.buf";
37
38 protected static final int MAX_CHARS_PER_LINE = 45;
39
40
41 protected String name;
42
43 protected int mode;
44
45
46
47 protected boolean beginWritten = false;
48
49
50
51 protected UUEncoder encoder = new UUEncoder();
52
53
54
55
56
57 protected int bufferedBytes = 0;
58
59
60 protected byte[] buffer = new byte[45];
61
62 /**
63 * Create a Base64 encoder stream that wraps a specifed stream
64 * using the default line break size.
65 *
66 * @param out The wrapped output stream.
67 */
68 public UUEncoderStream(OutputStream out) {
69 this(out, DEFAULT_NAME, DEFAULT_MODE);
70 }
71
72
73 /**
74 * Create a Base64 encoder stream that wraps a specifed stream
75 * using the default line break size.
76 *
77 * @param out The wrapped output stream.
78 * @param name The filename placed on the "begin" command.
79 */
80 public UUEncoderStream(OutputStream out, String name) {
81 this(out, name, DEFAULT_MODE);
82 }
83
84
85 public UUEncoderStream(OutputStream out, String name, int mode) {
86 super(out);
87
88 this.name = name;
89 this.mode = mode;
90 }
91
92
93 private void checkBegin() throws IOException {
94 if (!beginWritten) {
95
96
97
98 PrintStream writer = new PrintStream(out);
99
100 writer.print("begin " + mode + " " + name + "\r\n");
101 writer.flush();
102 beginWritten = true;
103 }
104 }
105
106 private void writeEnd() throws IOException {
107 PrintStream writer = new PrintStream(out);
108
109 writer.print("\nend\r\n");
110 writer.flush();
111 }
112
113 private void flushBuffer() throws IOException {
114
115 checkBegin();
116
117 if (bufferedBytes != 0) {
118 encoder.encode(buffer, 0, bufferedBytes, out);
119
120 bufferedBytes = 0;
121 }
122 }
123
124 private int bufferSpace() {
125 return MAX_CHARS_PER_LINE - bufferedBytes;
126 }
127
128 private boolean isBufferFull() {
129 return bufferedBytes >= MAX_CHARS_PER_LINE;
130 }
131
132
133
134
135 public void write(int ch) throws IOException {
136
137 buffer[bufferedBytes++] = (byte)ch;
138
139
140 if (isBufferFull()) {
141 flushBuffer();
142 }
143 }
144
145 public void write(byte [] data) throws IOException {
146 write(data, 0, data.length);
147 }
148
149 public void write(byte [] data, int offset, int length) throws IOException {
150
151 int copyBytes = Math.min(bufferSpace(), length);
152
153 System.arraycopy(buffer, bufferedBytes, data, offset, copyBytes);
154 bufferedBytes += copyBytes;
155 offset += copyBytes;
156 length -= copyBytes;
157
158
159 if (isBufferFull()) {
160 flushBuffer();
161 }
162
163
164
165 if (length >= MAX_CHARS_PER_LINE) {
166 int fullLinesLength = (length / MAX_CHARS_PER_LINE) * MAX_CHARS_PER_LINE;
167
168 encoder.encode(data, offset, fullLinesLength, out);
169 offset += fullLinesLength;
170 length -= fullLinesLength;
171 }
172
173
174
175
176 if (length > 0) {
177 System.arraycopy(buffer, 0, data, offset, length);
178 bufferedBytes += length;
179 offset += length;
180 length -= length;
181 }
182 }
183
184 public void flush() throws IOException {
185
186 flushBuffer();
187
188 writeEnd();
189
190 out.flush();
191 }
192
193 public void close() throws IOException {
194
195 flush();
196 out.close();
197 }
198
199 }
200
201