KickJava   Java API By Example, From Geeks To Geeks.

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


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  * @(#)UUDecoderStream.java 1.9 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 UUDecoder. It is implemented as
34  * a FilterInputStream, so one can just wrap this class around
35  * any input stream and read bytes from this filter. The decoding
36  * is done as the bytes are read out.
37  *
38  * @author John Mani
39  * @author Bill Shannon
40  */

41
42 public class UUDecoderStream extends FilterInputStream {
43     private String JavaDoc name;
44     private int mode;
45
46     private byte[] buffer; // cache of decoded bytes
47
private int bufsize = 0; // size of the cache
48
private int index = 0; // index into the cache
49
private boolean gotPrefix = false;
50     private boolean gotEnd = false;
51     private LineInputStream lin;
52
53     /**
54      * Create a UUdecoder that decodes the specified input stream
55      * @param in the input stream
56      */

57     public UUDecoderStream(InputStream in) {
58     super(in);
59     lin = new LineInputStream(in);
60     buffer = new byte[45]; // max decoded chars in a line = 45
61
}
62
63     /**
64      * Read the next decoded byte from this input stream. The byte
65      * is returned as an <code>int</code> in the range <code>0</code>
66      * to <code>255</code>. If no byte is available because the end of
67      * the stream has been reached, the value <code>-1</code> is returned.
68      * This method blocks until input data is available, the end of the
69      * stream is detected, or an exception is thrown.
70      *
71      * @return next byte of data, or <code>-1</code> if the end of
72      * stream is reached.
73      * @exception IOException if an I/O error occurs.
74      * @see java.io.FilterInputStream#in
75      */

76
77     public int read() throws IOException {
78     if (index >= bufsize) {
79         readPrefix();
80         if (!decode())
81         return -1;
82         index = 0; // reset index into buffer
83
}
84     return buffer[index++] & 0xff; // return lower byte
85
}
86
87     public int read(byte[] buf, int off, int len) throws IOException {
88     int i, c;
89     for (i = 0; i < len; i++) {
90         if ((c = read()) == -1) {
91         if (i == 0) // At end of stream, so we should
92
i = -1; // return -1, NOT 0.
93
break;
94         }
95         buf[off+i] = (byte)c;
96     }
97     return i;
98     }
99
100     public boolean markSupported() {
101     return false;
102     }
103
104     public int available() throws IOException {
105      // This is only an estimate, since in.available()
106
// might include CRLFs too ..
107
return ((in.available() * 3)/4 + (bufsize-index));
108     }
109
110     /**
111      * Get the "name" field from the prefix. This is meant to
112      * be the pathname of the decoded file
113      *
114      * @return name of decoded file
115      * @exception IOException if an I/O error occurs.
116      */

117     public String JavaDoc getName() throws IOException {
118     readPrefix();
119     return name;
120     }
121
122     /**
123      * Get the "mode" field from the prefix. This is the permission
124      * mode of the source file.
125      *
126      * @return permission mode of source file
127      * @exception IOException if an I/O error occurs.
128      */

129     public int getMode() throws IOException {
130     readPrefix();
131     return mode;
132     }
133
134     /**
135      * UUencoded streams start off with the line:
136      * "begin <mode> <filename>"
137      * Search for this prefix and gobble it up.
138      */

139     private void readPrefix() throws IOException {
140     if (gotPrefix) // got the prefix
141
return;
142
143     String JavaDoc s;
144     for (;;) {
145         // read till we get the prefix: "begin MODE FILENAME"
146
s = lin.readLine(); // NOTE: readLine consumes CRLF pairs too
147
if (s == null)
148         throw new IOException("UUDecoder error: No Begin");
149         if (s.regionMatches(true, 0, "begin", 0, 5)) {
150         try {
151             mode = Integer.parseInt(s.substring(6,9));
152         } catch (NumberFormatException JavaDoc ex) {
153             throw new IOException("UUDecoder error: " + ex.toString());
154         }
155         name = s.substring(10);
156         gotPrefix = true;
157         return;
158         }
159     }
160     }
161
162     private boolean decode() throws IOException {
163
164     if (gotEnd)
165         return false;
166     bufsize = 0;
167     String JavaDoc line;
168     do {
169         line = lin.readLine();
170
171         /*
172          * Improperly encoded data sometimes omits the zero length
173          * line that starts with a space character, we detect the
174          * following "end" line here.
175          */

176         if (line == null)
177         throw new IOException("Missing End");
178         if (line.regionMatches(true, 0, "end", 0, 3)) {
179         gotEnd = true;
180         return false;
181         }
182     } while (line.length() == 0);
183     int count = line.charAt(0);
184     if (count < ' ')
185         throw new IOException("Buffer format error");
186
187     /*
188      * The first character in a line is the number of original (not
189      * the encoded atoms) characters in the line. Note that all the
190      * code below has to handle the <SPACE> character that indicates
191      * end of encoded stream.
192      */

193     count = (count - ' ') & 0x3f;
194
195     if (count == 0) {
196         line = lin.readLine();
197         if (line == null || !line.regionMatches(true, 0, "end", 0, 3))
198         throw new IOException("Missing End");
199         gotEnd = true;
200         return false;
201     }
202
203     int need = ((count * 8)+5)/6;
204 //System.out.println("count " + count + ", need " + need + ", len " + line.length());
205
if (line.length() < need + 1)
206         throw new IOException("Short buffer error");
207         
208     int i = 1;
209     byte a, b;
210     /*
211      * A correct uuencoder always encodes 3 characters at a time, even
212      * if there aren't 3 characters left. But since some people out
213      * there have broken uuencoders we handle the case where they
214      * don't include these "unnecessary" characters.
215      */

216     while (bufsize < count) {
217         // continue decoding until we get 'count' decoded chars
218
a = (byte)((line.charAt(i++) - ' ') & 0x3f);
219         b = (byte)((line.charAt(i++) - ' ') & 0x3f);
220         buffer[bufsize++] = (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3));
221
222         if (bufsize < count) {
223         a = b;
224         b = (byte)((line.charAt(i++) - ' ') & 0x3f);
225         buffer[bufsize++] =
226                 (byte)(((a << 4) & 0xf0) | ((b >>> 2) & 0xf));
227         }
228
229         if (bufsize < count) {
230         a = b;
231         b = (byte)((line.charAt(i++) - ' ') & 0x3f);
232         buffer[bufsize++] = (byte)(((a << 6) & 0xc0) | (b & 0x3f));
233         }
234     }
235     return true;
236     }
237
238     /*** begin TEST program *****
239     public static void main(String argv[]) throws Exception {
240         FileInputStream infile = new FileInputStream(argv[0]);
241     UUDecoderStream decoder = new UUDecoderStream(infile);
242     int c;
243
244     try {
245         while ((c = decoder.read()) != -1)
246         System.out.write(c);
247         System.out.flush();
248     } catch (Exception e) {
249         e.printStackTrace();
250     }
251     }
252     **** end TEST program ****/

253 }
254
Popular Tags