blob: 42edd58cadb3eb1607aeba8f49a8c40a92e787e0 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1995-2001 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package sun.misc;
26
27import java.io.PushbackInputStream;
28import java.io.OutputStream;
29import java.io.PrintStream;
30import java.io.IOException;
31
32/**
33 * This class implements a Berkeley uu character decoder. This decoder
34 * was made famous by the uudecode program.
35 *
36 * The basic character coding is algorithmic, taking 6 bits of binary
37 * data and adding it to an ASCII ' ' (space) character. This converts
38 * these six bits into a printable representation. Note that it depends
39 * on the ASCII character encoding standard for english. Groups of three
40 * bytes are converted into 4 characters by treating the three bytes
41 * a four 6 bit groups, group 1 is byte 1's most significant six bits,
42 * group 2 is byte 1's least significant two bits plus byte 2's four
43 * most significant bits. etc.
44 *
45 * In this encoding, the buffer prefix is:
46 * <pre>
47 * begin [mode] [filename]
48 * </pre>
49 *
50 * This is followed by one or more lines of the form:
51 * <pre>
52 * (len)(data)(data)(data) ...
53 * </pre>
54 * where (len) is the number of bytes on this line. Note that groupings
55 * are always four characters, even if length is not a multiple of three
56 * bytes. When less than three characters are encoded, the values of the
57 * last remaining bytes is undefined and should be ignored.
58 *
59 * The last line of data in a uuencoded buffer is represented by a single
60 * space character. This is translated by the decoding engine to a line
61 * length of zero. This is immediately followed by a line which contains
62 * the word 'end[newline]'
63 *
64 * If an error is encountered during decoding this class throws a
65 * CEFormatException. The specific detail messages are:
66 *
67 * <pre>
68 * "UUDecoder: No begin line."
69 * "UUDecoder: Malformed begin line."
70 * "UUDecoder: Short Buffer."
71 * "UUDecoder: Bad Line Length."
72 * "UUDecoder: Missing 'end' line."
73 * </pre>
74 *
75 * @author Chuck McManis
76 * @see CharacterDecoder
77 * @see UUEncoder
78 */
79public class UUDecoder extends CharacterDecoder {
80
81 /**
82 * This string contains the name that was in the buffer being decoded.
83 */
84 public String bufferName;
85
86 /**
87 * Represents UNIX(tm) mode bits. Generally three octal digits
88 * representing read, write, and execute permission of the owner,
89 * group owner, and others. They should be interpreted as the bit groups:
90 * <pre>
91 * (owner) (group) (others)
92 * rwx rwx rwx (r = read, w = write, x = execute)
93 *</pre>
94 *
95 */
96 public int mode;
97
98
99 /**
100 * UU encoding specifies 3 bytes per atom.
101 */
102 protected int bytesPerAtom() {
103 return (3);
104 }
105
106 /**
107 * All UU lines have 45 bytes on them, for line length of 15*4+1 or 61
108 * characters per line.
109 */
110 protected int bytesPerLine() {
111 return (45);
112 }
113
114 /** This is used to decode the atoms */
115 private byte decoderBuffer[] = new byte[4];
116
117 /**
118 * Decode a UU atom. Note that if l is less than 3 we don't write
119 * the extra bits, however the encoder always encodes 4 character
120 * groups even when they are not needed.
121 */
122 protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int l)
123 throws IOException {
124 int i, c1, c2, c3, c4;
125 int a, b, c;
126 StringBuffer x = new StringBuffer();
127
128 for (i = 0; i < 4; i++) {
129 c1 = inStream.read();
130 if (c1 == -1) {
131 throw new CEStreamExhausted();
132 }
133 x.append((char)c1);
134 decoderBuffer[i] = (byte) ((c1 - ' ') & 0x3f);
135 }
136 a = ((decoderBuffer[0] << 2) & 0xfc) | ((decoderBuffer[1] >>> 4) & 3);
137 b = ((decoderBuffer[1] << 4) & 0xf0) | ((decoderBuffer[2] >>> 2) & 0xf);
138 c = ((decoderBuffer[2] << 6) & 0xc0) | (decoderBuffer[3] & 0x3f);
139 outStream.write((byte)(a & 0xff));
140 if (l > 1) {
141 outStream.write((byte)( b & 0xff));
142 }
143 if (l > 2) {
144 outStream.write((byte)(c&0xff));
145 }
146 }
147
148 /**
149 * For uuencoded buffers, the data begins with a line of the form:
150 * begin MODE FILENAME
151 * This line always starts in column 1.
152 */
153 protected void decodeBufferPrefix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
154 int c;
155 StringBuffer q = new StringBuffer(32);
156 String r;
157 boolean sawNewLine;
158
159 /*
160 * This works by ripping through the buffer until it finds a 'begin'
161 * line or the end of the buffer.
162 */
163 sawNewLine = true;
164 while (true) {
165 c = inStream.read();
166 if (c == -1) {
167 throw new CEFormatException("UUDecoder: No begin line.");
168 }
169 if ((c == 'b') && sawNewLine){
170 c = inStream.read();
171 if (c == 'e') {
172 break;
173 }
174 }
175 sawNewLine = (c == '\n') || (c == '\r');
176 }
177
178 /*
179 * Now we think its begin, (we've seen ^be) so verify it here.
180 */
181 while ((c != '\n') && (c != '\r')) {
182 c = inStream.read();
183 if (c == -1) {
184 throw new CEFormatException("UUDecoder: No begin line.");
185 }
186 if ((c != '\n') && (c != '\r')) {
187 q.append((char)c);
188 }
189 }
190 r = q.toString();
191 if (r.indexOf(' ') != 3) {
192 throw new CEFormatException("UUDecoder: Malformed begin line.");
193 }
194 mode = Integer.parseInt(r.substring(4,7));
195 bufferName = r.substring(r.indexOf(' ',6)+1);
196 /*
197 * Check for \n after \r
198 */
199 if (c == '\r') {
200 c = inStream.read ();
201 if ((c != '\n') && (c != -1))
202 inStream.unread (c);
203 }
204 }
205
206 /**
207 * In uuencoded buffers, encoded lines start with a character that
208 * represents the number of bytes encoded in this line. The last
209 * line of input is always a line that starts with a single space
210 * character, which would be a zero length line.
211 */
212 protected int decodeLinePrefix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
213 int c;
214
215 c = inStream.read();
216 if (c == ' ') {
217 c = inStream.read(); /* discard the (first)trailing CR or LF */
218 c = inStream.read(); /* check for a second one */
219 if ((c != '\n') && (c != -1))
220 inStream.unread (c);
221 throw new CEStreamExhausted();
222 } else if (c == -1) {
223 throw new CEFormatException("UUDecoder: Short Buffer.");
224 }
225
226 c = (c - ' ') & 0x3f;
227 if (c > bytesPerLine()) {
228 throw new CEFormatException("UUDecoder: Bad Line Length.");
229 }
230 return (c);
231 }
232
233
234 /**
235 * Find the end of the line for the next operation.
236 * The following sequences are recognized as end-of-line
237 * CR, CR LF, or LF
238 */
239 protected void decodeLineSuffix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
240 int c;
241 while (true) {
242 c = inStream.read();
243 if (c == -1) {
244 throw new CEStreamExhausted();
245 }
246 if (c == '\n') {
247 break;
248 }
249 if (c == '\r') {
250 c = inStream.read();
251 if ((c != '\n') && (c != -1)) {
252 inStream.unread (c);
253 }
254 break;
255 }
256 }
257 }
258
259 /**
260 * UUencoded files have a buffer suffix which consists of the word
261 * end. This line should immediately follow the line with a single
262 * space in it.
263 */
264 protected void decodeBufferSuffix(PushbackInputStream inStream, OutputStream outStream) throws IOException {
265 int c;
266
267 c = inStream.read(decoderBuffer);
268 if ((decoderBuffer[0] != 'e') || (decoderBuffer[1] != 'n') ||
269 (decoderBuffer[2] != 'd')) {
270 throw new CEFormatException("UUDecoder: Missing 'end' line.");
271 }
272 }
273
274}