KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > mail > util > UUDecoderStream


1 /*
2   GNU-Classpath Extensions: javamail
3   Copyright (C) 2000 2001 Andrew Selkirk, Nic Ferrier
4
5   For more information on the classpathx please mail: nferrier@tapsellferrier.co.uk
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Lesser General Public License
9   as published by the Free Software Foundation; either version 2
10   of the License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */

21 package gnu.mail.util;
22
23 import java.io.InputStream JavaDoc;
24 import java.io.FilterInputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26
27
28 /**
29  * A stream that does UU Decoding.
30  * UU-Decoding is defined in the MIME rfcs.
31  *
32  * @author Andrew Selkirk: aselkirk@mailandnews.com
33  * @author Nic Ferrier: nferrier@tapsellferrier.co.uk
34  * @version 1.0
35  */

36 public class UUDecoderStream
37   extends FilterInputStream JavaDoc
38 {
39
40   /** buffer of bytes to be decoded.
41    */

42   private byte[] decode_buffer;
43
44   /** current number of bytes in buffer to be decoded.
45    */

46   private int index;
47
48   /** decoded buffer.
49    */

50   private byte[] buffer;
51
52   /** current number of bytes in buffer.
53    */

54   private int bufsize;
55
56   /** flag to indicate if prefix read.
57    */

58   private boolean hasPrefix;
59
60   /** name of file to be uudecoded.
61    */

62   protected String JavaDoc name;
63
64   /** permission mode of file.
65    */

66   protected int mode;
67
68   /** create a new UU-Decoding stream.
69    *
70    * @param stream Input stream
71    */

72   public UUDecoderStream(InputStream JavaDoc in)
73   {
74     super(in);
75     if (!(in instanceof LineInputStream))
76       this.in = new LineInputStream(in);
77     this.name = null;
78     this.mode = -1;
79     hasPrefix = false;
80     buffer = new byte[45];
81     bufsize = 0;
82     decode_buffer = new byte[60];
83     index = 0;
84   }
85
86   /** @return Name of file
87    * @throws IOException IO Exception occurred
88    */

89   public String JavaDoc getName()
90     throws IOException JavaDoc
91   {
92     if (!hasPrefix)
93       readPrefix();
94     return name;
95   }
96
97   /**
98    * Decode bytes in decode_buffer to buffer for reading.
99    * @throws IOException IO Exception occurred
100    */

101   private void decode()
102     throws IOException JavaDoc
103   {
104     int decode_index;
105     int c1;
106     int c2;
107     int c3;
108     int c4;
109     int a;
110     int b;
111     int c;
112     // Process bytes in groups of four
113
decode_index = 0;
114     index = 0;
115     bufsize = 0;
116     while (decode_index < decode_buffer.length)
117     {
118       // Read in 4 bytes
119
c1 = (decode_buffer[decode_index] - ' ') & 0x3f;
120       c2 = (decode_buffer[decode_index+1] - ' ') & 0x3f;
121       c3 = (decode_buffer[decode_index+2] - ' ') & 0x3f;
122       c4 = (decode_buffer[decode_index+3] - ' ') & 0x3f;
123       // Decode Bytes
124
a = ((c1 << 2) & 0xfc) | ((c2 >>> 4) & 3);
125       b = ((c2 << 4) & 0xf0) | ((c3 >>> 2) & 0xf);
126       c = ((c3 << 6) & 0xc0) | (c4 & 0x3f);
127       // Store Decoded Bytes in read buffer
128
buffer[bufsize] = (byte) (a & 0xff);
129       buffer[bufsize+1] = (byte) (b & 0xff);
130       buffer[bufsize+2] = (byte) (c & 0xff);
131       // Increment Index
132
decode_index += 4;
133       bufsize += 3;
134     }
135   }
136
137   /**
138    * Read byte from decoded buffer.
139    * If buffer empty, the next line of encoded bytes
140    * is read and decoded.
141    *
142    * @return next byte
143    * @throws IOException IO Exception occurred
144    */

145   public int read()
146     throws IOException JavaDoc
147   {
148     int next;
149     int lengthByte;
150     int length;
151     int decodeLength;
152     int result;
153     String JavaDoc line;
154     // Check for Read Prefix
155
if (hasPrefix == false)
156       readPrefix();
157     // Check for Reading in Decoding buffer
158
LineInputStream lin = (LineInputStream)in;
159     if (index == bufsize)
160     {
161       // Read Line
162
line = lin.readLine();
163       // Get Length
164
lengthByte = line.getBytes()[0];
165       length = (lengthByte - ' ') & 0x3f;
166       // Check for Decoded length
167
if (length > 45)
168         throw new IOException JavaDoc("UUDecode error: line length to large ("
169             + length + ")");
170       // Check for End
171
if (length == 0)
172       {
173         readSuffix();
174         return -1;
175       }
176       // Get Encoded Line Size
177
decodeLength = line.length() - 1;
178       // Check for encoded line length multiple of 4
179
if ((decodeLength % 4) != 0)
180         throw new IOException JavaDoc("UUDecode error: line length not multiple of 4 ("
181             + decodeLength + ")");
182       // Get Encoded Line
183
decode_buffer = line.substring(1).getBytes();
184       // Decode Buffer
185
decode();
186     }
187     // Get Next Byte
188
next = buffer[index];
189     // Increment Index
190
index += 1;
191     return next;
192   }
193
194   /**
195    * Read byte from decoded buffer.
196    * If buffer empty, the next line of encoded bytes is read and decoded.
197    *
198    * @param bytes Byte array to write bytes into
199    * @param offset Offset of array to write
200    * @param length Number of bytes to write
201    * @return Number of bytes read
202    * @throws IOException IO Exception occurred
203    */

204   public int read(byte[] bytes, int offset, int length)
205     throws IOException JavaDoc
206   {
207     // FIXME: This implementation is not as efficient as
208
// it could be. Instead of delegating the work to
209
// read(), the bytes should be read in bulk
210
// to the buffer and initiating decoding if necessary.
211
// This idea does introduce some duplication of code.
212
int index;
213     // Write Bytes
214
for (index = offset; index < length; index++)
215       bytes[index] = (byte) read();
216     // Return Number of bytes
217
return length - offset;
218   }
219
220   /** @return the number of bytes that are available that will not block.
221    * @throws IOException IO Exception occurred
222    */

223   public int available()
224     throws IOException JavaDoc
225   {
226     if (hasPrefix == false)
227     {
228       readPrefix();
229       read();
230       index = 0;
231     }
232     // Calculate # bytes left in current buffer
233
return bufsize - index;
234   }
235
236   /** @return false because mark is not supported in UU Decoding.
237    */

238   public boolean markSupported()
239   {
240     return false;
241   }
242
243   /** get mode from UU-Decoding.
244    *
245    * @return File permission mode
246    * @throws IOException IO Exception occurred
247    */

248   public int getMode()
249     throws IOException JavaDoc
250   {
251     if (!hasPrefix)
252       readPrefix();
253     return mode;
254   }
255
256   /**
257    * Read prefix.
258    *
259    * @throws IOException IO Exception occurred
260    */

261   private void readPrefix()
262     throws IOException JavaDoc
263   {
264     // Note: One enhancement for this is to scan lines
265
// until we find a 'begin'. This way, it is fine
266
// if there are a number of newlines before the
267
// stream begins.
268
// Get First line
269
String JavaDoc line = ((LineInputStream)in).readLine();
270     // Check for 'begin'
271
if (!line.startsWith("begin") == false)
272       throw new IOException JavaDoc("UUDecoder error: No Begin");
273     // Check for Mode
274
try
275     {
276       mode = Integer.parseInt(line.substring(6, 9));
277     }
278     catch (Exception JavaDoc e)
279     {
280       throw new IOException JavaDoc("UUDecoder error: Unable to determine mode");
281     }
282     // Check for name
283
try
284     {
285       name = line.substring(10);
286     }
287     catch (Exception JavaDoc e)
288     {
289       throw new IOException JavaDoc("UUDecoder error: Unable to determine name");
290     }
291     // Mark Prefix Read
292
hasPrefix = true;
293   }
294
295   /**
296    * Read suffix.
297    *
298    * @throws IOException IO Exception occurred
299    */

300   private void readSuffix()
301     throws IOException JavaDoc
302   {
303     // Get First line
304
String JavaDoc line = ((LineInputStream)in).readLine();
305     // Check for 'end'
306
if (!line.startsWith("end"))
307       throw new IOException JavaDoc("UUDecoder error: No End: " + line);
308   }
309
310 }
311
Popular Tags